commit 6d9042e93d87e1e915ee9ee03a03c6372c626f7e
Author: JetBoom
Date: Wed Oct 1 20:49:54 2014 -0400
Imported from SVN.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..550a88b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,50 @@
+JBGM LICENSE
+
+VERSION Xx420xX2, 5 January 2014
+
+Copyright © 2013 William Moodhe
+
+Anyone is allowed to copy, upload, or distribute copies of this license, but changing it is not allowed.
+
+Preamble
+
+The GNU license was garbage so I made my own. If you don't like it then feel free to delete the gamemode.
+A good portion of people have seen fit to modify stuff I've made, make it so people can "donate" for premium features, and subsequently generate revenue using things that I and others have created without permission. Then they ban members of my Steam groups, DDoS my own servers, openly insult me despite never having talked to me, and be jerks in general.
+
+So I will be issuing DMCA take down notices to server hosts and others who think that I'm joking. Server hosts have typically sided with me during the few times I've needed to do this. I don't plan on being 'that guy' and going after gmod servers trying to stay alive but I do plan on weeding out a few of the bigger jerks out there.
+
+tl;dr - I won't screw with you if you don't screw with me.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+TERMS AND CONDITIONS
+
+0. Definitions
+
+"License" refers to this file. An updated version is available at . The version at is always correct and up-to-date.
+
+"Author" refers to the person William Moodhe
+
+"Content" refers to all files and folders that the license came with as well as the intellectual property and all derivitive works.
+
+"Copyright" refers to the laws on intellectual property and the legal rights automatically granted to the Author during the creation of the Content.
+
+"Modify" refers to editing the Content as well as creating programs or code which depends on the Content to run. For the purpose of this license, deleting things without deleting the entire Content is ALSO considered editing.
+
+1. For any conditions not outlined in the License, refer to your country or state laws for Copyright.
+[Host your server in Russia.]
+
+2. You may freely copy, distribute, create derivitive works and distribute derivitive works of the Content as long as you obey the License and the License is not Modified.
+[Feel free to make edits.]
+
+3. You will not Modify the Content in such a way that it will, directly or indirectly, generate revenue without explicit, written permission from the Author.
+[For example: making it so you can pay to have extra health, points, speed, etc.]
+
+4. You will not deny access to the Author to anything in such a way that it would not allow the Author to see if the Gamemode was Modified.
+[For example: banning my Steam groups from your server.]
+
+5. You will not host, distribute, Modify, or otherwise copy the Content if you are affiliated with HeLLsGamers .
+
+6. If you do not agree to any of the above conditions you must delete the Content in its entirety as well as all copies of the Content and derivitive works of the Content that you have made.
+
+END TERMS AND CONDITIONS
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..699dd88
--- /dev/null
+++ b/README.md
@@ -0,0 +1,55 @@
+ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
+ZZZ ZZZ
+ZZZ ZOMBIE SURVIVAL ZZZ
+ZZZ THE DEFINITIVE ZOMBIE EXPERIENCE ZZZ
+ZZZ A GAMEMODE FOR GMOD ZZZ
+ZZZ ZZZ
+ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
+
+Created and programmed by William "JetBoom" Moodhe
+E-mail: williammoodhe@gmail.com
+Alternate e-mail: jetboom@noxiousnet.com
+Web: http://www.noxiousnet.com
+
+Additional credits:
+Zombie view models 11k (tjd113@gmail.com)
+Zombie kill icons Eisiger (k2deseve@gmail.com)
+Some HUD textures Typhon (lukas-tinel@hotmail.com)
+Ambient beat sounds Austin "Little Nemo" Killey (austin_odyssey@yahoo.com)
+Melee weapon models Zombie Panic: Source (http://www.zombiepanic.org/)
+Board Kit model Samuel (samuel_games@hotmail.com)
+
+
+ ZZZZZZZZZZZZZZZZZZZZZZZZZ
+ZZ ZZ
+ZZ INSTALL ZZ
+ZZ ZZ
+ ZZZZZZZZZZZZZZZZZZZZZZZZZ
+
+1. Put the zombiesurvival folder in garrysmod/gamemodes with all the other gamemode folders.
+2. In console: gamemode zombiesurvival
+3. Run a zs_ map.
+
+
+ ZZZZZZZZZZZZZZZZZZZZZZZZZ
+ZZ ZZ
+ZZ RUNNING SERVERS ZZ
+ZZ ZZ
+ ZZZZZZZZZZZZZZZZZZZZZZZZZ
+
+1. Get srcds and configure it for garrysmod (requires steamcmd).
+2. Put the zombiesurvival folder in garrysmod/gamemodes with all the other gamemode folders.
+3. Get some maps. ZS_ maps are plentiful on the Internet and the game also supports many other map types: CS:S, Zombie Mod, Zombie Horde, Zombie Panic! Source
+4. Either setup a custom voting script or use mapcycle_zombiesurvival.txt. Make a file called mapcycle_zombiesurvival.txt in base garrysmod folder. Put in names of maps without the .bsp ending. One per line.
+5. Make your auto-start batch file or whatever you use. The line should look like this:
+srcds.exe -port 27015 -console -game garrysmod -secure +ip 24.102.103.104 +hostport 27015 +gamemode zombiesurvival +maxplayers 32 +map zs_oldhouse +hostname "Your ZS Server"
+6. Run it. You now have a server. See other guides on the web for setting up sv_downloadurl.
+
+
+ ZZZZZZZZZZZZZZZZZZZZZZZZ
+ZZ ZZ
+ZZ LEGAL JARGON ZZ
+ZZ ZZ
+ ZZZZZZZZZZZZZZZZZZZZZZZZZ
+
+See license file
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/backgrounds/zs_obj_mental_hospital_v30000.jpg b/gamemodes/zombiesurvival/backgrounds/zs_obj_mental_hospital_v30000.jpg
new file mode 100644
index 0000000..9bcce9d
Binary files /dev/null and b/gamemodes/zombiesurvival/backgrounds/zs_obj_mental_hospital_v30000.jpg differ
diff --git a/gamemodes/zombiesurvival/backgrounds/zs_obj_mental_hospital_v30002.jpg b/gamemodes/zombiesurvival/backgrounds/zs_obj_mental_hospital_v30002.jpg
new file mode 100644
index 0000000..7da36a4
Binary files /dev/null and b/gamemodes/zombiesurvival/backgrounds/zs_obj_mental_hospital_v30002.jpg differ
diff --git a/gamemodes/zombiesurvival/backgrounds/zs_obj_mental_hospital_v30004.jpg b/gamemodes/zombiesurvival/backgrounds/zs_obj_mental_hospital_v30004.jpg
new file mode 100644
index 0000000..d45b692
Binary files /dev/null and b/gamemodes/zombiesurvival/backgrounds/zs_obj_mental_hospital_v30004.jpg differ
diff --git a/gamemodes/zombiesurvival/backgrounds/zs_obj_mental_hospital_v30005.jpg b/gamemodes/zombiesurvival/backgrounds/zs_obj_mental_hospital_v30005.jpg
new file mode 100644
index 0000000..8edea95
Binary files /dev/null and b/gamemodes/zombiesurvival/backgrounds/zs_obj_mental_hospital_v30005.jpg differ
diff --git a/gamemodes/zombiesurvival/backgrounds/zs_obj_mental_hospital_v30006.jpg b/gamemodes/zombiesurvival/backgrounds/zs_obj_mental_hospital_v30006.jpg
new file mode 100644
index 0000000..93bdaca
Binary files /dev/null and b/gamemodes/zombiesurvival/backgrounds/zs_obj_mental_hospital_v30006.jpg differ
diff --git a/gamemodes/zombiesurvival/backgrounds/zs_snow0000.jpg b/gamemodes/zombiesurvival/backgrounds/zs_snow0000.jpg
new file mode 100644
index 0000000..0138518
Binary files /dev/null and b/gamemodes/zombiesurvival/backgrounds/zs_snow0000.jpg differ
diff --git a/gamemodes/zombiesurvival/content/data/profiler_premade/zm_vampire_medical_v3.txt b/gamemodes/zombiesurvival/content/data/profiler_premade/zm_vampire_medical_v3.txt
new file mode 100644
index 0000000..2d0aa08
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/profiler_premade/zm_vampire_medical_v3.txt
@@ -0,0 +1 @@
+SRL={Vector(871.37573242188,360.42572021484,-368.16879272461),Vector(875.85546875,719.78149414063,-368.16879272461),Vector(1155.1715087891,373.64172363281,212.6312713623),Vector(1347.3875732422,364.45297241211,212.6312713623),Vector(863.03234863281,703.64544677734,212.6312713623),Vector(1677.6591796875,513.53448486328,212.6312713623),Vector(834.53839111328,513.53387451172,212.63125610352),Vector(1249.8787841797,514.57690429688,212.6312713623),Vector(1162.1968994141,664.27563476563,212.63125610352),Vector(1259.6378173828,684.08599853516,-368.16879272461),Vector(1121.6794433594,993.43444824219,-368.16879272461),Vector(1464.2072753906,858.39038085938,-368.16879272461),Vector(1575.0606689453,15.023586273193,-368.16879272461),Vector(829.68444824219,900.55517578125,1.4312362670898)}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/profiler_premade/zs_asylum_reborn_b2.txt b/gamemodes/zombiesurvival/content/data/profiler_premade/zs_asylum_reborn_b2.txt
new file mode 100644
index 0000000..9eadfac
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/profiler_premade/zs_asylum_reborn_b2.txt
@@ -0,0 +1 @@
+SRL={Vector(1157.9351806641,220.32820129395,0.03125),Vector(1238.9333496094,215.02139282227,0.03125),Vector(1080.5122070313,207.50448608398,0.031257629394531),Vector(698.59252929688,386.18795776367,0.03125),Vector(846.43914794922,391.46920776367,0.03125),Vector(878.9755859375,126.01952362061,0.03125),Vector(699.96795654297,118.95901489258,0.03125),Vector(-777.42419433594,-101.4363861084,132.03125),Vector(-939.33502197266,-862.88177490234,132.03125),Vector(-582.48016357422,-896.11877441406,132.03125),Vector(-1221.58984375,80.204383850098,0.03125),Vector(-1230.2156982422,394.02905273438,128.03125),Vector(-598.71343994141,-437.43853759766,132.03125),Vector(-953.23559570313,-418.38458251953,132.03125),Vector(-209.88269042969,-718.51000976563,132.03125),Vector(-120.6521987915,-655.98040771484,0.03125),Vector(-321.83212280273,-935.94995117188,0.03125),Vector(-591.61437988281,-941.36633300781,0.03125),Vector(-593.89935302734,-801.06774902344,0.03125),Vector(-462.26495361328,-756.79211425781,0.03125),Vector(-532.95349121094,-590.29205322266,0.031257629394531),Vector(-839.83447265625,-951.7314453125,0.03125),Vector(-962.10803222656,-568.29797363281,0.03125),Vector(-1227.3950195313,-1039.7943115234,0.03125),Vector(956.48846435547,-326.80352783203,132.03125),Vector(-0.48359489440918,266.01257324219,0.031265258789063),Vector(-1074.3967285156,442.35125732422,0.03125),Vector(-934.98754882813,-89.87629699707,0.03125),Vector(-949.40582275391,-301.48315429688,0.03125),Vector(-718.46716308594,-81.181213378906,0.031242370605469),Vector(-1226.6297607422,-564.62634277344,0.03125),Vector(-634.35540771484,-396.59399414063,0.031242370605469),Vector(735.63562011719,-953.58331298828,132.03125),Vector(-636.85198974609,-95.365615844727,132.03125),Vector(739.98321533203,-742.23834228516,0.03125),Vector(-1285.1569824219,-1058.8470458984,128.03125)}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/profiler_premade/zs_church_fix.txt b/gamemodes/zombiesurvival/content/data/profiler_premade/zs_church_fix.txt
new file mode 100644
index 0000000..08a6a80
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/profiler_premade/zs_church_fix.txt
@@ -0,0 +1 @@
+SRL={Vector(-430.19137573242,85.761978149414,-87.968757629395),Vector(383.16650390625,242.04788208008,-87.96875),Vector(-571.11932373047,-189.10856628418,864.03125),Vector(-1022.1073608398,-631.96429443359,104.03125),Vector(-576.97222900391,343.27548217773,72.03125),Vector(-97.147399902344,231.46723937988,72.03125),Vector(-1163.8723144531,166.06677246094,72.03125),Vector(-272.81655883789,173.06968688965,-87.96875),Vector(225.27508544922,120.70548248291,-87.96875),Vector(141.39428710938,346.95562744141,-87.96875),Vector(-1180.9654541016,-322.31796264648,72.03125),Vector(-1184.3483886719,-119.69090270996,72.03125)}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/cf_haunted_b1.txt b/gamemodes/zombiesurvival/content/data/zsmaps/cf_haunted_b1.txt
new file mode 100644
index 0000000..51e9a99
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/cf_haunted_b1.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_undead",["Angles"]=Angle(0,179.49533081055,0),["Position"]=Vector(266.41079711914,1808.4088134766,51.171226501465)},{["Class"]="info_player_undead",["Angles"]=Angle(0,179.49533081055,0),["Position"]=Vector(176.85536193848,1809.1976318359,55.758682250977)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-2.1264553070068,0),["Position"]=Vector(-442.92947387695,1961.4650878906,58.328895568848)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-2.383855342865,0),["Position"]=Vector(-363.82998657227,2049.5141601563,58.098937988281)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-89.899879455566,0),["Position"]=Vector(-183.89532470703,1744.5864257813,88.74552154541)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-89.899879455566,-0),["Position"]=Vector(-82.104614257813,1624.8708496094,77.983413696289)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-89.899879455566,0),["Position"]=Vector(-35.548007965088,1466.8937988281,73.210037231445)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-108.69007110596,0),["Position"]=Vector(335.46643066406,1373.1656494141,87.609802246094)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-98.136657714844,0),["Position"]=Vector(302.09771728516,1575.5617675781,79.011108398438)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-98.136657714844,0),["Position"]=Vector(163.04374694824,1595.4422607422,36.982944488525)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-98.136657714844,0),["Position"]=Vector(128.56034851074,1485.6021728516,32.898445129395)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-98.136657714844,0),["Position"]=Vector(-87.829788208008,1352.1727294922,56.76880645752)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-98.136657714844,0),["Position"]=Vector(-269.41857910156,1318.7548828125,46.51921081543)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-98.136657714844,0),["Position"]=Vector(-504.6916809082,1352.2924804688,27.478816986084)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-74.970680236816,0),["Position"]=Vector(-425.25436401367,1658.01171875,51.866355895996)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-58.497055053711,0),["Position"]=Vector(21.228433609009,1941.3823242188,54.535346984863)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-159.39782714844,0),["Position"]=Vector(359.36804199219,2012.3250732422,71.447235107422)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.897148132324,0),["Position"]=Vector(-141.68391418457,-1672.2603759766,56.345706939697)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.897148132324,0),["Position"]=Vector(68.758293151855,-1668.9658203125,55.484016418457)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.897148132324,0),["Position"]=Vector(225.95999145508,-1488.0554199219,53.996948242188)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.897148132324,-0),["Position"]=Vector(223.23797607422,-1314.23046875,42.856792449951)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.897148132324,0),["Position"]=Vector(402.65173339844,-1262.0650634766,51.614189147949)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.897148132324,0),["Position"]=Vector(646.63671875,-1258.2454833984,55.170845031738)},{["Class"]="info_player_human",["Angles"]=Angle(0,133.8830871582,0),["Position"]=Vector(555.33020019531,-987.140625,52.470512390137)},{["Class"]="info_player_human",["Angles"]=Angle(0,168.88955688477,-0),["Position"]=Vector(304.16268920898,-988.36181640625,51.931510925293)},{["Class"]="info_player_human",["Angles"]=Angle(0,37.872932434082,0),["Position"]=Vector(-296.48571777344,-978.54376220703,52.831733703613)},{["Class"]="info_player_human",["Angles"]=Angle(0,20.627170562744,0),["Position"]=Vector(-533.34851074219,-1066.3448486328,53.022979736328)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,0),["Position"]=Vector(-519.32476806641,-1414.9749755859,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,0),["Position"]=Vector(-499.51904296875,-1551.8760986328,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,0),["Position"]=Vector(-487.93884277344,-1626.4073486328,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,0),["Position"]=Vector(-479.25369262695,-1682.3057861328,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,0),["Position"]=Vector(-467.67349243164,-1756.8370361328,47.473609924316)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,0),["Position"]=Vector(-250.87071228027,-1751.4948730469,42.453422546387)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,-0),["Position"]=Vector(-267.73071289063,-1642.5115966797,50.876045227051)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,-0),["Position"]=Vector(-282.3860168457,-1548.1884765625,49.060241699219)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,-0),["Position"]=Vector(-298.01834106445,-1447.5771484375,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,-0),["Position"]=Vector(-335.14511108398,-1208.6252441406,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,87.551200866699,0),["Position"]=Vector(103.35376739502,-1327.6031494141,35.686904907227)},{["Class"]="info_player_human",["Angles"]=Angle(0,87.551200866699,-0),["Position"]=Vector(-51.61999130249,-1320.9774169922,43.746704101563)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,0),["Position"]=Vector(329.98086547852,-2047.7274169922,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,-0),["Position"]=Vector(200.68173217773,-2048.0102539063,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,-0),["Position"]=Vector(86.136573791504,-2048.2607421875,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,-0),["Position"]=Vector(-15.681373596191,-2048.4833984375,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,-0),["Position"]=Vector(-149.31742858887,-2048.7756347656,51.240425109863)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,-0),["Position"]=Vector(-257.49893188477,-2049.0122070313,56.248825073242)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,-0),["Position"]=Vector(-384.77127075195,-2049.2905273438,55.402984619141)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,-0),["Position"]=Vector(-492.95275878906,-2049.5270996094,50.394584655762)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/cs_asylum.txt b/gamemodes/zombiesurvival/content/data/zsmaps/cs_asylum.txt
new file mode 100644
index 0000000..595d4de
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/cs_asylum.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,-83.381393432617,0),["Position"]=Vector(112.02564239502,2807.404296875,168.62425231934)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-42.929847717285,0),["Position"]=Vector(109.43133544922,2891.0932617188,168.62425231934)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-133.70729064941,0),["Position"]=Vector(175.36471557617,2844.7416992188,168.62425231934)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-150.98901367188,0),["Position"]=Vector(1276.9521484375,4377.2724609375,80.530494689941)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-148.50680541992,0),["Position"]=Vector(1412.6801757813,4107.9345703125,66.83324432373)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-121.52670288086,0),["Position"]=Vector(1034.4516601563,4146.2670898438,71.469200134277)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,12.80868434906,0),["Position"]=Vector(-1095.8961181641,627.0419921875,119.95462036133)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-5.7192797660828,0),["Position"]=Vector(-1119.4061279297,320.47164916992,119.95462036133)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,167.4070892334,0),["Position"]=Vector(1503.6135253906,2565.6081542969,800.57312011719)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,7.8192625045776,0),["Position"]=Vector(-437.70123291016,2240.1025390625,782.89862060547)},{["Class"]="zombiegasses",["Angles"]=Angle(0,-81.339965820313,0),["Position"]=Vector(1653.8688964844,4068.0336914063,1460.9046630859)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(104.25633239746,2919.228515625,168.62425231934)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/cs_island_b1.txt b/gamemodes/zombiesurvival/content/data/zsmaps/cs_island_b1.txt
new file mode 100644
index 0000000..7d537e3
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/cs_island_b1.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,179.67698669434,0),["Position"]=Vector(11439.862304688,7236.8374023438,787.64031982422)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-151.63998413086,0),["Position"]=Vector(11123.712890625,8456.0205078125,820.75347900391)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-139.69512939453,0),["Position"]=Vector(11063.388671875,8968.515625,820.75347900391)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-135.74557495117,0),["Position"]=Vector(10693.963867188,9267.810546875,846.62756347656)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-66.882308959961,0),["Position"]=Vector(8010.0678710938,9751.345703125,783.88812255859)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-75.114883422852,0),["Position"]=Vector(7729.8520507813,9667.6279296875,783.88812255859)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(8075.96875,9119.9453125,593.93505859375)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,165.99678039551,0),["Position"]=Vector(11512.452148438,7069.8232421875,775.33441162109)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,167.92729187012,0),["Position"]=Vector(11553.229492188,7260.5068359375,775.33441162109)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-160.15521240234,0),["Position"]=Vector(11571.541015625,7444.9951171875,775.33441162109)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,175.64920043945,0),["Position"]=Vector(11719.271484375,7231.958984375,783.89624023438)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-153.97760009766,0),["Position"]=Vector(11515.96484375,7627.0458984375,763.86627197266)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,103.83489990234,0),["Position"]=Vector(9933.376953125,6025.79296875,786.66217041016)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,108.46813201904,0),["Position"]=Vector(9639.2509765625,5761.7021484375,777.43023681641)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,42.831302642822,0),["Position"]=Vector(6663.3125,8183.0952148438,906.25939941406)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-61.15832901001,0),["Position"]=Vector(6628.1450195313,8504.6748046875,909.32098388672)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-98.381126403809,0),["Position"]=Vector(9611.9189453125,9774.970703125,770.71838378906)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-98.381126403809,0),["Position"]=Vector(9478.3603515625,9794.640625,770.71838378906)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-98.381126403809,0),["Position"]=Vector(9329.9619140625,9816.49609375,770.71838378906)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-60.028499603271,0),["Position"]=Vector(9162.9248046875,9761.1552734375,767.49011230469)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/cs_sprint_trading.txt b/gamemodes/zombiesurvival/content/data/zsmaps/cs_sprint_trading.txt
new file mode 100644
index 0000000..20b1c45
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/cs_sprint_trading.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,1.7892336845398,0),["Position"]=Vector(6.3562378883362,1634.5676269531,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,1.7892336845398,0),["Position"]=Vector(164.49366760254,1580.0205078125,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,1.7892336845398,0),["Position"]=Vector(344.79959106445,1557.2377929688,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,1.7892336845398,0),["Position"]=Vector(595.13873291016,1564.8397216797,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,1.7892336845398,0),["Position"]=Vector(776.95825195313,1532.7711181641,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-81.865791320801,0),["Position"]=Vector(962.28619384766,1258.3853759766,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-81.865791320801,0),["Position"]=Vector(968.45343017578,1096.9393310547,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-81.865791320801,0),["Position"]=Vector(984.12493896484,986.73461914063,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-95.765403747559,0),["Position"]=Vector(1002.295715332,447.42028808594,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.90573120117,-0),["Position"]=Vector(1011.1494140625,82.219505310059,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.90573120117,-0),["Position"]=Vector(1013.6997070313,-51.331890106201,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.90573120117,-0),["Position"]=Vector(1016.25,-184.88325500488,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,126.52542114258,0),["Position"]=Vector(1030.3385009766,-432.00476074219,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,93.835731506348,0),["Position"]=Vector(-134.27395629883,-759.40460205078,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,94.224914550781,0),["Position"]=Vector(-213.36650085449,-639.33612060547,64.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/cs_urban_v2.txt b/gamemodes/zombiesurvival/content/data/zsmaps/cs_urban_v2.txt
new file mode 100644
index 0000000..5f44bf7
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/cs_urban_v2.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_undead",["Angles"]=Angle(0,-26.911340713501,0),["Position"]=Vector(-834.61260986328,702.19067382813,-559.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-26.911340713501,0),["Position"]=Vector(-842.49523925781,638.87084960938,-559.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-26.911340713501,0),["Position"]=Vector(-735.96246337891,746.56750488281,-551.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.83637046813965,0),["Position"]=Vector(-1206.0075683594,463.45358276367,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,0),["Position"]=Vector(-1205.8140869141,293.24908447266,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,0),["Position"]=Vector(-1205.7354736328,224.24908447266,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,0),["Position"]=Vector(-1205.6397705078,140.24908447266,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,0),["Position"]=Vector(-1035.7039794922,114.45239257813,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,-0),["Position"]=Vector(-1035.8427734375,236.65682983398,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,-0),["Position"]=Vector(-1035.9487304688,329.65682983398,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,-0),["Position"]=Vector(-1036.0444335938,413.65682983398,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,-0),["Position"]=Vector(-1036.1401367188,497.65682983398,-196.96875)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/rd_zombocity_f.txt b/gamemodes/zombiesurvival/content/data/zsmaps/rd_zombocity_f.txt
new file mode 100644
index 0000000..fd31eca
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/rd_zombocity_f.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_undead",["Angles"]=Angle(0,-89.821304321289,0),["Position"]=Vector(969.45697021484,-376.62551879883,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-89.821304321289,0),["Position"]=Vector(870.00250244141,-376.93594360352,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-89.821304321289,0),["Position"]=Vector(870.68139648438,-594.94897460938,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-89.821304321289,0),["Position"]=Vector(976.14038085938,-596.06182861328,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-179.91157531738,0),["Position"]=Vector(811.67309570313,-71.39306640625,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-179.91157531738,0),["Position"]=Vector(704.58215332031,-38.537967681885,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,91.285461425781,0),["Position"]=Vector(562.36273193359,41.106063842773,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,91.285461425781,0),["Position"]=Vector(624.10540771484,226.02728271484,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,91.285461425781,0),["Position"]=Vector(560.87115478516,344.66305541992,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,91.285461425781,0),["Position"]=Vector(652.01159667969,422.61703491211,2)},{["Class"]="zombiegasses",["Angles"]=Angle(0,-89.047828674316,0),["Position"]=Vector(599.80163574219,376.7414855957,64.03125)},{["Class"]="zombiegasses",["Angles"]=Angle(0,-151.33853149414,0),["Position"]=Vector(831.65734863281,-45.869968414307,64.03125)},{["Class"]="zombiegasses",["Angles"]=Angle(0,-90.592094421387,0),["Position"]=Vector(923.57495117188,-599.26953125,64.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zm_airport_panic_beta1.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zm_airport_panic_beta1.txt
new file mode 100644
index 0000000..47cf83c
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zm_airport_panic_beta1.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-5177.3920898438,881.87573242188,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-5008.5498046875,882.27380371094,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-4947.1875,882.41845703125,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-4814.6264648438,882.73425292969,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-4806.4038085938,723.31970214844,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-4995.7001953125,722.87341308594,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-5073.42578125,722.69018554688,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-5186.1079101563,722.42449951172,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2501.1276855469,-4177.1557617188,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2501.2978515625,-4041.0400390625,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2501.3901367188,-3967.4052734375,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2501.5209960938,-3862.9047851563,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2338.8469238281,-3832.9125976563,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2338.6921386719,-3956.7556152344,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2338.6101074219,-4022.2087402344,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2338.4177246094,-4175.7993164063,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,3.466961145401,0),["Position"]=Vector(295.60876464844,2517.2038574219,64.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-88.939659118652,0),["Position"]=Vector(418.4680480957,2642.9868164063,64.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.969177246094,0),["Position"]=Vector(399.61096191406,2737.3371582031,64.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-95.529174804688,0),["Position"]=Vector(142.32482910156,2707.4641113281,64.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-95.529174804688,0),["Position"]=Vector(126.27494812012,2600.9431152344,64.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-95.529174804688,0),["Position"]=Vector(23.337768554688,2511.5346679688,64.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-86.984092712402,0),["Position"]=Vector(0.8810875415802,1615.1925048828,348.6696472168)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,90.776710510254,0),["Position"]=Vector(-0.97451484203339,-587.27484130859,338.22326660156)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.558349609375,0),["Position"]=Vector(-2526.5407714844,3066.7595214844,49.67798614502)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.558349609375,0),["Position"]=Vector(-2369.9714355469,3067.9650878906,49.773193359375)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.558349609375,0),["Position"]=Vector(-2272.3166503906,2951.3112792969,48.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.558349609375,0),["Position"]=Vector(-2421.1579589844,2893.0270996094,48.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.558349609375,0),["Position"]=Vector(-2621.8522949219,2897.1752929688,48.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zm_airport_panic_bobpoblo2.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zm_airport_panic_bobpoblo2.txt
new file mode 100644
index 0000000..8baba63
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zm_airport_panic_bobpoblo2.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,94.208526611328,0),["Position"]=Vector(0.70359867811203,-563.35388183594,291.58831787109)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-82.008033752441,0),["Position"]=Vector(0.94603204727173,1619.2587890625,294.5888671875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-25.838996887207,0),["Position"]=Vector(-2752.4768066406,-1340.2722167969,65.909980773926)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-39.210514068604,0),["Position"]=Vector(-2650.9807128906,-1311.9095458984,46.83390045166)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-39.210514068604,0),["Position"]=Vector(-2606.6291503906,-1348.0960693359,28.848808288574)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-39.210514068604,0),["Position"]=Vector(-2594.6633300781,-1435.2951660156,8.6155624389648)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-90.046928405762,0),["Position"]=Vector(-2578.14453125,-1553.7076416016,45.451591491699)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-34.938396453857,0),["Position"]=Vector(-2731.8713378906,-1174.8201904297,85.265144348145)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-48.323066711426,0),["Position"]=Vector(2.1428146362305,1502.4555664063,380.42538452148)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-76.775764465332,0),["Position"]=Vector(116.96301269531,1467.6391601563,378.39559936523)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-44.19310760498,0),["Position"]=Vector(-128.31594848633,1460.2230224609,372.91348266602)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,84.804176330566,0),["Position"]=Vector(-103.82947540283,-434.30938720703,358.95153808594)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,141.45643615723,0),["Position"]=Vector(121.70021057129,-451.2063293457,340.25900268555)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.309272766113,0),["Position"]=Vector(-2532.5078125,-1036.2810058594,326.05996704102)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-65.002670288086,0),["Position"]=Vector(-2828.994140625,-1086.7244873047,310.60717773438)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-85.342903137207,0),["Position"]=Vector(-2664.099609375,-1105.0885009766,308.28125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zm_countrytrain_b4.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zm_countrytrain_b4.txt
new file mode 100644
index 0000000..805f8dd
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zm_countrytrain_b4.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2283.3566894531,-356.65811157227,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2301.0249023438,-109.78955841064,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2310.1267089844,17.385183334351,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2321.3701171875,174.4833984375,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2331.0073242188,309.13897705078,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2341.1799316406,451.27542114258,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2351.8879394531,600.89300537109,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2362.060546875,743.03002929688,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2370.0915527344,855.24346923828,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2378.1225585938,967.45690917969,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2121.9406738281,876.75396728516,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2142.9118652344,660.26818847656,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2160.9904785156,473.64236450195,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2177.6228027344,301.94604492188,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2193.5319824219,137.71479797363,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2210.8874511719,-41.446578979492,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2226.0734863281,-198.21276855469,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1866.1898193359,-406.07916259766,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1941.2454833984,-162.37565612793,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1907.9040527344,603.64263916016,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1913.3283691406,948.60052490234,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1559.1120605469,927.50061035156,-39.968780517578)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1549.2573242188,635.16723632813,-39.968780517578)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1541.6767578125,410.29541015625,-39.968780517578)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1511.1018066406,-496.68859863281,-39.968780517578)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1694.2387695313,-291.76129150391,-39.968780517578)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1249.1533203125,243.01565551758,-39.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-733.59930419922,-1866.8619384766,24.549224853516)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-914.61810302734,-1840.1225585938,24.327178955078)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-907.76702880859,-1671.8056640625,24.092933654785)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-733.45739746094,-1678.8974609375,24.124599456787)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-574.13525390625,-1685.3795166016,27.344688415527)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-363.85452270508,-1693.9346923828,92.574867248535)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-191.33279418945,-1653.646484375,112.3578414917)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-316.61505126953,-1543.9284667969,86.603569030762)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-721.73376464844,-1527.4466552734,24.03125)},{["Class"]="zombiegasses",["Angles"]=Angle(0,0,0),["Position"]=Vector(2326.2819824219,1316.8853759766,-247.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,175.54666137695,0),["Position"]=Vector(-521.44866943359,1488.1628417969,53.552997589111)},{["Class"]="info_player_undead",["Angles"]=Angle(0,161.90469360352,0),["Position"]=Vector(-618.80981445313,1076.1794433594,26.424129486084)},{["Class"]="info_player_undead",["Angles"]=Angle(0,158.55857849121,0),["Position"]=Vector(-499.69006347656,1943.0633544922,51.498229980469)},{["Class"]="info_player_undead",["Angles"]=Angle(0,158.55857849121,0),["Position"]=Vector(-561.62939453125,1768.0362548828,52.462871551514)},{["Class"]="info_player_undead",["Angles"]=Angle(0,94.465721130371,0),["Position"]=Vector(-299.77606201172,2158.9619140625,37.194038391113)},{["Class"]="info_player_undead",["Angles"]=Angle(0,94.465721130371,0),["Position"]=Vector(-186.06781005859,2237.2316894531,24.940475463867)},{["Class"]="info_player_undead",["Angles"]=Angle(0,94.72314453125,0),["Position"]=Vector(138.06378173828,2235.4145507813,24.043266296387)},{["Class"]="info_player_undead",["Angles"]=Angle(0,90.604698181152,0),["Position"]=Vector(935.02667236328,2145.8947753906,36.031253814697)},{["Class"]="info_player_undead",["Angles"]=Angle(0,83.912338256836,0),["Position"]=Vector(851.232421875,2214.4675292969,32.263763427734)},{["Class"]="info_player_undead",["Angles"]=Angle(0,126.64091491699,0),["Position"]=Vector(1055.6389160156,2053.4914550781,33.352592468262)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zm_gilmanhouse_v2.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zm_gilmanhouse_v2.txt
new file mode 100644
index 0000000..bceb35c
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zm_gilmanhouse_v2.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(478.84704589844,2097.7121582031,-127.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1570.5426025391,2301.7939453125,-124.19820404053)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1753.4514160156,993.09088134766,-126.03686523438)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1749.9487304688,880.62506103516,-123.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1752.720703125,768.08325195313,-127.96350097656)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1748.43359375,693.12963867188,-124.69854736328)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1639.2078857422,696.43688964844,-125.82936096191)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1633.9425048828,861.35430908203,-123.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1630.9052734375,988.81970214844,-125.76992797852)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-89.98819732666,0),["Position"]=Vector(-227.21459960938,2280.6857910156,-47.376403808594)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-133.48905944824,0),["Position"]=Vector(1105.5577392578,665.96514892578,-63.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-92.305122375488,0),["Position"]=Vector(866.81414794922,655.40032958984,-63.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-92.047668457031,0),["Position"]=Vector(741.56134033203,613.06842041016,-62.785820007324)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-158.19943237305,0),["Position"]=Vector(1112.7219238281,541.21301269531,-59.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,170.44807434082,0),["Position"]=Vector(2017.8321533203,-699.46020507813,-59.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,170.44807434082,0),["Position"]=Vector(2035.8214111328,-592.55639648438,-59.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,177.91264343262,0),["Position"]=Vector(1923.9602050781,-589.78967285156,-59.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,177.91264343262,0),["Position"]=Vector(1920.02734375,-697.68725585938,-59.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,177.91264343262,0),["Position"]=Vector(1915.1812744141,-830.6298828125,-63.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,133.12510681152,0),["Position"]=Vector(1760.9949951172,-840.99938964844,-63.96875)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zm_macd_island17.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zm_macd_island17.txt
new file mode 100644
index 0000000..926bc1a
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zm_macd_island17.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="zombiegasses",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1261.6928710938,752.59942626953,-484.22457885742)},{["Class"]="zombiegasses",["Angles"]=Angle(0,0,0),["Position"]=Vector(4.5803527832031,769.865234375,-498.99688720703)},{["Class"]="info_player_undead",["Angles"]=Angle(0,80.489120483398,0),["Position"]=Vector(-1219.4189453125,-1423.4625244141,-368.30584716797)},{["Class"]="info_player_undead",["Angles"]=Angle(0,80.489120483398,0),["Position"]=Vector(-1099.873046875,-1443.4908447266,-368.30584716797)},{["Class"]="info_player_undead",["Angles"]=Angle(0,81.003952026367,0),["Position"]=Vector(-1078.5760498047,-1308.96875,-375.04183959961)},{["Class"]="info_player_undead",["Angles"]=Angle(0,81.003952026367,0),["Position"]=Vector(-1198.2967529297,-1290.015625,-375.04183959961)},{["Class"]="info_player_undead",["Angles"]=Angle(0,81.003952026367,0),["Position"]=Vector(-1279.4541015625,-1415.0611572266,-368.30584716797)},{["Class"]="info_player_undead",["Angles"]=Angle(0,81.003952026367,0),["Position"]=Vector(-1414.1398925781,-1393.7388916016,-368.30584716797)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-105.81706237793,0),["Position"]=Vector(29.790426254272,2076.8994140625,76.373329162598)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-105.81706237793,0),["Position"]=Vector(-9.9477834701538,1936.6263427734,118.01152038574)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-105.81706237793,0),["Position"]=Vector(-156.39741516113,1985.2071533203,119.83190917969)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-105.81706237793,0),["Position"]=Vector(-307.74627685547,2031.2620849609,116.58746337891)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-105.81706237793,0),["Position"]=Vector(-487.01440429688,2047.8312988281,100.84573364258)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-105.81706237793,0),["Position"]=Vector(-654.56030273438,2077.2150878906,84.57723236084)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-101.18389129639,0),["Position"]=Vector(-476.15606689453,2181.6181640625,96.826393127441)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-101.18389129639,0),["Position"]=Vector(-348.71481323242,2156.9099121094,105.06744384766)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-101.18389129639,0),["Position"]=Vector(-233.75730895996,1817.6870117188,137.04006958008)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-151.11936950684,0),["Position"]=Vector(704.87432861328,991.32629394531,-68.721725463867)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-151.11936950684,0),["Position"]=Vector(577.83068847656,1185.5118408203,-47.93180847168)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-151.11936950684,0),["Position"]=Vector(433.36639404297,974.91381835938,-70.211715698242)},{["Class"]="zombiegasses",["Angles"]=Angle(0,0,0),["Position"]=Vector(50.204395294189,199.12615966797,800.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zm_mall_beta_b1.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zm_mall_beta_b1.txt
new file mode 100644
index 0000000..03c27be
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zm_mall_beta_b1.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,33.253566741943,0),["Position"]=Vector(-1057.1306152344,-571.69378662109,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,33.253566741943,0),["Position"]=Vector(-970.69226074219,-703.51623535156,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-12.821060180664,0),["Position"]=Vector(-1078.8520507813,-377.36697387695,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-12.821060180664,0),["Position"]=Vector(-1040.9637451172,-210.88706970215,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-12.821060180664,0),["Position"]=Vector(-1069.7459716797,-90.333786010742,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-12.821060180664,0),["Position"]=Vector(-1041.5379638672,68.967910766602,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-98.792694091797,0),["Position"]=Vector(-927.45532226563,-19.888782501221,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-84.89306640625,0),["Position"]=Vector(-921.71276855469,-316.94296264648,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,68.877304077148,0),["Position"]=Vector(-1023.4549560547,-750.56842041016,400.03125)},{["Class"]="zombiegasses",["Angles"]=Angle(0,-16.756702423096,0),["Position"]=Vector(-1179.3800048828,-1046.6837158203,686.26385498047)},{["Class"]="zombiegasses",["Angles"]=Angle(0,98.815856933594,0),["Position"]=Vector(-979.36505126953,-490.10113525391,701.48748779297)},{["Class"]="info_player_undead",["Angles"]=Angle(0,16.705177307129,0),["Position"]=Vector(-1138.6627197266,-1156.177734375,672.03125)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-7.4904227256775,0),["Position"]=Vector(-1171.4055175781,-915.64013671875,672.03125)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.48896411061287,0),["Position"]=Vector(-1024.8121337891,-1081.0244140625,672.03125)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-1.4414720535278,0),["Position"]=Vector(-2810.0278320313,-424.20336914063,680.03125)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-1.4414720535278,0),["Position"]=Vector(-2817.1452636719,-706.73199462891,680.03125)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-1.4414720535278,0),["Position"]=Vector(-2634.0356445313,-711.3388671875,674.03125)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-1.4414720535278,0),["Position"]=Vector(-2627.3356933594,-445.38003540039,674.03125)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-1.4414720535278,0),["Position"]=Vector(-2618.798828125,-106.51457977295,674.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zm_mini_petrols_v6.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zm_mini_petrols_v6.txt
new file mode 100644
index 0000000..e750e94
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zm_mini_petrols_v6.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,-87.750694274902,0),["Position"]=Vector(-1898.0695800781,-1604.0020751953,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-87.750694274902,0),["Position"]=Vector(-1892.7457275391,-1739.5328369141,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-87.750694274902,0),["Position"]=Vector(-1884.3265380859,-1953.8663330078,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-98.486686706543,0),["Position"]=Vector(-1434.8188476563,-1929.6275634766,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-98.486686706543,0),["Position"]=Vector(-1440.7945556641,-1800.3289794922,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-98.486686706543,0),["Position"]=Vector(-1432.1508789063,-1674.5036621094,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-127.61452484131,0),["Position"]=Vector(-1387.5904541016,-2302.611328125,50.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-44.28666305542,0),["Position"]=Vector(-1876.7000732422,-2732.4299316406,53.71501159668)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,93.69734954834,0),["Position"]=Vector(-1305.2596435547,-4879.533203125,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,93.69734954834,0),["Position"]=Vector(-1304.2386474609,-5030.6069335938,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,93.69734954834,0),["Position"]=Vector(-1310.1351318359,-5132.7172851563,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,93.69734954834,0),["Position"]=Vector(-1304.56640625,-5222.0512695313,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,93.69734954834,0),["Position"]=Vector(-1311.0111083984,-5338.0629882813,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,88.505386352539,0),["Position"]=Vector(-1764.4903564453,-5183.3168945313,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,88.505386352539,0),["Position"]=Vector(-1767.6828613281,-5027.3017578125,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,88.505386352539,0),["Position"]=Vector(-1765.1447753906,-4932.6596679688,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,88.505386352539,0),["Position"]=Vector(-1763.0249023438,-4851.412109375,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-170.83099365234,0),["Position"]=Vector(2240.7080078125,-3599.41796875,53.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-170.83099365234,0),["Position"]=Vector(2233.9282226563,-3653.5532226563,50.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.190956115723,0),["Position"]=Vector(4206.8701171875,-1894.6364746094,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.190956115723,0),["Position"]=Vector(4209.1176757813,-1786.8790283203,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.190956115723,0),["Position"]=Vector(4208.3798828125,-1665.7077636719,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.190956115723,0),["Position"]=Vector(4210.4956054688,-1562.1838378906,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-89.782913208008,0),["Position"]=Vector(3752.5632324219,-1939.9093017578,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-89.782913208008,0),["Position"]=Vector(3752.1713867188,-1835.6391601563,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-89.782913208008,0),["Position"]=Vector(3751.9406738281,-1774.2139892578,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-89.782913208008,0),["Position"]=Vector(3751.5517578125,-1670.6687011719,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,87.801063537598,0),["Position"]=Vector(3748.1025390625,-6388.1245117188,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,87.801063537598,0),["Position"]=Vector(3754.5432128906,-6220.5546875,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,87.801063537598,0),["Position"]=Vector(3758.1350097656,-6127.02734375,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,87.801063537598,0),["Position"]=Vector(3760.5295410156,-6064.67578125,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,92.465057373047,0),["Position"]=Vector(4202.73828125,-6026.1254882813,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,92.465057373047,0),["Position"]=Vector(4205.2661132813,-6084.7124023438,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,92.465057373047,0),["Position"]=Vector(4206.0712890625,-6177.7431640625,121.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,92.465057373047,0),["Position"]=Vector(4202.9702148438,-6298.9228515625,121.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,150.80912780762,0),["Position"]=Vector(6063.8989257813,-3055.8273925781,212.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,150.80912780762,0),["Position"]=Vector(6008.0966796875,-2934.7570800781,212.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,150.80912780762,0),["Position"]=Vector(6023.2006835938,-2813.3764648438,212.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-26.854692459106,0),["Position"]=Vector(4845.7001953125,-2544.6472167969,258.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-26.854692459106,0),["Position"]=Vector(4829.443359375,-2659.1135253906,258.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-26.854692459106,0),["Position"]=Vector(4970.228515625,-2549.265625,258.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,12.209557533264,0),["Position"]=Vector(-2825.8852539063,-3744.7561035156,724.68359375)},{["Class"]="info_player_human",["Angles"]=Angle(0,12.209557533264,0),["Position"]=Vector(-2857.8669433594,-3596.9416503906,735.36352539063)},{["Class"]="info_player_human",["Angles"]=Angle(0,12.209557533264,0),["Position"]=Vector(-2884.2575683594,-3474.9650878906,731.15759277344)},{["Class"]="info_player_human",["Angles"]=Angle(0,12.209557533264,0),["Position"]=Vector(-2956.2849121094,-3142.05859375,736.94055175781)},{["Class"]="info_player_human",["Angles"]=Angle(0,73.017639160156,0),["Position"]=Vector(-76.771034240723,-5610.5361328125,50.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,73.017639160156,0),["Position"]=Vector(95.032257080078,-5617.2177734375,50.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,73.017639160156,0),["Position"]=Vector(309.17056274414,-5681.6157226563,50.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-126.7342300415,0),["Position"]=Vector(1756.5330810547,-3010.525390625,50.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-126.7342300415,0),["Position"]=Vector(1621.6956787109,-2925.3032226563,50.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-126.7342300415,0),["Position"]=Vector(1300.3564453125,-2960.3046875,50.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-126.7342300415,0),["Position"]=Vector(1003.5184936523,-3030.4790039063,50.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,96.433776855469,0),["Position"]=Vector(2641.0739746094,-5403.525390625,145.77557373047)},{["Class"]="info_player_human",["Angles"]=Angle(0,96.433776855469,0),["Position"]=Vector(2648.6716308594,-5470.9125976563,146.83924865723)},{["Class"]="info_player_human",["Angles"]=Angle(0,75.313552856445,0),["Position"]=Vector(1456.9422607422,-5728.642578125,64.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,75.313552856445,0),["Position"]=Vector(1697.5856933594,-5722.3852539063,64.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,82.52953338623,0),["Position"]=Vector(1670.7596435547,-5411.6645507813,64.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-166.59072875977,0),["Position"]=Vector(416.9638671875,-2424.9165039063,59.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-166.59072875977,0),["Position"]=Vector(214.32472229004,-2422.6376953125,59.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,173.38536071777,0),["Position"]=Vector(4634.07421875,-4362.9291992188,50.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,3.0175333023071,0),["Position"]=Vector(4857.822265625,-2575.2653808594,1366.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.615188598633,0),["Position"]=Vector(553.39636230469,-2996.5749511719,74.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.615188598633,0),["Position"]=Vector(556.75506591797,-3155.3923339844,74.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.615188598633,0),["Position"]=Vector(561.82800292969,-3320.8325195313,74.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zm_portal.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zm_portal.txt
new file mode 100644
index 0000000..5d5de8f
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zm_portal.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,-95.884979248047,0),["Position"]=Vector(-2481.1955566406,1457.8311767578,65.251358032227)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-84.430656433105,0),["Position"]=Vector(-2490.6472167969,1554.7725830078,69.629936218262)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-84.430656433105,0),["Position"]=Vector(-2474.0698242188,1616.6125488281,72.324447631836)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-140.80120849609,0),["Position"]=Vector(-2201.8845214844,1630.7214355469,56.527584075928)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-140.80120849609,0),["Position"]=Vector(-2168.0498046875,1490.2692871094,51.741508483887)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.66864013672,0),["Position"]=Vector(-2263.7248535156,1401.6044921875,79.121276855469)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zm_rundown.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zm_rundown.txt
new file mode 100644
index 0000000..0c33930
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zm_rundown.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,165.58557128906,0),["Position"]=Vector(2679.4357910156,1345.5612792969,-32.536735534668)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2678.6936035156,1420.5576171875,-32.536735534668)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2677.8771972656,1503.0535888672,-32.536735534668)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2676.7639160156,1615.5480957031,-32.536735534668)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2571.7707519531,1614.5107421875,-32.536949157715)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2572.8098144531,1509.5158691406,-32.536949157715)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2573.9973144531,1389.5217285156,-32.536949157715)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2575.1105957031,1277.0272216797,-32.536949157715)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2575.8527832031,1202.0308837891,-32.536949157715)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2463.4343261719,1193.4197998047,-32.537178039551)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2462.3952636719,1298.4146728516,-32.537178039551)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2461.2819824219,1410.9091796875,-32.537178039551)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-47.182506561279,0),["Position"]=Vector(-616.04760742188,2608.9611816406,-0.18497467041016)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-52.845317840576,0),["Position"]=Vector(-507.50048828125,2588.6520996094,-0.098777770996094)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-52.845317840576,0),["Position"]=Vector(-621.23864746094,2462.5378417969,-0.065223693847656)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zm_ryan_valley.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zm_ryan_valley.txt
new file mode 100644
index 0000000..f629cef
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zm_ryan_valley.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,-92.471572875977,0),["Position"]=Vector(-1112.5595703125,-213.70275878906,64.031204223633)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-92.471572875977,0),["Position"]=Vector(-1181.7622070313,-210.71572875977,64.031204223633)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-92.471572875977,0),["Position"]=Vector(-1189.6352539063,-393.09518432617,64.031188964844)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-92.471572875977,0),["Position"]=Vector(-1103.3397216797,-396.81991577148,64.031188964844)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-92.471572875977,0),["Position"]=Vector(-1164.4696044922,-510.32281494141,64.031188964844)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,90.952743530273,0),["Position"]=Vector(2756.0036621094,-4609.6274414063,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,176.92451477051,0),["Position"]=Vector(2743.3967285156,-4399.708984375,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,176.92451477051,0),["Position"]=Vector(2738.1301269531,-4497.7612304688,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,176.92451477051,0),["Position"]=Vector(2629.8334960938,-4491.9379882813,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,176.92451477051,0),["Position"]=Vector(2635.0075683594,-4395.6245117188,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,176.92451477051,0),["Position"]=Vector(2550.67578125,-4391.0903320313,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,176.92451477051,0),["Position"]=Vector(2545.0190429688,-4496.390625,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.44190979004,0),["Position"]=Vector(1217.0399169922,-1723.4877929688,81.781753540039)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.44190979004,0),["Position"]=Vector(1129.6169433594,-1725.865234375,70.528755187988)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zm_satisfaction_b1.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zm_satisfaction_b1.txt
new file mode 100644
index 0000000..d5f7d63
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zm_satisfaction_b1.txt
@@ -0,0 +1 @@
+SRL={{["Angles"]=Angle(0,0,0),["Position"]=Vector(1141.0535888672,522.19451904297,-87.96875),["Class"]="prop_blocker"},{["Angles"]=Angle(0,0,0),["Position"]=Vector(-1375.8060302734,-255.11293029785,162.03125),["Class"]="prop_blocker"},{["Angles"]=Angle(0,18.060001373291,-2.1011048829678e-006),["Position"]=Vector(-1884.1385498047,157.21321105957,-30.831848144531),["Class"]="prop_blocker"},{["Angles"]=Angle(0,89.670036315918,-2.1011048829678e-006),["Position"]=Vector(-1882.0345458984,159.42082214355,-90.822692871094),["Class"]="prop_blocker"},{["Angles"]=Angle(0,160.40800476074,0),["Position"]=Vector(2979.08984375,17.218254089355,139.49755859375),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-176.49195861816,0),["Position"]=Vector(2967.15625,211.85285949707,139.49755859375),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-176.49195861816,0),["Position"]=Vector(2957.05859375,376.54342651367,139.49755859375),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-176.49195861816,0),["Position"]=Vector(2949.255859375,503.80426025391,139.49755859375),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,179.50396728516,0),["Position"]=Vector(2892.3547363281,638.70385742188,153.55355834961),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,179.50396728516,0),["Position"]=Vector(2893.1989746094,736.19989013672,153.55355834961),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,179.50396728516,0),["Position"]=Vector(2894.3029785156,863.69470214844,153.55355834961),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,179.50396728516,0),["Position"]=Vector(2895.0822753906,953.69104003906,153.55355834961),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-170.79397583008,0),["Position"]=Vector(2680.9792480469,801.685546875,158.92269897461),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-170.79397583008,0),["Position"]=Vector(2582.1313476563,892.57501220703,158.71701049805),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-170.79397583008,0),["Position"]=Vector(2441.4682617188,869.77709960938,158.36404418945),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,95.111885070801,0),["Position"]=Vector(2018.3719482422,-78.427040100098,143.80459594727),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,86.079902648926,0),["Position"]=Vector(271.81274414063,-776.26446533203,124.20829772949),["Class"]="info_player_human"},{["Angles"]=Angle(0,86.079902648926,0),["Position"]=Vector(384.0495300293,-783.95581054688,124.20829772949),["Class"]="info_player_human"},{["Angles"]=Angle(0,86.079902648926,0),["Position"]=Vector(533.69848632813,-794.2109375,124.20829772949),["Class"]="info_player_human"},{["Angles"]=Angle(0,86.079902648926,0),["Position"]=Vector(690.82934570313,-804.97882080078,124.20829772949),["Class"]="info_player_human"},{["Angles"]=Angle(0,93.163879394531,0),["Position"]=Vector(700.15753173828,-533.23968505859,118.39696502686),["Class"]="info_player_human"},{["Angles"]=Angle(0,93.163879394531,0),["Position"]=Vector(573.45477294922,-489.95245361328,118.39044952393),["Class"]="info_player_human"},{["Angles"]=Angle(0,93.163879394531,0),["Position"]=Vector(425.4602355957,-497.93765258789,117.92371368408),["Class"]="info_player_human"},{["Angles"]=Angle(0,93.163879394531,0),["Position"]=Vector(276.42816162109,-506.17138671875,123.88252258301),["Class"]="info_player_human"},{["Angles"]=Angle(0,93.163879394531,0),["Position"]=Vector(191.80046081543,-403.11334228516,134.66290283203),["Class"]="info_player_human"},{["Angles"]=Angle(0,93.163879394531,0),["Position"]=Vector(180.55920410156,-235.07006835938,139.1148223877),["Class"]="info_player_human"},{["Angles"]=Angle(0,-0.62204265594482,0),["Position"]=Vector(-591.77276611328,423.59286499023,147.05798339844),["Class"]="info_player_human"},{["Angles"]=Angle(0,-0.62204265594482,0),["Position"]=Vector(-471.03164672852,387.5361328125,133.59588623047),["Class"]="info_player_human"},{["Angles"]=Angle(0,-0.62204265594482,0),["Position"]=Vector(-332.96331787109,259.02835083008,122.64764404297),["Class"]="info_player_human"},{["Angles"]=Angle(0,-68.074142456055,0),["Position"]=Vector(-437.49438476563,1198.3969726563,352.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,-68.074142456055,0),["Position"]=Vector(-310.82769775391,1165.703125,352.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,-68.074142456055,0),["Position"]=Vector(123.30609893799,1147.6600341797,352.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,-68.074142456055,0),["Position"]=Vector(276.16961669922,1209.1003417969,352.03125),["Class"]="info_player_human"}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zm_vegas_b2.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zm_vegas_b2.txt
new file mode 100644
index 0000000..2364a0e
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zm_vegas_b2.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.75692749023,0),["Position"]=Vector(543.18536376953,-6.8670520782471,685.93585205078)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.75692749023,0),["Position"]=Vector(413.01290893555,0.53862178325653,645.88916015625)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.75692749023,0),["Position"]=Vector(302.24990844727,-1.8648445606232,611.80810546875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-454.98114013672,2460.3229980469,88.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-272.42373657227,2540.0397949219,91.819473266602)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-146.35029602051,2661.4389648438,90.735443115234)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-127.26793670654,2793.7097167969,88.011512756348)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-187.04411315918,2830.4084472656,88.011512756348)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-261.48306274414,2774.294921875,88.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-338.23223876953,2649.3439941406,88.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-181.00827026367,2364.2822265625,91.313377380371)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0.4111455976963,0),["Position"]=Vector(-1789.4370117188,657.39410400391,120.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0.4111455976963,0),["Position"]=Vector(-1800.6716308594,793.13043212891,120.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0.4111455976963,0),["Position"]=Vector(-1670.1231689453,798.80676269531,120.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0.4111455976963,0),["Position"]=Vector(-1520.9969482422,785.85827636719,120.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0.4111455976963,0),["Position"]=Vector(-1476.4438476563,683.97564697266,120.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-2.2462017536163,0),["Position"]=Vector(-1510.1142578125,485.15933227539,120.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-9.8304996490479,0),["Position"]=Vector(-1587.0327148438,410.27966308594,120.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-15.135381698608,0),["Position"]=Vector(-1695.7869873047,341.62866210938,120.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,10.045001029968,0),["Position"]=Vector(-1723.8834228516,388.03848266602,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,6.8426365852356,0),["Position"]=Vector(-1621.6451416016,403.95626831055,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,3.8406736850739,0),["Position"]=Vector(-1613.4573974609,321.54705810547,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,1.6598534584045,0),["Position"]=Vector(-1701.4595947266,476.98834228516,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0.37076249718666,0),["Position"]=Vector(-1738.0891113281,593.16662597656,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-1.0910625457764,0),["Position"]=Vector(-1746.9387207031,767.83416748047,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-2.2889890670776,0),["Position"]=Vector(-1794.6461181641,769.23486328125,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-2.6556177139282,0),["Position"]=Vector(-1800.603515625,633.55023193359,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-2.6556177139282,0),["Position"]=Vector(-1759.9444580078,498.19912719727,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-154.98364257813,0),["Position"]=Vector(-395.18872070313,789.1279296875,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-154.98364257813,0),["Position"]=Vector(-700.78527832031,828.39526367188,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,95.720268249512,0),["Position"]=Vector(-103.2610168457,1030.7119140625,216.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-21.839691162109,0),["Position"]=Vector(22.527704238892,1711.9497070313,504.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-21.839691162109,0),["Position"]=Vector(101.77830505371,1562.3090820313,504.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-21.839691162109,0),["Position"]=Vector(176.60768127441,1386.1588134766,504.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-97.825981140137,0),["Position"]=Vector(-1963.3778076172,1452.6138916016,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-97.825981140137,0),["Position"]=Vector(-2029.1851806641,1319.3250732422,386.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,117.60589599609,0),["Position"]=Vector(-1341.4119873047,467.94543457031,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,117.60589599609,0),["Position"]=Vector(-1407.2569580078,633.58068847656,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,117.60589599609,0),["Position"]=Vector(-1463.63671875,742.55499267578,384.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zs_abandoned_mall_v4.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zs_abandoned_mall_v4.txt
new file mode 100644
index 0000000..a370b0a
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zs_abandoned_mall_v4.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.575614929199,0),["Position"]=Vector(410.48590087891,4182.78125,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.575614929199,0),["Position"]=Vector(551.11871337891,4178.9096679688,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.575614929199,0),["Position"]=Vector(581.24987792969,4036.3286132813,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.575614929199,0),["Position"]=Vector(692.17840576172,3970.5593261719,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.575614929199,0),["Position"]=Vector(578.57592773438,3845.4409179688,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-87.725524902344,0),["Position"]=Vector(220.41596984863,4008.7465820313,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-87.725524902344,0),["Position"]=Vector(54.488754272461,3943.6423339844,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-35.057514190674,0),["Position"]=Vector(-256.78802490234,3790.6596679688,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2023.8112792969,2714.9885253906,16.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2023.3077392578,2821.4377441406,16.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2006.9027099609,2563.1286621094,16.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2007.2639160156,2486.4050292969,16.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2007.5607910156,2423.4089355469,16.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zs_abandoned_mall_v5f.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zs_abandoned_mall_v5f.txt
new file mode 100644
index 0000000..2d179ef
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zs_abandoned_mall_v5f.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="zombiegasses",["Angles"]=Angle(0,34.391754150391,0),["Position"]=Vector(-475.69149780273,1811.4334716797,24.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zs_abandoned_motel_final.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zs_abandoned_motel_final.txt
new file mode 100644
index 0000000..4b72bd9
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zs_abandoned_motel_final.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(12.097787857056,-83.647125244141,0),["Position"]=Vector(-88.215301513672,948.83001708984,-769.30535888672)},{["Class"]="info_player_zombie",["Angles"]=Angle(12.097787857056,-83.647125244141,0),["Position"]=Vector(150.09777832031,858.90356445313,-778.85272216797)},{["Class"]="info_player_zombie",["Angles"]=Angle(7.721987247467,-84.161743164063,0),["Position"]=Vector(-332.27993774414,732.59112548828,-801.39300537109)},{["Class"]="info_player_zombie",["Angles"]=Angle(7.721987247467,-84.161743164063,0),["Position"]=Vector(-82.933174133301,758.08764648438,-772.73742675781)},{["Class"]="info_player_zombie",["Angles"]=Angle(7.721987247467,-84.161743164063,0),["Position"]=Vector(31.414106369019,769.77996826172,-769.53344726563)},{["Class"]="info_player_zombie",["Angles"]=Angle(6.6923861503601,-100.12055206299,0),["Position"]=Vector(439.25109863281,864.81079101563,-832.47149658203)},{["Class"]="info_player_zombie",["Angles"]=Angle(1.5444043874741,83.405708312988,0),["Position"]=Vector(-602.19354248047,-509.89099121094,-822.36529541016)},{["Class"]="info_player_zombie",["Angles"]=Angle(1.5444043874741,83.405708312988,0),["Position"]=Vector(-373.58245849609,-458.60223388672,-823.56256103516)},{["Class"]="info_player_zombie",["Angles"]=Angle(-1.2870172262192,68.836380004883,0),["Position"]=Vector(-962.76129150391,19.063621520996,-829.51812744141)},{["Class"]="info_player_zombie",["Angles"]=Angle(-1.029617190361,68.836380004883,0),["Position"]=Vector(-888.50946044922,252.73442077637,-828.74676513672)},{["Class"]="info_player_zombie",["Angles"]=Angle(9.2663812637329,-74.020645141602,0),["Position"]=Vector(-1004.6726074219,260.71377563477,-830.84045410156)},{["Class"]="info_player_zombie",["Angles"]=Angle(9.2663812637329,-74.020645141602,0),["Position"]=Vector(-843.08380126953,36.356174468994,-855.52374267578)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zs_bunker.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zs_bunker.txt
new file mode 100644
index 0000000..052c42b
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zs_bunker.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="zombiegasses",["Angles"]=Angle(0,103.12794494629,0),["Position"]=Vector(-521.33850097656,-1204.6079101563,-251.39431762695)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zs_haunted_manor_beta.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zs_haunted_manor_beta.txt
new file mode 100644
index 0000000..6e9d62a
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zs_haunted_manor_beta.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="zombiegasses",["Angles"]=Angle(0,-5.800464630127,0),["Position"]=Vector(-649.18768310547,454.41580200195,-1407.96875)},{["Class"]="zombiegasses",["Angles"]=Angle(0,20.94349861145,0),["Position"]=Vector(-665.25830078125,441.64990234375,-1380.0942382813)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zs_infected_city_b1.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zs_infected_city_b1.txt
new file mode 100644
index 0000000..625d06f
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zs_infected_city_b1.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,-114.80297088623,0),["Position"]=Vector(1529.556640625,2935.6630859375,-351.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-161.94329833984,0),["Position"]=Vector(1531.6019287109,2698.0905761719,-351.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-167.41758728027,0),["Position"]=Vector(1544.0848388672,2458.2739257813,-351.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-93.795570373535,0),["Position"]=Vector(1392.3697509766,2892.7141113281,-391.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.411094665527,0),["Position"]=Vector(1226.1566162109,2853.7238769531,-371.58312988281)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-89.090927124023,0),["Position"]=Vector(1111.5850830078,2820.5793457031,-357.69244384766)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-82.576148986816,0),["Position"]=Vector(1056.2716064453,2704.0500488281,-327.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-111.16773986816,0),["Position"]=Vector(1248.4578857422,2585.0168457031,-391.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-106.12110900879,0),["Position"]=Vector(1405.3708496094,2510.0786132813,-391.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-151.83157348633,0),["Position"]=Vector(1576.5661621094,2436.8127441406,-351.96875)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zs_peekay_highway17_01.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zs_peekay_highway17_01.txt
new file mode 100644
index 0000000..56f50a3
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zs_peekay_highway17_01.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(3.3461999893188,-78.138595581055,0),["Position"]=Vector(-1474.4702148438,191.99964904785,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(3.3461999893188,-78.138595581055,0),["Position"]=Vector(-1591.8939208984,167.33729553223,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(3.3461999893188,-78.138595581055,0),["Position"]=Vector(-1699.8421630859,144.66505432129,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(3.3461999893188,-78.138595581055,0),["Position"]=Vector(-1796.0579833984,124.45696258545,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(1.4318823104986e-007,-1.6907994747162,0),["Position"]=Vector(-1530.3336181641,-85.115386962891,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.6627998352051,-84.831008911133,0),["Position"]=Vector(-1309.7841796875,-36.310207366943,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.4054026603699,-171.83218383789,0),["Position"]=Vector(-1144.7758789063,63.759227752686,320.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(11.840404510498,-5.8091773986816,0),["Position"]=Vector(-888.31939697266,44.34158706665,320.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.1480059623718,-95.899169921875,0),["Position"]=Vector(-689.90447998047,68.908416748047,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.1480059623718,-95.899169921875,0),["Position"]=Vector(-503.03497314453,49.600151062012,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.1480059623718,-95.899169921875,0),["Position"]=Vector(-418.63555908203,40.879600524902,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.1480059623718,-95.899169921875,0),["Position"]=Vector(-371.92294311523,-125.17939758301,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.1480059623718,-95.899169921875,0),["Position"]=Vector(-545.91015625,-126.3844833374,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.1480059623718,-95.899169921875,0),["Position"]=Vector(-711.62677001953,-163.97529602051,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.1480059623718,-95.899169921875,0),["Position"]=Vector(-629.76641845703,-262.69570922852,321.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1111.7999267578,-2570.9545898438,260.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-918.54827880859,-2540.138671875,260.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-999.46154785156,-2538.2683105469,260.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1132.9802246094,-2310.9809570313,260.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1026.154296875,-2230.8935546875,260.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1190.0466308594,-2219.2734375,260.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1313.9781494141,-2307.7067871094,260.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1084.1000976563,-2587.8737792969,392.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zs_school.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zs_school.txt
new file mode 100644
index 0000000..b9f80bf
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zs_school.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-956.74139404297,-850.40509033203,356.95526123047)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-958.49877929688,-772.64721679688,356.95526123047)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-881.91168212891,-686.60418701172,356.95526123047)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1460.1417236328,-313.86346435547,356.81225585938)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1050.2445068359,-319.27752685547,356.81225585938)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1174.9249267578,-315.91256713867,356.81225585938)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(473.55883789063,-1197.8994140625,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(385.45025634766,-1101.5399169922,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(214.77722167969,-1108.0576171875,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-225.04792785645,-1113.0131835938,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-384.45269775391,-1114.8092041016,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-560.01531982422,-1116.787109375,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-262.05206298828,1834.3687744141,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(118.1318359375,1838.5329589844,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(454.70971679688,1832.7912597656,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(804.56475830078,1732.5345458984,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-484.17163085938,1740.8912353516,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-663.55169677734,1571.9674072266,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1624.3937988281,-1286.8486328125,-7.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1898.9047851563,-1281.2886962891,-7.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1087.0125732422,-1342.0225830078,-7.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2085.2734375,852.02819824219,212.17425537109)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2214.220703125,1071.9543457031,212.17425537109)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2215.7624511719,976.77740478516,212.17425537109)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2217.3041992188,881.60095214844,212.17425537109)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zs_subway_v8.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zs_subway_v8.txt
new file mode 100644
index 0000000..a01f314
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zs_subway_v8.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,81.158760070801,0),["Position"]=Vector(-131.15821838379,-2534.6545410156,96.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,81.158760070801,0),["Position"]=Vector(-91.431938171387,-2252.4736328125,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,81.158760070801,0),["Position"]=Vector(41.341178894043,-2251.4147949219,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,81.158760070801,0),["Position"]=Vector(152.10539245605,-2233.998046875,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,0),["Position"]=Vector(135.79827880859,-2123.7199707031,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,-0),["Position"]=Vector(73.630851745605,-2125.5769042969,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,-0),["Position"]=Vector(16.521320343018,-2127.283203125,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,-0),["Position"]=Vector(-27.469058990479,-2128.59765625,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,0),["Position"]=Vector(-118.14763641357,-2059.0317382813,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,0),["Position"]=Vector(-50.575801849365,-2050.3298339844,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,0),["Position"]=Vector(24.899143218994,-2048.0278320313,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,0),["Position"]=Vector(142.62985229492,-2019.8032226563,-31.96875)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zs_tunnels_fixed_v2.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zs_tunnels_fixed_v2.txt
new file mode 100644
index 0000000..f111dd8
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zs_tunnels_fixed_v2.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,96.060150146484,0),["Position"]=Vector(710.29382324219,-1395.2973632813,124.51078796387)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,95.030548095703,0),["Position"]=Vector(493.6311340332,-1414.3675537109,124.51078796387)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,95.030548095703,0),["Position"]=Vector(306.85363769531,-1430.8073730469,124.51078796387)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,95.030548095703,0),["Position"]=Vector(97.662544250488,-1449.2199707031,124.51078796387)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,49.985542297363,0),["Position"]=Vector(319.1953125,-1237.6873779297,116.81788635254)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,100.17853546143,0),["Position"]=Vector(676.552734375,-1240.7888183594,111.28171539307)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,102.49514007568,0),["Position"]=Vector(830.32159423828,-1206.7125244141,111.28171539307)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-127.51789093018,0),["Position"]=Vector(953.54467773438,1412.9068603516,117.04342651367)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-127.51789093018,0),["Position"]=Vector(1167.6989746094,1248.4722900391,117.04342651367)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-124.17168426514,0),["Position"]=Vector(899.64630126953,1190.0889892578,112.37947845459)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-47.208976745605,0),["Position"]=Vector(-1203.7399902344,1417.1822509766,126.55266571045)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-47.208976745605,0),["Position"]=Vector(-1341.3345947266,1289.8079833984,126.55266571045)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-47.208976745605,0),["Position"]=Vector(-1429.3951416016,1208.2884521484,126.55266571045)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-51.069980621338,0),["Position"]=Vector(-1204.3985595703,1192.8255615234,112.84037780762)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,41.079235076904,0),["Position"]=Vector(-1272.7183837891,-1162.4512939453,141.78689575195)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,41.079235076904,0),["Position"]=Vector(-1110.0870361328,-1349.0189208984,141.78689575195)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,41.079235076904,0),["Position"]=Vector(-941.46612548828,-1202.0291748047,117.57444763184)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,41.079235076904,0),["Position"]=Vector(-1187.8782958984,-919.35211181641,117.57444763184)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,41.079235076904,0),["Position"]=Vector(-1052.9808349609,-801.76031494141,98.204544067383)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,41.079235076904,0),["Position"]=Vector(-808.16265869141,-978.29547119141,90.785552978516)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/data/zsmaps/zs_zombienowhere_v3.txt b/gamemodes/zombiesurvival/content/data/zsmaps/zs_zombienowhere_v3.txt
new file mode 100644
index 0000000..cd14981
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/data/zsmaps/zs_zombienowhere_v3.txt
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,88.396209716797,0),["Position"]=Vector(-511.33920288086,667.03381347656,408.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/redeem.vmt b/gamemodes/zombiesurvival/content/materials/killicon/redeem.vmt
new file mode 100644
index 0000000..661fb7a
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/killicon/redeem.vmt
@@ -0,0 +1,8 @@
+"UnlitGeneric"
+{
+ "$translucent" 1
+ "$basetexture" "killicon/redeem"
+ "$vertexcolor" 0
+ "$ignorez" 1
+ "$additive" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/redeem.vtf b/gamemodes/zombiesurvival/content/materials/killicon/redeem.vtf
new file mode 100644
index 0000000..76fe67e
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/killicon/redeem.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_axe.vmt b/gamemodes/zombiesurvival/content/materials/killicon/zs_axe.vmt
new file mode 100644
index 0000000..eaa214a
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/killicon/zs_axe.vmt
@@ -0,0 +1,10 @@
+"UnlitGeneric"
+{
+ "$basetexture" "killicon/zs_axe"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_axe.vtf b/gamemodes/zombiesurvival/content/materials/killicon/zs_axe.vtf
new file mode 100644
index 0000000..3f2a44b
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/killicon/zs_axe.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_fryingpan.vmt b/gamemodes/zombiesurvival/content/materials/killicon/zs_fryingpan.vmt
new file mode 100644
index 0000000..45597c2
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/killicon/zs_fryingpan.vmt
@@ -0,0 +1,10 @@
+"UnlitGeneric"
+{
+ "$basetexture" "killicon/zs_fryingpan"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_fryingpan.vtf b/gamemodes/zombiesurvival/content/materials/killicon/zs_fryingpan.vtf
new file mode 100644
index 0000000..1a016cd
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/killicon/zs_fryingpan.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_hammer.vmt b/gamemodes/zombiesurvival/content/materials/killicon/zs_hammer.vmt
new file mode 100644
index 0000000..36f21ae
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/killicon/zs_hammer.vmt
@@ -0,0 +1,10 @@
+"UnlitGeneric"
+{
+ "$basetexture" "killicon/zs_hammer"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_hammer.vtf b/gamemodes/zombiesurvival/content/materials/killicon/zs_hammer.vtf
new file mode 100644
index 0000000..7353672
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/killicon/zs_hammer.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_keyboard.vmt b/gamemodes/zombiesurvival/content/materials/killicon/zs_keyboard.vmt
new file mode 100644
index 0000000..a39bdcc
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/killicon/zs_keyboard.vmt
@@ -0,0 +1,10 @@
+"UnlitGeneric"
+{
+ "$basetexture" "killicon/zs_keyboard"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_keyboard.vtf b/gamemodes/zombiesurvival/content/materials/killicon/zs_keyboard.vtf
new file mode 100644
index 0000000..4b82097
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/killicon/zs_keyboard.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_plank.vmt b/gamemodes/zombiesurvival/content/materials/killicon/zs_plank.vmt
new file mode 100644
index 0000000..a4b3fa9
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/killicon/zs_plank.vmt
@@ -0,0 +1,10 @@
+"UnlitGeneric"
+{
+ "$basetexture" "killicon/zs_plank"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_plank.vtf b/gamemodes/zombiesurvival/content/materials/killicon/zs_plank.vtf
new file mode 100644
index 0000000..9418c2e
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/killicon/zs_plank.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_pot.vmt b/gamemodes/zombiesurvival/content/materials/killicon/zs_pot.vmt
new file mode 100644
index 0000000..6b4a8dc
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/killicon/zs_pot.vmt
@@ -0,0 +1,10 @@
+"UnlitGeneric"
+{
+ "$basetexture" "killicon/zs_pot"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_pot.vtf b/gamemodes/zombiesurvival/content/materials/killicon/zs_pot.vtf
new file mode 100644
index 0000000..b3e3a5d
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/killicon/zs_pot.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_shovel.vmt b/gamemodes/zombiesurvival/content/materials/killicon/zs_shovel.vmt
new file mode 100644
index 0000000..862a1ed
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/killicon/zs_shovel.vmt
@@ -0,0 +1,10 @@
+"UnlitGeneric"
+{
+ "$basetexture" "killicon/zs_shovel"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_shovel.vtf b/gamemodes/zombiesurvival/content/materials/killicon/zs_shovel.vtf
new file mode 100644
index 0000000..aaa730c
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/killicon/zs_shovel.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_sledgehammer.vmt b/gamemodes/zombiesurvival/content/materials/killicon/zs_sledgehammer.vmt
new file mode 100644
index 0000000..90b2e80
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/killicon/zs_sledgehammer.vmt
@@ -0,0 +1,10 @@
+"UnlitGeneric"
+{
+ "$basetexture" "killicon/zs_sledgehammer"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_sledgehammer.vtf b/gamemodes/zombiesurvival/content/materials/killicon/zs_sledgehammer.vtf
new file mode 100644
index 0000000..1baae7b
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/killicon/zs_sledgehammer.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_zombie.vmt b/gamemodes/zombiesurvival/content/materials/killicon/zs_zombie.vmt
new file mode 100644
index 0000000..3295c31
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/killicon/zs_zombie.vmt
@@ -0,0 +1,8 @@
+"UnlitGeneric"
+{
+ "$translucent" 1
+ "$basetexture" "killicon/zs_zombie"
+ "$vertexcolor" 0
+ "$ignorez" 1
+ "$additive" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/killicon/zs_zombie.vtf b/gamemodes/zombiesurvival/content/materials/killicon/zs_zombie.vtf
new file mode 100644
index 0000000..a16b66c
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/killicon/zs_zombie.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/player/elis/fty/001.vmt b/gamemodes/zombiesurvival/content/materials/models/player/elis/fty/001.vmt
new file mode 100644
index 0000000..a07b60b
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/player/elis/fty/001.vmt
@@ -0,0 +1,10 @@
+VertexLitGeneric
+{
+ "$basetexture" "models\player\elis\fty\001"
+ "$envmap" "env_cubemap"
+ "$bumpmap" "models/player/elis\fty\001_normal"
+ "$normalmapalphaenvmapmask" "1"
+ "$envmapcontrast" 0.3
+ "$envmapsaturation" 0.7
+ "$envmaptint" "[ 0.36 0.36 0.36 ]"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/player/elis/fty/001.vtf b/gamemodes/zombiesurvival/content/materials/models/player/elis/fty/001.vtf
new file mode 100644
index 0000000..a20b8fd
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/player/elis/fty/001.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/player/elis/fty/001_normal.vtf b/gamemodes/zombiesurvival/content/materials/models/player/elis/fty/001_normal.vtf
new file mode 100644
index 0000000..2e08513
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/player/elis/fty/001_normal.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/hammer.vmt b/gamemodes/zombiesurvival/content/materials/models/weapons/hammer.vmt
new file mode 100644
index 0000000..63a23cb
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/weapons/hammer.vmt
@@ -0,0 +1,5 @@
+VertexLitGeneric
+{
+ "$basetexture" "models\weapons\hammer"
+
+}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/hammer.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/hammer.vtf
new file mode 100644
index 0000000..c6d2ba6
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/hammer.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/hammer2.vmt b/gamemodes/zombiesurvival/content/materials/models/weapons/hammer2.vmt
new file mode 100644
index 0000000..b0d13eb
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/weapons/hammer2.vmt
@@ -0,0 +1,6 @@
+VertexLitGeneric
+{
+ "$basetexture" "models\weapons\hammer2"
+ "$envmap" "env_cubemap"
+
+}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/hammer2.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/hammer2.vtf
new file mode 100644
index 0000000..2e2f035
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/hammer2.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/sledge.vmt b/gamemodes/zombiesurvival/content/materials/models/weapons/sledge.vmt
new file mode 100644
index 0000000..59f1a53
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/weapons/sledge.vmt
@@ -0,0 +1,5 @@
+VertexLitGeneric
+{
+ "$basetexture" "models\weapons\sledge"
+
+}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/sledge.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/sledge.vtf
new file mode 100644
index 0000000..9f80309
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/sledge.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/temptexture/handsmesh1.vmt b/gamemodes/zombiesurvival/content/materials/models/weapons/temptexture/handsmesh1.vmt
new file mode 100644
index 0000000..4b59926
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/weapons/temptexture/handsmesh1.vmt
@@ -0,0 +1,4 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "models\weapons\temptexture\handsmesh1"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/temptexture/handsmesh1.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/temptexture/handsmesh1.vtf
new file mode 100644
index 0000000..7ee1bd7
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/temptexture/handsmesh1.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_fza/fast_zombie_sheet.vmt b/gamemodes/zombiesurvival/content/materials/models/weapons/v_fza/fast_zombie_sheet.vmt
new file mode 100644
index 0000000..458375c
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/weapons/v_fza/fast_zombie_sheet.vmt
@@ -0,0 +1,8 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "Models/Weapons/v_fza/fast_zombie_sheet"
+ "$bumpmap" "Models/Weapons/v_fza/fast_zombie_sheet_normal"
+ "$envmap" "env_cubemap"
+ "$normalmapalphaenvmapmask" 1
+ "$selfillum" "1"
+}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_fza/fast_zombie_sheet.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/v_fza/fast_zombie_sheet.vtf
new file mode 100644
index 0000000..50753a0
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/v_fza/fast_zombie_sheet.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_fza/fast_zombie_sheet_normal.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/v_fza/fast_zombie_sheet_normal.vtf
new file mode 100644
index 0000000..8b4887e
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/v_fza/fast_zombie_sheet_normal.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_hand/armtexture.vmt b/gamemodes/zombiesurvival/content/materials/models/weapons/v_hand/armtexture.vmt
new file mode 100644
index 0000000..892811b
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/weapons/v_hand/armtexture.vmt
@@ -0,0 +1,4 @@
+"VertexLitGeneric"
+{
+ "$basetexture" "models/Weapons/V_hand/armtexture"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_hand/armtexture.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/v_hand/armtexture.vtf
new file mode 100644
index 0000000..fd7854e
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/v_hand/armtexture.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/Blackcrab_sheet.vmt b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/Blackcrab_sheet.vmt
new file mode 100644
index 0000000..07bfa0d
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/Blackcrab_sheet.vmt
@@ -0,0 +1,8 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "Models/Weapons/v_pza/Blackcrab_sheet"
+ "$bumpmap" "Models/Weapons/v_pza/blackcrab_sheet_normal"
+ "$envmap" "env_cubemap"
+ "$normalmapalphaenvmapmask" 1
+ "$selfillum" "1"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/Blackcrab_sheet.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/Blackcrab_sheet.vtf
new file mode 100644
index 0000000..d6f23b1
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/Blackcrab_sheet.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/Blackcrab_sheet_normal.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/Blackcrab_sheet_normal.vtf
new file mode 100644
index 0000000..3cfe13a
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/Blackcrab_sheet_normal.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/PoisonZombie_sheet.vmt b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/PoisonZombie_sheet.vmt
new file mode 100644
index 0000000..df1c86d
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/PoisonZombie_sheet.vmt
@@ -0,0 +1,8 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "Models/Weapons/v_pza/PoisonZombie_sheet"
+ "$bumpmap" "Models/Weapons/v_pza/PoisonZombie_sheet_normal"
+ "$envmap" "env_cubemap"
+ "$normalmapalphaenvmapmask" 1
+ "$selfillum" "1"
+}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/PoisonZombie_sheet.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/PoisonZombie_sheet.vtf
new file mode 100644
index 0000000..0156f61
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/PoisonZombie_sheet.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/PoisonZombie_sheet_normal.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/PoisonZombie_sheet_normal.vtf
new file mode 100644
index 0000000..bee1283
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/PoisonZombie_sheet_normal.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/hairs.vmt b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/hairs.vmt
new file mode 100644
index 0000000..18e41e7
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/hairs.vmt
@@ -0,0 +1,9 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "Models/Weapons/v_pza/hairs"
+ "$translucent" 1
+ "$nocull" 1
+ "$nodecal" 1
+ "$clamps" 1
+ "$clampt" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/hairs.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/hairs.vtf
new file mode 100644
index 0000000..8221e54
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/v_pza/hairs.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_zombiearms/Zombie_Classic_sheet.vmt b/gamemodes/zombiesurvival/content/materials/models/weapons/v_zombiearms/Zombie_Classic_sheet.vmt
new file mode 100644
index 0000000..88a61e1
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/weapons/v_zombiearms/Zombie_Classic_sheet.vmt
@@ -0,0 +1,5 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "models\weapons/v_zombiearms/Zombie_Classic_sheet"
+ "$bumpmap" "models\weapons/v_zombiearms/Zombie_Classic_sheet_normal"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_zombiearms/Zombie_Classic_sheet.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/v_zombiearms/Zombie_Classic_sheet.vtf
new file mode 100644
index 0000000..e60f829
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/v_zombiearms/Zombie_Classic_sheet.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_zombiearms/Zombie_Classic_sheet_normal.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/v_zombiearms/Zombie_Classic_sheet_normal.vtf
new file mode 100644
index 0000000..2bc154a
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/v_zombiearms/Zombie_Classic_sheet_normal.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_zombiearms/ghoulsheet.vmt b/gamemodes/zombiesurvival/content/materials/models/weapons/v_zombiearms/ghoulsheet.vmt
new file mode 100644
index 0000000..4179abb
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/weapons/v_zombiearms/ghoulsheet.vmt
@@ -0,0 +1,4 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "models/weapons/v_zombiearms/ghoulsheet"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/v_zombiearms/ghoulsheet.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/v_zombiearms/ghoulsheet.vtf
new file mode 100644
index 0000000..6d52420
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/v_zombiearms/ghoulsheet.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/weapons/w_annabelle/gun.vtf b/gamemodes/zombiesurvival/content/materials/models/weapons/w_annabelle/gun.vtf
new file mode 100644
index 0000000..cdac614
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/weapons/w_annabelle/gun.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_armfrontdull.vmt b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_armfrontdull.vmt
new file mode 100644
index 0000000..f65f3fa
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_armfrontdull.vmt
@@ -0,0 +1,8 @@
+"VertexLitGeneric"
+{
+ // Original shader: VertexLitMaskedEnvMappedTexture
+ "$basetexture" "models/wraith1/s_armfrontdull"
+ "$envmap" "models/wraith1/stalkerspec"
+ "$envmapmask" "models/wraith1/s_armfrontmask"
+ "$envmapsphere" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_armfrontdull.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_armfrontdull.vtf
new file mode 100644
index 0000000..2f3f3f5
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_armfrontdull.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_backdull.vmt b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_backdull.vmt
new file mode 100644
index 0000000..1d2193d
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_backdull.vmt
@@ -0,0 +1,8 @@
+"VertexLitGeneric"
+{
+ // Original shader: VertexLitMaskedEnvMappedTexture
+ "$basetexture" "models/wraith1/s_backdull"
+ "$envmap" "models/wraith1/stalkerspec"
+ "$envmapmask" "models/wraith1/s_backmask"
+ "$envmapsphere" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_backdull.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_backdull.vtf
new file mode 100644
index 0000000..4dde40b
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_backdull.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_chest2dull.vmt b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_chest2dull.vmt
new file mode 100644
index 0000000..ecc4b87
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_chest2dull.vmt
@@ -0,0 +1,8 @@
+"VertexLitGeneric"
+{
+ // Original shader: VertexLitMaskedEnvMappedTexture
+ "$basetexture" "models/wraith1/s_chest2dull"
+ "$envmap" "models/wraith1/stalkerspec"
+ "$envmapmask" "models/wraith1/s_chest2mask"
+ "$envmapsphere" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_chest2dull.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_chest2dull.vtf
new file mode 100644
index 0000000..7516a47
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_chest2dull.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_head(cyl)dull.vmt b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_head(cyl)dull.vmt
new file mode 100644
index 0000000..d930492
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_head(cyl)dull.vmt
@@ -0,0 +1,8 @@
+"VertexLitGeneric"
+{
+ // Original shader: VertexLitMaskedEnvMappedTexture
+ "$basetexture" "models/wraith1/s_head(cyl)dull"
+ "$envmap" "models/wraith1/stalkerspec"
+ "$envmapmask" "models/wraith1/s_head(cyl)mask"
+ "$envmapsphere" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_head(cyl)dull.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_head(cyl)dull.vtf
new file mode 100644
index 0000000..e718263
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_head(cyl)dull.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_loindropper.vmt b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_loindropper.vmt
new file mode 100644
index 0000000..0aa475d
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_loindropper.vmt
@@ -0,0 +1,6 @@
+"VertexLitGeneric"
+{
+ // Original shader: VertexLitAlphaTestedTexture
+ "$basetexture" "models/wraith1/s_loindropper"
+ "$alphatest" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_loindropper.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_loindropper.vtf
new file mode 100644
index 0000000..15c8c1b
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_loindropper.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_lowerlegfrontdull.vmt b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_lowerlegfrontdull.vmt
new file mode 100644
index 0000000..6405c60
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_lowerlegfrontdull.vmt
@@ -0,0 +1,8 @@
+"VertexLitGeneric"
+{
+ // Original shader: VertexLitMaskedEnvMappedTexture
+ "$basetexture" "models/wraith1/s_lowerlegfrontdull"
+ "$envmap" "models/wraith1/stalkerspec"
+ "$envmapmask" "models/wraith1/s_lowerlegfrontmask"
+ "$envmapsphere" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_lowerlegfrontdull.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_lowerlegfrontdull.vtf
new file mode 100644
index 0000000..91a0425
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_lowerlegfrontdull.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_midsectiondull.vmt b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_midsectiondull.vmt
new file mode 100644
index 0000000..75c2c88
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_midsectiondull.vmt
@@ -0,0 +1,8 @@
+"VertexLitGeneric"
+{
+ // Original shader: VertexLitMaskedEnvMappedTexture
+ "$basetexture" "models/wraith1/s_midsectiondull"
+ "$envmap" "models/wraith1/stalkerspec"
+ "$envmapmask" "models/wraith1/s_midsectionmask"
+ "$envmapsphere" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_midsectiondull.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_midsectiondull.vtf
new file mode 100644
index 0000000..79381dd
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_midsectiondull.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_wires.vmt b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_wires.vmt
new file mode 100644
index 0000000..58f2351
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_wires.vmt
@@ -0,0 +1,6 @@
+"VertexLitGeneric"
+{
+ // Original shader: VertexLitAlphaTestedTexture
+ "$basetexture" "models/wraith1/s_wires"
+ "$alphatest" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/S_wires.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_wires.vtf
new file mode 100644
index 0000000..71107d5
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/S_wires.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/cutter.vmt b/gamemodes/zombiesurvival/content/materials/models/wraith1/cutter.vmt
new file mode 100644
index 0000000..7c86edb
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/wraith1/cutter.vmt
@@ -0,0 +1,5 @@
+"VertexLitGeneric"
+{
+ // Original shader: VertexLitTexture
+ "$basetexture" "models/wraith1/cutter"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/cutter.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/cutter.vtf
new file mode 100644
index 0000000..6ab13e8
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/cutter.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/s_armfrontmask.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/s_armfrontmask.vtf
new file mode 100644
index 0000000..2629b72
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/s_armfrontmask.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/s_backmask.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/s_backmask.vtf
new file mode 100644
index 0000000..73e035a
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/s_backmask.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/s_chest2mask.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/s_chest2mask.vtf
new file mode 100644
index 0000000..6597575
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/s_chest2mask.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/s_head(cyl)mask.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/s_head(cyl)mask.vtf
new file mode 100644
index 0000000..92a9ec6
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/s_head(cyl)mask.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/s_lowerlegfrontmask.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/s_lowerlegfrontmask.vtf
new file mode 100644
index 0000000..5db99b2
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/s_lowerlegfrontmask.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/s_midsectionmask.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/s_midsectionmask.vtf
new file mode 100644
index 0000000..3ac3522
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/s_midsectionmask.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_head.vmt b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_head.vmt
new file mode 100644
index 0000000..d9a4895
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_head.vmt
@@ -0,0 +1,4 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "Models/wraith1/stalker_head"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_head.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_head.vtf
new file mode 100644
index 0000000..fb69370
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_head.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_limbs.vmt b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_limbs.vmt
new file mode 100644
index 0000000..d69300a
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_limbs.vmt
@@ -0,0 +1,4 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "Models/wraith1/stalker_limbs"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_limbs.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_limbs.vtf
new file mode 100644
index 0000000..721fb7c
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_limbs.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_sheet.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_sheet.vtf
new file mode 100644
index 0000000..09b9c31
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_sheet.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_torso.vmt b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_torso.vmt
new file mode 100644
index 0000000..93fc58b
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_torso.vmt
@@ -0,0 +1,4 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "Models/wraith1/stalker_torso"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_torso.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_torso.vtf
new file mode 100644
index 0000000..721fb7c
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalker_torso.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/models/wraith1/stalkerspec.vtf b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalkerspec.vtf
new file mode 100644
index 0000000..79c3b21
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/models/wraith1/stalkerspec.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray1.vmt b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray1.vmt
new file mode 100644
index 0000000..01eba02
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray1.vmt
@@ -0,0 +1,7 @@
+"UnlitGeneric"
+{
+ "$basetexture" "Decals/blood1"
+ "$translucent" "1"
+ "$vertexcolor" 1
+ "$vertexalpha" "1"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray2.vmt b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray2.vmt
new file mode 100644
index 0000000..42ceda2
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray2.vmt
@@ -0,0 +1,7 @@
+"UnlitGeneric"
+{
+ "$basetexture" "Decals/blood2"
+ "$translucent" "1"
+ "$vertexcolor" 1
+ "$vertexalpha" "1"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray3.vmt b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray3.vmt
new file mode 100644
index 0000000..648e44e
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray3.vmt
@@ -0,0 +1,7 @@
+"UnlitGeneric"
+{
+ "$basetexture" "Decals/blood3"
+ "$translucent" "1"
+ "$vertexcolor" 1
+ "$vertexalpha" "1"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray4.vmt b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray4.vmt
new file mode 100644
index 0000000..7975d69
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray4.vmt
@@ -0,0 +1,7 @@
+"UnlitGeneric"
+{
+ "$basetexture" "Decals/blood4"
+ "$translucent" "1"
+ "$vertexcolor" 1
+ "$vertexalpha" "1"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray5.vmt b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray5.vmt
new file mode 100644
index 0000000..ddb5d21
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray5.vmt
@@ -0,0 +1,7 @@
+"UnlitGeneric"
+{
+ "$basetexture" "Decals/blood5"
+ "$translucent" "1"
+ "$vertexcolor" 1
+ "$vertexalpha" "1"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray6.vmt b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray6.vmt
new file mode 100644
index 0000000..d141ffa
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray6.vmt
@@ -0,0 +1,7 @@
+"UnlitGeneric"
+{
+ "$basetexture" "Decals/blood6"
+ "$translucent" "1"
+ "$vertexcolor" 1
+ "$vertexalpha" "1"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray7.vmt b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray7.vmt
new file mode 100644
index 0000000..bc9cc6a
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray7.vmt
@@ -0,0 +1,7 @@
+"UnlitGeneric"
+{
+ "$basetexture" "Decals/blood7"
+ "$translucent" "1"
+ "$vertexcolor" 1
+ "$vertexalpha" "1"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray8.vmt b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray8.vmt
new file mode 100644
index 0000000..b093913
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/noxctf/sprite_bloodspray8.vmt
@@ -0,0 +1,7 @@
+"UnlitGeneric"
+{
+ "$basetexture" "Decals/blood8"
+ "$translucent" "1"
+ "$vertexcolor" 1
+ "$vertexalpha" "1"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/refract_ring.vmt b/gamemodes/zombiesurvival/content/materials/refract_ring.vmt
new file mode 100644
index 0000000..e5e4127
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/refract_ring.vmt
@@ -0,0 +1,23 @@
+"Refract"
+{
+ "$refractamount" "0.0"
+ "$bluramount" "0"
+
+ "$scale" "[1 1]"
+
+ "$dudvmap" "refract_ring"
+ "$normalmap" "refract_ring"
+
+ "$nocull" 1
+ "$ignorez" 0
+
+ "Refract_DX80"
+ {
+ "$fallbackmaterial" "null"
+ }
+
+ "Refract_DX60"
+ {
+ "$fallbackmaterial" "null"
+ }
+}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/materials/refract_ring.vtf b/gamemodes/zombiesurvival/content/materials/refract_ring.vtf
new file mode 100644
index 0000000..fcae9aa
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/refract_ring.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_f.vmt b/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_f.vmt
new file mode 100644
index 0000000..4f44ef0
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_f.vmt
@@ -0,0 +1,5 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "weapons\survivor01_hands\zp_sv1_F"
+ "$bumpmap" "weapons\survivor01_hands\zp_sv1_F_norm"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_f.vtf b/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_f.vtf
new file mode 100644
index 0000000..0e61f6f
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_f.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_f_norm.vtf b/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_f_norm.vtf
new file mode 100644
index 0000000..40f6c83
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_f_norm.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_fpv.vmt b/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_fpv.vmt
new file mode 100644
index 0000000..82432ed
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_fpv.vmt
@@ -0,0 +1,5 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "weapons\survivor01_hands\zp_sv1_FPV"
+ "$bumpmap" "weapons\survivor01_hands\zp_sv1_FPV_NM"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_fpv.vtf b/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_fpv.vtf
new file mode 100644
index 0000000..9ad18d0
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_fpv.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_fpv_nm.vtf b/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_fpv_nm.vtf
new file mode 100644
index 0000000..72b3a17
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/weapons/survivor01_hands/zp_sv1_fpv_nm.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/body_skin.vmt b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/body_skin.vmt
new file mode 100644
index 0000000..0da3ad4
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/body_skin.vmt
@@ -0,0 +1,10 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "weapons\v_supershorty\body_skin"
+ "$envmapmask" "weapons\v_supershorty\body_skin_specular"
+ "$envmap" "env_cubemap"
+ "$envmaptint" "[ .45 .45 .45 ]"
+ "$envmapconstrast" .4
+}
+
+
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/body_skin.vtf b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/body_skin.vtf
new file mode 100644
index 0000000..12ed3f8
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/body_skin.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/body_skin_specular.vtf b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/body_skin_specular.vtf
new file mode 100644
index 0000000..8fe7ad9
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/body_skin_specular.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/grip_skin.vmt b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/grip_skin.vmt
new file mode 100644
index 0000000..79c12bb
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/grip_skin.vmt
@@ -0,0 +1,8 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "weapons\v_supershorty\grip_skin"
+ "$envmapmask" "weapons\v_supershorty\grip_skin_specular"
+ "$envmap" "env_cubemap"
+ "$envmaptint" "[ .45 .45 .45 ]"
+ "$envmapconstrast" .4
+}
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/grip_skin.vtf b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/grip_skin.vtf
new file mode 100644
index 0000000..34340de
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/grip_skin.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/grip_skin_specular.vtf b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/grip_skin_specular.vtf
new file mode 100644
index 0000000..60cf3c5
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/grip_skin_specular.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/leftover_skin.vmt b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/leftover_skin.vmt
new file mode 100644
index 0000000..9cef973
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/leftover_skin.vmt
@@ -0,0 +1,8 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "weapons\v_supershorty\leftover_skin"
+ "$envmapmask" "weapons\v_supershorty\leftover_skin_specular"
+ "$envmap" "env_cubemap"
+ "$envmaptint" "[ .45 .45 .45 ]"
+ "$envmapconstrast" .4
+}
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/leftover_skin.vtf b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/leftover_skin.vtf
new file mode 100644
index 0000000..ca06ab0
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/leftover_skin.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/leftover_skin_specular.vtf b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/leftover_skin_specular.vtf
new file mode 100644
index 0000000..797f2f3
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/leftover_skin_specular.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/parts_skin.vmt b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/parts_skin.vmt
new file mode 100644
index 0000000..d63f5c2
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/parts_skin.vmt
@@ -0,0 +1,9 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "weapons\v_supershorty\parts_skin"
+ "$envmapmask" "weapons\v_supershorty\parts_skin_specular"
+ "$envmap" "env_cubemap"
+ "$envmaptint" "[ .45 .45 .45 ]"
+ "$envmapconstrast" .4
+}
+
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/parts_skin.vtf b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/parts_skin.vtf
new file mode 100644
index 0000000..9f2c5b4
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/parts_skin.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/parts_skin_specular.vtf b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/parts_skin_specular.vtf
new file mode 100644
index 0000000..a2b1ce1
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/parts_skin_specular.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/shell_red.vmt b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/shell_red.vmt
new file mode 100644
index 0000000..0a72456
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/shell_red.vmt
@@ -0,0 +1,4 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "weapons\v_supershorty\Shell_Red"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/shell_red.vtf b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/shell_red.vtf
new file mode 100644
index 0000000..a00a917
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/weapons/v_supershorty/shell_red.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/w_supershorty/shorty_w_low.vmt b/gamemodes/zombiesurvival/content/materials/weapons/w_supershorty/shorty_w_low.vmt
new file mode 100644
index 0000000..f2b57e0
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/weapons/w_supershorty/shorty_w_low.vmt
@@ -0,0 +1,4 @@
+"VertexLitGeneric"
+{
+ "$baseTexture" "weapons\w_supershorty/shorty_w_low"
+}
diff --git a/gamemodes/zombiesurvival/content/materials/weapons/w_supershorty/shorty_w_low.vtf b/gamemodes/zombiesurvival/content/materials/weapons/w_supershorty/shorty_w_low.vtf
new file mode 100644
index 0000000..32cb8a9
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/weapons/w_supershorty/shorty_w_low.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/circlegradient.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/circlegradient.vmt
new file mode 100644
index 0000000..7a2a3e4
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/circlegradient.vmt
@@ -0,0 +1,9 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/circlegradient"
+ "$ignorez" 1
+ "$vertexcolor" 1
+ "$vertexalpha" 1
+ "$nolod" 1
+}
+
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/circlegradient.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/circlegradient.vtf
new file mode 100644
index 0000000..ab00cca
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/circlegradient.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/fearometer.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/fearometer.vmt
new file mode 100644
index 0000000..730d30f
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/fearometer.vmt
@@ -0,0 +1,12 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/fearometer"
+ "$vertexcolor" 1
+ "$vertexalpha" 1
+ "$ignorez" 1
+ "$nolod" 1
+ "$nomip" 1
+ "$nocompress" 1
+ "$translucent" 1
+}
+
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/fearometer.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/fearometer.vtf
new file mode 100644
index 0000000..49391e5
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/fearometer.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/fearometerneedle.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/fearometerneedle.vmt
new file mode 100644
index 0000000..dd70aaf
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/fearometerneedle.vmt
@@ -0,0 +1,12 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/fearometerneedle"
+ "$vertexcolor" 1
+ "$vertexalpha" 1
+ "$ignorez" 1
+ "$nolod" 1
+ "$nomip" 1
+ "$nocompress" 1
+ "$translucent" 1
+}
+
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/fearometerneedle.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/fearometerneedle.vtf
new file mode 100644
index 0000000..49d8fdf
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/fearometerneedle.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/filmgrain/filmgrain.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/filmgrain/filmgrain.vmt
new file mode 100644
index 0000000..52fc3cd
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/filmgrain/filmgrain.vmt
@@ -0,0 +1,21 @@
+UnlitGeneric
+{
+$basetexture "zombiesurvival/filmgrain/filmgrain"
+$translucent 1
+$vertexcolor 1
+$vertexalpha 1
+$no_fullbright 1
+$ignorez 1
+$nolod 1
+
+"Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 15.00
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/filmgrain/filmgrain.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/filmgrain/filmgrain.vtf
new file mode 100644
index 0000000..4348832
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/filmgrain/filmgrain.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/horderally.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/horderally.vmt
new file mode 100644
index 0000000..68b14bd
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/horderally.vmt
@@ -0,0 +1,9 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/horderally"
+ "$vertexcolor" 1
+ "$vertexalpha" 1
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/horderally.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/horderally.vtf
new file mode 100644
index 0000000..49f98f6
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/horderally.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/humanhead.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/humanhead.vmt
new file mode 100644
index 0000000..35d5ae4
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/humanhead.vmt
@@ -0,0 +1,8 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/humanhead"
+ "$vertexcolor" 1
+ "$vertexalpha" 1
+ "$nolod" 1
+ "$ignorez" 1
+}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/humanhead.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/humanhead.vtf
new file mode 100644
index 0000000..f32ff08
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/humanhead.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/chemzombie.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/chemzombie.vmt
new file mode 100644
index 0000000..3d606ed
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/chemzombie.vmt
@@ -0,0 +1,19 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/chemzombie"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+ "Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 5
+ }
+ }
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/chemzombie.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/chemzombie.vtf
new file mode 100644
index 0000000..f7aa45c
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/chemzombie.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/crow.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/crow.vmt
new file mode 100644
index 0000000..d75327d
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/crow.vmt
@@ -0,0 +1,19 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/crow"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+ "Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 5
+ }
+ }
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/crow.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/crow.vtf
new file mode 100644
index 0000000..ee5b7db
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/crow.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/fastheadcrab.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/fastheadcrab.vmt
new file mode 100644
index 0000000..523d0d9
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/fastheadcrab.vmt
@@ -0,0 +1,19 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/fastheadcrab"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+ "Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 5
+ }
+ }
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/fastheadcrab.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/fastheadcrab.vtf
new file mode 100644
index 0000000..f37a6da
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/fastheadcrab.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/fastzombie.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/fastzombie.vmt
new file mode 100644
index 0000000..e9cd288
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/fastzombie.vmt
@@ -0,0 +1,19 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/fastzombie"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+ "Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 5
+ }
+ }
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/fastzombie.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/fastzombie.vtf
new file mode 100644
index 0000000..cacaae9
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/fastzombie.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/genericundead.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/genericundead.vmt
new file mode 100644
index 0000000..1a5b1dc
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/genericundead.vmt
@@ -0,0 +1,11 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/genericundead"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+}
+
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/genericundead.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/genericundead.vtf
new file mode 100644
index 0000000..a16b66c
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/genericundead.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/ghoul.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/ghoul.vmt
new file mode 100644
index 0000000..1aceb52
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/ghoul.vmt
@@ -0,0 +1,19 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/ghoul"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+ "Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 5
+ }
+ }
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/ghoul.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/ghoul.vtf
new file mode 100644
index 0000000..395bd29
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/ghoul.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/headcrab.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/headcrab.vmt
new file mode 100644
index 0000000..864a58d
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/headcrab.vmt
@@ -0,0 +1,19 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/headcrab"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+ "Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 5
+ }
+ }
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/headcrab.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/headcrab.vtf
new file mode 100644
index 0000000..45b00fa
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/headcrab.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/legs.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/legs.vmt
new file mode 100644
index 0000000..96755cd
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/legs.vmt
@@ -0,0 +1,19 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/legs"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+ "Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 5
+ }
+ }
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/legs.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/legs.vtf
new file mode 100644
index 0000000..ed91717
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/legs.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/nightmare.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/nightmare.vmt
new file mode 100644
index 0000000..5d8db93
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/nightmare.vmt
@@ -0,0 +1,19 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/nightmare"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+ "Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 3
+ }
+ }
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/nightmare.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/nightmare.vtf
new file mode 100644
index 0000000..126d50b
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/nightmare.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/poisonheadcrab.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/poisonheadcrab.vmt
new file mode 100644
index 0000000..cfe2709
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/poisonheadcrab.vmt
@@ -0,0 +1,19 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/poisonheadcrab"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+ "Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 5
+ }
+ }
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/poisonheadcrab.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/poisonheadcrab.vtf
new file mode 100644
index 0000000..8fb7356
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/poisonheadcrab.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/poisonzombie.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/poisonzombie.vmt
new file mode 100644
index 0000000..24e1854
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/poisonzombie.vmt
@@ -0,0 +1,19 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/poisonzombie"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+ "Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 5
+ }
+ }
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/poisonzombie.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/poisonzombie.vtf
new file mode 100644
index 0000000..1c06885
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/poisonzombie.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/projectile_poisonflesh.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/projectile_poisonflesh.vmt
new file mode 100644
index 0000000..2d7445b
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/projectile_poisonflesh.vmt
@@ -0,0 +1,10 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/projectile_poisonflesh"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/projectile_poisonflesh.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/projectile_poisonflesh.vtf
new file mode 100644
index 0000000..62270e7
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/projectile_poisonflesh.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/projectile_poisonspit.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/projectile_poisonspit.vmt
new file mode 100644
index 0000000..b2f0d2b
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/projectile_poisonspit.vmt
@@ -0,0 +1,10 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/projectile_poisonspit"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/projectile_poisonspit.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/projectile_poisonspit.vtf
new file mode 100644
index 0000000..4cd4ee2
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/projectile_poisonspit.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/prop_gunturret.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/prop_gunturret.vmt
new file mode 100644
index 0000000..d540df8
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/prop_gunturret.vmt
@@ -0,0 +1,10 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/prop_gunturret"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/prop_gunturret.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/prop_gunturret.vtf
new file mode 100644
index 0000000..c449c3d
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/prop_gunturret.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/pukepus.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/pukepus.vmt
new file mode 100644
index 0000000..9120595
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/pukepus.vmt
@@ -0,0 +1,19 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/pukepus"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+ "Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 5
+ }
+ }
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/pukepus.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/pukepus.vtf
new file mode 100644
index 0000000..1e6c2a3
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/pukepus.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/tickle.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/tickle.vmt
new file mode 100644
index 0000000..7fb93c2
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/tickle.vmt
@@ -0,0 +1,19 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/tickle"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+ "Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 5
+ }
+ }
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/tickle.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/tickle.vtf
new file mode 100644
index 0000000..4e8996e
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/tickle.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/torso.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/torso.vmt
new file mode 100644
index 0000000..cf15b1d
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/torso.vmt
@@ -0,0 +1,19 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/torso"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+ "Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 5
+ }
+ }
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/torso.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/torso.vtf
new file mode 100644
index 0000000..4137b89
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/torso.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/wraithv2.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/wraithv2.vmt
new file mode 100644
index 0000000..f3cb54f
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/wraithv2.vmt
@@ -0,0 +1,19 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/wraithv2"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+ "Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 5
+ }
+ }
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/wraithv2.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/wraithv2.vtf
new file mode 100644
index 0000000..60a27d5
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/wraithv2.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/zombie.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/zombie.vmt
new file mode 100644
index 0000000..cefc0fe
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/zombie.vmt
@@ -0,0 +1,19 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/killicons/zombie"
+ "$nolod" 1
+ "$nomip" 1
+ "$ignorez" 1
+ "$translucent" 1
+ "$vertexalpha" 1
+ "$vertexcolor" 1
+ "Proxies"
+ {
+ "AnimatedTexture"
+ {
+ "animatedtexturevar" "$basetexture"
+ "animatedtextureframenumvar" "$frame"
+ "animatedtextureframerate" 5
+ }
+ }
+}
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/zombie.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/zombie.vtf
new file mode 100644
index 0000000..ac6c2ae
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/killicons/zombie.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/scope.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/scope.vmt
new file mode 100644
index 0000000..a8db28a
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/scope.vmt
@@ -0,0 +1,8 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/scope"
+ "$ignorez" 1
+ "$vertexcolor" 1
+ "$vertexalpha" 1
+ "$nolod" 1
+}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/scope.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/scope.vtf
new file mode 100644
index 0000000..716f41d
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/scope.vtf differ
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/zombiehead.vmt b/gamemodes/zombiesurvival/content/materials/zombiesurvival/zombiehead.vmt
new file mode 100644
index 0000000..bc0db34
--- /dev/null
+++ b/gamemodes/zombiesurvival/content/materials/zombiesurvival/zombiehead.vmt
@@ -0,0 +1,8 @@
+"UnlitGeneric"
+{
+ "$basetexture" "zombiesurvival/zombiehead"
+ "$vertexcolor" 1
+ "$vertexalpha" 1
+ "$nolod" 1
+ "$ignorez" 1
+}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/content/materials/zombiesurvival/zombiehead.vtf b/gamemodes/zombiesurvival/content/materials/zombiesurvival/zombiehead.vtf
new file mode 100644
index 0000000..53be77b
Binary files /dev/null and b/gamemodes/zombiesurvival/content/materials/zombiesurvival/zombiehead.vtf differ
diff --git a/gamemodes/zombiesurvival/content/models/player/fatty/fatty.dx80.vtx b/gamemodes/zombiesurvival/content/models/player/fatty/fatty.dx80.vtx
new file mode 100644
index 0000000..0b208d4
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/player/fatty/fatty.dx80.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/player/fatty/fatty.dx90.vtx b/gamemodes/zombiesurvival/content/models/player/fatty/fatty.dx90.vtx
new file mode 100644
index 0000000..74fee89
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/player/fatty/fatty.dx90.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/player/fatty/fatty.mdl b/gamemodes/zombiesurvival/content/models/player/fatty/fatty.mdl
new file mode 100644
index 0000000..60d6632
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/player/fatty/fatty.mdl differ
diff --git a/gamemodes/zombiesurvival/content/models/player/fatty/fatty.phy b/gamemodes/zombiesurvival/content/models/player/fatty/fatty.phy
new file mode 100644
index 0000000..1e551b3
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/player/fatty/fatty.phy differ
diff --git a/gamemodes/zombiesurvival/content/models/player/fatty/fatty.sw.vtx b/gamemodes/zombiesurvival/content/models/player/fatty/fatty.sw.vtx
new file mode 100644
index 0000000..43bcf62
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/player/fatty/fatty.sw.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/player/fatty/fatty.vvd b/gamemodes/zombiesurvival/content/models/player/fatty/fatty.vvd
new file mode 100644
index 0000000..f47e3dc
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/player/fatty/fatty.vvd differ
diff --git a/gamemodes/zombiesurvival/content/models/player/fatty/fatty.xbox.vtx b/gamemodes/zombiesurvival/content/models/player/fatty/fatty.xbox.vtx
new file mode 100644
index 0000000..6277f18
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/player/fatty/fatty.xbox.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.dx80.vtx b/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.dx80.vtx
new file mode 100644
index 0000000..a101333
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.dx80.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.dx90.vtx b/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.dx90.vtx
new file mode 100644
index 0000000..58c0bc8
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.dx90.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.mdl b/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.mdl
new file mode 100644
index 0000000..2b2d7ac
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.mdl differ
diff --git a/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.phy b/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.phy
new file mode 100644
index 0000000..fbe44f9
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.phy differ
diff --git a/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.sw.vtx b/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.sw.vtx
new file mode 100644
index 0000000..6a863cd
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.sw.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.vvd b/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.vvd
new file mode 100644
index 0000000..cfa2ddb
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/vinrax/player/doll_player.vvd differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_aegiskit.dx80.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_aegiskit.dx80.vtx
new file mode 100644
index 0000000..28cdd21
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_aegiskit.dx80.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_aegiskit.dx90.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_aegiskit.dx90.vtx
new file mode 100644
index 0000000..30e8b1e
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_aegiskit.dx90.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_aegiskit.mdl b/gamemodes/zombiesurvival/content/models/weapons/v_aegiskit.mdl
new file mode 100644
index 0000000..e088308
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_aegiskit.mdl differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_aegiskit.sw.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_aegiskit.sw.vtx
new file mode 100644
index 0000000..3b0e071
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_aegiskit.sw.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_aegiskit.vvd b/gamemodes/zombiesurvival/content/models/weapons/v_aegiskit.vvd
new file mode 100644
index 0000000..233019f
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_aegiskit.vvd differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_annabelle.dx80.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_annabelle.dx80.vtx
new file mode 100644
index 0000000..82f92b0
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_annabelle.dx80.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_annabelle.dx90.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_annabelle.dx90.vtx
new file mode 100644
index 0000000..d9bb7f7
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_annabelle.dx90.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_annabelle.mdl b/gamemodes/zombiesurvival/content/models/weapons/v_annabelle.mdl
new file mode 100644
index 0000000..6ed5a81
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_annabelle.mdl differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_annabelle.sw.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_annabelle.sw.vtx
new file mode 100644
index 0000000..3a40f65
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_annabelle.sw.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_annabelle.vvd b/gamemodes/zombiesurvival/content/models/weapons/v_annabelle.vvd
new file mode 100644
index 0000000..cb11380
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_annabelle.vvd differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_fza.dx80.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_fza.dx80.vtx
new file mode 100644
index 0000000..5844785
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_fza.dx80.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_fza.dx90.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_fza.dx90.vtx
new file mode 100644
index 0000000..a3a82ac
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_fza.dx90.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_fza.mdl b/gamemodes/zombiesurvival/content/models/weapons/v_fza.mdl
new file mode 100644
index 0000000..4c7aaac
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_fza.mdl differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_fza.sw.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_fza.sw.vtx
new file mode 100644
index 0000000..4a58d94
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_fza.sw.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_fza.vvd b/gamemodes/zombiesurvival/content/models/weapons/v_fza.vvd
new file mode 100644
index 0000000..6d9e09d
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_fza.vvd differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_hammer/v_hammer.dx80.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_hammer/v_hammer.dx80.vtx
new file mode 100644
index 0000000..916573c
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_hammer/v_hammer.dx80.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_hammer/v_hammer.dx90.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_hammer/v_hammer.dx90.vtx
new file mode 100644
index 0000000..2cdfa81
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_hammer/v_hammer.dx90.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_hammer/v_hammer.mdl b/gamemodes/zombiesurvival/content/models/weapons/v_hammer/v_hammer.mdl
new file mode 100644
index 0000000..b5fe377
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_hammer/v_hammer.mdl differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_hammer/v_hammer.sw.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_hammer/v_hammer.sw.vtx
new file mode 100644
index 0000000..1d3c306
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_hammer/v_hammer.sw.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_hammer/v_hammer.vvd b/gamemodes/zombiesurvival/content/models/weapons/v_hammer/v_hammer.vvd
new file mode 100644
index 0000000..2b486c0
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_hammer/v_hammer.vvd differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_pza.dx80.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_pza.dx80.vtx
new file mode 100644
index 0000000..62da39c
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_pza.dx80.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_pza.dx90.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_pza.dx90.vtx
new file mode 100644
index 0000000..196a014
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_pza.dx90.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_pza.mdl b/gamemodes/zombiesurvival/content/models/weapons/v_pza.mdl
new file mode 100644
index 0000000..562a5cb
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_pza.mdl differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_pza.sw.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_pza.sw.vtx
new file mode 100644
index 0000000..5049580
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_pza.sw.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_pza.vvd b/gamemodes/zombiesurvival/content/models/weapons/v_pza.vvd
new file mode 100644
index 0000000..f66a7a4
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_pza.vvd differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_sledgehammer/v_sledgehammer.dx80.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_sledgehammer/v_sledgehammer.dx80.vtx
new file mode 100644
index 0000000..525788a
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_sledgehammer/v_sledgehammer.dx80.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_sledgehammer/v_sledgehammer.dx90.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_sledgehammer/v_sledgehammer.dx90.vtx
new file mode 100644
index 0000000..231a1ab
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_sledgehammer/v_sledgehammer.dx90.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_sledgehammer/v_sledgehammer.mdl b/gamemodes/zombiesurvival/content/models/weapons/v_sledgehammer/v_sledgehammer.mdl
new file mode 100644
index 0000000..88418f7
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_sledgehammer/v_sledgehammer.mdl differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_sledgehammer/v_sledgehammer.sw.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_sledgehammer/v_sledgehammer.sw.vtx
new file mode 100644
index 0000000..99a284b
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_sledgehammer/v_sledgehammer.sw.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_sledgehammer/v_sledgehammer.vvd b/gamemodes/zombiesurvival/content/models/weapons/v_sledgehammer/v_sledgehammer.vvd
new file mode 100644
index 0000000..50dc19d
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_sledgehammer/v_sledgehammer.vvd differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_supershorty/v_supershorty.dx80.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_supershorty/v_supershorty.dx80.vtx
new file mode 100644
index 0000000..5828d60
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_supershorty/v_supershorty.dx80.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_supershorty/v_supershorty.dx90.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_supershorty/v_supershorty.dx90.vtx
new file mode 100644
index 0000000..07384c1
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_supershorty/v_supershorty.dx90.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_supershorty/v_supershorty.mdl b/gamemodes/zombiesurvival/content/models/weapons/v_supershorty/v_supershorty.mdl
new file mode 100644
index 0000000..0bf4ceb
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_supershorty/v_supershorty.mdl differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_supershorty/v_supershorty.sw.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_supershorty/v_supershorty.sw.vtx
new file mode 100644
index 0000000..d4eb857
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_supershorty/v_supershorty.sw.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_supershorty/v_supershorty.vvd b/gamemodes/zombiesurvival/content/models/weapons/v_supershorty/v_supershorty.vvd
new file mode 100644
index 0000000..b1c11b3
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_supershorty/v_supershorty.vvd differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_zombiearms.dx80.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_zombiearms.dx80.vtx
new file mode 100644
index 0000000..ff87552
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_zombiearms.dx80.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_zombiearms.dx90.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_zombiearms.dx90.vtx
new file mode 100644
index 0000000..9ed9928
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_zombiearms.dx90.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_zombiearms.mdl b/gamemodes/zombiesurvival/content/models/weapons/v_zombiearms.mdl
new file mode 100644
index 0000000..ac1025c
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_zombiearms.mdl differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_zombiearms.sw.vtx b/gamemodes/zombiesurvival/content/models/weapons/v_zombiearms.sw.vtx
new file mode 100644
index 0000000..e32e7cd
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_zombiearms.sw.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/v_zombiearms.vvd b/gamemodes/zombiesurvival/content/models/weapons/v_zombiearms.vvd
new file mode 100644
index 0000000..1700b41
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/v_zombiearms.vvd differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_hammer.dx80.vtx b/gamemodes/zombiesurvival/content/models/weapons/w_hammer.dx80.vtx
new file mode 100644
index 0000000..6de0299
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_hammer.dx80.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_hammer.dx90.vtx b/gamemodes/zombiesurvival/content/models/weapons/w_hammer.dx90.vtx
new file mode 100644
index 0000000..fb7ec03
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_hammer.dx90.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_hammer.mdl b/gamemodes/zombiesurvival/content/models/weapons/w_hammer.mdl
new file mode 100644
index 0000000..5c02be7
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_hammer.mdl differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_hammer.phy b/gamemodes/zombiesurvival/content/models/weapons/w_hammer.phy
new file mode 100644
index 0000000..70d238d
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_hammer.phy differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_hammer.sw.vtx b/gamemodes/zombiesurvival/content/models/weapons/w_hammer.sw.vtx
new file mode 100644
index 0000000..883e517
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_hammer.sw.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_hammer.vvd b/gamemodes/zombiesurvival/content/models/weapons/w_hammer.vvd
new file mode 100644
index 0000000..c154214
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_hammer.vvd differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.dx80.vtx b/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.dx80.vtx
new file mode 100644
index 0000000..cb5ccf9
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.dx80.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.dx90.vtx b/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.dx90.vtx
new file mode 100644
index 0000000..fe48fbd
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.dx90.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.mdl b/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.mdl
new file mode 100644
index 0000000..b678917
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.mdl differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.phy b/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.phy
new file mode 100644
index 0000000..98fc74a
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.phy differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.sw.vtx b/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.sw.vtx
new file mode 100644
index 0000000..e751e69
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.sw.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.vvd b/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.vvd
new file mode 100644
index 0000000..684247c
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_sledgehammer.vvd differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.dx80.vtx b/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.dx80.vtx
new file mode 100644
index 0000000..ba1e34e
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.dx80.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.dx90.vtx b/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.dx90.vtx
new file mode 100644
index 0000000..6da3241
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.dx90.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.mdl b/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.mdl
new file mode 100644
index 0000000..40c5621
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.mdl differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.phy b/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.phy
new file mode 100644
index 0000000..97742e8
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.phy differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.sw.vtx b/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.sw.vtx
new file mode 100644
index 0000000..08e76e3
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.sw.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.vvd b/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.vvd
new file mode 100644
index 0000000..d88b58a
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/weapons/w_supershorty.vvd differ
diff --git a/gamemodes/zombiesurvival/content/models/wraith_zsv1.dx80.vtx b/gamemodes/zombiesurvival/content/models/wraith_zsv1.dx80.vtx
new file mode 100644
index 0000000..305b3a0
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/wraith_zsv1.dx80.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/wraith_zsv1.dx90.vtx b/gamemodes/zombiesurvival/content/models/wraith_zsv1.dx90.vtx
new file mode 100644
index 0000000..2d11fc2
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/wraith_zsv1.dx90.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/wraith_zsv1.mdl b/gamemodes/zombiesurvival/content/models/wraith_zsv1.mdl
new file mode 100644
index 0000000..53853c0
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/wraith_zsv1.mdl differ
diff --git a/gamemodes/zombiesurvival/content/models/wraith_zsv1.phy b/gamemodes/zombiesurvival/content/models/wraith_zsv1.phy
new file mode 100644
index 0000000..b950769
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/wraith_zsv1.phy differ
diff --git a/gamemodes/zombiesurvival/content/models/wraith_zsv1.sw.vtx b/gamemodes/zombiesurvival/content/models/wraith_zsv1.sw.vtx
new file mode 100644
index 0000000..fc0cba7
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/wraith_zsv1.sw.vtx differ
diff --git a/gamemodes/zombiesurvival/content/models/wraith_zsv1.vvd b/gamemodes/zombiesurvival/content/models/wraith_zsv1.vvd
new file mode 100644
index 0000000..22663ab
Binary files /dev/null and b/gamemodes/zombiesurvival/content/models/wraith_zsv1.vvd differ
diff --git a/gamemodes/zombiesurvival/content/resource/fonts/hidden.ttf b/gamemodes/zombiesurvival/content/resource/fonts/hidden.ttf
new file mode 100644
index 0000000..2d00f81
Binary files /dev/null and b/gamemodes/zombiesurvival/content/resource/fonts/hidden.ttf differ
diff --git a/gamemodes/zombiesurvival/content/resource/fonts/typenoksidi.ttf b/gamemodes/zombiesurvival/content/resource/fonts/typenoksidi.ttf
new file mode 100644
index 0000000..65b5f02
Binary files /dev/null and b/gamemodes/zombiesurvival/content/resource/fonts/typenoksidi.ttf differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/crowbar/crowbar_hit-1.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/crowbar/crowbar_hit-1.ogg
new file mode 100644
index 0000000..d02f546
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/crowbar/crowbar_hit-1.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/crowbar/crowbar_hit-2.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/crowbar/crowbar_hit-2.ogg
new file mode 100644
index 0000000..3b40d6d
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/crowbar/crowbar_hit-2.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/crowbar/crowbar_hit-3.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/crowbar/crowbar_hit-3.ogg
new file mode 100644
index 0000000..4834c5d
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/crowbar/crowbar_hit-3.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/crowbar/crowbar_hit-4.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/crowbar/crowbar_hit-4.ogg
new file mode 100644
index 0000000..67e957e
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/crowbar/crowbar_hit-4.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/frying_pan/pan_hit-01.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/frying_pan/pan_hit-01.ogg
new file mode 100644
index 0000000..75f3512
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/frying_pan/pan_hit-01.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/frying_pan/pan_hit-02.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/frying_pan/pan_hit-02.ogg
new file mode 100644
index 0000000..402301f
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/frying_pan/pan_hit-02.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/frying_pan/pan_hit-03.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/frying_pan/pan_hit-03.ogg
new file mode 100644
index 0000000..c132e28
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/frying_pan/pan_hit-03.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/frying_pan/pan_hit-04.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/frying_pan/pan_hit-04.ogg
new file mode 100644
index 0000000..6ec683e
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/frying_pan/pan_hit-04.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/golf club/golf_hit-01.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/golf club/golf_hit-01.ogg
new file mode 100644
index 0000000..718ed79
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/golf club/golf_hit-01.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/golf club/golf_hit-02.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/golf club/golf_hit-02.ogg
new file mode 100644
index 0000000..143eff3
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/golf club/golf_hit-02.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/golf club/golf_hit-03.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/golf club/golf_hit-03.ogg
new file mode 100644
index 0000000..adcc7c5
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/golf club/golf_hit-03.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/golf club/golf_hit-04.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/golf club/golf_hit-04.ogg
new file mode 100644
index 0000000..39583fa
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/golf club/golf_hit-04.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/keyboard/keyboard_hit-01.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/keyboard/keyboard_hit-01.ogg
new file mode 100644
index 0000000..c46b120
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/keyboard/keyboard_hit-01.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/keyboard/keyboard_hit-02.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/keyboard/keyboard_hit-02.ogg
new file mode 100644
index 0000000..f4a4973
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/keyboard/keyboard_hit-02.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/keyboard/keyboard_hit-03.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/keyboard/keyboard_hit-03.ogg
new file mode 100644
index 0000000..ad3a396
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/keyboard/keyboard_hit-03.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/keyboard/keyboard_hit-04.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/keyboard/keyboard_hit-04.ogg
new file mode 100644
index 0000000..2834e99
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/keyboard/keyboard_hit-04.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/shovel/shovel_hit-01.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/shovel/shovel_hit-01.ogg
new file mode 100644
index 0000000..47652a8
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/shovel/shovel_hit-01.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/shovel/shovel_hit-02.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/shovel/shovel_hit-02.ogg
new file mode 100644
index 0000000..3daf0fc
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/shovel/shovel_hit-02.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/shovel/shovel_hit-03.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/shovel/shovel_hit-03.ogg
new file mode 100644
index 0000000..f825878
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/shovel/shovel_hit-03.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/weapons/melee/shovel/shovel_hit-04.ogg b/gamemodes/zombiesurvival/content/sound/weapons/melee/shovel/shovel_hit-04.ogg
new file mode 100644
index 0000000..204286e
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/weapons/melee/shovel/shovel_hit-04.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/1.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/1.ogg
new file mode 100644
index 0000000..c1c162f
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/1.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/2.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/2.ogg
new file mode 100644
index 0000000..90edcf0
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/2.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/3.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/3.ogg
new file mode 100644
index 0000000..7d94c2a
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/3.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/4.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/4.ogg
new file mode 100644
index 0000000..d4736f8
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/4.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/5.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/5.ogg
new file mode 100644
index 0000000..a218793
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/5.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/6.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/6.ogg
new file mode 100644
index 0000000..1763bfe
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/6.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/7.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/7.ogg
new file mode 100644
index 0000000..766ba87
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/7.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/8.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/8.ogg
new file mode 100644
index 0000000..4713087
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/8.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/9.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/9.ogg
new file mode 100644
index 0000000..cccb9cc
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaulthuman/9.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/1.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/1.ogg
new file mode 100644
index 0000000..d6eabea
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/1.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/10.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/10.ogg
new file mode 100644
index 0000000..5bc747f
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/10.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/2.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/2.ogg
new file mode 100644
index 0000000..6d42cf5
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/2.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/3.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/3.ogg
new file mode 100644
index 0000000..c52c5e8
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/3.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/4.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/4.ogg
new file mode 100644
index 0000000..4d37509
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/4.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/5.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/5.ogg
new file mode 100644
index 0000000..61bd598
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/5.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/6.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/6.ogg
new file mode 100644
index 0000000..a03d2c8
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/6.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/7.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/7.ogg
new file mode 100644
index 0000000..2c0d5a5
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/7.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/8.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/8.ogg
new file mode 100644
index 0000000..45f1858
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/8.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/9.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/9.ogg
new file mode 100644
index 0000000..35873df
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/beats/defaultzombiev2/9.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/ding.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/ding.ogg
new file mode 100644
index 0000000..0771566
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/ding.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/lasthuman.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/lasthuman.ogg
new file mode 100644
index 0000000..a88fa44
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/lasthuman.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/music_lose.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/music_lose.ogg
new file mode 100644
index 0000000..c339259
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/music_lose.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/music_win.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/music_win.ogg
new file mode 100644
index 0000000..67356e7
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/music_win.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/wraithdeath1.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/wraithdeath1.ogg
new file mode 100644
index 0000000..ca6e8dd
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/wraithdeath1.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/wraithdeath2.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/wraithdeath2.ogg
new file mode 100644
index 0000000..513148c
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/wraithdeath2.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/wraithdeath3.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/wraithdeath3.ogg
new file mode 100644
index 0000000..5924a28
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/wraithdeath3.ogg differ
diff --git a/gamemodes/zombiesurvival/content/sound/zombiesurvival/wraithdeath4.ogg b/gamemodes/zombiesurvival/content/sound/zombiesurvival/wraithdeath4.ogg
new file mode 100644
index 0000000..290e5f5
Binary files /dev/null and b/gamemodes/zombiesurvival/content/sound/zombiesurvival/wraithdeath4.ogg differ
diff --git a/gamemodes/zombiesurvival/convars.txt b/gamemodes/zombiesurvival/convars.txt
new file mode 100644
index 0000000..6a79f13
--- /dev/null
+++ b/gamemodes/zombiesurvival/convars.txt
@@ -0,0 +1,2 @@
+There are a plethora of new convars. You can use these after the +map declaration in your srcds.exe line or just put them in the console.
+For an updated list of convars and what they do, type "find zs_" in the console.
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/entities/effects/bloodstream.lua b/gamemodes/zombiesurvival/entities/effects/bloodstream.lua
new file mode 100644
index 0000000..e1a24f1
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/bloodstream.lua
@@ -0,0 +1,87 @@
+util.PrecacheSound("physics/flesh/flesh_bloody_impact_hard1.wav")
+util.PrecacheSound("physics/flesh/flesh_squishy_impact_hard1.wav")
+util.PrecacheSound("physics/flesh/flesh_squishy_impact_hard2.wav")
+util.PrecacheSound("physics/flesh/flesh_squishy_impact_hard3.wav")
+util.PrecacheSound("physics/flesh/flesh_squishy_impact_hard4.wav")
+
+local function CollideCallbackSmall(particle, hitpos, hitnormal)
+ if particle:GetDieTime() == 0 then return end
+ particle:SetDieTime(0)
+
+ if math.random(3) == 3 then
+ sound.Play("physics/flesh/flesh_bloody_impact_hard1.wav", hitpos, 50, math.Rand(95, 105))
+ util.Decal("Impact.Flesh", hitpos + hitnormal, hitpos - hitnormal)
+ end
+end
+
+local function CollideCallback(oldparticle, hitpos, hitnormal)
+ if oldparticle:GetDieTime() == 0 then return end
+ oldparticle:SetDieTime(0)
+
+ local pos = hitpos + hitnormal
+
+ if math.random(3) == 3 then
+ sound.Play("physics/flesh/flesh_squishy_impact_hard"..math.random(4)..".wav", hitpos, 50, math.Rand(95, 105))
+ end
+ util.Decal("Blood", pos, hitpos - hitnormal)
+
+ local num = math.random(-4, 4)
+ if num < 1 then return end
+
+ local nhitnormal = hitnormal * 90
+
+ local emitter = ParticleEmitter(pos)
+ for i=1, num do
+ local particle = emitter:Add("noxctf/sprite_bloodspray"..math.random(8), pos)
+ particle:SetLighting(true)
+ particle:SetVelocity(VectorRand():GetNormalized() * math.Rand(75, 150) + nhitnormal)
+ particle:SetDieTime(3)
+ particle:SetStartAlpha(255)
+ particle:SetEndAlpha(255)
+ particle:SetStartSize(math.Rand(1.5, 2.5))
+ particle:SetEndSize(1.5)
+ particle:SetRoll(math.Rand(-25, 25))
+ particle:SetRollDelta(math.Rand(-25, 25))
+ particle:SetAirResistance(5)
+ particle:SetGravity(Vector(0, 0, -600))
+ particle:SetCollide(true)
+ particle:SetColor(255, 0, 0)
+ particle:SetCollideCallback(CollideCallbackSmall)
+ end
+ emitter:Finish()
+end
+
+function EFFECT:Init(data)
+ local pos = data:GetOrigin() + Vector(0, 0, 10)
+
+ local dir = data:GetNormal()
+ local force = data:GetScale()
+
+ local emitter = ParticleEmitter(pos)
+ for i=1, data:GetMagnitude() do
+ local heading = (VectorRand():GetNormalized() * 3 + dir) / 4
+ local particle = emitter:Add("noxctf/sprite_bloodspray"..math.random(8), pos + heading)
+ particle:SetVelocity(force * math.Rand(0.8, 1) * heading)
+ particle:SetDieTime(math.Rand(3, 6))
+ particle:SetStartAlpha(200)
+ particle:SetEndAlpha(200)
+ particle:SetStartSize(math.Rand(3, 5))
+ particle:SetEndSize(3)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-20, 20))
+ particle:SetAirResistance(5)
+ particle:SetGravity(Vector(0, 0, -600))
+ particle:SetCollide(true)
+ particle:SetLighting(true)
+ particle:SetColor(255, 0, 0)
+ particle:SetCollideCallback(CollideCallback)
+ end
+ emitter:Finish()
+end
+
+function EFFECT:Think()
+ return false
+end
+
+function EFFECT:Render()
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/bonemeshexplode.lua b/gamemodes/zombiesurvival/entities/effects/bonemeshexplode.lua
new file mode 100644
index 0000000..b28e9ff
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/bonemeshexplode.lua
@@ -0,0 +1,43 @@
+function EFFECT:Think()
+ return false
+end
+
+function EFFECT:Render()
+end
+
+function EFFECT:Init(data)
+ local pos = data:GetOrigin()
+
+ sound.Play("physics/body/body_medium_break"..math.random(2, 4)..".wav", pos, 77, math.Rand(95, 105))
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(16, 48)
+
+ local particle = emitter:Add("particles/smokey", pos)
+ particle:SetDieTime(0.5)
+ particle:SetStartAlpha(255)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(1)
+ particle:SetEndSize(32)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(40, 60) * (math.random(2) == 1 and -1 or 1))
+ particle:SetColor(255, 30, 30)
+ particle:SetLighting(true)
+
+ for i = 1, math.random(100, 130) do
+ local particle = emitter:Add("particles/smokey", pos)
+ particle:SetVelocity(VectorRand():GetNormalized() * math.Rand(128, 350))
+ particle:SetAirResistance(100)
+ particle:SetDieTime(math.Rand(0.9, 2))
+ particle:SetStartAlpha(200)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(math.Rand(1, 3))
+ particle:SetEndSize(0)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-30, 30))
+ particle:SetColor(255, 30, 30)
+ particle:SetLighting(true)
+ end
+
+ emitter:Finish()
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/chemzombieexplode.lua b/gamemodes/zombiesurvival/entities/effects/chemzombieexplode.lua
new file mode 100644
index 0000000..24650d7
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/chemzombieexplode.lua
@@ -0,0 +1,67 @@
+function EFFECT:Init(data)
+ local pos = data:GetOrigin()
+ pos = pos + Vector(0, 0, 48)
+
+ sound.Play("ambient/explosions/explode_9.wav", pos, 90, math.Rand(85, 95))
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(40, 45)
+ for i=1, math.random(12, 15) do
+ local heading = VectorRand():GetNormalized()
+ local particle = emitter:Add("particle/smokestack", pos + heading * 16)
+ particle:SetVelocity(heading * 72)
+ particle:SetDieTime(math.Rand(1.7, 2.0))
+ particle:SetStartAlpha(220)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(32)
+ particle:SetEndSize(4)
+ particle:SetColor(20, 100, 20)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-1, 1))
+ end
+ for i=1, math.random(5, 8) do
+ local particle = emitter:Add("particle/smokestack", pos)
+ particle:SetVelocity(VectorRand():GetNormalized() * math.Rand(48, 82))
+ particle:SetDieTime(math.Rand(2.2, 3.6))
+ particle:SetStartAlpha(220)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(8)
+ particle:SetEndSize(100)
+ particle:SetColor(0, 30, 0)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-1, 1))
+ particle:SetAirResistance(10)
+ end
+ for i=1, math.random(17, 21) do
+ local particle = emitter:Add("effects/fire_cloud1", pos + VectorRand() * 32)
+ local dir = VectorRand():GetNormalized()
+ particle:SetVelocity(dir * math.Rand(500, 600))
+ particle:SetDieTime(math.Rand(1.0, 1.25))
+ particle:SetStartAlpha(220)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(60)
+ particle:SetEndSize(30)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-3, 3))
+ particle:SetAirResistance(60)
+ particle:SetGravity(dir * math.Rand(-600, -500))
+ end
+ for i=1, 2 do
+ local particle = emitter:Add("effects/fire_cloud1", pos)
+ particle:SetDieTime(math.Rand(0.3, 0.35))
+ particle:SetStartAlpha(255)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(16)
+ particle:SetEndSize(300)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-30, 30))
+ end
+ emitter:Finish()
+end
+
+function EFFECT:Think()
+ return false
+end
+
+function EFFECT:Render()
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/damagenumber.lua b/gamemodes/zombiesurvival/entities/effects/damagenumber.lua
new file mode 100644
index 0000000..b8984cc
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/damagenumber.lua
@@ -0,0 +1,84 @@
+EFFECT.LifeTime = 3
+
+local TEXT_ALIGN_CENTER = TEXT_ALIGN_CENTER
+local TEXT_ALIGN_TOP = TEXT_ALIGN_TOP
+local draw = draw
+local cam = cam
+
+local Particles = {}
+
+local col = Color(220, 0, 0)
+local colprop = Color(220, 220, 0)
+hook.Add("PostDrawTranslucentRenderables", "DrawDamage", function()
+ if #Particles == 0 then return end
+
+ local done = true
+ local curtime = CurTime()
+
+ local ang = EyeAngles()
+ local right = ang:Right()
+ ang:RotateAroundAxis(ang:Up(), -90)
+ ang:RotateAroundAxis(ang:Forward(), 90)
+
+ --cam.IgnoreZ(true)
+
+ for _, particle in pairs(Particles) do
+ if particle and curtime < particle.DieTime then
+ local c = particle.Type == 1 and colprop or col
+
+ done = false
+
+ c.a = math.Clamp(particle.DieTime - curtime, 0, 1) * 220
+
+ cam.Start3D2D(particle:GetPos(), ang, 0.1)
+ draw.SimpleText(particle.Amount, "ZS3D2DFont2", 0, 0, c, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
+ cam.End3D2D()
+ end
+ end
+
+ --cam.IgnoreZ(false)
+
+ if done then
+ Particles = {}
+ end
+end)
+
+local gravity = Vector(0, 0, -500)
+
+function EFFECT:Init(data)
+ local pos = data:GetOrigin()
+ local amount = data:GetMagnitude()
+ local Type = data:GetScale()
+
+ local vel = VectorRand()
+ vel.z = math.Rand(0.7, 0.98)
+ vel:Normalize()
+
+ local emitter = ParticleEmitter(pos)
+ local particle = emitter:Add("sprites/glow04_noz", pos)
+ particle:SetDieTime(2)
+ particle:SetStartAlpha(0)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(0)
+ particle:SetEndSize(0)
+ particle:SetCollide(true)
+ particle:SetBounce(0.7)
+ particle:SetAirResistance(32)
+ particle:SetGravity(gravity)
+ particle:SetVelocity(math.Clamp(amount, 5, 50) * 4 * vel)
+
+ particle.Amount = amount
+ particle.DieTime = CurTime() + 2
+ particle.Type = Type
+
+ table.insert(Particles, particle)
+
+ emitter:Finish()
+end
+
+function EFFECT:Think()
+ return false
+end
+
+function EFFECT:Render()
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/dismemberment.lua b/gamemodes/zombiesurvival/entities/effects/dismemberment.lua
new file mode 100644
index 0000000..4cf0052
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/dismemberment.lua
@@ -0,0 +1,137 @@
+function EFFECT:Init(data)
+ self.eEnt = data:GetEntity()
+ self.iScale = math.Round(data:GetScale())
+
+ self.DieTime = CurTime() + 3
+end
+
+local Dismembers = {DISMEMBER_HEAD, DISMEMBER_LEFTLEG, DISMEMBER_RIGHTLEG, DISMEMBER_LEFTARM, DISMEMBER_RIGHTARM}
+local DismemberBones = {
+{ToZero = {"ValveBiped.Bip01_Head1"}, ToBleed = {["ValveBiped.Bip01_Head1"] = true}},
+{ToZero = {"ValveBiped.Bip01_L_Thigh", "ValveBiped.Bip01_L_Calf", "ValveBiped.Bip01_L_Foot"}, ToBleed = {["ValveBiped.Bip01_L_Thigh"]=true}},
+{ToZero = {"ValveBiped.Bip01_R_Thigh", "ValveBiped.Bip01_R_Calf", "ValveBiped.Bip01_R_Foot"}, ToBleed = {["ValveBiped.Bip01_R_Thigh"]=true}},
+{ToZero = {"ValveBiped.Bip01_L_UpperArm", "ValveBiped.Bip01_L_Forearm", "ValveBiped.Bip01_L_Hand"}, ToBleed = {["ValveBiped.Bip01_L_UpperArm"]=true}},
+{ToZero = {"ValveBiped.Bip01_R_UpperArm", "ValveBiped.Bip01_R_Forearm", "ValveBiped.Bip01_R_Hand"}, ToBleed = {["ValveBiped.Bip01_R_UpperArm"]=true}}
+}
+
+local BoneTranslates = {}
+BoneTranslates["models/zombie/classic.mdl"] = {["ValveBiped.Bip01_Head1"]="ValveBiped.Bip01_Spine2"}
+BoneTranslates["models/zombie/poison.mdl"] = {["ValveBiped.Bip01_Head1"]="ValveBiped.Bip01_Spine4"}
+BoneTranslates["models/zombie/fast.mdl"] = {["ValveBiped.Bip01_Head1"]="ValveBiped.HC_BodyCube"}
+BoneTranslates["models/player/zombie_classic.mdl"] = {["ValveBiped.Bip01_Head1"]="ValveBiped.Bip01_Spine4"}
+
+local function CollideCallback(particle, hitpos, hitnormal)
+ if particle:GetDieTime() == 0 then return end
+ particle:SetDieTime(0)
+
+ if math.random(6) == 1 then
+ sound.Play("physics/flesh/flesh_bloody_impact_hard1.wav", hitpos, 50, math.random(95, 105))
+ end
+
+ util.Decal("Impact.Flesh", hitpos + hitnormal, hitpos - hitnormal)
+end
+
+function EFFECT:Think()
+ local eEnt = self.eEnt
+
+ if not self.SetDoll and eEnt:IsValid() and eEnt:IsPlayer() then
+ local eRag = eEnt:GetRagdollEntity()
+ if eRag and eRag:IsValid() then
+ self.SetDoll = true
+ self.eRagdoll = eRag
+ eRag.Dismemberment = bit.bor((eRag.Dismemberment or 0), self.iScale)
+ self.DieTime = CurTime() + math.Rand(5, 7)
+ eRag.NextEmit = 0
+ self.Entity:SetRenderBounds(Vector(-128, -128, -128), Vector(128, 128, 128))
+ end
+ end
+
+ if self.eRagdoll and self.eRagdoll:IsValid() then
+ self.Entity:SetPos(self.eRagdoll:GetPos())
+ end
+
+ return CurTime() < self.DieTime
+end
+
+function EFFECT:Render()
+ local eRagdoll = self.eRagdoll
+ local fCurTime = CurTime()
+
+ if eRagdoll and eRagdoll:IsValid() and eRagdoll.NextEmit <= fCurTime then
+ eRagdoll.NextEmit = fCurTime + 0.05
+
+ local emitter = ParticleEmitter(eRagdoll:GetPos())
+ emitter:SetNearClip(20, 30)
+
+ local iDismemberment = eRagdoll.Dismemberment or 0
+ for index, iDismemberPart in pairs(Dismembers) do
+ if bit.band(iDismemberPart, iDismemberment) == iDismemberPart then
+ for _, sZeroBone in pairs(DismemberBones[index].ToZero) do
+ local mdl = string.lower(eRagdoll:GetModel())
+ if BoneTranslates[mdl] and BoneTranslates[mdl][sZeroBone] then
+ sZeroBone = BoneTranslates[mdl][sZeroBone]
+ end
+
+ local iBone = eRagdoll:LookupBone(sZeroBone)
+ if iBone and iBone > 0 then
+ eRagdoll:ManipulateBoneScale(iBone, vector_tiny)
+ end
+ end
+
+ for sZeroBone in pairs(DismemberBones[index].ToBleed) do
+ local mdl = string.lower(eRagdoll:GetModel())
+ if BoneTranslates[mdl] and BoneTranslates[mdl][sZeroBone] then
+ sZeroBone = BoneTranslates[mdl][sZeroBone]
+ end
+
+ local iBone = eRagdoll:LookupBone(sZeroBone)
+ if iBone and iBone > 0 then
+ local delta = math.max(0, self.DieTime - fCurTime)
+ if 0 < delta then
+ local vBonePos, aBoneAng = eRagdoll:GetBonePosition(iBone)
+ if vBonePos and aBoneAng then
+ emitter:SetPos(vBonePos)
+ local vForward = aBoneAng:Forward()
+ for i=1, math.random(0, 2) do
+ local particle = emitter:Add("noxctf/sprite_bloodspray"..math.random(8), vBonePos)
+ local force = math.min(1.5, delta) * math.Rand(175, 300)
+ particle:SetVelocity(force * vForward + 0.2 * force * VectorRand())
+ particle:SetDieTime(math.Rand(2.25, 3))
+ particle:SetStartAlpha(240)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(math.random(1, 8))
+ particle:SetEndSize(0)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-40, 40))
+ particle:SetColor(255, 0, 0)
+ particle:SetAirResistance(5)
+ particle:SetBounce(0)
+ particle:SetGravity(Vector(0, 0, -600))
+ particle:SetCollide(true)
+ particle:SetCollideCallback(CollideCallback)
+ particle:SetLighting(true)
+ end
+ local particle = emitter:Add("noxctf/sprite_bloodspray"..math.random(8), vBonePos)
+ local vel = eRagdoll:GetVelocity()
+ particle:SetVelocity(vel)
+ particle:SetDieTime(math.Rand(0.5, 0.75))
+ particle:SetStartAlpha(240)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(math.random(6, 12))
+ particle:SetEndSize(0)
+ particle:SetRoll(math.Rand(0, 360))
+ local vellength = vel:Length() * 0.45
+ particle:SetRollDelta(math.Rand(-vellength, vellength))
+ particle:SetColor(255, 0, 0)
+ particle:SetAirResistance(20)
+ particle:SetLighting(true)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ emitter:Finish()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/fatexplosion.lua b/gamemodes/zombiesurvival/entities/effects/fatexplosion.lua
new file mode 100644
index 0000000..5001c50
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/fatexplosion.lua
@@ -0,0 +1,47 @@
+function EFFECT:Init(data)
+ local pos = data:GetOrigin()
+ local norm = data:GetNormal()
+
+ sound.Play("physics/body/body_medium_break"..math.random(2, 4)..".wav", pos, 77, math.Rand(90, 110))
+ for i=0, math.random(2, 3) do
+ timer.SimpleEx(i * math.Rand(0.1, 0.3), sound.Play, "physics/flesh/flesh_squishy_impact_hard"..math.random(4)..".wav", pos, 77, math.Rand(90, 110))
+ end
+
+ local emitter = ParticleEmitter(pos)
+
+ for i=1, 12 do
+ local particle = emitter:Add("noxctf/sprite_bloodspray"..math.random(8), pos)
+ particle:SetVelocity(norm * 32 + VectorRand() * 16)
+ particle:SetDieTime(math.Rand(1.5, 2.5))
+ particle:SetStartAlpha(200)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(math.Rand(13, 14))
+ particle:SetEndSize(math.Rand(10, 12))
+ particle:SetRoll(180)
+ particle:SetDieTime(3)
+ particle:SetColor(255, 255, 0)
+ particle:SetLighting(true)
+ end
+
+ local particle = emitter:Add("noxctf/sprite_bloodspray"..math.random(8), pos)
+ particle:SetVelocity(norm * 32)
+ particle:SetDieTime(math.Rand(2.25, 3))
+ particle:SetStartAlpha(200)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(math.Rand(28, 32))
+ particle:SetEndSize(math.Rand(14, 28))
+ particle:SetRoll(180)
+ particle:SetColor(255, 255, 0)
+ particle:SetLighting(true)
+
+ emitter:Finish()
+
+ util.Blood(pos, math.random(16, 22), Vector(0,0,1), 300)
+end
+
+function EFFECT:Think()
+ return false
+end
+
+function EFFECT:Render()
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/fleshhit.lua b/gamemodes/zombiesurvival/entities/effects/fleshhit.lua
new file mode 100644
index 0000000..2e90d4a
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/fleshhit.lua
@@ -0,0 +1,48 @@
+function EFFECT:Think()
+ return false
+end
+
+function EFFECT:Render()
+end
+
+local function CollideCallback(particle, hitpos, hitnormal)
+ if particle:GetDieTime() == 0 then return end
+ particle:SetDieTime(0)
+
+ if math.random(3) == 3 then
+ sound.Play("physics/flesh/flesh_bloody_impact_hard1.wav", hitpos, 50, math.Rand(95, 105))
+ end
+
+ if math.random(3) == 3 then
+ util.Decal("Impact.Antlion", hitpos + hitnormal, hitpos - hitnormal)
+ end
+end
+
+function EFFECT:Init(data)
+ local pos = data:GetOrigin()
+ local normal = data:GetNormal() * -1
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(28, 32)
+ local grav = Vector(0, 0, -500)
+ for i=1, math.random(4, 7) do
+ local particle = emitter:Add("decals/Yblood"..math.random(6), pos)
+ particle:SetVelocity(VectorRand():GetNormalized() * math.Rand(16, 64))
+ particle:SetDieTime(math.Rand(2.5, 4.0))
+ particle:SetStartAlpha(255)
+ particle:SetEndAlpha(50)
+ particle:SetStartSize(math.Rand(2, 4))
+ particle:SetEndSize(0)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-1, 1))
+ particle:SetCollide(true)
+ particle:SetGravity(grav)
+ particle:SetCollideCallback(CollideCallback)
+ particle:SetLighting(true)
+ end
+ emitter:Finish()
+
+ util.Decal("YellowBlood", pos + normal, pos - normal)
+
+ sound.Play("physics/flesh/flesh_squishy_impact_hard"..math.random(4)..".wav", pos, 80, math.Rand(95, 110))
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/floatingscore.lua b/gamemodes/zombiesurvival/entities/effects/floatingscore.lua
new file mode 100644
index 0000000..96bbc59
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/floatingscore.lua
@@ -0,0 +1,49 @@
+EFFECT.LifeTime = 3
+
+function EFFECT:Init(data)
+ self:SetRenderBounds(Vector(-64, -64, -64), Vector(64, 64, 64))
+
+ self.Seed = math.Rand(0, 10)
+
+ local pos = data:GetOrigin()
+ local amount = math.Round(data:GetMagnitude())
+
+ self.Pos = pos
+ local flag = math.Round(data:GetScale()) or 0
+ if flag == FM_LOCALKILLOTHERASSIST then
+ self.Amount = amount.." (assisted)"
+ elseif flag == FM_LOCALASSISTOTHERKILL then
+ self.Amount = amount.." (assist)"
+ else
+ self.Amount = amount
+ end
+ self.ColID = flag
+
+ self.DeathTime = CurTime() + self.LifeTime
+end
+
+function EFFECT:Think()
+ self.Pos.z = self.Pos.z + FrameTime() * 32
+ return CurTime() < self.DeathTime
+end
+
+local cols = {}
+cols[0] = Color(190, 190, 220, 255)
+cols[1] = Color(255, 255, 10, 255)
+cols[2] = Color(255, 10, 10, 255)
+local col2 = Color(0, 0, 0, 255)
+function EFFECT:Render()
+ local delta = math.Clamp(self.DeathTime - CurTime(), 0, self.LifeTime) / self.LifeTime
+ local col = cols[self.ColID] or cols[0]
+ col.a = delta * 240
+ col2.a = col.a
+ local ang = EyeAngles()
+ local right = ang:Right()
+ ang:RotateAroundAxis(ang:Up(), 270)
+ ang:RotateAroundAxis(ang:Forward(), 90)
+ cam.IgnoreZ(true)
+ cam.Start3D2D(self.Pos + math.sin(CurTime() + self.Seed) * 30 * delta * right, ang, (delta * 0.12 + 0.045) / 2)
+ draw.SimpleText(self.Amount, "ZS3D2DFont2Big", 0, -21, col, TEXT_ALIGN_CENTER)
+ cam.End3D2D()
+ cam.IgnoreZ(false)
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/floatingscore_com.lua b/gamemodes/zombiesurvival/entities/effects/floatingscore_com.lua
new file mode 100644
index 0000000..76d7091
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/floatingscore_com.lua
@@ -0,0 +1,37 @@
+EFFECT.LifeTime = 3
+
+function EFFECT:Init(data)
+ self:SetRenderBounds(Vector(-64, -64, -64), Vector(64, 64, 64))
+
+ self.Seed = math.Rand(0, 10)
+
+ local pos = data:GetOrigin()
+ local amount = math.Round(data:GetMagnitude())
+
+ self.Pos = pos
+ self.Amount = amount
+
+ self.DeathTime = CurTime() + self.LifeTime
+end
+
+function EFFECT:Think()
+ self.Pos.z = self.Pos.z + FrameTime() * 32
+ return CurTime() < self.DeathTime
+end
+
+local col = Color(255, 255, 0, 255)
+local col2 = Color(0, 0, 0, 255)
+function EFFECT:Render()
+ local delta = math.Clamp(self.DeathTime - CurTime(), 0, self.LifeTime) / self.LifeTime
+ col.a = delta * 240
+ col2.a = col.a
+ local ang = EyeAngles()
+ local right = ang:Right()
+ ang:RotateAroundAxis(ang:Up(), -90)
+ ang:RotateAroundAxis(ang:Forward(), 90)
+ cam.IgnoreZ(true)
+ cam.Start3D2D(self.Pos + math.sin(CurTime() + self.Seed) * 30 * delta * right, ang, (delta * 0.12 + 0.045) / 2)
+ draw.SimpleText(self.Amount.." point"..(self.Amount ~= 1 and "s" or ""), "ZS3D2DFont2Big", 0, -21, col, TEXT_ALIGN_CENTER)
+ cam.End3D2D()
+ cam.IgnoreZ(false)
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/floatingscore_und.lua b/gamemodes/zombiesurvival/entities/effects/floatingscore_und.lua
new file mode 100644
index 0000000..515e370
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/floatingscore_und.lua
@@ -0,0 +1,50 @@
+local messages = {"MUNCH!",
+"BRAIN GET!",
+"+1!",
+"JOIN US!",
+"ONE OF US!",
+"BUTT MANGLED!",
+"CHOMP!"
+}
+
+EFFECT.LifeTime = 3
+
+function EFFECT:Init(data)
+ self:SetRenderBounds(Vector(-64, -64, -64), Vector(64, 64, 64))
+
+ self.Seed = math.Rand(0, 10)
+
+ local pos = data:GetOrigin()
+ local amount = math.Round(data:GetMagnitude())
+
+ self.Pos = pos
+ if amount > 1 then
+ self.Message = amount.." BRAINS!"
+ else
+ self.Message = messages[math.random(#messages)]
+ end
+
+ self.DeathTime = CurTime() + self.LifeTime
+end
+
+function EFFECT:Think()
+ self.Pos.z = self.Pos.z + FrameTime() * 32
+ return CurTime() < self.DeathTime
+end
+
+local col = Color(40, 255, 40, 255)
+local col2 = Color(0, 0, 0, 255)
+function EFFECT:Render()
+ local delta = math.Clamp(self.DeathTime - CurTime(), 0, self.LifeTime) / self.LifeTime
+ col.a = delta * 240
+ col2.a = col.a
+ local ang = EyeAngles()
+ local right = ang:Right()
+ ang:RotateAroundAxis(ang:Up(), -90)
+ ang:RotateAroundAxis(ang:Forward(), 90)
+ cam.IgnoreZ(true)
+ cam.Start3D2D(self.Pos + math.sin(CurTime() + self.Seed) * 30 * delta * right, ang, (delta * 0.24 + 0.09) / 2)
+ draw.SimpleText(self.Message, "ZS3D2DFont2", 0, -21, col, TEXT_ALIGN_CENTER)
+ cam.End3D2D()
+ cam.IgnoreZ(false)
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/gib_player.lua b/gamemodes/zombiesurvival/entities/effects/gib_player.lua
new file mode 100644
index 0000000..d93601f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/gib_player.lua
@@ -0,0 +1,77 @@
+util.PrecacheSound("physics/flesh/flesh_bloody_break.wav")
+
+local function CollideCallback(oldparticle, hitpos, hitnormal)
+ if oldparticle:GetDieTime() == 0 then return end
+ oldparticle:SetDieTime(0)
+
+ local pos = hitpos + hitnormal
+
+ if math.random(3) == 3 then
+ sound.Play("physics/flesh/flesh_squishy_impact_hard"..math.random(4)..".wav", hitpos, 50, math.Rand(95, 105))
+ end
+ util.Decal("Blood", pos, hitpos - hitnormal)
+end
+
+local vecGravity = Vector(0, 0, -500)
+function EFFECT:Init(data)
+ local ent = data:GetEntity()
+ if not ent:IsValid() then return end
+
+ ent:EmitSound("physics/flesh/flesh_bloody_break.wav")
+
+ local basepos = ent:GetPos()
+ local vel = ent:GetVelocity()
+ local dir = vel:GetNormalized()
+ local up = ent:GetUp()
+ local speed = math.Clamp(vel:Length() * 2, 512, 2048)
+
+ local emitter = ParticleEmitter(ent:LocalToWorld(ent:OBBCenter()))
+ emitter:SetNearClip(24, 32)
+
+ for boneid = 1, ent:GetBoneCount() - 1 do
+ local pos, ang = ent:GetBonePositionMatrixed(boneid)
+ if pos and pos ~= basepos then
+ for i=1, math.random(1, 3) do
+ local heading = (VectorRand():GetNormalized() + up + dir * 2) / 4
+ local particle = emitter:Add("noxctf/sprite_bloodspray"..math.random(8), pos + heading)
+ particle:SetVelocity(speed * math.Rand(0.5, 1) * heading)
+ particle:SetDieTime(math.Rand(3, 6))
+ particle:SetStartAlpha(200)
+ particle:SetEndAlpha(200)
+ particle:SetStartSize(math.Rand(3, 4))
+ particle:SetEndSize(2)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-20, 20))
+ particle:SetAirResistance(8)
+ particle:SetGravity(vecGravity)
+ particle:SetCollide(true)
+ particle:SetLighting(true)
+ particle:SetColor(255, 0, 0)
+ particle:SetCollideCallback(CollideCallback)
+ end
+
+ for i=1, 4 do
+ local particle = emitter:Add("noxctf/sprite_bloodspray"..math.random(8), pos)
+ particle:SetVelocity(math.Rand(0.5, 4) * (VectorRand():GetNormalized() + dir))
+ particle:SetDieTime(math.Rand(0.75, 2))
+ particle:SetStartAlpha(230)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(math.Rand(4, 5))
+ particle:SetEndSize(3)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-1, 1))
+ particle:SetLighting(true)
+ particle:SetColor(255, 0, 0)
+ end
+ end
+ end
+
+ emitter:Finish()
+end
+
+function EFFECT:Think()
+ return false
+end
+
+function EFFECT:Render()
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/headshot.lua b/gamemodes/zombiesurvival/entities/effects/headshot.lua
new file mode 100644
index 0000000..6901e1f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/headshot.lua
@@ -0,0 +1,73 @@
+function EFFECT:Init(data)
+ local pos = data:GetOrigin()
+ local norm = data:GetNormal()
+ local mag = data:GetMagnitude()
+ local ent = data:GetEntity()
+ local scale = math.Round(data:GetScale())
+
+ if ent:IsPlayer() then
+ ent:Dismember(DISMEMBER_HEAD)
+ end
+
+ sound.Play("physics/flesh/flesh_bloody_break.wav", pos, 77, math.Rand(50, 100))
+ sound.Play("physics/body/body_medium_break"..math.random(2, 4)..".wav", pos, 77, math.Rand(90, 110))
+
+ local emitter = ParticleEmitter(pos)
+ for i=1, 12 do
+ local particle = emitter:Add("noxctf/sprite_bloodspray"..math.random(8), pos)
+ particle:SetVelocity(norm * 32 + VectorRand() * 16)
+ particle:SetDieTime(math.Rand(1.5, 2.5))
+ particle:SetStartAlpha(200)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(math.Rand(13, 14))
+ particle:SetEndSize(math.Rand(10, 12))
+ particle:SetRoll(180)
+ particle:SetDieTime(3)
+ particle:SetColor(255, 0, 0)
+ particle:SetLighting(true)
+ end
+ local particle = emitter:Add("noxctf/sprite_bloodspray"..math.random(8), pos)
+ particle:SetVelocity(norm * 32)
+ particle:SetDieTime(math.Rand(2.25, 3))
+ particle:SetStartAlpha(200)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(math.Rand(28, 32))
+ particle:SetEndSize(math.Rand(14, 28))
+ particle:SetRoll(180)
+ particle:SetColor(255, 0, 0)
+ particle:SetLighting(true)
+ emitter:Finish()
+
+ util.Blood(pos, math.random(8, 10), Vector(0, 0, 1), 128)
+
+ local maxbound = Vector(3, 3, 3)
+ local minbound = maxbound * -1
+ for i=1, math.random(5, 8) do
+ local dir = (norm * 2 + VectorRand()) / 3
+ dir:Normalize()
+
+ local ent = ClientsideModel("models/props_junk/Rock001a.mdl", RENDERGROUP_OPAQUE)
+ if ent:IsValid() then
+ ent:SetMaterial("models/flesh")
+ ent:SetModelScale(math.Rand(0.2, 0.5), 0)
+ ent:SetPos(pos + dir * 6)
+ ent:PhysicsInitBox(minbound, maxbound)
+ ent:SetCollisionBounds(minbound, maxbound)
+
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMaterial("zombieflesh")
+ phys:ApplyForceOffset(ent:GetPos() + VectorRand() * 5, dir * math.Rand(300, 800))
+ end
+
+ SafeRemoveEntityDelayed(ent, math.Rand(6, 10))
+ end
+ end
+end
+
+function EFFECT:Think()
+ return false
+end
+
+function EFFECT:Render()
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/hit_healdart.lua b/gamemodes/zombiesurvival/entities/effects/hit_healdart.lua
new file mode 100644
index 0000000..749faec
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/hit_healdart.lua
@@ -0,0 +1,47 @@
+function EFFECT:Init(data)
+ local pos = data:GetOrigin()
+ local norm = data:GetNormal()
+ local ent = data:GetEntity()
+
+ if ent and ent:IsValid() then
+ ent:EmitSound("ambient/machines/steam_release_2.wav", 70, 255)
+
+ if ent:IsPlayer() then
+ ent:EmitSound("weapons/crossbow/hitbod"..math.random(2)..".wav", 70, 140)
+ end
+ else
+ sound.Play("ambient/machines/steam_release_2.wav", pos, 70, 255)
+ end
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(16, 24)
+
+ for i=1, 32 do
+ local ang = norm:Angle()
+ ang:RotateAroundAxis(ang:Up(), math.Rand(0, 360))
+ ang:RotateAroundAxis(ang:Right(), math.Rand(-80, 80))
+
+ local particle = emitter:Add("particle/smokestack", pos)
+ particle:SetVelocity(ang:Forward() * math.Rand(4, 32))
+ particle:SetDieTime(math.Rand(0.75, 1.25))
+ particle:SetStartAlpha(255)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(0)
+ particle:SetEndSize(6)
+ particle:SetColor(10, 255, 10)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-4, 4))
+ particle:SetGravity(Vector(0, 0, -10))
+ particle:SetAirResistance(100)
+ end
+
+ emitter:Finish()
+end
+
+function EFFECT:Think()
+ return false
+end
+
+function EFFECT:Render()
+end
+
diff --git a/gamemodes/zombiesurvival/entities/effects/hit_hunter.lua b/gamemodes/zombiesurvival/entities/effects/hit_hunter.lua
new file mode 100644
index 0000000..5d98225
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/hit_hunter.lua
@@ -0,0 +1,42 @@
+EFFECT.LifeTime = 0.375
+EFFECT.Size = 128
+
+function EFFECT:Init(data)
+ self.DieTime = CurTime() + self.LifeTime
+
+ local normal = data:GetNormal()
+ local pos = data:GetOrigin()
+
+ pos = pos + normal * 2
+ self.Pos = pos
+ self.Normal = normal
+
+ sound.Play("physics/metal/metal_sheet_impact_bullet"..math.random(2)..".wav", pos, 80, math.Rand(85, 95))
+end
+
+function EFFECT:Think()
+ return CurTime() < self.DieTime
+end
+
+local matRefraction = Material("refract_ring")
+local matGlow = Material("effects/rollerglow")
+local colGlow = Color(255, 30, 255)
+function EFFECT:Render()
+ local delta = math.Clamp((self.DieTime - CurTime()) / self.LifeTime, 0, 1)
+ local rdelta = 1 - delta
+ local size = rdelta ^ 0.5 * self.Size
+ colGlow.a = delta * 220
+ colGlow.r = delta * 255
+ colGlow.b = colGlow.r - 255
+
+ render.SetMaterial(matGlow)
+ render.DrawQuadEasy(self.Pos, self.Normal, size, size, colGlow, 0)
+ render.DrawQuadEasy(self.Pos, self.Normal * -1, size, size, colGlow, 0)
+ render.DrawSprite(self.Pos, size, size, colGlow)
+ matRefraction:SetFloat("$refractamount", math.sin(delta * 2 * math.pi) * 0.2)
+ render.SetMaterial(matRefraction)
+ render.UpdateRefractTexture()
+ render.DrawQuadEasy(self.Pos, self.Normal, size, size, color_white, 0)
+ render.DrawQuadEasy(self.Pos, self.Normal * -1, size, size, color_white, 0)
+ render.DrawSprite(self.Pos, size, size, color_white)
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/hit_stone.lua b/gamemodes/zombiesurvival/entities/effects/hit_stone.lua
new file mode 100644
index 0000000..56b1632
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/hit_stone.lua
@@ -0,0 +1,37 @@
+function EFFECT:Init(data)
+ local pos = data:GetOrigin()
+ local norm = data:GetNormal() * -1
+
+ sound.Play("ambient/materials/rock4.wav", pos, 77, math.Rand(95, 105))
+ sound.Play("physics/concrete/concrete_break2.wav", pos, 77, math.Rand(110, 120))
+
+ local maxbound = Vector(3, 3, 3)
+ local minbound = maxbound * -1
+ for i=1, 5 do
+ local dir = (norm * 2 + VectorRand()) / 3
+ dir:Normalize()
+
+ local ent = ClientsideModel("models/props_junk/Rock001a.mdl", RENDERGROUP_OPAQUE)
+ if ent:IsValid() then
+ ent:SetModelScale(math.Rand(0.2, 0.5), 0)
+ ent:SetPos(pos + dir * 6)
+ ent:PhysicsInitBox(minbound, maxbound)
+ ent:SetCollisionBounds(minbound, maxbound)
+
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMaterial("rock")
+ phys:ApplyForceOffset(ent:GetPos() + VectorRand() * 5, dir * math.Rand(300, 800))
+ end
+
+ SafeRemoveEntityDelayed(ent, math.Rand(6, 10))
+ end
+ end
+end
+
+function EFFECT:Think()
+ return false
+end
+
+function EFFECT:Render()
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/nailrepaired.lua b/gamemodes/zombiesurvival/entities/effects/nailrepaired.lua
new file mode 100644
index 0000000..f76caaa
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/nailrepaired.lua
@@ -0,0 +1,34 @@
+function EFFECT:Init(data)
+ local pos = data:GetOrigin()
+ local norm = data:GetNormal()
+ local magnitude = data:GetMagnitude()
+
+ local norepair = data:GetMagnitude() == 0
+
+ local emitter = ParticleEmitter(pos)
+ for i=1, math.random(16, 24) do
+ local particle = emitter:Add("sprites/glow04_noz", pos)
+ particle:SetVelocity((norm + VectorRand()):GetNormalized() * math.Rand(8, 24))
+ particle:SetAirResistance(8)
+ if norepair then
+ particle:SetColor(255, 0, 0)
+ particle:SetEndSize(2)
+ else
+ particle:SetColor(0, 255, 0)
+ particle:SetEndSize(math.Rand(2, 3) * math.max(magnitude, 0.1))
+ end
+ particle:SetDieTime(math.Rand(0.2, 0.5))
+ particle:SetStartSize(0)
+ particle:SetStartAlpha(255)
+ particle:SetEndAlpha(0)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-8, 8))
+ end
+end
+
+function EFFECT:Think()
+ return false
+end
+
+function EFFECT:Render()
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/redeem.lua b/gamemodes/zombiesurvival/entities/effects/redeem.lua
new file mode 100644
index 0000000..19bbb04
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/redeem.lua
@@ -0,0 +1,35 @@
+function EFFECT:Init(data)
+ local pos = data:GetOrigin()
+
+ sound.Play("ambient/energy/whiteflash.wav", pos)
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(24, 32)
+
+ for x=1, math.random(150, 200) do
+ local vecRan = VectorRand():GetNormalized()
+ vecRan = vecRan * math.Rand(24, 64)
+ vecRan.z = math.Rand(-32, -1)
+
+ local particle = emitter:Add("sprites/light_glow02_add", pos + vecRan)
+ particle:SetVelocity(Vector(0, 0, math.Rand(16, 64)))
+ particle:SetDieTime(math.Rand(1.2, 2))
+ particle:SetStartAlpha(255)
+ particle:SetEndAlpha(255)
+ particle:SetStartSize(math.Rand(7, 8))
+ particle:SetEndSize(0)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-32, 32))
+ end
+
+ emitter:Finish()
+end
+
+function EFFECT:Think()
+ return false
+end
+
+function EFFECT:Render()
+end
+
+util.PrecacheSound("ambient/energy/whiteflash.wav")
diff --git a/gamemodes/zombiesurvival/entities/effects/rico_trace.lua b/gamemodes/zombiesurvival/entities/effects/rico_trace.lua
new file mode 100644
index 0000000..b6c203c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/rico_trace.lua
@@ -0,0 +1,26 @@
+EFFECT.DieTime = 0
+
+function EFFECT:Init(data)
+ self.StartPos = data:GetStart()
+ self.EndPos = data:GetOrigin()
+ self.Dir = self.EndPos - self.StartPos
+ self.Entity:SetRenderBoundsWS(self.StartPos, self.EndPos)
+
+ self.DieTime = CurTime() + 0.1
+
+ sound.Play("weapons/fx/rics/ric"..math.random(5)..".wav", self.StartPos, 73, math.random(100, 110))
+end
+
+function EFFECT:Think()
+ return CurTime() < self.DieTime
+end
+
+local matBeam = Material("effects/spark")
+function EFFECT:Render()
+ local fDelta = (self.DieTime - CurTime()) / 0.1
+ fDelta = math.Clamp(fDelta, 0, 1)
+ local sinWave = math.sin(fDelta * math.pi)
+
+ render.SetMaterial(matBeam)
+ render.DrawBeam(self.EndPos - self.Dir * (fDelta - sinWave * 0.3), self.EndPos - self.Dir * (fDelta + sinWave * 0.3), 2 + sinWave * 8, 1, 0, color_white)
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/shadedeflect.lua b/gamemodes/zombiesurvival/entities/effects/shadedeflect.lua
new file mode 100644
index 0000000..9890a19
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/shadedeflect.lua
@@ -0,0 +1,41 @@
+util.PrecacheModel("models/props_phx/construct/metal_dome360.mdl")
+
+EFFECT.LifeTime = 2
+
+function EFFECT:Init(data)
+ local pos = data:GetOrigin()
+ local angles = data:GetAngles()
+
+ self.Offset = data:GetStart()
+ self.Ent = data:GetEntity()
+
+ sound.Play("weapons/fx/rics/ric"..math.random(5)..".wav", pos, 68, math.Rand(120, 130))
+
+ self.Entity:SetModel("models/props_phx/construct/metal_dome360.mdl")
+ self.Entity:SetMoveType(MOVETYPE_NONE)
+ self.Entity:SetModelScale(0.5, 0)
+ self.Entity:SetAngles(angles)
+
+ self.DieTime = CurTime() + self.LifeTime
+end
+
+function EFFECT:Think()
+ return CurTime() < self.DieTime
+end
+
+local matRefract = Material("models/spawn_effect")
+function EFFECT:Render()
+ local ent = self.Ent
+ if ent:IsValid() then
+ self:SetPos(ent:LocalToWorld(self.Offset))
+ end
+
+ render.UpdateRefractTexture()
+ matRefract:SetFloat("$refractamount", math.Clamp((self.DieTime - CurTime()) / self.LifeTime, 0, 1) ^ 2 * 0.05)
+
+ render.ModelMaterialOverride(matRefract)
+
+ self.Entity:DrawModel()
+
+ render.ModelMaterialOverride(0)
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/spithit.lua b/gamemodes/zombiesurvival/entities/effects/spithit.lua
new file mode 100644
index 0000000..4aced29
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/spithit.lua
@@ -0,0 +1,50 @@
+function EFFECT:Think()
+ return false
+end
+
+function EFFECT:Render()
+end
+
+local function CollideCallback(particle, hitpos, hitnormal)
+ if particle:GetDieTime() == 0 then return end
+ particle:SetDieTime(0)
+
+ if math.random(3) == 3 then
+ sound.Play("physics/flesh/flesh_squishy_impact_hard"..math.random(4)..".wav", hitpos, 50, math.Rand(95, 105))
+ end
+
+ if math.random(3) == 3 then
+ util.Decal("Impact.AlienFlesh", hitpos + hitnormal, hitpos - hitnormal)
+ end
+end
+
+function EFFECT:Init(data)
+ local pos = data:GetOrigin()
+ local hitnormal = data:GetNormal() * -1
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(24, 48)
+
+ local grav = Vector(0, 0, -500)
+ for i = 1, math.random(60, 85) do
+ local particle = emitter:Add("particles/smokey", pos)
+ particle:SetVelocity(VectorRand():GetNormalized() * math.Rand(32, 72) + hitnormal * math.Rand(48, 198))
+ particle:SetDieTime(math.Rand(0.9, 2))
+ particle:SetStartAlpha(200)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(math.Rand(1, 5))
+ particle:SetEndSize(0)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-15, 15))
+ particle:SetColor(math.Rand(25, 30), math.Rand(200, 240), math.Rand(25, 30))
+ particle:SetLighting(true)
+ particle:SetGravity(grav)
+ particle:SetCollide(true)
+ particle:SetCollideCallback(CollideCallback)
+ end
+ emitter:Finish()
+
+ util.Decal("Impact.AlienFlesh", pos + hitnormal, pos - hitnormal)
+
+ sound.Play("npc/antlion_grub/squashed.wav", pos, 74, math.random(95, 110))
+end
diff --git a/gamemodes/zombiesurvival/entities/effects/wraithdeath.lua b/gamemodes/zombiesurvival/entities/effects/wraithdeath.lua
new file mode 100644
index 0000000..4da4141
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/effects/wraithdeath.lua
@@ -0,0 +1,26 @@
+function EFFECT:Init(data)
+ local ent = data:GetEntity()
+ if ent:IsValid() then
+ self.DieTime = CurTime() + 1
+
+ self.Entity:SetModel(ent:GetModel())
+ self.Entity:SetPos(data:GetOrigin())
+ self.Entity:SetAngles(data:GetNormal():Angle())
+ else
+ self.DieTime = 0
+ end
+end
+
+function EFFECT:Think()
+ return CurTime() < self.DieTime
+end
+
+function EFFECT:Render()
+ local delta = self.DieTime - CurTime()
+
+ local brightness = delta * 120
+ self.Entity:SetColor(Color(brightness, brightness, brightness, delta * 220))
+ local size = 1 + math.sin(delta * 20) * (delta + 0.25)
+ self.Entity:SetModelScale(size, 0)
+ self.Entity:DrawModel()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/dummy_chemzombie/init.lua b/gamemodes/zombiesurvival/entities/entities/dummy_chemzombie/init.lua
new file mode 100644
index 0000000..d1045ab
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/dummy_chemzombie/init.lua
@@ -0,0 +1 @@
+ENT.Type = "point"
diff --git a/gamemodes/zombiesurvival/entities/entities/env_propbroken/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/env_propbroken/cl_init.lua
new file mode 100644
index 0000000..5bff262
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/env_propbroken/cl_init.lua
@@ -0,0 +1,55 @@
+include("shared.lua")
+
+ENT.NextEmit = 0
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetModelScale(1.03, 0)
+
+ self.ParticlePositions = {}
+
+ self:RandomizePositions()
+end
+
+function ENT:RandomizePositions()
+ for i=1, 5 do
+ local mins, maxs = self:OBBMins(), self:OBBMaxs()
+ mins = mins * 0.75
+ maxs = maxs * 0.75
+ self.ParticlePositions[i] = Vector(math.Rand(-mins.x, maxs.x), math.Rand(-mins.y, maxs.y), math.Rand(-mins.z, maxs.z))
+ end
+end
+
+local matDamage = Material("Models/props_debris/concretefloor013a")
+function ENT:Draw()
+ local sat = 1 - math.abs(math.sin(CurTime() * 3)) * 0.6
+
+ render.ModelMaterialOverride(matDamage)
+ render.SetBlend(0.35)
+ render.SetColorModulation(1, sat, sat)
+ self:DrawModel()
+ render.SetColorModulation(1, 1, 1)
+ render.SetBlend(1)
+ render.ModelMaterialOverride(0)
+
+ if CurTime() < self.NextEmit then return end
+ self.NextEmit = CurTime() + 0.02
+
+ local emitter = ParticleEmitter(self:GetPos())
+ emitter:SetNearClip(16, 24)
+ for _, pos in pairs(self.ParticlePositions) do
+ local particle = emitter:Add("effects/fire_cloud"..math.random(2), self:LocalToWorld(pos))
+ particle:SetDieTime(math.Rand(0.3, 0.4))
+ particle:SetGravity(Vector(math.random(-1, 1), math.random(-1, 1), math.random(3, 8)):GetNormal() * 300)
+ particle:SetStartAlpha(200)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(4)
+ particle:SetEndSize(1)
+ particle:SetStartLength(10)
+ particle:SetEndLength(18)
+ particle:SetColor(0, 255, 0)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-20, 20))
+ end
+ emitter:Finish()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/env_propbroken/init.lua b/gamemodes/zombiesurvival/entities/entities/env_propbroken/init.lua
new file mode 100644
index 0000000..62a9fb9
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/env_propbroken/init.lua
@@ -0,0 +1,48 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+ENT.DieTime = 0
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetSolid(SOLID_NONE)
+ self:SetMoveType(MOVETYPE_NONE)
+ self:SetModelScale(1.03, 0)
+
+ self.DieTime = CurTime() + 10
+end
+
+function ENT:AttachTo(ent)
+ if IsValid(ent) and ent:GetModel() ~= "models/error.mdl" then
+ self:SetModel(ent:GetModel())
+ self:SetSkin(ent:GetSkin() or 0)
+ self:SetPos(ent:GetPos())
+ self:SetAngles(ent:GetAngles())
+ self:SetAlpha(ent:GetAlpha())
+ self:SetOwner(ent)
+ self:SetParent(ent)
+ ent._BARRICADEBROKEN = self
+ else
+ self:Fire("kill", "", 1)
+ end
+end
+
+function ENT:Think()
+ if CurTime() >= self.DieTime and not self.Broken then
+ self.Broken = true
+
+ local ent = self:GetParent()
+ if ent:IsValid() then
+ ent:Fire("break", "", 0)
+ ent:Fire("kill", "", 0.01)
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(ent:WorldSpaceCenter())
+ util.Effect("Explosion", effectdata)
+ end
+
+ self:Remove()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/env_propbroken/shared.lua b/gamemodes/zombiesurvival/entities/entities/env_propbroken/shared.lua
new file mode 100644
index 0000000..40b3860
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/env_propbroken/shared.lua
@@ -0,0 +1 @@
+ENT.Type = "anim"
diff --git a/gamemodes/zombiesurvival/entities/entities/env_shadecontrol/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/env_shadecontrol/cl_init.lua
new file mode 100644
index 0000000..35e5a60
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/env_shadecontrol/cl_init.lua
@@ -0,0 +1,33 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetModelScale(1.03, 0)
+
+ self.AmbientSound = CreateSound(self, ")weapons/physcannon/superphys_hold_loop.wav")
+ self.AmbientSound:PlayEx(0.5, 60)
+
+ self:GetOwner().ShadeControl = self
+end
+
+function ENT:OnRemove()
+ self.AmbientSound:Stop()
+
+ local owner = self:GetOwner()
+ if owner.ShadeControl == self then
+ owner.ShadeControl = nil
+ end
+end
+
+local matRefract = Material("models/spawn_effect")
+function ENT:Draw()
+ if not render.SupportsPixelShaders_2_0() then return end
+
+ render.UpdateRefractTexture()
+
+ matRefract:SetFloat("$refractamount", 0.02)
+
+ render.ModelMaterialOverride(matRefract)
+ self:DrawModel()
+ render.ModelMaterialOverride(0)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/env_shadecontrol/init.lua b/gamemodes/zombiesurvival/entities/entities/env_shadecontrol/init.lua
new file mode 100644
index 0000000..875fe29
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/env_shadecontrol/init.lua
@@ -0,0 +1,56 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetSolid(SOLID_NONE)
+ self:SetMoveType(MOVETYPE_NONE)
+ self:SetModelScale(1.03, 0)
+end
+
+function ENT:AttachTo(ent)
+ self:SetModel(ent:GetModel())
+ self:SetSkin(ent:GetSkin() or 0)
+ self:SetPos(ent:GetPos())
+ self:SetAngles(ent:GetAngles())
+ self:SetAlpha(ent:GetAlpha())
+ self:SetParent(ent)
+
+ self.ObjectPosition = ent:GetPos() + Vector(0, 0, 40)
+end
+
+local ShadowParams = {secondstoarrive = 0.05, maxangular = 15, maxangulardamp = 1, maxspeed = 100, maxspeeddamp = 1000, dampfactor = 0.65, teleportdistance = 0}
+function ENT:Think()
+ local owner = self:GetOwner()
+ if owner:IsValid() and owner:IsPlayer() and owner:Alive() and owner:Team() == TEAM_UNDEAD and owner:GetZombieClassTable().Name == "Shade" then
+ local ent = self:GetParent()
+ if ent:IsValid() then
+ local eyepos = owner:EyePos()
+ if eyepos:Distance(ent:NearestPoint(eyepos)) <= 400 then
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() and phys:IsMoveable() and phys:GetMass() <= 300 then
+ local ct = CurTime()
+
+ local frametime = ct - (self.LastThink or ct)
+ self.LastThink = ct
+
+ phys:Wake()
+
+ ShadowParams.pos = (self.ObjectPosition or ent:GetPos()) + VectorRand():GetNormalized() * math.Rand(-24, 24)
+ ShadowParams.angle = AngleRand()
+ ShadowParams.deltatime = frametime
+ phys:ComputeShadowControl(ShadowParams)
+
+ ent:SetPhysicsAttacker(owner)
+
+ self:NextThink(CurTime())
+ return true
+ end
+ end
+ end
+ end
+
+ self:Remove()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/env_shadecontrol/shared.lua b/gamemodes/zombiesurvival/entities/entities/env_shadecontrol/shared.lua
new file mode 100644
index 0000000..40b3860
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/env_shadecontrol/shared.lua
@@ -0,0 +1 @@
+ENT.Type = "anim"
diff --git a/gamemodes/zombiesurvival/entities/entities/fakedeath/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/fakedeath/cl_init.lua
new file mode 100644
index 0000000..eebe06b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/fakedeath/cl_init.lua
@@ -0,0 +1,29 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+function ENT:Initialize()
+ self:SharedInitialize()
+end
+
+function ENT:DrawTranslucent()
+ local cycle = math.Clamp((CurTime() - self.Created) * 0.8, 0, 1) * self:GetDeathSequenceLength()
+ local sequence = self:GetDeathSequence()
+
+ if cycle == 1 then
+ local idleseq = self:LookupSequence("zombie_slump_idle_01")
+ if idleseq and idleseq > 0 then
+ sequence = idleseq
+ end
+ end
+
+ self:SetSequence(sequence)
+ self:SetCycle(cycle)
+ self:SetAngles(self:GetDeathAngles())
+
+ cam.Start3D(EyePos() + Vector(0, 0, 4), EyeAngles())
+ render.SetBlend(math.Clamp(self:GetRemoveTime() - CurTime(), 0, 1))
+ self:DrawModel()
+ render.SetBlend(1)
+ cam.End3D()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/fakedeath/init.lua b/gamemodes/zombiesurvival/entities/entities/fakedeath/init.lua
new file mode 100644
index 0000000..440af06
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/fakedeath/init.lua
@@ -0,0 +1,19 @@
+AddCSLuaFile("shared.lua")
+AddCSLuaFile("cl_init.lua")
+
+include("shared.lua")
+
+local ViewHullMins = Vector(-4, -4, -4)
+local ViewHullMaxs = Vector(4, 4, 4)
+function ENT:Initialize()
+ self:SharedInitialize()
+
+ local tr = util.TraceHull({start = self:GetPos(), endpos = self:GetPos() + Vector(0, 0, -10240), mask = MASK_SOLID_BRUSHONLY, mins = ViewHullMins, maxs = ViewHullMaxs})
+ self:SetPos(tr.HitPos + tr.HitNormal)
+end
+
+function ENT:Think()
+ if self:GetRemoveTime() > 0 and CurTime() >= self:GetRemoveTime() then
+ self:Remove()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/fakedeath/shared.lua b/gamemodes/zombiesurvival/entities/entities/fakedeath/shared.lua
new file mode 100644
index 0000000..12267ef
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/fakedeath/shared.lua
@@ -0,0 +1,23 @@
+ENT.Type = "anim"
+
+AccessorFuncDT(ENT, "DeathSequence", "Int", 0)
+AccessorFuncDT(ENT, "DeathAngles", "Angle", 0)
+AccessorFuncDT(ENT, "DeathSequenceLength", "Float", 0)
+AccessorFuncDT(ENT, "RemoveTime", "Float", 1)
+
+function ENT:SharedInitialize()
+ self:SetSolid(SOLID_NONE)
+ self:SetMoveType(MOVETYPE_NONE)
+
+ self:UseClientSideAnimation(true)
+
+ self.Created = CurTime()
+
+ if self:GetDeathSequenceLength() == 0 then
+ self:SetDeathSequenceLength(1)
+ end
+
+ if self:GetRemoveTime() == 0 then
+ self:SetRemoveTime(CurTime() + 10)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/func_noair/init.lua b/gamemodes/zombiesurvival/entities/entities/func_noair/init.lua
new file mode 100644
index 0000000..cc8eb02
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/func_noair/init.lua
@@ -0,0 +1,61 @@
+ENT.Type = "brush"
+
+function ENT:Initialize()
+ self:SetTrigger(true)
+
+ if self.On == nil then self.On = true end
+end
+
+function ENT:Think()
+end
+
+function ENT:AcceptInput(name, caller, activator, arg)
+ name = string.lower(name)
+ if name == "seton" then
+ self.On = tonumber(arg) == 1
+ return true
+ elseif name == "enable" then
+ self.On = true
+ return true
+ elseif name == "disable" then
+ self.On = false
+ return true
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "enabled" then
+ self.On = tonumber(value) == 1
+ end
+end
+
+function ENT:Enter(ent)
+ ent.NoAirBrush = self
+ if not IsValid(ent.status_drown) then
+ ent:GiveStatus("drown")
+ end
+end
+
+function ENT:Leave(ent)
+ ent.NoAirBrush = nil
+ ent:RemoveStatus("drown", false, true)
+end
+
+function ENT:Touch(ent)
+ if ent:IsPlayer() and ent.NoAirBrush == self and not self.On then
+ self:Leave(ent)
+ end
+end
+
+function ENT:StartTouch(ent)
+ if self.On and ent:IsPlayer() and ent:Alive() and ent:Team() == TEAM_HUMAN and not ent.NoAirBrush then
+ ent.NoAirBrush = self
+ end
+end
+
+function ENT:EndTouch(ent)
+ if ent:IsPlayer() and ent.NoAirBrush == self then
+ self:Leave(ent)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/gmod_player_start/init.lua b/gamemodes/zombiesurvival/entities/entities/gmod_player_start/init.lua
new file mode 100644
index 0000000..d80bf14
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/gmod_player_start/init.lua
@@ -0,0 +1,44 @@
+-- This makes old gmod9 ZS maps playable
+
+ENT.Type = "point"
+
+function ENT:Initialize()
+ if self.RedTeam or self.GreenTeam or self.YellowTeam or self.BlueTeam then
+ self.BlueTeam = self.BlueTeam or false
+ self.GreenTeam = self.GreenTeam or false
+ self.YellowTeam = self.YellowTeam or false
+ self.RedTeam = self.RedTeam or false
+ else
+ self.BlueTeam = true
+ self.GreenTeam = true
+ self.YellowTeam = true
+ self.RedTeam = true
+ end
+ self.Entity:GetTable().BlueTeam = self.BlueTeam
+ self.Entity:GetTable().GreenTeam = self.GreenTeam
+ self.Entity:GetTable().RedTeam = self.RedTeam
+ self.Entity:GetTable().YellowTeam = self.YellowTeam
+end
+
+function ENT:KeyValue(key, value)
+ if key == "spawnflags" then
+ local sf = tonumber(value)
+ for i=15, 0, -1 do
+ local bit = math.pow(2, i)
+ if sf - bit >= 0 then
+ if bit == 8 then self.RedTeam = true self.Entity:GetTable().RedTeam = true
+ elseif bit == 4 then self.GreenTeam = true self.Entity:GetTable().GreenTeam = true
+ elseif bit == 2 then self.YellowTeam = true self.Entity:GetTable().YellowTeam = true
+ elseif bit == 1 then self.BlueTeam = true self.Entity:GetTable().BlueTeam = true
+ end
+ sf = sf - bit
+ else
+ if bit == 8 then self.RedTeam = false self.Entity:GetTable().RedTeam = false
+ elseif bit == 4 then self.GreenTeam = false self.Entity:GetTable().GreenTeam = false
+ elseif bit == 2 then self.YellowTeam = false self.Entity:GetTable().YellowTeam = false
+ elseif bit == 1 then self.BlueTeam = false self.Entity:GetTable().BlueTeam = false
+ end
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/entities/entities/info_player_human/init.lua b/gamemodes/zombiesurvival/entities/entities/info_player_human/init.lua
new file mode 100644
index 0000000..6027084
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/info_player_human/init.lua
@@ -0,0 +1,27 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "disabled" then
+ self.Disabled = tonumber(value) == 1
+ elseif key == "active" then
+ self.Disabled = tonumber(value) == 0
+ end
+end
+
+function ENT:AcceptInput(name, activator, caller, arg)
+ name = string.lower(name)
+ if name == "enable" then
+ self.Disabled = false
+ return true
+ elseif name == "disable" then
+ self.Disabled = true
+ return true
+ elseif name == "toggle" then
+ self.Disabled = not self.Disabled
+ return true
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/info_player_redeemed/init.lua b/gamemodes/zombiesurvival/entities/entities/info_player_redeemed/init.lua
new file mode 100644
index 0000000..6027084
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/info_player_redeemed/init.lua
@@ -0,0 +1,27 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "disabled" then
+ self.Disabled = tonumber(value) == 1
+ elseif key == "active" then
+ self.Disabled = tonumber(value) == 0
+ end
+end
+
+function ENT:AcceptInput(name, activator, caller, arg)
+ name = string.lower(name)
+ if name == "enable" then
+ self.Disabled = false
+ return true
+ elseif name == "disable" then
+ self.Disabled = true
+ return true
+ elseif name == "toggle" then
+ self.Disabled = not self.Disabled
+ return true
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/info_player_undead/init.lua b/gamemodes/zombiesurvival/entities/entities/info_player_undead/init.lua
new file mode 100644
index 0000000..6027084
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/info_player_undead/init.lua
@@ -0,0 +1,27 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "disabled" then
+ self.Disabled = tonumber(value) == 1
+ elseif key == "active" then
+ self.Disabled = tonumber(value) == 0
+ end
+end
+
+function ENT:AcceptInput(name, activator, caller, arg)
+ name = string.lower(name)
+ if name == "enable" then
+ self.Disabled = false
+ return true
+ elseif name == "disable" then
+ self.Disabled = true
+ return true
+ elseif name == "toggle" then
+ self.Disabled = not self.Disabled
+ return true
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/info_player_undead_boss/init.lua b/gamemodes/zombiesurvival/entities/entities/info_player_undead_boss/init.lua
new file mode 100644
index 0000000..6027084
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/info_player_undead_boss/init.lua
@@ -0,0 +1,27 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "disabled" then
+ self.Disabled = tonumber(value) == 1
+ elseif key == "active" then
+ self.Disabled = tonumber(value) == 0
+ end
+end
+
+function ENT:AcceptInput(name, activator, caller, arg)
+ name = string.lower(name)
+ if name == "enable" then
+ self.Disabled = false
+ return true
+ elseif name == "disable" then
+ self.Disabled = true
+ return true
+ elseif name == "toggle" then
+ self.Disabled = not self.Disabled
+ return true
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/info_player_zombie/init.lua b/gamemodes/zombiesurvival/entities/entities/info_player_zombie/init.lua
new file mode 100644
index 0000000..88302e3
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/info_player_zombie/init.lua
@@ -0,0 +1,30 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+end
+
+function ENT:Think()
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "disabled" then
+ self.Disabled = tonumber(value) == 1
+ elseif key == "active" then
+ self.Disabled = tonumber(value) == 0
+ end
+end
+
+function ENT:AcceptInput(name, activator, caller, arg)
+ name = string.lower(name)
+ if name == "enable" then
+ self.Disabled = false
+ return true
+ elseif name == "disable" then
+ self.Disabled = true
+ return true
+ elseif name == "toggle" then
+ self.Disabled = not self.Disabled
+ return true
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/info_player_zombie_boss/init.lua b/gamemodes/zombiesurvival/entities/entities/info_player_zombie_boss/init.lua
new file mode 100644
index 0000000..6027084
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/info_player_zombie_boss/init.lua
@@ -0,0 +1,27 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "disabled" then
+ self.Disabled = tonumber(value) == 1
+ elseif key == "active" then
+ self.Disabled = tonumber(value) == 0
+ end
+end
+
+function ENT:AcceptInput(name, activator, caller, arg)
+ name = string.lower(name)
+ if name == "enable" then
+ self.Disabled = false
+ return true
+ elseif name == "disable" then
+ self.Disabled = true
+ return true
+ elseif name == "toggle" then
+ self.Disabled = not self.Disabled
+ return true
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/info_zombiespawn/init.lua b/gamemodes/zombiesurvival/entities/entities/info_zombiespawn/init.lua
new file mode 100644
index 0000000..4ecc2b6
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/info_zombiespawn/init.lua
@@ -0,0 +1,29 @@
+-- Zombie Master compat.
+
+ENT.Type = "point"
+
+function ENT:Initialize()
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "disabled" then
+ self.Disabled = tonumber(value) == 1
+ elseif key == "active" then
+ self.Disabled = tonumber(value) == 0
+ end
+end
+
+function ENT:AcceptInput(name, activator, caller, arg)
+ name = string.lower(name)
+ if name == "enable" or name == "unhide" then
+ self.Disabled = false
+ return true
+ elseif name == "disable" or name == "hide" then
+ self.Disabled = true
+ return true
+ elseif name == "toggle" then
+ self.Disabled = not self.Disabled
+ return true
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_antigrief/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_antigrief/init.lua
new file mode 100644
index 0000000..d5bee17
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_antigrief/init.lua
@@ -0,0 +1,29 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+end
+
+function ENT:Think()
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if name == "disablethese" then
+ for _, entname in pairs(string.Explode(",", args)) do
+ for __, ent in pairs(self:FindByNameHammer(entname, activator, caller)) do
+ ent.m_AntiGrief = nil
+ end
+ end
+ return true
+ elseif name == "enablethese" then
+ for _, entname in pairs(string.Explode(",", args)) do
+ for __, ent in pairs(self:FindByNameHammer(entname, activator, caller)) do
+ ent.m_AntiGrief = true
+ end
+ end
+ return true
+ end
+end
+
+function ENT:KeyValue(key, value)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_barricade/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_barricade/init.lua
new file mode 100644
index 0000000..57a875d
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_barricade/init.lua
@@ -0,0 +1,34 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+end
+
+function ENT:Think()
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if name == "disablethese" then
+ for _, entname in pairs(string.Explode(",", args)) do
+ for __, ent in pairs(self:FindByNameHammer(entname, activator, caller)) do
+ ent.NoNails = true
+ end
+ end
+ return true
+ elseif name == "enablethese" then
+ for _, entname in pairs(string.Explode(",", args)) do
+ for __, ent in pairs(self:FindByNameHammer(entname, activator, caller)) do
+ ent.NoNails = nil
+ end
+ end
+ return true
+ end
+end
+
+-- Just in case people use these as key values.
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "disablethese" or key == "enablethese" then
+ self:Fire(key, value, 0)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_beats/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_beats/init.lua
new file mode 100644
index 0000000..1c31c5d
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_beats/init.lua
@@ -0,0 +1,17 @@
+ENT.Type = "point"
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if name == "enable" then
+ SetGlobalBool("beatsdisabled", false)
+ elseif name == "disable" then
+ SetGlobalBool("beatsdisabled", true)
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "enabled" then
+ SetGlobalBool("beatsdisabled", value == "0")
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_brains/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_brains/init.lua
new file mode 100644
index 0000000..b129859
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_brains/init.lua
@@ -0,0 +1,43 @@
+ENT.Base = "logic_points"
+ENT.Type = "point"
+
+ENT.ValidTeam = TEAM_UNDEAD
+
+function ENT:Add(pl, amount)
+ if pl and pl:IsValid() and pl:IsPlayer() and pl:Team() == self.ValidTeam then
+ amount = math.Round(amount)
+ if amount < 0 then
+ pl:TakeBrains(-amount)
+ else
+ pl:AddBrains(amount)
+ end
+ end
+end
+
+function ENT:SetAmount(pl, amount)
+ local diff = amount - self:GetAmount(pl)
+ pl:SetFrags(amount)
+ pl.BrainsEaten = pl.BrainsEaten + diff
+ pl:CheckRedeem()
+end
+
+function ENT:GetAmount(pl)
+ return pl:Frags()
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if name == "setredeembrains" then
+ GAMEMODE:SetRedeemBrains(tonumber(args) or 0)
+ elseif name == "redeemactivator" then
+ if activator and activator:IsValid() and activator:IsPlayer() and activator:Team() == TEAM_UNDEAD then
+ activator:Redeem()
+ end
+ elseif name == "redeemcaller" then
+ if caller and caller:IsValid() and caller:IsPlayer() and caller:Team() == TEAM_UNDEAD then
+ caller:Redeem()
+ end
+ else
+ self.BaseClass.AcceptInput(self, name, activator, caller, args)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_classunlock/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_classunlock/init.lua
new file mode 100644
index 0000000..1650557
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_classunlock/init.lua
@@ -0,0 +1,63 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+ self.Class = self.Class or 1
+end
+
+function ENT:Think()
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if string.sub(name, 1, 2) == "on" then
+ self:FireOutput(name, activator, caller, args)
+ elseif name == "lockclass" then
+ local classname = string.lower(args)
+ for k, v in ipairs(GAMEMODE.ZombieClasses) do
+ if classname == "all" or string.lower(v.Name) == classname then
+ v.Locked = true
+ v.Unlocked = false
+
+ if classname ~= "all" then
+ for _, pl in pairs(player.GetAll()) do
+ if pl:GetZombieClass() == k then
+ for classid, classtab in ipairs(GAMEMODE.ZombieClasses) do
+ if GAMEMODE:IsClassUnlocked(k) and not classtab.Hidden then
+ pl.DeathClass = classid
+ break
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ elseif name == "unlockclass" then
+ local classname = string.lower(args)
+ for k, v in ipairs(GAMEMODE.ZombieClasses) do
+ if classname == "all" or string.lower(v.Name) == classname then
+ v.Unlocked = true
+ v.Locked = false
+ end
+ end
+ elseif name == "defaultclass" then
+ local classname = string.lower(args)
+ for k, v in ipairs(GAMEMODE.ZombieClasses) do
+ if string.lower(v.Name) == classname then
+ v.IsDefault = true
+ GAMEMODE.DefaultZombieClass = k
+ else
+ v.IsDefault = nil
+ end
+ end
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "class" then
+ self.Class = value or self.Class
+ elseif string.sub(key, 1, 2) == "on" then
+ self:AddOnOutput(key, value)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_difficulty/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_difficulty/init.lua
new file mode 100644
index 0000000..094c291
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_difficulty/init.lua
@@ -0,0 +1,10 @@
+ENT.Type = "point"
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if name == "setzombiedamagemultiplier" then
+ GAMEMODE.ZombieDamageMultiplier = tonumber(args) or 1
+ elseif name == "setzombiespeedmultiplier" then
+ GAMEMODE.ZombieSpeedMultiplier = tonumber(args) or 1
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_dynamicspawning/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_dynamicspawning/init.lua
new file mode 100644
index 0000000..a5d3cb7
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_dynamicspawning/init.lua
@@ -0,0 +1,17 @@
+ENT.Type = "point"
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if name == "enable" then
+ GAMEMODE:SetDynamicSpawning(true)
+ elseif name == "disable" then
+ GAMEMODE:SetDynamicSpawning(false)
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "enabled" then
+ GAMEMODE:SetDynamicSpawning(value ~= "0")
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_infliction/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_infliction/init.lua
new file mode 100644
index 0000000..43bccc4
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_infliction/init.lua
@@ -0,0 +1,28 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+ self.Infliction = self.Infliction or 0.5
+end
+
+function ENT:Think()
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if string.sub(name, 1, 2) == "on" then
+ self:FireOutput(name, activator, caller, args)
+ elseif name == "capinfliction" then
+ GAMEMODE.CappedInfliction = math.max(GAMEMODE.CappedInfliction, tonumber(args) or 0)
+ elseif name == "setinfliction" then
+ GAMEMODE.CappedInfliction = tonumber(args) or 0
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "infliction" then
+ self.Infliction = tonumber(value) or self.Infliction
+ elseif string.sub(key, 1, 2) == "on" then
+ self:AddOnOutput(key, value)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_pantsmode/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_pantsmode/init.lua
new file mode 100644
index 0000000..71ec9e5
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_pantsmode/init.lua
@@ -0,0 +1,17 @@
+ENT.Type = "point"
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if name == "enable" then
+ GAMEMODE:SetPantsMode(true)
+ elseif name == "disable" then
+ GAMEMODE:SetPantsMode(false)
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "enabled" then
+ GAMEMODE:SetPantsMode(value ~= "0")
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_pickupdrop/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_pickupdrop/init.lua
new file mode 100644
index 0000000..89304bf
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_pickupdrop/init.lua
@@ -0,0 +1,43 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+ self.EntityToWatch = self.EntityToWatch or "_____"
+end
+
+function ENT:Think()
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if string.sub(name, 1, 2) == "on" then
+ self:FireOutput(name, activator, caller, args)
+ return true
+ elseif name == "disablepickup" then
+ for _, ent in pairs(ents.FindByName(self.EntityToWatch)) do
+ ent.m_NoPickup = true
+ end
+ return true
+ elseif name == "enablepickup" then
+ for _, ent in pairs(ents.FindByName(self.EntityToWatch)) do
+ ent.m_NoPickup = nil
+ end
+ return true
+ elseif name == "forcedrop" then
+ for _, ent in pairs(ents.FindByClass("status_human_holding")) do
+ local object = ent:GetObject()
+ if object:IsValid() and object:GetName() == self.EntityToWatch then
+ ent:Remove()
+ end
+ end
+ return true
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "entitytowatch" then
+ self.EntityToWatch = value or self.EntityToWatch
+ elseif string.sub(key, 1, 2) == "on" then
+ self:AddOnOutput(key, value)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_pickups/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_pickups/init.lua
new file mode 100644
index 0000000..81bfa98
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_pickups/init.lua
@@ -0,0 +1,48 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+end
+
+function ENT:Think()
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if name == "setmaxweaponpickups" then
+ self:SetKeyValue("maxweaponpickups", args)
+ elseif name == "setmaxammopickups" then
+ self:SetKeyValue("maxammopickups", args)
+ elseif name == "setmaxflashlightpickups" then
+ self:SetKeyValue("maxflashlightpickups", args)
+ elseif name == "setweaponrequiredforammo" then
+ self:SetKeyValue("weaponrequiredforammo", args)
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "maxweaponpickups" then
+ value = tonumber(value) or -1
+ if value == -1 then
+ GAMEMODE.MaxWeaponPickups = nil
+ else
+ GAMEMODE.MaxWeaponPickups = value
+ end
+ elseif key == "maxammopickups" then
+ value = tonumber(value) or -1
+ if value == -1 then
+ GAMEMODE.MaxAmmoPickups = nil
+ else
+ GAMEMODE.MaxAmmoPickups = value
+ end
+ elseif key == "maxflashlightpickups" then
+ value = tonumber(value) or -1
+ if value == -1 then
+ GAMEMODE.MaxFlashlightPickups = nil
+ else
+ GAMEMODE.MaxFlashlightPickups = value
+ end
+ elseif key == "weaponrequiredforammo" then
+ GAMEMODE.WeaponRequiredForAmmo = tonumber(value) == 1
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_points/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_points/init.lua
new file mode 100644
index 0000000..645f4c3
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_points/init.lua
@@ -0,0 +1,75 @@
+ENT.Type = "point"
+
+ENT.ValidTeam = TEAM_HUMAN
+
+function ENT:Add(pl, amount)
+ if pl and pl:IsValid() and pl:IsPlayer() and pl:Team() == self.ValidTeam then
+ amount = math.Round(amount)
+ if amount < 0 then
+ pl:TakePoints(-amount)
+ else
+ pl:AddPoints(amount)
+ end
+ end
+end
+
+function ENT:Set(pl, amount)
+ if pl and pl:IsValid() and pl:IsPlayer() and pl:Team() == self.ValidTeam then
+ self:SetAmount(pl, amount)
+ end
+end
+
+function ENT:SetAmount(pl, amount)
+ pl:SetPoints(amount)
+end
+
+function ENT:GetAmount(pl)
+ return pl:GetPoints()
+end
+
+function ENT:CallIf(pl, amount)
+ if pl and pl:IsValid() and pl:IsPlayer() then
+ self:Input(pl:Team() == self.ValidTeam and self:GetAmount(pl) >= amount and "onconditionpassed" or "onconditionfailed", pl, self, amount)
+ end
+end
+
+function ENT:CallIfNot(pl, amount)
+ if pl and pl:IsValid() and pl:IsPlayer() then
+ self:Input(pl:Team() == self.ValidTeam and self:GetAmount(pl) >= amount and "onconditionfailed" or "onconditionpassed", pl, self, amount)
+ end
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ local amount = tonumber(args) or 0
+ if string.sub(name, 1, 2) == "on" then
+ self:FireOutput(name, activator, caller, args)
+ elseif name == "addtoactivator" then
+ self:Add(activator, amount)
+ elseif name == "takefromactivator" then
+ self:Add(activator, -amount)
+ elseif name == "addtocaller" then
+ self:Add(caller, amount)
+ elseif name == "takefromcaller" then
+ self:Add(caller, -amount)
+ elseif name == "callifactivatorhave" then
+ self:CallIf(activator, amount)
+ elseif name == "callifactivatornothave" then
+ self:CallIfNot(activator, amount)
+ elseif name == "callifcallerhave" then
+ self:CallIf(caller, amount)
+ elseif name == "callifcallernothave" then
+ self:CallIfNot(caller, amount)
+ elseif name == "setactivatoramount" then
+ self:Set(activator, amount)
+ elseif name == "setcalleramount" then
+ self:Set(caller, amount)
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if string.sub(key, 1, 2) == "on" then
+ self:AddOnOutput(key, value)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_startingloadout/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_startingloadout/init.lua
new file mode 100644
index 0000000..34e8793
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_startingloadout/init.lua
@@ -0,0 +1,55 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+end
+
+function ENT:Think()
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if name == "setstartingloadout" then
+ self:SetKeyValue("startingloadout", args)
+
+ return true
+ elseif name == "setredeemloadout" then
+ self:SetKeyValue("redeemloadout", args)
+
+ return true
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "startingloadout" then
+ if value == "worth" then
+ GAMEMODE.StartingLoadout = nil
+ elseif value == "none" then
+ GAMEMODE.StartingLoadout = {}
+ else
+ local tab = {}
+ for k, v in pairs(string.Explode(",", value)) do
+ local item, amount = string.match(v, "(.+):(%d+)")
+ if item and amount then
+ tab[item] = tonumber(amount) or 1
+ end
+ end
+
+ GAMEMODE.StartingLoadout = tab
+ end
+ elseif key == "redeemloadout" then
+ if value == "none" then
+ GAMEMODE.RedeemLoadout = {}
+ else
+ local tab = {}
+ for k, v in pairs(string.Explode(",", value)) do
+ local item, amount = string.match(v, "(.+):(%d+)")
+ if item and amount then
+ tab[item] = tonumber(amount) or 1
+ end
+ end
+
+ GAMEMODE.RedeemLoadout = tab
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_waveend/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_waveend/init.lua
new file mode 100644
index 0000000..895f8b3
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_waveend/init.lua
@@ -0,0 +1,24 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+ self.Infliction = self.Infliction or 0
+end
+
+function ENT:Think()
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if string.sub(name, 1, 2) == "on" then
+ self:FireOutput(name, activator, caller, args)
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "infliction" then
+ self.Infliction = tonumber(value) or self.Infliction
+ elseif string.sub(key, 1, 2) == "on" then
+ self:AddOnOutput(key, value)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_waves/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_waves/init.lua
new file mode 100644
index 0000000..388afbc
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_waves/init.lua
@@ -0,0 +1,48 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+ self.Wave = self.Wave or -1
+end
+
+function ENT:Think()
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if string.sub(name, 1, 2) == "on" then
+ self:FireOutput(name, activator, caller, args)
+ elseif name == "advancewave" then
+ gamemode.Call("SetWaveActive", false)
+ gamemode.Call("SetWaveStart", CurTime())
+ return true
+ elseif name == "endwave" then
+ gamemode.Call("SetWaveEnd", CurTime())
+ return true
+ elseif name == "setwave" then
+ gamemode.Call("SetWave", tonumber(args) or 1)
+ return true
+ elseif name == "setwaves" then
+ SetGlobalInt("numwaves", tonumber(args) or GAMEMODE.NumberOfWaves)
+ return true
+ elseif name == "startwave" then
+ gamemode.Call("SetWaveStart", CurTime())
+ return true
+ elseif name == "setwavestart" then
+ local time = tonumber(args) or 0
+ gamemode.Call("SetWaveStart", time == -1 and time or (CurTime() + time))
+ return true
+ elseif name == "setwaveend" then
+ local time = tonumber(args) or 0
+ gamemode.Call("SetWaveEnd", time == -1 and time or (CurTime() + time))
+ return true
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if string.sub(key, 1, 2) == "on" then
+ self:AddOnOutput(key, value)
+ elseif key == "wave" then
+ self.Wave = tonumber(value) or -1
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_wavestart/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_wavestart/init.lua
new file mode 100644
index 0000000..895f8b3
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_wavestart/init.lua
@@ -0,0 +1,24 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+ self.Infliction = self.Infliction or 0
+end
+
+function ENT:Think()
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if string.sub(name, 1, 2) == "on" then
+ self:FireOutput(name, activator, caller, args)
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "infliction" then
+ self.Infliction = tonumber(value) or self.Infliction
+ elseif string.sub(key, 1, 2) == "on" then
+ self:AddOnOutput(key, value)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_winlose/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_winlose/init.lua
new file mode 100644
index 0000000..c9526a2
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_winlose/init.lua
@@ -0,0 +1,61 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+end
+
+function ENT:Think()
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if string.sub(name, 1, 2) == "on" then
+ self:FireOutput(name, activator, caller, args)
+ return true
+ elseif name == "win" then
+ gamemode.Call("EndRound", TEAM_HUMAN)
+ return true
+ elseif name == "lose" then
+ gamemode.Call("EndRound", TEAM_UNDEAD)
+ return true
+ elseif name == "setendslomo" then
+ self:SetKeyValue("endslomo", args)
+ return true
+ elseif name == "setendcamera" then
+ self:SetKeyValue("endcamera", args)
+ return true
+ elseif name == "setendcamerapos" then
+ self:SetKeyValue("endcamerapos", args)
+ return true
+ elseif name == "setwinmusic" then
+ self:SetKeyValue("winmusic", args)
+ return true
+ elseif name == "setlosemusic" then
+ self:SetKeyValue("losemusic", args)
+ return true
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if string.sub(key, 1, 2) == "on" then
+ self:AddOnOutput(key, value)
+ elseif key == "endslomo" then
+ GAMEMODE.OverrideEndSlomo = value == "1"
+ elseif key == "endcamera" then
+ SetGlobalBool("endcamera", value == "1")
+ elseif key == "setendcamerapos" then
+ SetGlobalVector("endcamerapos", Vector(value))
+ elseif key == "winmusic" then
+ if value == "default" then
+ SetGlobalString("winmusic", nil)
+ else
+ SetGlobalString("winmusic", value)
+ end
+ elseif key == "losemusic" then
+ if value == "default" then
+ SetGlobalString("losemusic", nil)
+ else
+ SetGlobalString("losemusic", value)
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/logic_worth/init.lua b/gamemodes/zombiesurvival/entities/entities/logic_worth/init.lua
new file mode 100644
index 0000000..febd3af
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/logic_worth/init.lua
@@ -0,0 +1,22 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+end
+
+function ENT:Think()
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if name == "setstartingworth" then
+ self:SetKeyValue("startingworth", args)
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "startingworth" then
+ GAMEMODE.OverrideStartingWorth = true
+ GAMEMODE.StartingWorth = tonumber(value) or 100
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/point_propnocollide.lua b/gamemodes/zombiesurvival/entities/entities/point_propnocollide.lua
new file mode 100644
index 0000000..f76dc29
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/point_propnocollide.lua
@@ -0,0 +1,95 @@
+ENT.Type = "point"
+
+AccessorFunc(ENT, "m_fTimeOut", "TimeOut", FORCE_NUMBER)
+AccessorFunc(ENT, "m_fExtraRadius", "ExtraRadius", FORCE_NUMBER)
+AccessorFunc(ENT, "m_iTeam", "Team", FORCE_NUMBER)
+AccessorFunc(ENT, "m_entProp", "Prop")
+
+function ENT:Initialize()
+ self:SetTimeOut(0)
+ self:SetExtraRadius(8)
+ self:SetProp(NULL)
+end
+
+function ENT:SetProp(ent)
+ self.m_entProp = ent
+
+ if not IsValid(ent) then return end
+
+ for _, e in pairs(ents.FindByClass(self:GetClass())) do
+ if e ~= self and e:GetProp() == ent then return end
+ end
+
+ local teamid = self:GetTeam()
+ local inrad = false
+ for _, pl in pairs(ents.FindInSphere(ent:LocalToWorld(ent:OBBCenter()), ent:BoundingRadius() / 2 + self:GetExtraRadius())) do
+ if pl:IsValid() and pl:IsPlayer() and pl:Alive() and (teamid == 0 or pl:Team() == teamid) then
+ inrad = true
+ break
+ end
+ end
+
+ if not inrad then return end
+
+ self.OldMaterial = ent:GetMaterial()
+ self.OldCollisionGroup = ent:GetCollisionGroup()
+
+ ent:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
+ ent:SetMaterial("models/spawn_effect")
+end
+
+function ENT:OnRemove()
+ local ent = self:GetProp()
+ if not IsValid(ent) then return end
+
+ if self.OldMaterial then
+ ent:SetMaterial(self.OldMaterial)
+ end
+
+ if self.OldCollisionGroup then
+ ent:SetCollisionGroup(self.OldCollisionGroup)
+ end
+end
+
+function ENT:Think()
+ local ent = self:GetProp()
+ if not IsValid(ent) then
+ self:Remove()
+ return
+ end
+
+ local pushout = false
+ local timeout = self:GetTimeOut() > 0 and CurTime() >= self:GetTimeOut()
+ local teamid = self:GetTeam()
+ local rate = 900 * FrameTime()
+ local center = ent:LocalToWorld(ent:OBBCenter())
+
+ for _, pl in pairs(ents.FindInSphere(center, ent:BoundingRadius() / 2 + self:GetExtraRadius())) do
+ if pl:IsValid() and pl:IsPlayer() and pl:Alive() and (teamid == 0 or pl:Team() == teamid) then
+ pushout = true
+
+ if timeout then
+ if ent:IsBarricadeProp() and pl:Team() == TEAM_HUMAN then
+ pl:SetBarricadeGhosting(true)
+ end
+ else
+ local plpos = pl:LocalToWorld(pl:OBBCenter())
+ local diff = plpos - center
+ diff.z = 0
+ diff:Normalize()
+ local heading = diff * rate
+ local starttrace = plpos + heading
+ if util.TraceLine({start = starttrace, endpos = starttrace + Vector(0, 0, -80), mask = MASK_SOLID_BRUSHONLY}).Hit then
+ pl:SetVelocity(heading)
+ end
+ end
+ end
+ end
+
+ if not pushout or timeout then
+ self:Remove()
+ end
+
+ self:NextThink(CurTime())
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/point_servercommand.lua b/gamemodes/zombiesurvival/entities/entities/point_servercommand.lua
new file mode 100644
index 0000000..444f0c1
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/point_servercommand.lua
@@ -0,0 +1,14 @@
+-- This is for Zombie Escape so messages can be printed.
+
+ENT.Type = "point"
+
+function ENT:AcceptInput(name, caller, activator, arg)
+ name = string.lower(name)
+ if name == "command" then
+ if string.sub(string.lower(arg), 1, 4) == "say " then
+ PrintMessage(HUD_PRINTTALK, string.sub(arg, 5))
+ end
+
+ return true
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/point_worldhint/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/point_worldhint/cl_init.lua
new file mode 100644
index 0000000..032dd62
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/point_worldhint/cl_init.lua
@@ -0,0 +1,33 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetMoveType(MOVETYPE_NONE)
+ self:SetSolid(SOLID_NONE)
+ self:SetCollisionGroup(COLLISION_GROUP_WORLD)
+end
+
+function ENT:Draw()
+end
+
+function ENT:DrawHint()
+ if self:GetViewable() == 0 or self:GetViewable() == MySelf:Team() then
+ local pos = self:GetPos()
+ local eyepos = EyePos()
+ local range = self:GetRange()
+
+ if range <= 0 then
+ DrawWorldHint(self:GetHint(), pos)
+ else
+ local dist = pos:Distance(eyepos)
+ if dist <= range then
+ --[[local fadeoff = range * 0.75
+ if dist >= fadeoff then
+ DrawWorldHint(self:GetHint(), pos, 1 - (dist - fadeoff) / range)
+ else]]
+ DrawWorldHint(self:GetHint(), pos)
+ --end
+ end
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/point_worldhint/init.lua b/gamemodes/zombiesurvival/entities/entities/point_worldhint/init.lua
new file mode 100644
index 0000000..bad88d9
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/point_worldhint/init.lua
@@ -0,0 +1,39 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetMoveType(MOVETYPE_NONE)
+ self:SetSolid(SOLID_NONE)
+ self:SetCollisionGroup(COLLISION_GROUP_WORLD)
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ if name == "setviewer" then
+ self:SetKeyValue("viewer", args)
+ return true
+ elseif name == "sethint" then
+ self:SetKeyValue("hint", args)
+ return true
+ elseif name == "setrange" then
+ self:SetKeyValue("range", args)
+ return true
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "viewer" then
+ self:SetViewable(tonumber(value) or 0)
+ elseif key == "hint" then
+ self:SetHint(value)
+ elseif key == "range" then
+ self:SetRange(tonumber(value) or 0)
+ end
+end
+
+function ENT:UpdateTransmitState()
+ return TRANSMIT_ALWAYS
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/point_worldhint/shared.lua b/gamemodes/zombiesurvival/entities/entities/point_worldhint/shared.lua
new file mode 100644
index 0000000..1c18e54
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/point_worldhint/shared.lua
@@ -0,0 +1,14 @@
+ENT.Type = "anim"
+
+AccessorFuncDT(ENT, "Viewable", "Int", 0)
+AccessorFuncDT(ENT, "Hint", "String", 0)
+AccessorFuncDT(ENT, "Range", "Float", 0)
+AccessorFuncDT(ENT, "Translated", "Bool", 0)
+
+function ENT:GetHint()
+ local hint = self:GetDTString(0)
+
+ if self:GetTranslated() then return translate.Get(hint) end
+
+ return hint
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/point_zsmessage/init.lua b/gamemodes/zombiesurvival/entities/entities/point_zsmessage/init.lua
new file mode 100644
index 0000000..28555a5
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/point_zsmessage/init.lua
@@ -0,0 +1,61 @@
+ENT.Type = "point"
+
+function ENT:Initialize()
+ self.SendTo = self.SendTo or -1
+end
+
+function ENT:Think()
+end
+
+function ENT:AcceptInput(name, caller, activator, args)
+ name = string.lower(name)
+ if name == "message" then
+ args = args or ""
+
+ args = string.gsub(args, "<.-=.->", "")
+ args = string.gsub(args, "", "")
+
+ if self.SendTo == 0 then
+ GAMEMODE:CenterNotifyAll(args)
+ elseif self.SendTo == -1 then
+ for _, pl in pairs(player.GetAll()) do
+ if pl == activator or pl == caller then
+ pl:CenterNotify(args)
+ break
+ end
+ end
+ else
+ for _, pl in pairs(player.GetAll()) do
+ if pl:Team() == self.SendTo then
+ pl:CenterNotify(args)
+ end
+ end
+ end
+
+ return true
+ elseif name == "setundeadhudmessage" or name == "setzombiehudmessage" then
+ SetGlobalString("hudoverride"..TEAM_UNDEAD, args)
+ elseif name == "sethumanhudmessage" or name == "setsurvivorhudmessage" then
+ SetGlobalString("hudoverride"..TEAM_HUMAN, args)
+ elseif name == "clearundeadhudmessage" or name == "clearzombiehudmessage" then
+ SetGlobalString("hudoverride"..TEAM_UNDEAD, "")
+ elseif name == "clearhumanhudmessage" or name == "clearsurvivorhudmessage" then
+ SetGlobalString("hudoverride"..TEAM_HUMAN, "")
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "team" then
+ value = string.lower(value or "")
+ if value == "zombie" or value == "undead" or value == "zombies" then
+ self.SendTo = TEAM_UNDEAD
+ elseif value == "human" or value == "humans" then
+ self.SendTo = TEAM_HUMAN
+ elseif value == "activator" or value == "caller" or value == "private" then
+ self.SendTo = -1
+ else
+ self.SendTo = 0
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_arrow/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/projectile_arrow/cl_init.lua
new file mode 100644
index 0000000..631e84c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_arrow/cl_init.lua
@@ -0,0 +1,45 @@
+include("shared.lua")
+
+local matTrail = Material("Effects/laser1.vmt")
+local colTrail = Color(255, 0, 0)
+
+function ENT:Draw()
+ self.Entity:DrawModel()
+
+ local vOffset = self.Entity:GetPos()
+
+ render.SetMaterial(matTrail)
+ for i=1, #self.TrailPositions do
+ if self.TrailPositions[i+1] then
+ render.DrawBeam(self.TrailPositions[i], self.TrailPositions[i+1], 6, 1, 0, colTrail)
+ end
+ end
+end
+
+function ENT:Initialize()
+ self.Trailing = CurTime() + 0.25
+ self.TrailPositions = {}
+end
+
+function ENT:Think()
+ if self.Entity:GetVelocity():Length() <= 0 and self.Trailing < CurTime() then
+ function self:Draw() self.Entity:DrawModel() end
+ function self:Think() end
+ else
+ table.insert(self.TrailPositions, 1, self.Entity:GetPos())
+ if self.TrailPositions[23] then
+ table.remove(self.TrailPositions, 23)
+ end
+ local dist = 0
+ local mypos = self.Entity:GetPos()
+ for i=1, #self.TrailPositions do
+ if self.TrailPositions[i]:Distance(mypos) > dist then
+ self.Entity:SetRenderBoundsWS(self.TrailPositions[i], mypos, Vector(16, 16, 16))
+ dist = self.TrailPositions[i]:Distance(mypos)
+ end
+ end
+ end
+end
+
+function ENT:OnRemove()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_arrow/init.lua b/gamemodes/zombiesurvival/entities/entities/projectile_arrow/init.lua
new file mode 100644
index 0000000..69a81e9
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_arrow/init.lua
@@ -0,0 +1,68 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include('shared.lua')
+
+function ENT:Initialize()
+ self.DieTime = CurTime() + 15
+
+ self:SetModel("models/Items/CrossbowRounds.mdl")
+ self:PhysicsInit(SOLID_VPHYSICS)
+ self:SetCollisionGroup(COLLISION_GROUP_WEAPON)
+ self:SetTrigger(true)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMass(4)
+ phys:SetBuoyancyRatio(0.01)
+ phys:EnableDrag(false)
+ phys:Wake()
+ end
+ self.Touched = {}
+ self.OriginalAngles = self:GetAngles()
+
+ self:EmitSound("weapons/crossbow/bolt_fly4.wav")
+end
+
+function ENT:Think()
+ if self.DieTime <= CurTime() then
+ self:Remove()
+ end
+end
+
+function ENT:PhysicsCollide(data, phys)
+ if self.Done then return end
+ self.Done = true
+
+ phys:EnableMotion(false)
+ self:EmitSound("physics/metal/sawblade_stick"..math.random(3)..".wav")
+ self.DieTime = CurTime() + 8
+
+ self:SetPos(data.HitPos)
+ self:SetAngles(data.HitNormal:Angle())
+
+ local hitent = data.HitEntity
+ if hitent and hitent:IsValid() then
+ local hitphys = hitent:GetPhysicsObject()
+ if hitphys:IsValid() and hitphys:IsMoveable() then
+ self:SetParent(hitent)
+ end
+ end
+end
+
+function ENT:StartTouch(ent)
+ if not self.Done and not self.Touched[tostring(ent)] and ent:IsValid() then
+ local owner = self:GetOwner()
+ if not owner:IsValid() then owner = self end
+
+ if ent ~= owner and not (ent:IsPlayer() and ent:Team() == self.Team) then
+ ent:TakeDamage(100, owner, self)
+ ent:EmitSound("weapons/crossbow/hitbod"..math.random(1,2)..".wav")
+ self.Touched[tostring(ent)] = true
+ end
+ end
+end
+
+function ENT:UpdateTransmitState()
+ return TRANSMIT_PVS
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_arrow/shared.lua b/gamemodes/zombiesurvival/entities/entities/projectile_arrow/shared.lua
new file mode 100644
index 0000000..b1555d0
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_arrow/shared.lua
@@ -0,0 +1,9 @@
+ENT.Type = "anim"
+
+util.PrecacheModel("models/Items/CrossbowRounds.mdl")
+util.PrecacheSound("weapons/crossbow/bolt_fly4.wav")
+util.PrecacheSound("physics/metal/sawblade_stick1.wav")
+util.PrecacheSound("physics/metal/sawblade_stick2.wav")
+util.PrecacheSound("physics/metal/sawblade_stick3.wav")
+util.PrecacheSound("weapons/crossbow/hitbod1.wav")
+util.PrecacheSound("weapons/crossbow/hitbod2.wav")
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_bonemesh/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/projectile_bonemesh/cl_init.lua
new file mode 100644
index 0000000..3b904d3
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_bonemesh/cl_init.lua
@@ -0,0 +1,33 @@
+include("shared.lua")
+
+ENT.NextEmit = 0
+
+function ENT:Initialize()
+ self:SetModelScale(2.5, 0)
+ self:SetMaterial("models/flesh")
+end
+
+function ENT:Draw()
+ self:DrawModel()
+
+ if CurTime() >= self.NextEmit and self:GetVelocity():Length() >= 16 then
+ self.NextEmit = CurTime() + 0.05
+
+ local emitter = ParticleEmitter(self:GetPos())
+ emitter:SetNearClip(16, 24)
+
+ local particle = emitter:Add("noxctf/sprite_bloodspray"..math.random(8), self:GetPos())
+ particle:SetVelocity(VectorRand():GetNormalized() * math.Rand(8, 16))
+ particle:SetDieTime(1)
+ particle:SetStartAlpha(230)
+ particle:SetEndAlpha(230)
+ particle:SetStartSize(10)
+ particle:SetEndSize(0)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-25, 25))
+ particle:SetColor(255, 0, 0)
+ particle:SetLighting(true)
+
+ emitter:Finish()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_bonemesh/init.lua b/gamemodes/zombiesurvival/entities/entities/projectile_bonemesh/init.lua
new file mode 100644
index 0000000..98f57f2
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_bonemesh/init.lua
@@ -0,0 +1,93 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+ENT.LifeTime = 3
+
+function ENT:Initialize()
+ self:SetModel("models/Gibs/HGIBS.mdl")
+ self:PhysicsInitSphere(13)
+ self:SetSolid(SOLID_VPHYSICS)
+ self:SetCollisionGroup(COLLISION_GROUP_PROJECTILE)
+ self:SetModelScale(2.5, 0)
+ self:SetCustomCollisionCheck(true)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMass(20)
+ phys:SetBuoyancyRatio(0.002)
+ phys:EnableMotion(true)
+ phys:Wake()
+ end
+
+ self:SetMaterial("models/flesh")
+
+ self.DeathTime = CurTime() + 30
+ self.ExplodeTime = CurTime() + self.LifeTime
+end
+
+function ENT:Think()
+ if self.ExplodeTime <= CurTime() then
+ self:Explode()
+ end
+
+ if self.DeathTime <= CurTime() then
+ self:Remove()
+ end
+
+ self:NextThink(CurTime())
+ return true
+end
+
+function ENT:Explode()
+ if self.Exploded then return end
+ self.Exploded = true
+ self.DeathTime = 0
+
+ local pos = self:GetPos()
+ local owner = self:GetOwner()
+ if not owner:IsValid() then owner = self end
+
+ util.BlastDamageEx(self, owner, pos, 100, 15, DMG_SLASH)
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(pos)
+ util.Effect("bonemeshexplode", effectdata)
+
+ util.Blood(pos, 150, Vector(0, 0, 1), 300, true)
+
+ for i=1, 4 do
+ local ent = ents.CreateLimited("prop_playergib")
+ if ent:IsValid() then
+ ent:SetPos(pos + VectorRand() * 4)
+ ent:SetAngles(VectorRand():Angle())
+ ent:SetGibType(math.random(3, #GAMEMODE.HumanGibs))
+ ent:Spawn()
+
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:SetVelocityInstantaneous(VectorRand():GetNormalized() * math.Rand(120, 620))
+ phys:AddAngleVelocity(VectorRand() * 360)
+ end
+ end
+ end
+end
+
+function ENT:PhysicsCollide(data, physobj)
+ if 20 < data.Speed and 0.2 < data.DeltaTime then
+ self:EmitSound("physics/body/body_medium_impact_hard"..math.random(6)..".wav", 74, math.Rand(95, 105))
+ end
+
+ local ent = data.HitEntity
+ if ent and ent:IsValid() and ent:IsPlayer() and ent:Team() ~= TEAM_UNDEAD then
+ self.ExplodeTime = 0
+ self:NextThink(CurTime())
+ else
+ local normal = data.OurOldVelocity:GetNormalized()
+ local DotProduct = data.HitNormal:Dot(normal * -1)
+
+ physobj:SetVelocityInstantaneous((2 * DotProduct * data.HitNormal + normal) * math.max(100, data.Speed) * 0.9)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_bonemesh/shared.lua b/gamemodes/zombiesurvival/entities/entities/projectile_bonemesh/shared.lua
new file mode 100644
index 0000000..cd7ed80
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_bonemesh/shared.lua
@@ -0,0 +1,7 @@
+ENT.Type = "anim"
+
+function ENT:ShouldNotCollide(ent)
+ return ent:IsPlayer() and ent:Team() == TEAM_UNDEAD
+end
+
+util.PrecacheModel("models/Gibs/HGIBS.mdl")
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_healdart/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/projectile_healdart/cl_init.lua
new file mode 100644
index 0000000..d4a89ee
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_healdart/cl_init.lua
@@ -0,0 +1,64 @@
+include("shared.lua")
+
+ENT.NextEmit = 0
+
+function ENT:Initialize()
+ local cmodel = ClientsideModel("models/healthvial.mdl")
+ if cmodel:IsValid() then
+ cmodel:SetPos(self:LocalToWorld(Vector(-4, 0, 0)))
+ cmodel:SetAngles(self:LocalToWorldAngles(Angle(90, 0, 0)))
+ cmodel:SetSolid(SOLID_NONE)
+ cmodel:SetMoveType(MOVETYPE_NONE)
+ cmodel:SetParent(self)
+ cmodel:SetOwner(self)
+ cmodel:SetModelScale(0.6, 0)
+ cmodel:Spawn()
+
+ self.CModel = cmodel
+ end
+end
+
+function ENT:OnRemove()
+ if self.CModel and self.CModel:IsValid() then
+ self.CModel:Remove()
+ end
+end
+
+local matOverride = Material("models/shiny")
+function ENT:Draw()
+ --[[local parent = self:GetParent()
+ if parent == LocalPlayer() and parent:IsValid() and not parent:ShouldDrawLocalPlayer() then return end]]
+
+ local hittime = self:GetHitTime()
+ if hittime == 0 then
+ render.SetColorModulation(0, 1, 0)
+ else
+ render.SetColorModulation(0, 1 - math.Clamp(CurTime() - hittime, 0, 1), 0)
+ end
+ render.ModelMaterialOverride(matOverride)
+
+ self:DrawModel()
+
+ render.ModelMaterialOverride()
+ render.SetColorModulation(1, 1, 1)
+
+ if self:GetMoveType() == MOVETYPE_NONE or CurTime() < self.NextEmit then return end
+ self.NextEmit = CurTime() + 0.01
+
+ local pos = self:GetPos()
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(24, 32)
+
+ local particle = emitter:Add("particles/smokey", pos)
+ particle:SetDieTime(0.35)
+ particle:SetStartAlpha(255)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(1)
+ particle:SetEndSize(0)
+ particle:SetRoll(math.Rand(0, 255))
+ particle:SetRollDelta(math.Rand(-10, 10))
+ particle:SetColor(30, 255, 30)
+
+ emitter:Finish()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_healdart/init.lua b/gamemodes/zombiesurvival/entities/entities/projectile_healdart/init.lua
new file mode 100644
index 0000000..624a424
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_healdart/init.lua
@@ -0,0 +1,104 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+ENT.Heal = 3
+
+function ENT:Initialize()
+ self:SetModel("models/Items/CrossbowRounds.mdl")
+ self:SetModelScale(0.5, 0)
+ self:PhysicsInit(SOLID_VPHYSICS)
+ self:SetCollisionGroup(COLLISION_GROUP_PROJECTILE)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMass(3)
+ phys:SetBuoyancyRatio(0.002)
+ phys:EnableMotion(true)
+ phys:Wake()
+ end
+
+ self:Fire("kill", "", 30)
+end
+
+function ENT:Think()
+ if self.PhysicsData then
+ self:Explode(self.PhysicsData.HitPos, self.PhysicsData.HitNormal, self.PhysicsData.HitEntity, self.PhysicsData.OurOldVelocity)
+ end
+
+ local parent = self:GetParent()
+ if parent:IsValid() and parent:IsPlayer() and not parent:Alive() then
+ self:Remove()
+ end
+end
+
+function ENT:Explode(vHitPos, vHitNormal, eHitEntity, vOldVelocity)
+ if self:GetHitTime() ~= 0 then return end
+ self:SetHitTime(CurTime())
+
+ self:Fire("kill", "", 10)
+
+ local owner = self:GetOwner()
+ if not owner:IsValid() then owner = self end
+
+ vHitPos = vHitPos or self:GetPos()
+ vHitNormal = (vHitNormal or Vector(0, 0, -1)) * -1
+
+ self:SetSolid(SOLID_NONE)
+ self:SetMoveType(MOVETYPE_NONE)
+
+ self:SetPos(vHitPos + vHitNormal)
+
+ if eHitEntity:IsValid() then
+ self:AddEFlags(EFL_SETTING_UP_BONES)
+
+ local followed = false
+ if eHitEntity:GetBoneCount() > 1 then
+ local boneindex = eHitEntity:NearestBone(vHitPos)
+ if boneindex and boneindex > 0 then
+ self:FollowBone(eHitEntity, boneindex)
+ self:SetPos((eHitEntity:GetBonePositionMatrixed(boneindex) * 2 + vHitPos) / 3)
+ followed = true
+ end
+ end
+ if not followed then
+ self:SetParent(eHitEntity)
+ end
+ self:SetOwner(eHitEntity)
+
+ if eHitEntity:IsPlayer() and eHitEntity:Team() ~= TEAM_UNDEAD then
+ eHitEntity:GiveStatus("healdartboost").DieTime = CurTime() + 10
+
+ local oldhealth = eHitEntity:Health()
+ local newhealth = math.min(oldhealth + self.Heal, eHitEntity:GetMaxHealth())
+ if oldhealth ~= newhealth then
+ eHitEntity:SetHealth(newhealth)
+
+ if owner:IsPlayer() then
+ gamemode.Call("PlayerHealedTeamMember", owner, eHitEntity, newhealth - oldhealth, self)
+ end
+ end
+ end
+ end
+
+ self:SetAngles(vOldVelocity:Angle())
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(vHitPos)
+ effectdata:SetNormal(vHitNormal)
+ if eHitEntity:IsValid() then
+ effectdata:SetEntity(eHitEntity)
+ else
+ effectdata:SetEntity(NULL)
+ end
+ util.Effect("hit_healdart", effectdata)
+end
+
+function ENT:PhysicsCollide(data, phys)
+ if not self:HitFence(data, phys) then
+ self.PhysicsData = data
+ end
+
+ self:NextThink(CurTime())
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_healdart/shared.lua b/gamemodes/zombiesurvival/entities/entities/projectile_healdart/shared.lua
new file mode 100644
index 0000000..b51b1f0
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_healdart/shared.lua
@@ -0,0 +1,3 @@
+ENT.Type = "anim"
+
+AccessorFuncDT(ENT, "HitTime", "Float", 0)
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_poisonflesh/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/projectile_poisonflesh/cl_init.lua
new file mode 100644
index 0000000..b05afc8
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_poisonflesh/cl_init.lua
@@ -0,0 +1,38 @@
+include("shared.lua")
+
+ENT.NextEmit = 0
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+
+ self.Size = math.Rand(10, 14)
+end
+
+local colFlesh = Color(255, 255, 255, 255)
+local matFlesh = Material("decals/Yblood1")
+function ENT:Draw()
+ local size = self.Size
+
+ render.SetMaterial(matFlesh)
+ local pos = self:GetPos()
+ render.DrawSprite(pos, size, size, colFlesh)
+
+ if CurTime() < self.NextEmit then return end
+ self.NextEmit = CurTime() + 0.05
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(36, 44)
+
+ local particle = emitter:Add("decals/Yblood"..math.random(6), pos + VectorRand():GetNormalized() * math.Rand(1, 4))
+ particle:SetVelocity(VectorRand():GetNormalized() * math.Rand(1, 4))
+ particle:SetDieTime(math.Rand(0.6, 0.9))
+ particle:SetStartAlpha(255)
+ particle:SetEndAlpha(255)
+ particle:SetStartSize(size * math.Rand(0.1, 0.22))
+ particle:SetEndSize(0)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-4, 4))
+ particle:SetLighting(true)
+
+ emitter:Finish()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_poisonflesh/init.lua b/gamemodes/zombiesurvival/entities/entities/projectile_poisonflesh/init.lua
new file mode 100644
index 0000000..393cba6
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_poisonflesh/init.lua
@@ -0,0 +1,63 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+ENT.Damage = 5
+ENT.Type = "anim"
+
+function ENT:Initialize()
+ self.DeathTime = CurTime() + 30
+
+ self:DrawShadow(false)
+ self:PhysicsInitSphere(1)
+ self:SetSolid(SOLID_VPHYSICS)
+ self:SetCollisionGroup(COLLISION_GROUP_PROJECTILE)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMass(4)
+ phys:SetBuoyancyRatio(0.002)
+ phys:EnableMotion(true)
+ phys:Wake()
+ end
+end
+
+function ENT:Think()
+ if self.PhysicsData then
+ self:Explode(self.PhysicsData.HitPos, self.PhysicsData.HitNormal, self.PhysicsData.HitEntity)
+ end
+
+ if self.DeathTime <= CurTime() then
+ self:Remove()
+ end
+end
+
+function ENT:Explode(vHitPos, vHitNormal, eHitEntity)
+ if self.Exploded then return end
+ self.Exploded = true
+ self.DeathTime = 0
+
+ local owner = self:GetOwner()
+ if not owner:IsValid() then owner = self end
+
+ vHitPos = vHitPos or self:GetPos()
+ vHitNormal = vHitNormal or Vector(0, 0, 1)
+
+ if eHitEntity:IsValid() then
+ eHitEntity:PoisonDamage(self.Damage, owner, self)
+ end
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(vHitPos)
+ effectdata:SetNormal(vHitNormal)
+ util.Effect("fleshhit", effectdata)
+end
+
+function ENT:PhysicsCollide(data, phys)
+ if not self:HitFence(data, phys) then
+ self.PhysicsData = data
+ end
+
+ self:NextThink(CurTime())
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_poisonflesh/shared.lua b/gamemodes/zombiesurvival/entities/entities/projectile_poisonflesh/shared.lua
new file mode 100644
index 0000000..9539e7a
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_poisonflesh/shared.lua
@@ -0,0 +1,5 @@
+ENT.Type = "anim"
+
+function ENT:ShouldNotCollide(ent)
+ return ent:IsPlayer() and ent:Team() == TEAM_UNDEAD
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_poisonpuke.lua b/gamemodes/zombiesurvival/entities/entities/projectile_poisonpuke.lua
new file mode 100644
index 0000000..5d70c2b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_poisonpuke.lua
@@ -0,0 +1,4 @@
+AddCSLuaFile()
+
+ENT.Base = "projectile_poisonflesh"
+ENT.Type = "anim"
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_poisonspit/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/projectile_poisonspit/cl_init.lua
new file mode 100644
index 0000000..fbebce0
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_poisonspit/cl_init.lua
@@ -0,0 +1,33 @@
+include("shared.lua")
+
+ENT.NextEmit = 0
+
+function ENT:Initialize()
+ self:SetColor(Color(0, 255, 0, 255))
+end
+
+function ENT:Draw()
+ self:DrawModel()
+
+ if CurTime() < self.NextEmit then return end
+ self.NextEmit = CurTime() + 0.025
+
+ local pos = self:GetPos()
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(24, 32)
+
+ local particle = emitter:Add("particles/smokey", pos)
+ particle:SetDieTime(math.Rand(0.4, 0.5))
+ particle:SetStartAlpha(255)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(math.Rand(3, 5))
+ particle:SetEndSize(0)
+ particle:SetRoll(math.Rand(0, 255))
+ particle:SetRollDelta(math.Rand(-10, 10))
+ particle:SetVelocity((self:GetVelocity():GetNormalized() * -1 + VectorRand():GetNormalized()):GetNormalized() * math.Rand(16, 48))
+ particle:SetLighting(true)
+ particle:SetColor(30, 255, 30)
+
+ emitter:Finish()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_poisonspit/init.lua b/gamemodes/zombiesurvival/entities/entities/projectile_poisonspit/init.lua
new file mode 100644
index 0000000..35c49b4
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_poisonspit/init.lua
@@ -0,0 +1,74 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self.DeathTime = CurTime() + 30
+
+ self:SetModel("models/props/cs_italy/orange.mdl")
+ self:PhysicsInitSphere(1)
+ self:SetSolid(SOLID_VPHYSICS)
+ self:SetCollisionGroup(COLLISION_GROUP_PROJECTILE)
+ self:SetColor(Color(0, 255, 0, 255))
+ self:SetCustomCollisionCheck(true)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMass(4)
+ phys:SetBuoyancyRatio(0.002)
+ phys:EnableMotion(true)
+ phys:Wake()
+ end
+end
+
+function ENT:Think()
+ if self.PhysicsData then
+ self:Explode(self.PhysicsData.HitPos, self.PhysicsData.HitNormal, self.PhysicsData.HitEntity)
+ end
+
+ if self.DeathTime <= CurTime() then
+ self:Remove()
+ end
+end
+
+function ENT:Explode(vHitPos, vHitNormal, eHitEntity)
+ if self.Exploded then return end
+ self.Exploded = true
+ self.DeathTime = 0
+
+ local owner = self:GetOwner()
+ if not owner:IsValid() then owner = self end
+
+ vHitPos = vHitPos or self:GetPos()
+ vHitNormal = vHitNormal or Vector(0, 0, 1)
+
+ if eHitEntity:IsValid() then
+ eHitEntity:PoisonDamage(15, owner, self)
+ if eHitEntity:IsPlayer() and eHitEntity:Team() ~= TEAM_UNDEAD then
+ local attach = eHitEntity:GetAttachment(1)
+ if attach then
+ if vHitPos:Distance(attach.Pos) <= 18 then
+ eHitEntity:PlayEyePoisonedSound()
+ local status = eHitEntity:GiveStatus("confusion")
+ if status then
+ status.EyeEffect = true
+ end
+ end
+ end
+ end
+ end
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(vHitPos)
+ effectdata:SetNormal(vHitNormal)
+ util.Effect("spithit", effectdata)
+end
+
+function ENT:PhysicsCollide(data, phys)
+ if not self:HitFence(data, phys) then
+ self.PhysicsData = data
+ end
+
+ self:NextThink(CurTime())
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_poisonspit/shared.lua b/gamemodes/zombiesurvival/entities/entities/projectile_poisonspit/shared.lua
new file mode 100644
index 0000000..3334048
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_poisonspit/shared.lua
@@ -0,0 +1,8 @@
+ENT.Type = "anim"
+
+function ENT:ShouldNotCollide(ent)
+ return ent:IsPlayer() and ent:Team() == TEAM_UNDEAD
+end
+
+util.PrecacheModel("models/props/cs_italy/orange.mdl")
+util.PrecacheSound("npc/antlion_grub/squashed.wav")
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_stone/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/projectile_stone/cl_init.lua
new file mode 100644
index 0000000..33dcc35
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_stone/cl_init.lua
@@ -0,0 +1 @@
+include("shared.lua")
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_stone/init.lua b/gamemodes/zombiesurvival/entities/entities/projectile_stone/init.lua
new file mode 100644
index 0000000..6d644f9
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_stone/init.lua
@@ -0,0 +1,66 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include('shared.lua')
+
+function ENT:Initialize()
+ self.DieTime = CurTime() + 30
+
+ self:SetModel("models/props_junk/rock001a.mdl")
+ self:PhysicsInit(SOLID_VPHYSICS)
+ self:SetCollisionGroup(COLLISION_GROUP_WEAPON)
+ self:SetTrigger(true)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMass(4)
+ phys:SetBuoyancyRatio(0.01)
+ phys:EnableDrag(false)
+ phys:Wake()
+ end
+end
+
+function ENT:Think()
+ if self.PhysicsData then
+ self:Explode(self.PhysicsData.HitPos, self.PhysicsData.HitNormal)
+ end
+
+ if self.DieTime <= CurTime() then
+ self:Remove()
+ end
+end
+
+function ENT:PhysicsCollide(data, phys)
+ if data.Speed >= 50 then
+ self.PhysicsData = data
+ self:NextThink(CurTime())
+ end
+end
+
+function ENT:StartTouch(ent)
+ if self.DieTime ~= 0 and ent:IsValid() and ent:IsPlayer() then
+ local owner = self:GetOwner()
+ if not owner:IsValid() then owner = self end
+
+ if ent ~= owner and ent:Team() ~= self.Team then
+ ent:EmitSound("weapons/crossbow/hitbod"..math.random(2)..".wav")
+ ent:TakeDamage(self.Damage, owner, self)
+ self:Explode()
+ end
+ end
+end
+
+function ENT:Explode(hitpos, hitnormal)
+ if self.DieTime == 0 then return end
+ self.DieTime = 0
+
+ hitpos = hitpos or self:GetPos()
+ hitnormal = hitnormal or (self:GetVelocity():GetNormalized() * -1)
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(hitpos)
+ effectdata:SetNormal(hitnormal)
+ util.Effect("hit_stone", effectdata)
+
+ self:NextThink(CurTime())
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_stone/shared.lua b/gamemodes/zombiesurvival/entities/entities/projectile_stone/shared.lua
new file mode 100644
index 0000000..b53d255
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_stone/shared.lua
@@ -0,0 +1,3 @@
+ENT.Type = "anim"
+
+ENT.Damage = 100
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_zsgrenade/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/projectile_zsgrenade/cl_init.lua
new file mode 100644
index 0000000..d03674b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_zsgrenade/cl_init.lua
@@ -0,0 +1,65 @@
+include("shared.lua")
+
+ENT.NextTickSound = 0
+ENT.LastTickSound = 0
+ENT.NextEmit = 0
+
+function ENT:Initialize()
+ self.DieTime = CurTime() + self.LifeTime
+end
+
+function ENT:Think()
+ local curtime = CurTime()
+
+ if curtime >= self.NextEmit then
+ self.NextEmit = curtime + 0.05
+
+ local pos = self:GetPos() + self:GetUp() * 8
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(16, 24)
+
+ local particle = emitter:Add("particles/smokey", pos)
+ particle:SetVelocity(VectorRand():GetNormalized() * math.Rand(2, 14))
+ particle:SetDieTime(math.Rand(0.6, 0.74))
+ particle:SetStartAlpha(math.Rand(200, 220))
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(1)
+ particle:SetEndSize(math.Rand(8, 10))
+ particle:SetRoll(math.Rand(-0.2, 0.2))
+ particle:SetColor(50, 50, 50)
+
+ emitter:Finish()
+ end
+
+ if curtime >= self.NextTickSound then
+ local delta = self.DieTime - curtime
+
+ self.NextTickSound = curtime + math.max(0.2, delta * 0.25)
+ self.LastTickSound = curtime
+ self:EmitSound("weapons/grenade/tick1.wav", 75, math.Clamp((1 - delta / self.LifeTime) * 160, 100, 160))
+ end
+end
+
+local matGlow = Material("sprites/glow04_noz")
+function ENT:Draw()
+ self:DrawModel()
+
+ if math.abs(self.LastTickSound - CurTime()) < 0.1 then
+ local pos = self:GetPos() + self:GetUp() * 8
+
+ render.SetMaterial(matGlow)
+ render.DrawSprite(pos, 16, 16, COLOR_RED)
+
+ local dlight = DynamicLight(self:EntIndex())
+ if dlight then
+ dlight.Pos = pos
+ dlight.r = 255
+ dlight.g = 0
+ dlight.b = 0
+ dlight.Brightness = 0.75
+ dlight.Size = 64
+ dlight.Decay = 256
+ dlight.DieTime = CurTime() + 0.1
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_zsgrenade/init.lua b/gamemodes/zombiesurvival/entities/entities/projectile_zsgrenade/init.lua
new file mode 100644
index 0000000..8e85cf9
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_zsgrenade/init.lua
@@ -0,0 +1,49 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self.DieTime = CurTime() + self.LifeTime
+
+ self:SetModel("models/weapons/w_grenade.mdl")
+ self:PhysicsInit(SOLID_VPHYSICS)
+ self:SetSolid(SOLID_VPHYSICS)
+ self:SetCollisionGroup(COLLISION_GROUP_WEAPON)
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:SetMass(4)
+ phys:SetMaterial("metal")
+ end
+end
+
+function ENT:PhysicsCollide(data, phys)
+ if 20 < data.Speed and 0.25 < data.DeltaTime then
+ self:EmitSound("physics/metal/metal_grenade_impact_hard"..math.random(1,3)..".wav")
+ end
+end
+
+function ENT:Think()
+ if self.Exploded then
+ self:Remove()
+ elseif self.DieTime <= CurTime() then
+ self:Explode()
+ end
+end
+
+function ENT:Explode()
+ if self.Exploded then return end
+ self.Exploded = true
+
+ local owner = self:GetOwner()
+ if owner:IsValid() and owner:IsPlayer() and owner:Team() == TEAM_HUMAN then
+ local pos = self:GetPos()
+
+ util.BlastDamage2(self, owner, pos, self.GrenadeRadius or 256, self.GrenadeDamage or 256)
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(pos)
+ util.Effect("Explosion", effectdata)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/projectile_zsgrenade/shared.lua b/gamemodes/zombiesurvival/entities/entities/projectile_zsgrenade/shared.lua
new file mode 100644
index 0000000..629f983
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/projectile_zsgrenade/shared.lua
@@ -0,0 +1,9 @@
+ENT.Type = "anim"
+
+ENT.LifeTime = 2.5
+
+ENT.NoPropDamageDuringWave0 = true
+
+util.PrecacheSound("physics/metal/metal_grenade_impact_hard1.wav")
+util.PrecacheSound("physics/metal/metal_grenade_impact_hard2.wav")
+util.PrecacheSound("physics/metal/metal_grenade_impact_hard3.wav")
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_aegisboard/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_aegisboard/cl_init.lua
new file mode 100644
index 0000000..39ac30b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_aegisboard/cl_init.lua
@@ -0,0 +1,58 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+end
+
+function ENT:DrawHealthBar(percentage)
+ local y = -50
+ local maxbarwidth = 560
+ local barheight = 30
+ local barwidth = maxbarwidth * percentage
+ local startx = maxbarwidth * -0.5
+
+ surface.SetDrawColor(0, 0, 0, 220)
+ surface.DrawRect(startx, y, maxbarwidth, barheight)
+ surface.SetDrawColor((1 - percentage) * 255, percentage * 255, 0, 220)
+ surface.DrawRect(startx + 4, y + 4, barwidth - 8, barheight - 8)
+ surface.DrawOutlinedRect(startx, y, maxbarwidth, barheight)
+end
+
+function ENT:Draw()
+ if MySelf:IsValid() and MySelf:Team() == TEAM_HUMAN then
+ local percentage = math.Clamp(self:GetObjectHealth() / self:GetMaxObjectHealth(), 0, 1)
+ local ang = self:GetAngles()
+ ang:RotateAroundAxis(ang:Up(), 270)
+ ang:RotateAroundAxis(ang:Right(), 90)
+ ang:RotateAroundAxis(ang:Forward(), 270)
+ local vPos = self:GetPos()
+ local vOffset = self:GetForward() * self:OBBMaxs().x
+ local name
+ local owner = self:GetObjectOwner()
+ if owner:IsValid() and owner:IsPlayer() and owner:Team() == TEAM_HUMAN then
+ name = owner:Name()
+ end
+
+ self:DrawModel()
+
+ cam.Start3D2D(vPos + vOffset, ang, 0.05)
+ self:DrawHealthBar(percentage)
+ if name then
+ draw.SimpleText(name, "ZS3D2DFont", 0, 0, COLOR_WHITE, TEXT_ALIGN_CENTER)
+ end
+ cam.End3D2D()
+
+ ang:RotateAroundAxis(ang:Right(), 180)
+
+ cam.Start3D2D(vPos - vOffset, ang, 0.05)
+ self:DrawHealthBar(percentage)
+ if name then
+ draw.SimpleText(name, "ZS3D2DFont", 0, 0, COLOR_WHITE, TEXT_ALIGN_CENTER)
+ end
+ cam.End3D2D()
+ else
+ self:DrawModel()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_aegisboard/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_aegisboard/init.lua
new file mode 100644
index 0000000..ff01823
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_aegisboard/init.lua
@@ -0,0 +1,92 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:SetModel("models/props_debris/wood_board05a.mdl")
+ self:PhysicsInit(SOLID_VPHYSICS)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:EnableMotion(false)
+ phys:Wake()
+ end
+
+ self:SetMaxObjectHealth(450)
+ self:SetObjectHealth(self:GetMaxObjectHealth())
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "maxboardhealth" then
+ value = tonumber(value)
+ if not value then return end
+
+ self:SetMaxObjectHealth(value)
+ elseif key == "boardhealth" then
+ value = tonumber(value)
+ if not value then return end
+
+ self:SetObjectHealth(value)
+ end
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ if name == "setboardhealth" then
+ self:KeyValue("boardhealth", args)
+ return true
+ elseif name == "setmaxboardhealth" then
+ self:KeyValue("maxboardhealth", args)
+ return true
+ end
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ self:TakePhysicsDamage(dmginfo)
+
+ local attacker = dmginfo:GetAttacker()
+ if not (attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_HUMAN) then
+ self:ResetLastBarricadeAttacker(attacker, dmginfo)
+ self:SetObjectHealth(self:GetObjectHealth() - dmginfo:GetDamage())
+ end
+end
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+ if health <= 0 and not self.Destroyed then
+ self.Destroyed = true
+
+ local ent = ents.Create("prop_physics")
+ if ent:IsValid() then
+ ent:SetModel(self:GetModel())
+ ent:SetMaterial(self:GetMaterial())
+ ent:SetAngles(self:GetAngles())
+ ent:SetPos(self:GetPos())
+ ent:SetSkin(self:GetSkin() or 0)
+ ent:SetColor(self:GetColor())
+ ent:Spawn()
+ ent:Fire("break", "", 0)
+ ent:Fire("kill", "", 0.1)
+ end
+ end
+end
+
+function ENT:AltUse(activator, tr)
+ self:PackUp(activator)
+end
+
+function ENT:OnPackedUp(pl)
+ pl:GiveEmptyWeapon("weapon_zs_barricadekit")
+ pl:GiveAmmo(1, "SniperRound")
+
+ pl:PushPackedItem(self:GetClass(), self:GetObjectHealth())
+
+ self:Remove()
+end
+
+function ENT:Think()
+ if self.Destroyed then
+ self:Remove()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_aegisboard/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_aegisboard/shared.lua
new file mode 100644
index 0000000..5cdc982
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_aegisboard/shared.lua
@@ -0,0 +1,42 @@
+ENT.Type = "anim"
+
+ENT.m_NoNailUnfreeze = true
+ENT.NoNails = true
+
+ENT.CanPackUp = true
+ENT.PackUpTime = 3
+
+ENT.IsBarricadeObject = true
+
+function ENT:GetObjectHealth()
+ return self:GetDTFloat(0)
+end
+
+function ENT:SetMaxObjectHealth(health)
+ self:SetDTFloat(1, health)
+end
+
+function ENT:GetMaxObjectHealth()
+ return self:GetDTFloat(1)
+end
+
+function ENT:SetObjectOwner(ent)
+ self:SetDTEntity(0, ent)
+end
+
+function ENT:GetObjectOwner()
+ return self:GetDTEntity(0)
+end
+
+function ENT:ClearObjectOwner()
+ self:SetObjectOwner(NULL)
+end
+
+function ENT:HitByWrench(wep, owner, tr)
+ return true
+end
+
+function ENT:CanBePackedBy(pl)
+ local owner = self:GetObjectOwner()
+ return not owner:IsValid() or owner == pl or owner:Team() ~= TEAM_HUMAN or gamemode.Call("PlayerIsAdmin", pl)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_ammo/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_ammo/cl_init.lua
new file mode 100644
index 0000000..2be6653
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_ammo/cl_init.lua
@@ -0,0 +1,3 @@
+include("shared.lua")
+
+ENT.ColorModulation = Color(0.25, 1, 0.25)
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_ammo/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_ammo/init.lua
new file mode 100644
index 0000000..5466dfa
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_ammo/init.lua
@@ -0,0 +1,90 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+ENT.CleanupPriority = 2
+
+function ENT:Initialize()
+ self.m_Health = 50
+
+ self:PhysicsInit(SOLID_VPHYSICS)
+ self:SetSolid(SOLID_VPHYSICS)
+ self:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
+
+ self:SetUseType(SIMPLE_USE)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMaterial("material")
+ phys:EnableMotion(true)
+ phys:Wake()
+ end
+
+ self:ItemCreated()
+end
+
+function ENT:SetAmmoType(ammotype)
+ self:SetModel(GAMEMODE.AmmoModels[string.lower(ammotype)] or "models/Items/BoxMRounds.mdl")
+ self.m_AmmoType = ammotype
+end
+
+function ENT:GetAmmoType()
+ return self.m_AmmoType or "pistol"
+end
+
+function ENT:SetAmmo(ammo)
+ self.m_Ammo = tonumber(ammo) or self:GetAmmo()
+end
+
+function ENT:GetAmmo()
+ return self.m_Ammo or 0
+end
+
+function ENT:Use(activator, caller)
+ if activator:IsPlayer() and activator:Alive() and not activator:KeyDown(GAMEMODE.UtilityKey) and activator:Team() ~= TEAM_UNDEAD and not self.Removing then
+ if not self.PlacedInMap or not GAMEMODE.MaxAmmoBoxPickups or (activator.AmmoPickups or 0) < GAMEMODE.MaxAmmoBoxPickups or team.NumPlayers(TEAM_HUMAN) <= 1 then
+ if self.PlacedInMap and GAMEMODE.WeaponRequiredForAmmo and team.NumPlayers(TEAM_HUMAN) > 1 then
+ local hasweapon = false
+ for _, wep in pairs(activator:GetWeapons()) do
+ if wep.Primary and wep.Primary.Ammo and string.lower(wep.Primary.Ammo) == string.lower(self:GetAmmoType())
+ or wep.Secondary and wep.Secondary.Ammo and string.lower(wep.Secondary.Ammo) == string.lower(self:GetAmmoType()) then
+ hasweapon = true
+ break
+ end
+ end
+
+ if not hasweapon then
+ activator:CenterNotify(COLOR_RED, translate.ClientGet(activator, "nothing_for_this_ammo"))
+ return
+ end
+ end
+
+ activator:GiveAmmo(self:GetAmmo(), self:GetAmmoType())
+
+ activator.AmmoPickups = (activator.AmmoPickups or 0) + 1
+
+ self:RemoveNextFrame(0)
+ else
+ activator:CenterNotify(COLOR_RED, translate.ClientGet(activator, "you_decide_to_leave_some"))
+ end
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "ammotype" then
+ self:SetAmmoType(value)
+ elseif key == "amount" then
+ self:SetAmmo(math.ceil(tonumber(value) or 0))
+ end
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ self:TakePhysicsDamage(dmginfo)
+
+ self.m_Health = self.m_Health - dmginfo:GetDamage()
+ if self.m_Health <= 0 then
+ self:RemoveNextFrame()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_ammo/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_ammo/shared.lua
new file mode 100644
index 0000000..e15f4c0
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_ammo/shared.lua
@@ -0,0 +1,8 @@
+ENT.Type = "anim"
+ENT.Base = "prop_baseoutlined"
+
+ENT.NoNails = true
+
+function ENT:HumanHoldable(pl)
+ return pl:KeyDown(GAMEMODE.UtilityKey)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_arsenalcrate/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_arsenalcrate/cl_init.lua
new file mode 100644
index 0000000..c977071
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_arsenalcrate/cl_init.lua
@@ -0,0 +1,37 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:SetRenderBounds(Vector(-72, -72, -72), Vector(72, 72, 128))
+end
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+end
+
+local colFlash = Color(30, 255, 30)
+function ENT:Draw()
+ self:DrawModel()
+
+ if not MySelf:IsValid() then return end
+
+ local owner = self:GetObjectOwner()
+
+ local w, h = 600, 420
+
+ cam.Start3D2D(self:LocalToWorld(Vector(1, 0, self:OBBMaxs().z)), self:GetAngles(), 0.05)
+
+ draw.RoundedBox(64, w * -0.5, h * -0.5, w, h, color_black_alpha120)
+
+ draw.SimpleText(translate.Get("arsenal_crate"), "ZS3D2DFont2", 0, 0, COLOR_GRAY, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+
+ if MySelf:Team() == TEAM_HUMAN and GAMEMODE:PlayerCanPurchase(MySelf) then
+ colFlash.a = math.abs(math.sin(CurTime() * 5)) * 255
+ draw.SimpleText(translate.Get("purchase_now"), "ZS3D2DFont2Small", 0, -64, colFlash, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
+ end
+
+ if owner:IsValid() and owner:IsPlayer() then
+ draw.SimpleText("("..owner:ClippedName()..")", "ZS3D2DFont2Small", 0, 64, owner == MySelf and COLOR_BLUE or COLOR_GRAY, TEXT_ALIGN_CENTER)
+ end
+
+ cam.End3D2D()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_arsenalcrate/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_arsenalcrate/init.lua
new file mode 100644
index 0000000..b284f69
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_arsenalcrate/init.lua
@@ -0,0 +1,115 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+local function RefreshCrateOwners(pl)
+ for _, ent in pairs(ents.FindByClass("prop_arsenalcrate")) do
+ if ent:IsValid() and ent:GetObjectOwner() == pl then
+ ent:SetObjectOwner(NULL)
+ end
+ end
+end
+hook.Add("PlayerDisconnected", "ArsenalCrate.PlayerDisconnected", RefreshCrateOwners)
+hook.Add("OnPlayerChangedTeam", "ArsenalCrate.OnPlayerChangedTeam", RefreshCrateOwners)
+
+function ENT:Initialize()
+ self:SetModel("models/Items/item_item_crate.mdl")
+ self:PhysicsInit(SOLID_VPHYSICS)
+ self:SetUseType(SIMPLE_USE)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:EnableMotion(false)
+ end
+
+ self:SetMaxObjectHealth(200)
+ self:SetObjectHealth(self:GetMaxObjectHealth())
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "maxcratehealth" then
+ value = tonumber(value)
+ if not value then return end
+
+ self:SetMaxObjectHealth(value)
+ elseif key == "cratehealth" then
+ value = tonumber(value)
+ if not value then return end
+
+ self:SetObjectHealth(value)
+ end
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ if name == "setcratehealth" then
+ self:KeyValue("cratehealth", args)
+ return true
+ elseif name == "setmaxcratehealth" then
+ self:KeyValue("maxcratehealth", args)
+ return true
+ end
+end
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+ if health <= 0 and not self.Destroyed then
+ self.Destroyed = true
+
+ local ent = ents.Create("prop_physics")
+ if ent:IsValid() then
+ ent:SetModel(self:GetModel())
+ ent:SetMaterial(self:GetMaterial())
+ ent:SetAngles(self:GetAngles())
+ ent:SetPos(self:GetPos())
+ ent:SetSkin(self:GetSkin() or 0)
+ ent:SetColor(self:GetColor())
+ ent:Spawn()
+ ent:Fire("break", "", 0)
+ ent:Fire("kill", "", 0.1)
+ end
+ end
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ self:TakePhysicsDamage(dmginfo)
+
+ local attacker = dmginfo:GetAttacker()
+ if not (attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_HUMAN) then
+ self:ResetLastBarricadeAttacker(attacker, dmginfo)
+ self:SetObjectHealth(self:GetObjectHealth() - dmginfo:GetDamage())
+ end
+end
+
+function ENT:Use(activator, caller)
+ local ishuman = activator:Team() == TEAM_HUMAN and activator:Alive()
+ if not self:GetObjectOwner():IsValid() and ishuman then
+ self:SetObjectOwner(activator)
+ end
+
+ if gamemode.Call("PlayerCanPurchase", activator) then
+ activator:SendLua("GAMEMODE:OpenPointsShop()")
+ elseif ishuman then
+ activator:CenterNotify(COLOR_RED, translate.ClientGet(activator, "you_cant_purchase_now"))
+ end
+end
+
+function ENT:AltUse(activator, tr)
+ self:PackUp(activator)
+end
+
+function ENT:OnPackedUp(pl)
+ pl:GiveEmptyWeapon("weapon_zs_arsenalcrate")
+ pl:GiveAmmo(1, "airboatgun")
+
+ pl:PushPackedItem(self:GetClass(), self:GetObjectHealth())
+
+ self:Remove()
+end
+
+function ENT:Think()
+ if self.Destroyed then
+ self:Remove()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_arsenalcrate/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_arsenalcrate/shared.lua
new file mode 100644
index 0000000..f3729d7
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_arsenalcrate/shared.lua
@@ -0,0 +1,58 @@
+ENT.Type = "anim"
+
+ENT.m_NoNailUnfreeze = true
+ENT.NoNails = true
+
+ENT.CanPackUp = true
+
+ENT.IsBarricadeObject = true
+ENT.AlwaysGhostable = true
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+ if health <= 0 and not self.Destroyed then
+ self.Destroyed = true
+
+ local ent = ents.Create("prop_physics")
+ if ent:IsValid() then
+ ent:SetModel(self:GetModel())
+ ent:SetMaterial(self:GetMaterial())
+ ent:SetAngles(self:GetAngles())
+ ent:SetPos(self:GetPos())
+ ent:SetSkin(self:GetSkin() or 0)
+ ent:SetColor(self:GetColor())
+ ent:Spawn()
+ ent:Fire("break", "", 0)
+ ent:Fire("kill", "", 0.1)
+ end
+ end
+end
+
+function ENT:GetObjectHealth()
+ return self:GetDTFloat(0)
+end
+
+function ENT:SetMaxObjectHealth(health)
+ self:SetDTFloat(1, health)
+end
+
+function ENT:GetMaxObjectHealth()
+ return self:GetDTFloat(1)
+end
+
+function ENT:SetObjectOwner(ent)
+ self:SetDTEntity(0, ent)
+end
+
+function ENT:GetObjectOwner()
+ return self:GetDTEntity(0)
+end
+
+function ENT:ClearObjectOwner()
+ self:SetObjectOwner(NULL)
+end
+
+function ENT:CanBePackedBy(pl)
+ local owner = self:GetObjectOwner()
+ return not owner:IsValid() or owner == pl or owner:Team() ~= TEAM_HUMAN or gamemode.Call("PlayerIsAdmin", pl)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_baseoutlined.lua b/gamemodes/zombiesurvival/entities/entities/prop_baseoutlined.lua
new file mode 100644
index 0000000..4297906
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_baseoutlined.lua
@@ -0,0 +1,73 @@
+AddCSLuaFile()
+
+ENT.Type = "anim"
+
+if not CLIENT then return end
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+ENT.ColorModulation = Color(1, 0.5, 1)
+ENT.Seed = 0
+
+function ENT:Initialize()
+ self.Seed = math.Rand(0, 10)
+end
+
+local matWireframe = Material("models/wireframe")
+local matWhite = Material("models/debug/debugwhite")
+function ENT:DrawTranslucent()
+ if not MySelf:IsValid() or MySelf:Team() ~= TEAM_HUMAN then
+ self:DrawModel()
+ return
+ end
+
+ local time = (CurTime() * 1.5 + self.Seed) % 2
+
+ self:DrawModel()
+
+ if time <= 1 and EyePos():Distance(self:GetPos()) <= 1024 then
+ self.NoDrawSubModels = true
+
+ local oldscale = self:GetModelScale()
+ local normal = self:GetUp()
+ local rnormal = normal * -1
+ local mins = self:OBBMins()
+ local dist = self:OBBMaxs().z - mins.z
+ mins.x = 0
+ mins.y = 0
+ local pos = self:LocalToWorld(mins)
+
+ self:SetModelScale(oldscale * 1.01, 0)
+
+ if render.SupportsVertexShaders_2_0() then
+ render.EnableClipping(true)
+ render.PushCustomClipPlane(normal, normal:Dot(pos + dist * time * normal))
+ render.PushCustomClipPlane(rnormal, rnormal:Dot(pos + dist * time * 1.25 * normal))
+ end
+
+ render.SetColorModulation(self.ColorModulation.r, self.ColorModulation.g, self.ColorModulation.b)
+ render.SuppressEngineLighting(true)
+
+ render.SetBlend(0.15)
+ render.ModelMaterialOverride(matWhite)
+ self:DrawModel()
+
+ render.SetBlend(0.4)
+ render.ModelMaterialOverride(matWireframe)
+ self:DrawModel()
+
+ render.ModelMaterialOverride(0)
+ render.SuppressEngineLighting(false)
+ render.SetBlend(1)
+ render.SetColorModulation(1, 1, 1)
+
+ if render.SupportsVertexShaders_2_0() then
+ render.PopCustomClipPlane()
+ render.PopCustomClipPlane()
+ render.EnableClipping(false)
+ end
+ self:SetModelScale(oldscale, 0)
+
+ self.NoDrawSubModels = false
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_blocker/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_blocker/cl_init.lua
new file mode 100644
index 0000000..33dcc35
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_blocker/cl_init.lua
@@ -0,0 +1 @@
+include("shared.lua")
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_blocker/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_blocker/init.lua
new file mode 100644
index 0000000..8e0662c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_blocker/init.lua
@@ -0,0 +1,15 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:SetModel("models/props_wasteland/medbridge_post01.mdl")
+ self:PhysicsInit(SOLID_VPHYSICS)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:EnableMotion(false)
+ phys:Wake()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_blocker/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_blocker/shared.lua
new file mode 100644
index 0000000..40b3860
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_blocker/shared.lua
@@ -0,0 +1 @@
+ENT.Type = "anim"
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_creepernest/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_creepernest/cl_init.lua
new file mode 100644
index 0000000..0f53872
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_creepernest/cl_init.lua
@@ -0,0 +1,167 @@
+include("shared.lua")
+
+ENT.Seed = 0
+ENT.Tall = 0
+ENT.Blocked = false
+
+function ENT:Initialize()
+ local dist = math.max(16, GAMEMODE.DynamicSpawnDist) * 2
+
+ self:SetRenderBounds(Vector(-dist, -dist, -dist), Vector(dist, dist, dist))
+ self:ManipulateBoneScale(0, self.ModelScale)
+
+ self.AmbientSound = CreateSound(self, "ambient/levels/citadel/citadel_drone_loop5.wav")
+
+ self.FloorModel = ClientsideModel("models/props_wasteland/antlionhill.mdl")
+ if self.FloorModel:IsValid() then
+ self.FloorModel:SetParent(self)
+ self.FloorModel:SetOwner(self)
+ self.FloorModel:SetPos(self:GetPos())
+ self.FloorModel:SetAngles(self:GetAngles())
+ self.FloorModel:Spawn()
+ self.FloorModel:ManipulateBoneScale(0, Vector(0.01, 0.01, 0.01))
+ self.FloorModel:SetMaterial("models/flesh")
+ end
+
+ self.Seed = math.Rand(0, 10)
+end
+
+local EmitSounds = {
+ Sound("physics/flesh/flesh_squishy_impact_hard1.wav"),
+ Sound("physics/flesh/flesh_squishy_impact_hard2.wav"),
+ Sound("physics/flesh/flesh_squishy_impact_hard3.wav"),
+ Sound("physics/flesh/flesh_squishy_impact_hard4.wav"),
+ Sound(")npc/barnacle/barnacle_die1.wav"),
+ Sound(")npc/barnacle/barnacle_die2.wav"),
+ Sound(")npc/barnacle/barnacle_digesting1.wav"),
+ Sound(")npc/barnacle/barnacle_digesting2.wav"),
+ Sound(")npc/barnacle/barnacle_gulp1.wav"),
+ Sound(")npc/barnacle/barnacle_gulp2.wav")
+}
+
+function ENT:Think()
+ self.Tall = math.Approach(self.Tall, math.Clamp(self:GetNestHealth() / self:GetNestMaxHealth(), 0.001, 1), FrameTime())
+
+ if MySelf:IsValid() and MySelf:Team() == TEAM_UNDEAD then
+ local blocked = false
+ local nearest = self:GetPos()
+ for _, human in pairs(team.GetPlayers(TEAM_HUMAN)) do
+ if util.SkewedDistance(human:GetPos(), nearest, 2.75) <= GAMEMODE.DynamicSpawnDist then
+ blocked = true
+ break
+ end
+ end
+
+ self.Blocked = blocked
+ end
+
+ if self.FloorModel:IsValid() then
+ local a = math.abs(math.sin(CurTime())) ^ 3
+ local hscale = 0.2 + a * 0.04
+ self.FloorModel:ManipulateBoneScale(0, Vector(hscale * 1.1 + 0.05, hscale * 1.1 + 0.05, 0.02 * self.Tall))
+ end
+
+ if self.DoEmitNextFrame then
+ self.DoEmitNextFrame = nil
+ self:EmitSound(EmitSounds[math.random(#EmitSounds)], 65, math.random(95, 105))
+ end
+
+ self.AmbientSound:PlayEx(0.6, 100 + CurTime() % 1)
+end
+
+function ENT:OnRemove()
+ self.AmbientSound:Stop()
+
+ if self.FloorModel:IsValid() then
+ self.FloorModel:Remove()
+ end
+end
+
+ENT.NextEmit = 0
+local gravParticle = Vector(0, 0, -200)
+local matFlesh = Material("models/flesh")
+local matWireframe = Material("models/wireframe")
+local matBeam = Material("Effects/laser1", "smooth")
+local r, g = 0, 0
+local colRing = Color(0, 0, 0, 255)
+function ENT:Draw()
+ local curtime = CurTime() + self.Seed
+ local a = math.abs(math.sin(curtime)) ^ 3
+ local hscale = 0.2 + a * 0.04
+ local built = self:GetNestBuilt()
+ local floormodel = self.FloorModel
+ local fmvalid = floormodel:IsValid()
+
+ if MySelf:IsValid() and MySelf:Team() == TEAM_UNDEAD and built then
+ local frametime = FrameTime() * 500
+ local ringtime = (curtime / 2 % 1) ^ 0.5
+ local ringsize = ringtime * GAMEMODE.DynamicSpawnDist
+ local beamsize = ringtime * 20
+ local up = self:GetUp()
+ local ang = self:GetForward():Angle()
+ ang.yaw = curtime * 360 % 360
+ local ringpos = self:GetPos() + up * 16
+ local blocked = self.Blocked
+ local a = (1 - ringtime) * 0.8
+
+ r = math.Approach(r, blocked and 255 or 0, frametime)
+ g = math.Approach(g, blocked and 0 or 255, frametime)
+ colRing.r = r * a
+ colRing.g = g * a
+
+ render.SetMaterial(matBeam)
+ render.StartBeam(19)
+ for i=1, 19 do
+ render.AddBeam(ringpos + ang:Forward() * ringsize, beamsize, beamsize, colRing)
+ ang:RotateAroundAxis(up, 20)
+ end
+ render.EndBeam()
+ end
+
+ if built then
+ render.ModelMaterialOverride(matFlesh)
+ --if fmvalid then floormodel:SetNoDraw(false) end
+ else
+ render.ModelMaterialOverride(matWireframe)
+ render.SetColorModulation(self.Tall, 0, 0)
+ --if fmvalid then floormodel:SetNoDraw(true) end
+ end
+
+ if fmvalid then
+ floormodel:ManipulateBoneScale(0, Vector(hscale * 1.1 + 0.05, hscale * 1.1 + 0.05, 0.02 * self.Tall))
+ end
+
+ self:ManipulateBoneScale(0, Vector(hscale, hscale, (0.1 - a * 0.005) * self.Tall))
+ self:DrawModel()
+
+ render.SetColorModulation(1, 1, 1)
+ render.ModelMaterialOverride()
+
+ if not built or curtime < self.NextEmit then return end
+ self.NextEmit = curtime + math.Rand(0.4, 2)
+
+ if math.random(4) == 1 then
+ self.DoEmitNextFrame = true
+ end
+
+ local pos = self:GetPos() + self:GetUp() * 8
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(16, 24)
+
+ for i=0, math.Rand(0, 1) ^ 0.5 * 10 do
+ local particle = emitter:Add("noxctf/sprite_bloodspray"..math.random(8), pos)
+ particle:SetGravity(gravParticle)
+ particle:SetDieTime(math.Rand(4, 6))
+ particle:SetVelocity(Angle(math.Rand(-85, -70), math.Rand(0, 360), 0):Forward() * math.Rand(100, 200))
+ particle:SetStartAlpha(255)
+ particle:SetEndAlpha(255)
+ particle:SetStartSize(math.Rand(2, 4))
+ particle:SetEndSize(0)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-2, 2))
+ particle:SetColor(180, 0, 0)
+ particle:SetCollide(true)
+ end
+
+ emitter:Finish()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_creepernest/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_creepernest/init.lua
new file mode 100644
index 0000000..16d7ac9
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_creepernest/init.lua
@@ -0,0 +1,132 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+ENT.NextDecay = 0
+ENT.BuildsThisTick = 0
+
+function ENT:Initialize()
+ self:SetModel("models/props_wasteland/antlionhill.mdl")
+ self:PhysicsInitBox(Vector(-20, -20, 0), Vector(20, 20, 40))
+ self:SetCollisionBounds(Vector(-20, -20, 0), Vector(20, 20, 40))
+ self:SetUseType(SIMPLE_USE)
+
+ --self:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
+ self:SetCustomCollisionCheck(true)
+ self:CollisionRulesChanged()
+
+ self:ManipulateBoneScale(0, self.ModelScale)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMaterial("flesh")
+ phys:EnableMotion(false)
+ phys:Wake()
+ end
+
+ self:SetNestHealth(self.MaxHealth)
+
+ self.LastBuild = CurTime()
+end
+
+function ENT:BuildUp()
+ if CurTime() ~= self.LastBuildTime then
+ self.LastBuildTime = CurTime()
+ self.BuildsThisTick = 0
+ end
+
+ if self.BuildsThisTick < 3 then
+ self.BuildsThisTick = self.BuildsThisTick + 1
+
+ self:SetNestHealth(math.min(self:GetNestHealth() + FrameTime() * self:GetNestMaxHealth() * 0.025, self:GetNestMaxHealth()))
+ end
+end
+
+function ENT:Use()
+end
+
+function ENT:Think()
+ if not self:GetNestBuilt() then
+ local time = CurTime()
+ if time >= self.LastBuild + 10 and time >= self.NextDecay then
+ self.NextDecay = time + 1
+
+ self:TakeDamage(5)
+ end
+ end
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ if self:GetNestHealth() <= 0 then return end
+
+ local attacker = dmginfo:GetAttacker()
+ if attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_UNDEAD then
+ local owner = self.Owner
+ if attacker:GetZombieClassTable().Name ~= "Flesh Creeper" then
+ return
+ end
+
+ if owner and owner:IsValid() and owner:Team() == TEAM_UNDEAD and owner ~= attacker and not attacker:IsAdmin() and owner:GetZombieClassTable().Name == "Flesh Creeper" and owner:Alive() and owner:GetPos():Distance(self:GetPos()) <= 768 then
+ attacker:CenterNotify(COLOR_RED, translate.ClientFormat(attacker, "x_has_built_this_nest_and_is_still_around", owner))
+ return
+ end
+
+ if #ents.FindByClass(self:GetClass()) == 1 and not attacker:IsAdmin() and owner ~= attacker then
+ attacker:CenterNotify(COLOR_RED, translate.ClientGet(attacker, "no_other_nests"))
+ return
+ end
+ end
+
+ self:SetNestHealth(self:GetNestHealth() - dmginfo:GetDamage())
+ self:SetNestLastDamaged(CurTime())
+
+ if self:GetNestHealth() <= 0 then
+ if self:GetNestBuilt() and attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_HUMAN then
+ attacker:AddPoints(5)
+ attacker.NestsDestroyed = attacker.NestsDestroyed + 1
+ end
+
+ gamemode.Call("NestDestroyed", self, attacker)
+
+ self:Destroy()
+ end
+end
+
+function ENT:Destroy()
+ self.Destroyed = true
+
+ local pos = self:WorldSpaceCenter()
+
+ local effectdata = EffectData()
+ effectdata:SetEntity(self)
+ effectdata:SetOrigin(pos)
+ util.Effect("gib_player", effectdata, true, true)
+
+ util.Blood(pos, 100, self:GetUp(), 256)
+
+ self:Fire("kill", "", 0.01)
+end
+
+function ENT:OnRemove()
+ if self.Destroyed and self:GetNestBuilt() then
+ for _, pl in pairs(team.GetPlayers(TEAM_UNDEAD)) do
+ pl:CenterNotify(COLOR_RED, translate.ClientFormat(pl, "nest_destroyed", name))
+ end
+
+ local pos = self:WorldSpaceCenter()
+ for i=1, 8 do
+ local ent = ents.CreateLimited("prop_playergib")
+ if ent:IsValid() then
+ ent:SetPos(pos + VectorRand() * 12)
+ ent:SetAngles(VectorRand():Angle())
+ ent:SetGibType(math.random(3, #GAMEMODE.HumanGibs))
+ ent:Spawn()
+ end
+ end
+ end
+end
+
+function ENT:UpdateTransmitState()
+ return TRANSMIT_ALWAYS
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_creepernest/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_creepernest/shared.lua
new file mode 100644
index 0000000..b24440f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_creepernest/shared.lua
@@ -0,0 +1,25 @@
+ENT.Type = "anim"
+
+ENT.MaxHealth = 100
+
+ENT.ModelScale = Vector(0.2, 0.2, 0.1)
+
+ENT.m_NoNailUnfreeze = true
+ENT.NoNails = true
+
+AccessorFuncDT(ENT, "NestHealth", "Float", 0)
+AccessorFuncDT(ENT, "NestBuilt", "Bool", 0)
+AccessorFuncDT(ENT, "NestLastDamaged", "Float", 1)
+
+function ENT:SetNestBuilt(b)
+ self:SetDTBool(0, b)
+ self:CollisionRulesChanged()
+end
+
+function ENT:ShouldNotCollide(ent)
+ return ent:IsPlayer() and (not self:GetNestBuilt() or ent:Team() == TEAM_UNDEAD)
+end
+
+function ENT:GetNestMaxHealth()
+ return self.MaxHealth
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_detpack/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_detpack/cl_init.lua
new file mode 100644
index 0000000..6dafcb9
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_detpack/cl_init.lua
@@ -0,0 +1,30 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_BOTH
+
+function ENT:Draw()
+ self:DrawModel()
+end
+
+local matGlow = Material("sprites/glow04_noz")
+local colBlue = Color(100, 100, 255)
+function ENT:DrawTranslucent()
+ local lightpos = self:GetPos() + self:GetUp() * 8 - self:GetRight() * 2
+
+ if self:GetExplodeTime() == 0 then
+ if self:GetOwner():IsValid() then
+ render.SetMaterial(matGlow)
+ render.DrawSprite(lightpos, 16, 16, COLOR_GREEN)
+ render.DrawSprite(lightpos, 4, 4, COLOR_DARKGREEN)
+ else
+ render.SetMaterial(matGlow)
+ render.DrawSprite(lightpos, 16, 16, colBlue)
+ render.DrawSprite(lightpos, 4, 4, COLOR_WHITE)
+ end
+ else
+ local size = (CurTime() * 2.5 % 1) * 24
+ render.SetMaterial(matGlow)
+ render.DrawSprite(lightpos, size, size, COLOR_RED)
+ render.DrawSprite(lightpos, size / 4, size / 4, COLOR_DARKRED)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_detpack/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_detpack/init.lua
new file mode 100644
index 0000000..0865707
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_detpack/init.lua
@@ -0,0 +1,101 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+local function RefreshDetpackOwners(pl)
+ for _, ent in pairs(ents.FindByClass("prop_detpack")) do
+ if ent:IsValid() and ent:GetOwner() == pl then
+ ent:SetOwner(NULL)
+ end
+ end
+end
+hook.Add("PlayerDisconnected", "Detpack.PlayerDisconnected", RefreshDetpackOwners)
+hook.Add("OnPlayerChangedTeam", "Detpack.OnPlayerChangedTeam", RefreshDetpackOwners)
+
+ENT.NextBlip = 0
+
+function ENT:Initialize()
+ self:SetModel("models/weapons/w_c4_planted.mdl")
+ self:PhysicsInit(SOLID_VPHYSICS)
+ self:SetUseType(SIMPLE_USE)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:EnableMotion(false)
+ phys:Wake()
+ end
+
+ self:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
+end
+
+function ENT:AltUse(activator, tr)
+ self:PackUp(activator)
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ self:TakePhysicsDamage(dmginfo)
+
+ if not self.Exploded and dmginfo:GetDamage() >= 9 then
+ local attacker = dmginfo:GetAttacker()
+ if not (attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_HUMAN) then
+ self.ForceExplode = true
+ self:Explode()
+ end
+ end
+end
+
+function ENT:Use(activator, caller)
+ if self.Exploded or self:GetExplodeTime() ~= 0 or not activator:IsPlayer() or activator:Team() ~= TEAM_HUMAN or self:GetMaterial() ~= "" then return end
+
+ if self:GetOwner() == activator or not self:GetOwner():IsValid() then
+ self:SetOwner(activator)
+
+ if not activator:HasWeapon("weapon_zs_detpackremote") then
+ activator:Give("weapon_zs_detpackremote")
+ end
+ activator:SelectWeapon("weapon_zs_detpackremote")
+ end
+end
+
+function ENT:Explode()
+ if self.Exploded then return end
+ self.Exploded = true
+
+ local owner = self:GetOwner()
+ if owner:IsValid() and owner:IsPlayer() and owner:Team() == TEAM_HUMAN then
+ local pos = self:GetPos()
+
+ util.BlastDamage2(self, owner, pos, 320, 600)
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(pos)
+ util.Effect("Explosion", effectdata)
+ end
+end
+
+function ENT:Think()
+ if self.Exploded then
+ self:Remove()
+ return
+ end
+
+ if self:GetExplodeTime() ~= 0 then
+ if CurTime() >= self:GetExplodeTime() then
+ self:Explode()
+ elseif self.NextBlip <= CurTime() then
+ self.NextBlip = CurTime() + 0.4
+ self:EmitSound("weapons/c4/c4_beep1.wav")
+ end
+ end
+
+ self:NextThink(CurTime())
+ return true
+end
+
+function ENT:OnPackedUp(pl)
+ pl:GiveEmptyWeapon("weapon_zs_detpack")
+ pl:GiveAmmo(1, "sniperpenetratedround")
+
+ self:Remove()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_detpack/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_detpack/shared.lua
new file mode 100644
index 0000000..544e39a
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_detpack/shared.lua
@@ -0,0 +1,27 @@
+ENT.Type = "anim"
+
+ENT.CanPackUp = true
+ENT.PackUpTime = 4
+
+ENT.m_NoNailUnfreeze = true
+ENT.NoNails = true
+
+ENT.NoPropDamageDuringWave0 = true
+
+ENT.ExplosionDelay = 1
+
+function ENT:SetExplodeTime(time)
+ self:SetDTFloat(0, time)
+end
+
+function ENT:GetExplodeTime()
+ return self:GetDTFloat(0)
+end
+
+function ENT:SetObjectOwner(owner)
+ self:SetOwner(owner)
+end
+
+function ENT:GetObjectOwner()
+ return self:GetOwner()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_drone/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_drone/cl_init.lua
new file mode 100644
index 0000000..9e4f073
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_drone/cl_init.lua
@@ -0,0 +1,168 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:SetRenderBounds(Vector(-72, -72, -72), Vector(72, 72, 72))
+
+ self.AmbientSound = CreateSound(self, "npc/scanner/scanner_combat_loop1.wav")
+ self.AmbientSound:Play()
+
+ self.PixVis = util.GetPixelVisibleHandle()
+
+ hook.Add("CreateMove", self, self.CreateMove)
+ hook.Add("ShouldDrawLocalPlayer", self, self.ShouldDrawLocalPlayer)
+ hook.Add("CalcView", self, self.CalcView)
+end
+
+ENT.NextEmit = 0
+local smokegravity = Vector(0, 0, 64)
+function ENT:Think()
+ self.AmbientSound:PlayEx(0.5, math.Clamp(90 + self:GetVelocity():Length() * 0.4, 90, 160))
+
+ if CurTime() >= self.NextEmit then
+ local perc = math.Clamp(self:GetObjectHealth() / self:GetMaxObjectHealth(), 0, 255)
+ if perc < 0.5 then
+ self.NextEmit = CurTime() + 0.05 + perc * math.Rand(0.05, 0.25)
+
+ local sat = perc * 90
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(16, 24)
+
+ local particle = emitter:Add("particles/smokey", pos)
+ particle:SetStartAlpha(180)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(0)
+ particle:SetEndSize(math.Rand(10, 24))
+ particle:SetVelocity(self:GetVelocity() * 0.7 + VectorRand():GetNormalized() * math.Rand(4, 24))
+ particle:SetGravity(smokegravity)
+ particle:SetDieTime(math.Rand(0.8, 1.6))
+ particle:SetAirResistance(150)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-2, 2))
+ particle:SetCollide(true)
+ particle:SetBounce(0.2)
+ particle:SetColor(sat, sat, sat)
+
+ emitter:Finish()
+ end
+ end
+end
+
+function ENT:OnRemove()
+ self.AmbientSound:Stop()
+end
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+end
+
+local colLight = Color(255, 0, 0)
+local colWhite = Color(255, 255, 255)
+local colHealth = Color(255, 255, 255)
+local matLight = Material("sprites/light_ignorez")
+function ENT:DrawTranslucent()
+ self:DrawModel()
+
+ local lp = LocalPlayer()
+ local owner = self:GetOwner()
+
+ if lp:IsValid() and lp:Team() ~= TEAM_UNDEAD and owner:IsValid() and owner:IsPlayer() then
+ local ang = EyeAngles()
+ ang.pitch = 0
+ local right = ang:Right()
+ ang:RotateAroundAxis(ang:Up(), 270)
+ ang:RotateAroundAxis(ang:Forward(), 90)
+ cam.Start3D2D(self:LocalToWorld(Vector(0, 0, 26)), ang, 0.025)
+ draw.SimpleTextBlurry(owner:Name(), "ZS3D2DFont", 0, 0, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
+ local perc = math.Clamp(self:GetObjectHealth() / self:GetMaxObjectHealth(), 0, 1)
+ colHealth.r = 255
+ colHealth.g = perc ^ 0.3 * 255
+ colHealth.b = perc * 255
+ draw.SimpleTextBlurry(math.ceil(perc * 100), "ZS3D2DFontBig", 0, 0, colHealth, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM)
+ cam.End3D2D()
+ end
+
+ local epos = self:GetRedLightPos()
+ local LightNrm = self:GetRedLightAngles():Forward()
+ local ViewNormal = epos - EyePos()
+ local Distance = ViewNormal:Length()
+ ViewNormal:Normalize()
+ local ViewDot = math.min(1, ViewNormal:Dot( LightNrm * -1 ) + 0.25)
+
+ if ViewDot > 0 then
+ if owner:IsValid() and owner:IsPlayer() then
+ local vcol = owner:GetPlayerColor()
+ if vcol then
+ if vcol == vector_origin then
+ vcol.x = 1 vcol.y = 1 vcol.z = 1
+ end
+ vcol:Normalize()
+ vcol = vcol * 2.55
+ colLight.r = math.Clamp(vcol.r * 100, 0, 255)
+ colLight.g = math.Clamp(vcol.g * 100, 0, 255)
+ colLight.b = math.Clamp(vcol.b * 100, 0, 255)
+ end
+ end
+
+ local LightPos = epos + LightNrm * 5
+
+ render.SetMaterial(matLight)
+ local Visibile = util.PixelVisible( LightPos, 16, self.PixVis )
+
+ if not Visibile then return end
+
+ local Size = math.Clamp(Distance * Visibile * ViewDot, 25, 250)
+
+ Distance = math.Clamp(Distance, 32, 800)
+ local Alpha = math.Clamp((1000 - Distance) * Visibile * ViewDot, 0, 120)
+ colLight.a = Alpha
+ colWhite.a = Alpha
+
+ render.DrawSprite(LightPos, Size, Size, colLight, Visibile * ViewDot)
+ render.DrawSprite(LightPos, Size*0.4, Size*0.4, colWhite, Visibile * ViewDot)
+ end
+end
+
+function ENT:CreateMove(cmd)
+ if self:GetOwner() ~= LocalPlayer() then return end
+
+ if not self:BeingControlled() then return end
+
+ local buttons = cmd:GetButtons()
+
+ cmd:ClearMovement()
+
+ if bit.band(buttons, IN_JUMP) ~= 0 then
+ buttons = buttons - IN_JUMP
+ buttons = buttons + IN_BULLRUSH
+ end
+
+ if bit.band(buttons, IN_DUCK) ~= 0 then
+ buttons = buttons - IN_DUCK
+ buttons = buttons + IN_GRENADE1
+ end
+
+ cmd:SetButtons(buttons)
+end
+
+function ENT:ShouldDrawLocalPlayer(pl)
+ if self:GetOwner() ~= LocalPlayer() then return end
+
+ if self:BeingControlled() then
+ return true
+ end
+end
+
+local ViewHullMins = Vector(-4, -4, -4)
+local ViewHullMaxs = Vector(4, 4, 4)
+function ENT:CalcView(pl, origin, angles, fov, znear, zfar)
+ if self:GetOwner() ~= pl then return end
+
+ if not self:BeingControlled() then return end
+
+ local filter = player.GetAll()
+ filter[#filter + 1] = self
+ local tr = util.TraceHull({start = self:GetPos(), endpos = self:GetPos() + angles:Forward() * -48, mask = MASK_SHOT, filter = filter, mins = ViewHullMins, maxs = ViewHullMaxs})
+
+ return {origin = tr.HitPos + tr.HitNormal * 3}
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_drone/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_drone/init.lua
new file mode 100644
index 0000000..527629a
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_drone/init.lua
@@ -0,0 +1,259 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+ENT.NextWaterDamage = 0
+
+function ENT:Initialize()
+ self:SetModel("models/combine_scanner.mdl")
+ self:SetUseType(SIMPLE_USE)
+
+ self:PhysicsInit(SOLID_VPHYSICS)
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMass(75)
+ phys:EnableDrag(false)
+ phys:EnableMotion(true)
+ phys:Wake()
+ phys:SetBuoyancyRatio(0.8)
+
+ local Constraint = ents.Create("phys_keepupright")
+ Constraint:SetAngles(Angle(0, 0, 0))
+ Constraint:SetKeyValue("angularlimit", 2)
+ Constraint:SetPhysConstraintObjects(phys, phys)
+ Constraint:Spawn()
+ Constraint:Activate()
+ self:DeleteOnRemove(Constraint)
+ end
+
+ self:StartMotionController()
+
+ self:SetMaxObjectHealth(100)
+ self:SetObjectHealth(self:GetMaxObjectHealth())
+
+ self.LastThink = CurTime()
+
+ self:SetSequence(2)
+ self:SetPlaybackRate(1)
+ self:UseClientSideAnimation(true)
+
+ --[[local ent = ents.Create("fhb")
+ if ent:IsValid() then
+ ent:SetPos(self:GetPos())
+ ent:SetAngles(self:GetAngles())
+ ent:SetParent(self)
+ ent:SetOwner(self)
+ ent.Size = 9
+ ent:Spawn()
+ end]]
+
+ self:CollisionRulesChanged()
+
+ hook.Add("SetupPlayerVisibility", self, self.SetupPlayerVisibility)
+end
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+
+ if health <= 0 then
+ self:Destroy()
+ end
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ --if dmginfo:GetDamageType() ~= DMG_CRUSH and not self._AllowDamage then return end
+
+ local attacker = dmginfo:GetAttacker()
+ if not (attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_HUMAN) then
+ self:TakePhysicsDamage(dmginfo)
+
+ self:SetObjectHealth(self:GetObjectHealth() - dmginfo:GetDamage())
+
+ --self:EmitSound("npc/scanner/scanner_pain"..math.random(2)..".wav", 0.65, math.Rand(120, 130))
+ self:EmitSound("npc/manhack/gib.wav")
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(self:NearestPoint(dmginfo:GetDamagePosition()))
+ effectdata:SetNormal(VectorRand():GetNormalized())
+ effectdata:SetMagnitude(4)
+ effectdata:SetScale(1.33)
+ util.Effect("sparks", effectdata)
+ end
+end
+
+function ENT:Use(pl)
+ if pl == self:GetOwner() and pl:Team() == TEAM_HUMAN and pl:Alive() and self:GetVelocity():Length() <= self.HoverSpeed then
+ self:OnPackedUp(pl)
+ end
+end
+
+function ENT:PhysicsCollide(data, phys)
+ self.HitData = data
+ self:NextThink(CurTime())
+end
+
+function ENT:OnPackedUp(pl)
+ pl:GiveEmptyWeapon("weapon_zs_drone")
+ pl:GiveAmmo(1, "drone")
+
+ pl:PushPackedItem(self:GetClass(), self:GetObjectHealth())
+
+ self:Remove()
+end
+
+function ENT:PhysicsSimulate(phys, frametime)
+ phys:Wake()
+
+ local owner = self:GetOwner()
+ if not owner:IsValid() then return SIM_NOTHING end
+
+ local vel = phys:GetVelocity()
+ local movedir = Vector()
+ local eyeangles = owner:SyncAngles()
+ local aimangles = owner:EyeAngles()
+
+ if self:BeingControlled() then
+ if owner:KeyDown(IN_FORWARD) then
+ movedir = movedir + aimangles:Forward()
+ end
+ if owner:KeyDown(IN_BACK) then
+ movedir = movedir - aimangles:Forward()
+ end
+ if owner:KeyDown(IN_MOVERIGHT) then
+ movedir = movedir + aimangles:Right()
+ end
+ if owner:KeyDown(IN_MOVELEFT) then
+ movedir = movedir - aimangles:Right()
+ end
+ if owner:KeyDown(IN_BULLRUSH) then
+ movedir = movedir + Vector(0, 0, 0.5)
+ end
+ if owner:KeyDown(IN_GRENADE1) then
+ movedir = movedir - Vector(0, 0, 0.5)
+ end
+ end
+
+ if movedir == vector_origin then
+ vel = vel * (1 - frametime * self.IdleDrag)
+ else
+ movedir:Normalize()
+
+ vel = vel + frametime * self.Acceleration * math.Clamp((self:GetObjectHealth() / self:GetMaxObjectHealth() + 1) / 2, 0.5, 1) * movedir
+ end
+
+ if vel:Length() > self.MaxSpeed then
+ vel:Normalize()
+ vel = vel * self.MaxSpeed
+ end
+
+ if movedir == vector_origin and vel:Length() <= self.HoverSpeed then
+ local trace = {mask = MASK_HOVER, filter = self}
+ trace.start = self:GetPos()
+ trace.endpos = trace.start + Vector(0, 0, self.HoverHeight * -2)
+ local tr = util.TraceLine(trace)
+
+ local hoverdir = (trace.start - tr.HitPos):GetNormalized()
+ local hoverfrac = (0.5 - tr.Fraction) * 2
+ vel = vel + frametime * hoverfrac * self.HoverForce * hoverdir
+ end
+
+ phys:EnableGravity(false)
+ phys:SetAngleDragCoefficient(20000)
+ phys:SetVelocityInstantaneous(vel)
+ phys:AddAngleVelocity(Vector(0, 0, math.Clamp(math.AngleDifference(eyeangles.yaw, phys:GetAngles().yaw), -32, 32) * frametime * 3))
+
+ return SIM_NOTHING
+end
+
+function ENT:Destroy()
+ if self.Destroyed then return end
+ self.Destroyed = true
+
+ self:EmitSound("npc/manhack/gib.wav")
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(self:LocalToWorld(self:OBBCenter()))
+ util.Effect("HelicopterMegaBomb", effectdata, true, true)
+ effectdata:SetNormal(Vector(0, 0, 1))
+ effectdata:SetMagnitude(5)
+ effectdata:SetScale(1.5)
+ util.Effect("sparks", effectdata)
+end
+
+ENT.PhysDamageImmunity = 0
+function ENT:Think()
+ if self.Destroyed then
+ if not self.CreatedDebris then
+ self.CreatedDebris = true
+
+ local ent = ents.Create("prop_physics")
+ if ent:IsValid() then
+ ent:SetPos(self:GetPos())
+ ent:SetAngles(self:GetAngles())
+ ent:SetModel(self:GetModel())
+ ent:Spawn()
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetVelocityInstantaneous(self:GetVelocity())
+ end
+
+ ent:Fire("break")
+ ent:Fire("kill", "", 0.05)
+ end
+ end
+
+ self:Remove()
+ return
+ end
+
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ self:SetPhysicsAttacker(owner)
+
+ if not owner:Alive() or owner:Team() ~= TEAM_HUMAN then
+ self:Destroy()
+ return
+ end
+ else
+ self:Destroy()
+ return
+ end
+
+ if self:WaterLevel() >= 2 and CurTime() >= self.NextWaterDamage then
+ self.NextWaterDamage = CurTime() + 0.2
+
+ self:TakeDamage(10)
+ end
+
+ local data = self.HitData
+ if not data then return end
+ self.HitData = nil
+
+ local ent = data.HitEntity
+ if ent and ent:IsValid() then
+ local physattacker = ent:GetPhysicsAttacker()
+ if physattacker:IsValid() and physattacker:Team() == TEAM_HUMAN then
+ self.PhysDamageImmunity = CurTime() + 0.5
+ end
+ end
+
+ local dir = (self:GetPos() - data.HitPos):GetNormalized()
+
+ if data.Speed > self.HoverSpeed then
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:AddVelocity(dir * 50)
+ end
+ end
+
+ if data.Speed >= self.MaxSpeed * 0.75 and ent and ent:IsWorld() and CurTime() >= self.PhysDamageImmunity then
+ self:TakeDamage(math.Clamp(data.Speed * 0.11, 0, 40))
+ end
+end
+
+function ENT:SetupPlayerVisibility(pl)
+ if pl ~= self:GetOwner() then return end
+
+ AddOriginToPVS(self:GetPos())
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_drone/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_drone/shared.lua
new file mode 100644
index 0000000..badbf36
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_drone/shared.lua
@@ -0,0 +1,57 @@
+ENT.Type = "anim"
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+ENT.m_NoNailUnfreeze = true
+ENT.NoNails = true
+
+ENT.WrenchRepairMultiplier = 0.666
+
+ENT.Acceleration = 110
+ENT.MaxSpeed = 160
+ENT.HoverSpeed = 64
+ENT.HoverHeight = 58
+ENT.HoverForce = 64
+ENT.TurnSpeed = 45
+ENT.IdleDrag = 0.25
+
+function ENT:ShouldNotCollide(ent)
+ return ent:IsPlayer() and ent:Team() == TEAM_HUMAN
+end
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+
+ if health <= 0 and not self.Destroyed then
+ self.Destroyed = true
+ end
+end
+
+function ENT:BeingControlled()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ local wep = owner:GetActiveWeapon()
+ return wep:IsValid() and wep:GetClass() == "weapon_zs_dronecontrol" and wep:GetDTBool(0)
+ end
+
+ return false
+end
+
+function ENT:GetObjectHealth()
+ return self:GetDTFloat(0)
+end
+
+function ENT:SetMaxObjectHealth(health)
+ self:SetDTFloat(1, health)
+end
+
+function ENT:GetMaxObjectHealth()
+ return self:GetDTFloat(1)
+end
+
+function ENT:GetRedLightPos()
+ return self:LocalToWorld(Vector(3, 0, 13.75))
+end
+
+function ENT:GetRedLightAngles()
+ return self:GetAngles()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_ffemitter/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_ffemitter/cl_init.lua
new file mode 100644
index 0000000..33dcc35
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_ffemitter/cl_init.lua
@@ -0,0 +1 @@
+include("shared.lua")
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_ffemitter/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_ffemitter/init.lua
new file mode 100644
index 0000000..b959e6e
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_ffemitter/init.lua
@@ -0,0 +1,74 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+ENT.m_Health = 150
+
+function ENT:Initialize()
+ self:SetModel("models/props_lab/lab_flourescentlight002b.mdl")
+ self:PhysicsInit(SOLID_VPHYSICS)
+ self:SetUseType(SIMPLE_USE)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:EnableMotion(false)
+ phys:Wake()
+ end
+
+ local ent = ents.Create("prop_ffemitterfield")
+ if ent:IsValid() then
+ self.Field = ent
+
+ ent:SetPos(self:GetPos() + self:GetForward() * 48)
+ ent:SetAngles(self:GetAngles())
+ ent:SetOwner(self)
+ ent:Spawn()
+ end
+end
+
+function ENT:OnRemove()
+ if self.Field and self.Field:IsValid() then
+ self.Field:Remove()
+ end
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ self:TakePhysicsDamage(dmginfo)
+
+ if not self.Destroyed then
+ local attacker = dmginfo:GetAttacker()
+ if not (attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_HUMAN) then
+ if attacker.LifeBarricadeDamage ~= nil and self:HumanNearby() then
+ attacker:AddLifeBarricadeDamage(dmginfo:GetDamage())
+ end
+
+ self.m_Health = self.m_Health - dmginfo:GetDamage()
+ if self.m_Health <= 0 then
+ self.Destroyed = true
+ local effectdata = EffectData()
+ effectdata:SetOrigin(self:LocalToWorld(self:OBBCenter()))
+ util.Effect("Explosion", effectdata, true, true)
+ end
+ end
+ end
+end
+
+function ENT:AltUse(activator, tr)
+ self:PackUp(activator)
+end
+
+function ENT:OnPackedUp(pl)
+ pl:GiveEmptyWeapon("weapon_zs_ffemitter")
+ pl:GiveAmmo(1, "slam")
+
+ pl:PushPackedItem(self:GetClass(), self.m_Health)
+
+ self:Remove()
+end
+
+function ENT:Think()
+ if self.Destroyed then
+ self:Remove()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_ffemitter/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_ffemitter/shared.lua
new file mode 100644
index 0000000..981423f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_ffemitter/shared.lua
@@ -0,0 +1,18 @@
+ENT.Type = "anim"
+
+ENT.CanPackUp = true
+ENT.PackUpTime = 5
+
+ENT.m_NoNailUnfreeze = true
+ENT.NoNails = true
+
+ENT.IsBarricadeObject = true
+ENT.AlwaysGhostable = true
+
+function ENT:SetObjectOwner(owner)
+ self:SetDTEntity(0, owner)
+end
+
+function ENT:GetObjectOwner()
+ return self:GetDTEntity(0)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_ffemitterfield/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_ffemitterfield/cl_init.lua
new file mode 100644
index 0000000..60559a1
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_ffemitterfield/cl_init.lua
@@ -0,0 +1,46 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+function ENT:Initialize()
+ self.Seed = math.Rand(0, 10)
+
+ self:DrawShadow(false)
+
+ self.AmbientSound = CreateSound(self, "ambient/machines/combine_shield_touch_loop1.wav")
+ self.AmbientSound:PlayEx(0.1, 100)
+end
+
+function ENT:Think()
+ self.AmbientSound:PlayEx(0.1, 100 + RealTime() % 1)
+end
+
+function ENT:OnRemove()
+ self.AmbientSound:Stop()
+end
+
+local matRefract = Material("models/spawn_effect")
+local matGlow = Material("Models/props_combine/combine_fenceglow")
+function ENT:DrawTranslucent()
+ render.SuppressEngineLighting(true)
+ render.ModelMaterialOverride(matGlow)
+
+ render.SetBlend(0.05 + math.max(0, math.cos(CurTime())) ^ 4 * 0.01)
+ self:DrawModel()
+
+ if render.SupportsPixelShaders_2_0() then
+ render.UpdateRefractTexture()
+
+ matRefract:SetFloat("$refractamount", 0.0125 + math.sin(CurTime() * 2) ^ 2 * 0.0025)
+
+ render.SetBlend(1)
+
+ render.ModelMaterialOverride(matRefract)
+ self:DrawModel()
+ else
+ render.SetBlend(1)
+ end
+
+ render.ModelMaterialOverride(0)
+ render.SuppressEngineLighting(false)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_ffemitterfield/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_ffemitterfield/init.lua
new file mode 100644
index 0000000..430d663
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_ffemitterfield/init.lua
@@ -0,0 +1,20 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetModel("models/props_junk/TrashDumpster02b.mdl")
+ self:PhysicsInit(SOLID_VPHYSICS)
+ self:SetUseType(SIMPLE_USE)
+ self:SetCustomCollisionCheck(true)
+
+ self:SetCollisionGroup(COLLISION_GROUP_PASSABLE_DOOR)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:EnableMotion(false)
+ phys:Wake()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_ffemitterfield/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_ffemitterfield/shared.lua
new file mode 100644
index 0000000..0182cdf
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_ffemitterfield/shared.lua
@@ -0,0 +1,11 @@
+ENT.Type = "anim"
+
+ENT.CanPackUp = true
+ENT.PackUpTime = 3
+
+ENT.m_NoNailUnfreeze = true
+ENT.NoNails = true
+
+function ENT:ShouldNotCollide(ent)
+ return not ent:IsPlayer() and not ent:IsProjectile()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_gunturret/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_gunturret/cl_init.lua
new file mode 100644
index 0000000..1e60b20
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_gunturret/cl_init.lua
@@ -0,0 +1,168 @@
+include("shared.lua")
+
+ENT.NextEmit = 0
+
+function ENT:Initialize()
+ self.BeamColor = Color(0, 255, 0, 255)
+
+ self.ScanningSound = CreateSound(self, "npc/turret_wall/turret_loop1.wav")
+ self.ShootingSound = CreateSound(self, "npc/combine_gunship/gunship_weapon_fire_loop6.wav")
+
+ local size = self.SearchDistance + 32
+ local nsize = -size
+ self:SetRenderBounds(Vector(nsize, nsize, nsize * 0.25), Vector(size, size, size * 0.25))
+end
+
+function ENT:Think()
+ if self:GetObjectOwner():IsValid() and self:GetAmmo() > 0 and self:GetMaterial() == "" then
+ self.ScanningSound:PlayEx(0.55, 100 + math.sin(CurTime()))
+ if self:IsFiring() or self:GetTarget():IsValid() then
+ self.ShootingSound:PlayEx(1, 100 + math.cos(CurTime()))
+ else
+ self.ShootingSound:Stop()
+ end
+ else
+ self.ScanningSound:Stop()
+ self.ShootingSound:Stop()
+ end
+end
+
+function ENT:OnRemove()
+ self.ScanningSound:Stop()
+ self.ShootingSound:Stop()
+end
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(3, health)
+end
+
+local smokegravity = Vector(0, 0, 200)
+local aScreen = Angle(0, 270, 60)
+local vScreen = Vector(0, -2, 45)
+function ENT:Draw()
+ self:CalculatePoseAngles()
+ self:SetPoseParameter("aim_yaw", self.PoseYaw)
+ self:SetPoseParameter("aim_pitch", self.PosePitch)
+
+ self:DrawModel()
+
+ local healthpercent = self:GetObjectHealth() / self:GetMaxObjectHealth()
+
+ if healthpercent <= 0.5 and CurTime() >= self.NextEmit then
+ self.NextEmit = CurTime() + 0.05
+
+ local pos = self:DefaultPos()
+ local sat = healthpercent * 360
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(24, 32)
+
+ local particle = emitter:Add("particles/smokey", pos)
+ particle:SetStartAlpha(180)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(0)
+ particle:SetEndSize(math.Rand(8, 32))
+ particle:SetColor(sat, sat, sat)
+ particle:SetVelocity(VectorRand():GetNormalized() * math.Rand(8, 64))
+ particle:SetGravity(smokegravity)
+ particle:SetDieTime(math.Rand(0.8, 1.6))
+ particle:SetAirResistance(150)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-4, 4))
+ particle:SetCollide(true)
+ particle:SetBounce(0.2)
+
+ emitter:Finish()
+ end
+
+ local owner = self:GetObjectOwner()
+ local ammo = self:GetAmmo()
+ local flash = math.sin(CurTime() * 15) > 0
+
+ local wid, hei = 128, 92
+ cam.Start3D2D(self:LocalToWorld(vScreen), self:LocalToWorldAngles(aScreen), 0.075)
+
+ surface.SetDrawColor(0, 0, 0, 160)
+ surface.DrawRect(0, 0, wid, hei)
+
+ surface.SetDrawColor(200, 200, 200, 160)
+ surface.DrawRect(0, 0, 8, 16)
+ surface.DrawRect(wid - 8, 0, 8, 16)
+ surface.DrawRect(8, 0, wid - 16, 8)
+
+ surface.DrawRect(0, hei - 16, 8, 16)
+ surface.DrawRect(wid - 8, hei - 16, 8, 16)
+ surface.DrawRect(8, hei - 8, wid - 16, 8)
+
+ if owner:IsValid() and owner:IsPlayer() then
+ draw.SimpleText(owner:ClippedName(), "DefaultFont", wid * 0.5, 10, owner == MySelf and COLOR_BLUE or COLOR_WHITE, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM)
+ end
+ draw.SimpleText(translate.Format("integrity_x", math.ceil(healthpercent * 100)), "DefaultFontBold", wid * 0.5, hei * 0.5, COLOR_WHITE, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+
+ if flash and self:GetManualControl() then
+ draw.SimpleText(translate.Get("manual_control"), "DefaultFont", wid * 0.5, hei * 0.325, COLOR_YELLOW, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+ end
+
+ if ammo > 0 then
+ draw.SimpleText("["..ammo.." / "..self.MaxAmmo.."]", "DefaultFontBold", wid * 0.5, hei - 10, COLOR_WHITE, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
+ elseif flash then
+ draw.SimpleText(translate.Get("empty"), "DefaultFontBold", wid * 0.5, hei - 10, COLOR_RED, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
+ end
+
+ cam.End3D2D()
+end
+
+local matBeam = Material("effects/laser1")
+local matGlow = Material("sprites/glow04_noz")
+function ENT:DrawTranslucent()
+ if self:GetMaterial() ~= "" then return end
+
+ local lightpos = self:LightPos()
+
+ local ang = self:GetGunAngles()
+
+ local colBeam = self.BeamColor
+
+ local hasowner = self:GetObjectOwner():IsValid()
+ local hasammo = self:GetAmmo() > 0
+ local manualcontrol = self:GetManualControl()
+
+ local tr = util.TraceLine({start = lightpos, endpos = lightpos + ang:Forward() * (manualcontrol and 4096 or self.SearchDistance), mask = MASK_SHOT, filter = self:GetCachedScanFilter()})
+
+ if not hasowner then
+ local rate = FrameTime() * 512
+ colBeam.r = math.Approach(colBeam.r, 0, rate)
+ colBeam.g = math.Approach(colBeam.g, 0, rate)
+ colBeam.b = math.Approach(colBeam.b, 255, rate)
+ elseif not hasammo or not manualcontrol and self:GetTarget():IsValid() then
+ local rate = FrameTime() * 512
+ colBeam.r = math.Approach(colBeam.r, 255, rate)
+ colBeam.g = math.Approach(colBeam.g, 0, rate)
+ colBeam.b = math.Approach(colBeam.b, 0, rate)
+ elseif manualcontrol then
+ local rate = FrameTime() * 512
+ colBeam.r = math.Approach(colBeam.r, 255, rate)
+ colBeam.g = math.Approach(colBeam.g, 255, rate)
+ colBeam.b = math.Approach(colBeam.b, 0, rate)
+ else
+ local rate = FrameTime() * 200
+ colBeam.r = math.Approach(colBeam.r, 0, rate)
+ colBeam.g = math.Approach(colBeam.g, 255, rate)
+ colBeam.b = math.Approach(colBeam.b, 0, rate)
+ end
+
+ if hasowner and hasammo then
+ render.SetMaterial(matBeam)
+ render.DrawBeam(lightpos, tr.HitPos, 1, 0, 1, COLOR_WHITE)
+ render.DrawBeam(lightpos, tr.HitPos, 4, 0, 1, colBeam)
+ render.SetMaterial(matGlow)
+ render.DrawSprite(lightpos, 4, 4, COLOR_WHITE)
+ render.DrawSprite(lightpos, 16, 16, colBeam)
+ render.DrawSprite(tr.HitPos, 2, 2, COLOR_WHITE)
+ render.DrawSprite(tr.HitPos, 8, 8, colBeam)
+ else
+ render.SetMaterial(matGlow)
+ render.DrawSprite(lightpos, 4, 4, COLOR_WHITE)
+ render.DrawSprite(lightpos, 16, 16, colBeam)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_gunturret/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_gunturret/init.lua
new file mode 100644
index 0000000..ef752cd
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_gunturret/init.lua
@@ -0,0 +1,218 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+ENT.LastHitSomething = 0
+
+local function RefreshTurretOwners(pl)
+ for _, ent in pairs(ents.FindByClass("prop_gunturret")) do
+ if ent:IsValid() and ent:GetObjectOwner() == pl then
+ ent:ClearObjectOwner()
+ ent:ClearTarget()
+ end
+ end
+end
+hook.Add("PlayerDisconnected", "GunTurret.PlayerDisconnected", RefreshTurretOwners)
+hook.Add("OnPlayerChangedTeam", "GunTurret.OnPlayerChangedTeam", RefreshTurretOwners)
+
+function ENT:Initialize()
+ self:SetModel("models/Combine_turrets/Floor_turret.mdl")
+ self:PhysicsInit(SOLID_VPHYSICS)
+
+ self:SetUseType(SIMPLE_USE)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMass(50)
+ phys:EnableMotion(false)
+ phys:Wake()
+ end
+
+ self:SetAmmo(self.DefaultAmmo)
+ self:SetMaxObjectHealth(250)
+ self:SetObjectHealth(self:GetMaxObjectHealth())
+end
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(3, health)
+ if health <= 0 and not self.Destroyed then
+ self.Destroyed = true
+
+ local pos = self:LocalToWorld(self:OBBCenter())
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(pos)
+ util.Effect("Explosion", effectdata, true, true)
+
+ local amount = math.ceil(self:GetAmmo() * 0.5)
+ while amount > 0 do
+ local todrop = math.min(amount, 50)
+ amount = amount - todrop
+ local ent = ents.Create("prop_ammo")
+ if ent:IsValid() then
+ local heading = VectorRand():GetNormalized()
+ ent:SetAmmoType("smg1")
+ ent:SetAmmo(todrop)
+ ent:SetPos(pos + heading * 8)
+ ent:SetAngles(VectorRand():Angle())
+ ent:Spawn()
+
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:ApplyForceOffset(heading * math.Rand(8000, 32000), pos)
+ end
+ end
+ end
+ end
+end
+
+local tempknockback
+function ENT:StartBulletKnockback()
+ tempknockback = {}
+end
+
+function ENT:EndBulletKnockback()
+ tempknockback = nil
+end
+
+function ENT:DoBulletKnockback(scale)
+ for ent, prevvel in pairs(tempknockback) do
+ local curvel = ent:GetVelocity()
+ ent:SetVelocity(curvel * -1 + (curvel - prevvel) * scale + prevvel)
+ end
+end
+
+local function BulletCallback(attacker, tr, dmginfo)
+ local ent = tr.Entity
+ if ent:IsValid() then
+ if ent:IsPlayer() then
+ if ent:Team() == TEAM_UNDEAD and tempknockback then
+ if attacker:GetTarget() == ent then
+ attacker.LastHitSomething = CurTime()
+ end
+ tempknockback[ent] = ent:GetVelocity()
+ end
+ else
+ local phys = ent:GetPhysicsObject()
+ if ent:GetMoveType() == MOVETYPE_VPHYSICS and phys:IsValid() and phys:IsMoveable() then
+ ent:SetPhysicsAttacker(attacker)
+ end
+ end
+
+ dmginfo:SetAttacker(attacker:GetObjectOwner())
+ dmginfo:SetInflictor(attacker)
+ end
+end
+
+function ENT:FireTurret(src, dir)
+ if self:GetNextFire() <= CurTime() then
+ local curammo = self:GetAmmo()
+ if curammo > 0 then
+ self:SetNextFire(CurTime() + 0.1)
+ self:SetAmmo(curammo - 1)
+
+ self:StartBulletKnockback()
+ self:FireBullets({Num = 1, Src = src, Dir = dir, Spread = Vector(0.05, 0.05, 0), Tracer = 1, Force = 1, Damage = 12, Callback = BulletCallback})
+ self:DoBulletKnockback(0.05)
+ self:EndBulletKnockback()
+ else
+ self:SetNextFire(CurTime() + 2)
+ self:EmitSound("npc/turret_floor/die.wav")
+ end
+ end
+end
+
+function ENT:Think()
+ if self.Destroyed then
+ self:Remove()
+ return
+ end
+
+ self:CalculatePoseAngles()
+
+ local owner = self:GetObjectOwner()
+ if owner:IsValid() and self:GetAmmo() > 0 and self:GetMaterial() == "" then
+ if self:GetManualControl() then
+ if owner:KeyDown(IN_ATTACK) then
+ if not self:IsFiring() then self:SetFiring(true) end
+ self:FireTurret(self:ShootPos(), self:GetGunAngles():Forward())
+ elseif self:IsFiring() then
+ self:SetFiring(false)
+ end
+
+ local target = self:GetTarget()
+ if target:IsValid() then self:ClearTarget() end
+ else
+ if self:IsFiring() then self:SetFiring(false) end
+ local target = self:GetTarget()
+ if target:IsValid() then
+ if self:IsValidTarget(target) and CurTime() < self.LastHitSomething + 0.5 then
+ local shootpos = self:ShootPos()
+ self:FireTurret(shootpos, (self:GetTargetPos(target) - shootpos):GetNormalized())
+ else
+ self:ClearTarget()
+ self:EmitSound("npc/turret_floor/deploy.wav")
+ end
+ else
+ local target = self:SearchForTarget()
+ if target then
+ self:SetTarget(target)
+ self:SetTargetReceived(CurTime())
+ self:EmitSound("npc/turret_floor/active.wav")
+ end
+ end
+ end
+ elseif self:IsFiring() then
+ self:SetFiring(false)
+ end
+
+ self:NextThink(CurTime())
+ return true
+end
+
+function ENT:Use(activator, caller)
+ if self.Removing or not activator:IsPlayer() or self:GetMaterial() ~= "" then return end
+
+ if activator:Team() == TEAM_HUMAN then
+ if self:GetObjectOwner():IsValid() then
+ local curammo = self:GetAmmo()
+ local togive = math.min(math.min(15, activator:GetAmmoCount("smg1")), self.MaxAmmo - curammo)
+ if togive > 0 then
+ self:SetAmmo(curammo + togive)
+ activator:RemoveAmmo(togive, "smg1")
+ activator:RestartGesture(ACT_GMOD_GESTURE_ITEM_GIVE)
+ self:EmitSound("npc/turret_floor/click1.wav")
+ gamemode.Call("PlayerRepairedObject", activator, self, togive * 1.5, self)
+ end
+ else
+ self:SetObjectOwner(activator)
+ if not activator:HasWeapon("weapon_zs_gunturretcontrol") then
+ activator:Give("weapon_zs_gunturretcontrol")
+ end
+ end
+ end
+end
+
+function ENT:AltUse(activator, tr)
+ self:PackUp(activator)
+end
+
+function ENT:OnPackedUp(pl)
+ pl:GiveEmptyWeapon("weapon_zs_gunturret")
+ pl:GiveAmmo(1, "thumper")
+
+ pl:PushPackedItem(self:GetClass(), self:GetObjectHealth(), self:GetAmmo())
+
+ self:Remove()
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ self:TakePhysicsDamage(dmginfo)
+
+ local attacker = dmginfo:GetAttacker()
+ if not (attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_HUMAN) then
+ self:ResetLastBarricadeAttacker(attacker, dmginfo)
+ self:SetObjectHealth(self:GetObjectHealth() - dmginfo:GetDamage())
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_gunturret/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_gunturret/shared.lua
new file mode 100644
index 0000000..4105da6
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_gunturret/shared.lua
@@ -0,0 +1,262 @@
+ENT.Type = "anim"
+ENT.RenderGroup = RENDERGROUP_BOTH
+
+ENT.SearchDistance = 768
+ENT.MinimumAimDot = 0.5
+ENT.DefaultAmmo = 250
+ENT.MaxAmmo = 1000
+
+ENT.NoReviveFromKills = true
+
+ENT.PosePitch = 0
+ENT.PoseYaw = 0
+
+ENT.m_NoNailUnfreeze = true
+ENT.NoNails = true
+
+ENT.CanPackUp = true
+
+ENT.IsBarricadeObject = true
+ENT.AlwaysGhostable = true
+
+function ENT:GetLocalAnglesToTarget(target)
+ return self:WorldToLocalAngles(self:GetAnglesToTarget(target))
+end
+
+function ENT:GetAnglesToTarget(target)
+ return self:GetAnglesToPos(self:GetTargetPos(target))
+end
+
+function ENT:GetLocalAnglesToPos(pos)
+ return self:WorldToLocalAngles(self:GetAnglesToPos(pos))
+end
+
+function ENT:GetAnglesToPos(pos)
+ return (pos - self:ShootPos()):Angle()
+end
+
+function ENT:IsValidTarget(target)
+ return target:IsPlayer() and target:Team() == TEAM_UNDEAD and target:Alive() and self:GetForward():Dot(self:GetAnglesToTarget(target):Forward()) >= self.MinimumAimDot and TrueVisible(self:ShootPos(), self:GetTargetPos(target), self)
+end
+
+function ENT:GetManualTrace()
+ local owner = self:GetObjectOwner()
+ local filter = owner:GetMeleeFilter()
+ table.insert(filter, self)
+ return owner:TraceLine(4096, MASK_SOLID, filter)
+end
+
+function ENT:CalculatePoseAngles()
+ local owner = self:GetObjectOwner()
+ if not owner:IsValid() or self:GetAmmo() <= 0 or self:GetMaterial() ~= "" then
+ self.PoseYaw = math.Approach(self.PoseYaw, 0, FrameTime() * 60)
+ self.PosePitch = math.Approach(self.PosePitch, 15, FrameTime() * 30)
+ return
+ end
+
+ if self:GetManualControl() then
+ local ang = self:GetLocalAnglesToPos(self:GetManualTrace().HitPos)
+ self.PoseYaw = math.Approach(self.PoseYaw, math.Clamp(math.NormalizeAngle(ang.yaw), -60, 60), FrameTime() * 140)
+ self.PosePitch = math.Approach(self.PosePitch, math.Clamp(math.NormalizeAngle(ang.pitch), -15, 15), FrameTime() * 140)
+ else
+ local target = self:GetTarget()
+ if target:IsValid() then
+ local ang = self:GetLocalAnglesToTarget(target)
+ self.PoseYaw = math.Approach(self.PoseYaw, math.Clamp(math.NormalizeAngle(ang.yaw), -60, 60), FrameTime() * 140)
+ self.PosePitch = math.Approach(self.PosePitch, math.Clamp(math.NormalizeAngle(ang.pitch), -15, 15), FrameTime() * 100)
+ else
+ local ct = CurTime()
+ self.PoseYaw = math.Approach(self.PoseYaw, math.sin(ct) * 45, FrameTime() * 60)
+ self.PosePitch = math.Approach(self.PosePitch, math.cos(ct * 1.4) * 15, FrameTime() * 30)
+ end
+ end
+end
+
+function ENT:GetScanFilter()
+ local filter = team.GetPlayers(TEAM_HUMAN)
+ filter[#filter + 1] = self
+ return filter
+end
+
+-- Getting all of some team is straining every frame when there's 5 or so turrets. I could probably use CONTENTS_TEAM* if I knew what they did.
+ENT.NextCache = 0
+function ENT:GetCachedScanFilter()
+ if CurTime() < self.NextCache and self.CachedFilter then return self.CachedFilter end
+
+ self.CachedFilter = self:GetScanFilter()
+ self.NextCache = CurTime() + 1
+
+ return self.CachedFilter
+end
+
+local tabSearch = {mask = MASK_SHOT}
+function ENT:SearchForTarget()
+ local shootpos = self:ShootPos()
+
+ tabSearch.start = shootpos
+ tabSearch.endpos = shootpos + self:GetGunAngles():Forward() * self.SearchDistance
+ tabSearch.filter = self:GetCachedScanFilter()
+ local tr = util.TraceLine(tabSearch)
+ local ent = tr.Entity
+ if ent and ent:IsValid() and self:IsValidTarget(ent) then
+ return ent
+ end
+end
+
+function ENT:GetTargetPos(target)
+ if not (target:IsPlayer() and target:GetZombieClassTable().NoHead) then
+ local boneid = target:GetHitBoxBone(HITGROUP_HEAD, 0)
+ if boneid and boneid > 0 then
+ local p, a = target:GetBonePosition(boneid)
+ if pl then
+ return p
+ end
+ end
+ end
+
+ return target:LocalToWorld(target:OBBCenter())
+end
+
+function ENT:HumanHoldable(pl)
+ return true
+end
+
+function ENT:DefaultPos()
+ return self:GetPos() + self:GetUp() * 55
+end
+
+function ENT:ShootPos()
+ local attachid = self:LookupAttachment("eyes")
+ if attachid then
+ local attach = self:GetAttachment(attachid)
+ if attach then return attach.Pos end
+ end
+
+ return self:DefaultPos()
+end
+
+function ENT:LaserPos()
+ local attachid = self:LookupAttachment("light")
+ if attachid then
+ local attach = self:GetAttachment(attachid)
+ if attach then return attach.Pos end
+ end
+
+ return self:DefaultPos()
+end
+ENT.LightPos = ENT.LaserPos
+
+function ENT:GetGunAngles()
+ local ang = self:GetAngles()
+ ang:RotateAroundAxis(ang:Right(), -self.PosePitch)
+ ang:RotateAroundAxis(ang:Up(), self.PoseYaw)
+ return ang
+end
+
+function ENT:SetAmmo(ammo)
+ self:SetDTInt(0, ammo)
+end
+
+function ENT:GetAmmo()
+ return self:GetDTInt(0)
+end
+
+function ENT:SetTarget(ent)
+ if ent:IsValid() then
+ self:SetTargetReceived(CurTime())
+ if SERVER then
+ self.LastHitSomething = CurTime()
+ end
+ else
+ self:SetTargetLost(CurTime())
+ end
+ self:SetDTEntity(0, ent)
+end
+
+function ENT:GetObjectHealth()
+ return self:GetDTFloat(3)
+end
+
+function ENT:SetMaxObjectHealth(health)
+ self:SetDTInt(1, health)
+end
+
+function ENT:GetMaxObjectHealth()
+ return self:GetDTInt(1)
+end
+
+function ENT:GetTarget()
+ return self:GetDTEntity(0)
+end
+
+function ENT:SetObjectOwner(ent)
+ self:SetDTEntity(1, ent)
+end
+
+function ENT:GetObjectOwner()
+ return self:GetDTEntity(1)
+end
+
+function ENT:ClearObjectOwner()
+ self:SetObjectOwner(NULL)
+end
+
+function ENT:ClearTarget()
+ self:SetTarget(NULL)
+end
+
+function ENT:SetTargetReceived(tim)
+ self:SetDTFloat(0, tim)
+end
+
+function ENT:GetTargetReceived()
+ return self:GetDTFloat(0)
+end
+
+function ENT:SetTargetLost(tim)
+ self:SetDTFloat(1, tim)
+end
+
+function ENT:GetTargetLost()
+ return self:GetDTFloat(1)
+end
+
+function ENT:SetNextFire(tim)
+ self:SetDTFloat(2, tim)
+end
+
+function ENT:GetNextFire()
+ return self:GetDTFloat(2)
+end
+
+function ENT:SetFiring(onoff)
+ self:SetDTBool(0, onoff)
+end
+
+function ENT:IsFiring()
+ return self:GetDTBool(0)
+end
+
+function ENT:GetManualControl()
+ local owner = self:GetObjectOwner()
+ if owner:IsValid() and owner:Alive() and owner:Team() == TEAM_HUMAN then
+ local wep = owner:GetActiveWeapon()
+ if wep:IsValid() and wep:GetClass() == "weapon_zs_gunturretcontrol" and wep.GetTurret and wep:GetTurret() == self and not wep:GetDTBool(0) then
+ return true
+ end
+ end
+
+ return false
+end
+
+function ENT:CanBePackedBy(pl)
+ local owner = self:GetObjectOwner()
+ return not owner:IsValid() or owner == pl or owner:Team() ~= TEAM_HUMAN or gamemode.Call("PlayerIsAdmin", pl)
+end
+
+util.PrecacheSound("npc/turret_floor/die.wav")
+util.PrecacheSound("npc/turret_floor/active.wav")
+util.PrecacheSound("npc/turret_floor/deploy.wav")
+util.PrecacheSound("npc/turret_floor/shoot1.wav")
+util.PrecacheSound("npc/turret_floor/shoot2.wav")
+util.PrecacheSound("npc/turret_floor/shoot3.wav")
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_manhack/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_manhack/cl_init.lua
new file mode 100644
index 0000000..fc8585f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_manhack/cl_init.lua
@@ -0,0 +1,190 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:SetRenderBounds(Vector(-72, -72, -72), Vector(72, 72, 72))
+
+ self:CreateAmbientSounds()
+ self:CreateSubModel()
+
+ self.PixVis = util.GetPixelVisibleHandle()
+
+ hook.Add("CreateMove", self, self.CreateMove)
+ hook.Add("ShouldDrawLocalPlayer", self, self.ShouldDrawLocalPlayer)
+ hook.Add("CalcView", self, self.CalcView)
+end
+
+function ENT:CreateSubModel()
+end
+
+function ENT:CreateAmbientSounds()
+ self.AmbientSound = CreateSound(self, "npc/manhack/mh_engine_loop1.wav")
+ self.AmbientSound2 = CreateSound(self, "npc/manhack/mh_blade_loop1.wav")
+end
+
+function ENT:PlayAmbientSounds()
+ self.AmbientSound:PlayEx(0.5, math.min(80 + self:GetVelocity():Length() * 0.3, 160))
+ self.AmbientSound2:PlayEx(0.3, 100 + math.sin(CurTime()))
+end
+
+ENT.NextEmit = 0
+local smokegravity = Vector(0, 0, 64)
+function ENT:Think()
+ self:PlayAmbientSounds()
+
+ local perc = math.Clamp(self:GetObjectHealth() / self:GetMaxObjectHealth(), 0, 255)
+ if perc < 0.5 and CurTime() >= self.NextEmit then
+ self.NextEmit = CurTime() + 0.05 + perc * math.Rand(0.05, 0.25)
+
+ local pos = self:GetPos()
+ local sat = perc * 90
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(16, 24)
+
+ local particle = emitter:Add("particles/smokey", pos)
+ particle:SetStartAlpha(180)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(0)
+ particle:SetEndSize(math.Rand(8, 20))
+ particle:SetVelocity(self:GetVelocity() * 0.7 + VectorRand():GetNormalized() * math.Rand(4, 24))
+ particle:SetGravity(smokegravity)
+ particle:SetDieTime(math.Rand(0.8, 1.6))
+ particle:SetAirResistance(150)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-2, 2))
+ particle:SetCollide(true)
+ particle:SetBounce(0.2)
+ particle:SetColor(sat, sat, sat)
+
+ emitter:Finish()
+ end
+end
+
+function ENT:OnRemove()
+ self.AmbientSound:Stop()
+ self.AmbientSound2:Stop()
+ self:RemoveSubModel()
+end
+
+function ENT:RemoveSubModel()
+end
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+end
+
+function ENT:DrawSubModel()
+end
+
+local colLight = Color(255, 0, 0)
+local colWhite = Color(255, 255, 255)
+local colHealth = Color(255, 255, 255)
+local matLight = Material("sprites/light_ignorez")
+function ENT:DrawTranslucent()
+ self:DrawModel()
+
+ self:DrawSubModel()
+
+ local lp = LocalPlayer()
+ local owner = self:GetOwner()
+
+ if lp:IsValid() and lp:Team() ~= TEAM_UNDEAD and owner:IsValid() and owner:IsPlayer() then
+ local ang = EyeAngles()
+ ang.pitch = 0
+ local right = ang:Right()
+ ang:RotateAroundAxis(ang:Up(), 270)
+ ang:RotateAroundAxis(ang:Forward(), 90)
+ cam.Start3D2D(self:LocalToWorld(Vector(0, 0, 16)), ang, 0.025)
+ draw.SimpleTextBlurry(owner:Name(), "ZS3D2DFont", 0, 0, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
+ local perc = math.Clamp(self:GetObjectHealth() / self:GetMaxObjectHealth(), 0, 1)
+ colHealth.r = 255
+ colHealth.g = perc ^ 0.3 * 255
+ colHealth.b = perc * 255
+ draw.SimpleTextBlurry(math.ceil(perc * 100), "ZS3D2DFontBig", 0, 0, colHealth, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM)
+ cam.End3D2D()
+ end
+
+ local epos = self:GetRedLightPos()
+ local LightNrm = self:GetRedLightAngles():Forward()
+ local ViewNormal = epos - EyePos()
+ local Distance = ViewNormal:Length()
+ ViewNormal:Normalize()
+ local ViewDot = ViewNormal:Dot( LightNrm * -1 )
+
+ if ViewDot >= 0 then
+ if owner:IsValid() and owner:IsPlayer() then
+ local vcol = owner:GetPlayerColor()
+ if vcol then
+ if vcol == vector_origin then
+ vcol.x = 1 vcol.y = 1 vcol.z = 1
+ end
+ vcol:Normalize()
+ vcol = vcol * 2.55
+ colLight.r = math.Clamp(vcol.r * 100, 0, 255)
+ colLight.g = math.Clamp(vcol.g * 100, 0, 255)
+ colLight.b = math.Clamp(vcol.b * 100, 0, 255)
+ end
+ end
+
+ local LightPos = epos + LightNrm * 5
+
+ render.SetMaterial(matLight)
+ local Visibile = util.PixelVisible( LightPos, 16, self.PixVis )
+
+ if not Visibile then return end
+
+ local Size = math.Clamp(Distance * Visibile * ViewDot * 0.9, 20, 210)
+
+ Distance = math.Clamp(Distance, 32, 800)
+ local Alpha = math.Clamp((1000 - Distance) * Visibile * ViewDot, 0, 100)
+ colLight.a = Alpha
+ colWhite.a = Alpha
+
+ render.DrawSprite(LightPos, Size, Size, colLight, Visibile * ViewDot)
+ render.DrawSprite(LightPos, Size*0.4, Size*0.4, colWhite, Visibile * ViewDot)
+ end
+end
+
+function ENT:CreateMove(cmd)
+ if self:GetOwner() ~= LocalPlayer() then return end
+
+ if not self:BeingControlled() then return end
+
+ local buttons = cmd:GetButtons()
+
+ cmd:ClearMovement()
+
+ if bit.band(buttons, IN_JUMP) ~= 0 then
+ buttons = buttons - IN_JUMP
+ buttons = buttons + IN_BULLRUSH
+ end
+
+ if bit.band(buttons, IN_DUCK) ~= 0 then
+ buttons = buttons - IN_DUCK
+ buttons = buttons + IN_GRENADE1
+ end
+
+ cmd:SetButtons(buttons)
+end
+
+function ENT:ShouldDrawLocalPlayer(pl)
+ if self:GetOwner() ~= LocalPlayer() then return end
+
+ if self:BeingControlled() then
+ return true
+ end
+end
+
+local ViewHullMins = Vector(-4, -4, -4)
+local ViewHullMaxs = Vector(4, 4, 4)
+function ENT:CalcView(pl, origin, angles, fov, znear, zfar)
+ if self:GetOwner() ~= pl then return end
+
+ if not self:BeingControlled() then return end
+
+ local filter = player.GetAll()
+ filter[#filter + 1] = self
+ local tr = util.TraceHull({start = self:GetPos(), endpos = self:GetPos() + angles:Forward() * -48, mask = MASK_SHOT, filter = filter, mins = ViewHullMins, maxs = ViewHullMaxs})
+
+ return {origin = tr.HitPos + tr.HitNormal * 3}
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_manhack/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_manhack/init.lua
new file mode 100644
index 0000000..aba6e97
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_manhack/init.lua
@@ -0,0 +1,409 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+ENT.NextWaterDamage = 0
+
+function ENT:Initialize()
+ self:SetModel(self.Model)
+ self:SetUseType(SIMPLE_USE)
+
+ self:PhysicsInit(SOLID_VPHYSICS)
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMass(self.Mass)
+ phys:EnableDrag(false)
+ phys:EnableMotion(true)
+ phys:Wake()
+ phys:SetBuoyancyRatio(0.8)
+
+ local Constraint = ents.Create("phys_keepupright")
+ Constraint:SetAngles(Angle(0, 0, 0))
+ Constraint:SetKeyValue("angularlimit", 5)
+ Constraint:SetPhysConstraintObjects(phys, phys)
+ Constraint:Spawn()
+ Constraint:Activate()
+ self:DeleteOnRemove(Constraint)
+ end
+
+ self:StartMotionController()
+
+ self:SetMaxObjectHealth(self.MaxHealth)
+ self:SetObjectHealth(self:GetMaxObjectHealth())
+
+ self.LastThink = CurTime()
+
+ self.NextTouch = {}
+
+ self:SetBodygroup(1, 1)
+ self:SetBodygroup(2, 1)
+ self:SetSequence(1)
+ self:SetPlaybackRate(1)
+ self:UseClientSideAnimation(true)
+
+ local ent = ents.Create("fhb")
+ if ent:IsValid() then
+ ent:SetPos(self:GetPos())
+ ent:SetAngles(self:GetAngles())
+ ent:SetParent(self)
+ ent:SetOwner(self)
+ ent.Size = self.HitBoxSize
+ ent:Spawn()
+ end
+
+ ent = ents.Create("env_projectedtexture")
+ if ent:IsValid() then
+ ent:SetPos(self:GetRedLightPos())
+ ent:SetAngles(self:GetRedLightAngles())
+ ent:SetKeyValue("enableshadows", 0)
+ ent:SetKeyValue("farz", 400)
+ ent:SetKeyValue("nearz", 8)
+ ent:SetKeyValue("lightfov", 80)
+ local owner = self:GetOwner()
+ if owner:IsValid() and owner:IsPlayer() then
+ local vcol = owner:GetPlayerColor()
+ if vcol then
+ if vcol == vector_origin then
+ vcol.x = 1 vcol.y = 1 vcol.z = 1
+ end
+ vcol:Normalize()
+ vcol = (vcol * 2 + Vector(1, 1, 1)) / 3
+ vcol.x = math.Clamp(math.ceil(vcol.x * 255), 0, 255)
+ vcol.y = math.Clamp(math.ceil(vcol.y * 255), 0, 255)
+ vcol.z = math.Clamp(math.ceil(vcol.z * 255), 0, 255)
+ ent:SetKeyValue("lightcolor", vcol.x.." "..vcol.y.." "..vcol.z.." "..255)
+ else
+ ent:SetKeyValue("lightcolor", "200 220 255 255")
+ end
+ else
+ ent:SetKeyValue("lightcolor", "200 220 255 255")
+ end
+ ent:SetParent(self)
+ ent:Spawn()
+ ent:Input("SpotlightTexture", NULL, NULL, "effects/flashlight001")
+ end
+
+ self:CollisionRulesChanged()
+
+ hook.Add("SetupPlayerVisibility", self, self.SetupPlayerVisibility)
+end
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+
+ if health <= 0 then
+ self:Destroy()
+ end
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ --if dmginfo:GetDamageType() ~= DMG_CRUSH and not self._AllowDamage then return end
+
+ local attacker = dmginfo:GetAttacker()
+ if not (attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_HUMAN) then
+ self:TakePhysicsDamage(dmginfo)
+
+ self:SetObjectHealth(self:GetObjectHealth() - dmginfo:GetDamage())
+
+ --self:EmitSound("npc/scanner/scanner_pain"..math.random(2)..".wav", 0.65, math.Rand(120, 130))
+ self:EmitSound("npc/manhack/gib.wav")
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(self:NearestPoint(dmginfo:GetDamagePosition()))
+ effectdata:SetNormal(VectorRand():GetNormalized())
+ effectdata:SetMagnitude(4)
+ effectdata:SetScale(1.33)
+ util.Effect("sparks", effectdata)
+ end
+end
+
+function ENT:Use(pl)
+ if pl == self:GetOwner() and pl:Team() == TEAM_HUMAN and pl:Alive() and self:GetVelocity():Length() <= self.HoverSpeed then
+ self:OnPackedUp(pl)
+ end
+end
+
+function ENT:PhysicsCollide(data, phys)
+ self.HitData = data
+ self:NextThink(CurTime())
+end
+
+function ENT:OnPackedUp(pl)
+ pl:GiveEmptyWeapon(self.WeaponClass)
+ pl:GiveAmmo(1, self.AmmoType)
+
+ pl:PushPackedItem(self:GetClass(), self:GetObjectHealth())
+
+ self:Remove()
+end
+
+function ENT:PhysicsSimulate(phys, frametime)
+ phys:Wake()
+
+ local owner = self:GetOwner()
+ if not owner:IsValid() then return SIM_NOTHING end
+
+ local vel = phys:GetVelocity()
+ local movedir = Vector()
+ local eyeangles = owner:SyncAngles()
+ local aimangles = owner:EyeAngles()
+
+ if self:BeingControlled() then
+ if owner:KeyDown(IN_FORWARD) then
+ movedir = movedir + aimangles:Forward()
+ end
+ if owner:KeyDown(IN_BACK) then
+ movedir = movedir - aimangles:Forward()
+ end
+ if owner:KeyDown(IN_MOVERIGHT) then
+ movedir = movedir + aimangles:Right()
+ end
+ if owner:KeyDown(IN_MOVELEFT) then
+ movedir = movedir - aimangles:Right()
+ end
+ if owner:KeyDown(IN_BULLRUSH) then
+ movedir = movedir + Vector(0, 0, 0.5)
+ end
+ if owner:KeyDown(IN_GRENADE1) then
+ movedir = movedir - Vector(0, 0, 0.5)
+ end
+ end
+
+ if movedir == vector_origin then
+ vel = vel * (1 - frametime * self.IdleDrag)
+ else
+ movedir:Normalize()
+
+ vel = vel + frametime * self.Acceleration * math.Clamp((self:GetObjectHealth() / self:GetMaxObjectHealth() + 1) / 2, 0.5, 1) * movedir
+ end
+
+ if vel:Length() > self.MaxSpeed then
+ vel:Normalize()
+ vel = vel * self.MaxSpeed
+ end
+
+ if movedir == vector_origin and vel:Length() <= self.HoverSpeed then
+ local trace = {mask = MASK_HOVER, filter = self}
+ trace.start = self:GetPos()
+ trace.endpos = trace.start + Vector(0, 0, self.HoverHeight * -2)
+ local tr = util.TraceLine(trace)
+
+ local hoverdir = (trace.start - tr.HitPos):GetNormalized()
+ local hoverfrac = (0.5 - tr.Fraction) * 2
+ vel = vel + frametime * hoverfrac * self.HoverForce * hoverdir
+ end
+
+ phys:EnableGravity(false)
+ phys:SetAngleDragCoefficient(10000)
+ phys:SetVelocityInstantaneous(vel)
+ phys:AddAngleVelocity(Vector(0, 0, math.Clamp(math.AngleDifference(eyeangles.yaw, phys:GetAngles().yaw), -32, 32) * frametime * 3))
+
+ return SIM_NOTHING
+end
+
+function ENT:Destroy()
+ if self.Destroyed then return end
+ self.Destroyed = true
+
+ self:EmitSound("npc/manhack/gib.wav")
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(self:LocalToWorld(self:OBBCenter()))
+ util.Effect("HelicopterMegaBomb", effectdata, true, true)
+ effectdata:SetNormal(Vector(0, 0, 1))
+ effectdata:SetMagnitude(5)
+ effectdata:SetScale(1.5)
+ util.Effect("sparks", effectdata)
+end
+
+ENT.PhysDamageImmunity = 0
+function ENT:Think()
+ if self.Destroyed then
+ if not self.CreatedDebris then
+ self.CreatedDebris = true
+
+ local ent = ents.Create("prop_physics")
+ if ent:IsValid() then
+ ent:SetPos(self:GetPos())
+ ent:SetAngles(self:GetAngles())
+ ent:SetModel(self:GetModel())
+ ent:Spawn()
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetVelocityInstantaneous(self:GetVelocity())
+ end
+
+ ent:Fire("break")
+ ent:Fire("kill", "", 0.05)
+ end
+ end
+
+ self:Remove()
+ return
+ end
+
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ self:SetPhysicsAttacker(owner)
+
+ if not owner:Alive() or owner:Team() ~= TEAM_HUMAN then
+ self:Destroy()
+ return
+ end
+ else
+ self:Destroy()
+ return
+ end
+
+ if self:WaterLevel() >= 2 and CurTime() >= self.NextWaterDamage then
+ self.NextWaterDamage = CurTime() + 0.2
+
+ self:TakeDamage(10)
+ end
+
+ local data = self.HitData
+ if data then
+ self.HitData = nil
+ self:ThreadSafePhysicsCollide(data)
+ end
+end
+
+function ENT:ThreadSafePhysicsCollide(data)
+ local diddamage = false
+ local ent = data.HitEntity
+ if ent and ent:IsValid() then
+ if ent:IsPlayer() and ent:Team() == TEAM_UNDEAD and ent:Alive() and CurTime() >= (self.NextTouch[ent] or 0) then
+ diddamage = true
+
+ self.NextTouch[ent] = CurTime() + self.HitCooldown
+
+ local owner = self:GetOwner()
+ if not owner:IsValid() then owner = self end
+
+ ent:TakeDamage(self.HitDamage, owner, self)
+ self:EmitHitFleshSound()
+
+ local dir = (self:GetPos() - data.HitPos):GetNormalized()
+
+ util.Blood(data.HitPos, math.random(10, 14), dir, 200)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:AddVelocity(dir * self.BounceFleshVelocity)
+ end
+ else
+ local physattacker = ent:GetPhysicsAttacker()
+ if physattacker:IsValid() and physattacker:Team() == TEAM_HUMAN then
+ self.PhysDamageImmunity = CurTime() + 0.5
+ end
+ end
+ end
+
+ if not diddamage then
+ local dir = (self:GetPos() - data.HitPos):GetNormalized()
+
+ if data.Speed > self.HoverSpeed then
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:AddVelocity(dir * self.BounceVelocity)
+ end
+ end
+
+ if data.DeltaTime > 0.33 and data.Speed > 32 then
+ self:EmitHitSound()
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(self:NearestPoint(data.HitPos))
+ effectdata:SetNormal(data.HitNormal)
+ effectdata:SetMagnitude(2)
+ effectdata:SetScale(1)
+ util.Effect("sparks", effectdata)
+ end
+
+ if data.Speed >= self.MaxSpeed * self.SelfDamageSpeed and ent and ent:IsWorld() and CurTime() >= self.PhysDamageImmunity then
+ self:TakeDamage(math.Clamp(data.Speed * self.SelfDamageMul, 0, 30))
+ end
+ end
+end
+
+function ENT:EmitHitFleshSound()
+ self:EmitSound("npc/manhack/grind_flesh"..math.random(3)..".wav")
+end
+
+function ENT:EmitHitSound()
+ self:EmitSound("npc/manhack/grind"..math.random(5)..".wav")
+end
+
+function ENT:SetupPlayerVisibility(pl)
+ if pl ~= self:GetOwner() then return end
+
+ AddOriginToPVS(self:GetPos())
+end
+
+if CLIENT then return end
+
+local ENT = {}
+
+ENT.Type = "anim"
+
+function ENT:Initialize()
+ local size = self.Size or 16
+
+ self:SetNoDraw(true)
+ self:DrawShadow(false)
+
+ self:SetCollisionGroup(COLLISION_GROUP_WORLD)
+
+ local vecsize = Vector(size, size, size)
+ self:PhysicsInitBox(vecsize * -1, vecsize)
+ self:SetSolid(SOLID_BBOX)
+ self:SetMoveType(MOVETYPE_NONE)
+ self:SetCollisionBounds(vecsize * -1, vecsize)
+
+ self:SetUseType(SIMPLE_USE)
+end
+
+--[[function ENT:OnTakeDamage(dmginfo)
+ local parent = self:GetParent()
+ if parent:IsValid() then
+ parent._AllowDamage = true
+ parent:TakePhysicsDamage(dmginfo)
+ parent:TakeDamage(dmginfo)
+ parent._AllowDamage = false
+ end
+end]]
+
+function ENT:Use(ent)
+ local parent = self:GetParent()
+ if parent:IsValid() then
+ parent:Use(ent, ent, 0, 0)
+ end
+end
+
+-- Unfortunately I couldn't come up with a way to do this without hijacking these rather expensive functions.
+local oldtl = util.TraceLine
+function util.TraceLine(t)
+ local r = oldtl(t)
+ local e = r.Entity
+ if e:IsValid() and e:GetClass() == "fhb" then
+ r.Entity = e:GetParent()
+ end
+ return r
+end
+
+local oldth = util.TraceHull
+function util.TraceHull(t)
+ local r = oldth(t)
+ local e = r.Entity
+ if e:IsValid() and e:GetClass() == "fhb" then
+ r.Entity = e:GetParent()
+ end
+ return r
+end
+
+function ENT:UpdateTransmitState()
+ return TRANSMIT_NEVER
+end
+
+scripted_ents.Register(ENT, "fhb")
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_manhack/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_manhack/shared.lua
new file mode 100644
index 0000000..adf5244
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_manhack/shared.lua
@@ -0,0 +1,72 @@
+ENT.Type = "anim"
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+ENT.m_NoNailUnfreeze = true
+ENT.NoNails = true
+
+ENT.WrenchRepairMultiplier = 0.25
+
+ENT.Model = "models/manhack.mdl"
+ENT.HitBoxSize = 9.5
+ENT.Mass = 50
+ENT.WeaponClass = "weapon_zs_manhack"
+ENT.ControllerClass = "weapon_zs_manhackcontrol"
+ENT.AmmoType = "manhack"
+
+ENT.Acceleration = 160
+ENT.MaxSpeed = 230
+ENT.HoverSpeed = 64
+ENT.HoverHeight = 48
+ENT.HoverForce = 64
+ENT.TurnSpeed = 30
+ENT.IdleDrag = 0.25
+
+ENT.MaxHealth = 55
+ENT.HitCooldown = 0.25
+ENT.HitDamage = 15
+ENT.BounceFleshVelocity = 66
+ENT.BounceVelocity = 50
+ENT.SelfDamageSpeed = 0.7
+ENT.SelfDamageMul = 0.08
+
+function ENT:ShouldNotCollide(ent)
+ return ent:IsPlayer() and ent:Team() == TEAM_HUMAN
+end
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+
+ if health <= 0 and not self.Destroyed then
+ self.Destroyed = true
+ end
+end
+
+function ENT:BeingControlled()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ local wep = owner:GetActiveWeapon()
+ return wep:IsValid() and wep:GetClass() == self.ControllerClass and wep:GetDTBool(0)
+ end
+
+ return false
+end
+
+function ENT:GetObjectHealth()
+ return self:GetDTFloat(0)
+end
+
+function ENT:SetMaxObjectHealth(health)
+ self:SetDTFloat(1, health)
+end
+
+function ENT:GetMaxObjectHealth()
+ return self:GetDTFloat(1)
+end
+
+function ENT:GetRedLightPos()
+ return self:LocalToWorld(Vector(0, 0, -3))
+end
+
+function ENT:GetRedLightAngles()
+ return self:GetAngles()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_manhack_saw/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_manhack_saw/cl_init.lua
new file mode 100644
index 0000000..017e6dd
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_manhack_saw/cl_init.lua
@@ -0,0 +1,40 @@
+include("shared.lua")
+
+function ENT:CreateSubModel()
+ local ent = ClientsideModel("models/props_junk/sawblade001a.mdl", RENDERGROUP_OPAQUE)
+ if ent:IsValid() then
+ ent:SetOwner(self)
+ ent:SetParent(self)
+ ent:SetPos(self:LocalToWorld(Vector(0, 0, -1.5)))
+ ent:SetNoDraw(true)
+ ent:SetModelScale(0.8, 0)
+ ent:Spawn()
+ self.SubModel = ent
+ end
+end
+
+function ENT:RemoveSubModel()
+ if self.SubModel and self.SubModel:IsValid() then
+ self.SubModel:Remove()
+ end
+end
+
+function ENT:DrawSubModel()
+ if self.SubModel and self.SubModel:IsValid() then
+ local ang = self:GetAngles()
+ ang:RotateAroundAxis(ang:Up(), (CurTime() * 2000) % 360)
+
+ self.SubModel:SetRenderAngles(ang)
+ self.SubModel:DrawModel()
+ end
+end
+
+function ENT:CreateAmbientSounds()
+ self.AmbientSound = CreateSound(self, "ambient/machines/spin_loop.wav")
+ self.AmbientSound2 = CreateSound(self, "npc/manhack/mh_blade_loop1.wav")
+end
+
+function ENT:PlayAmbientSounds()
+ self.AmbientSound:PlayEx(0.5, math.min(100 + self:GetVelocity():Length() * 0.2, 140))
+ self.AmbientSound2:PlayEx(0.3, 85 + math.sin(CurTime()))
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_manhack_saw/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_manhack_saw/init.lua
new file mode 100644
index 0000000..061939e
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_manhack_saw/init.lua
@@ -0,0 +1,4 @@
+AddCSLuaFile("shared.lua")
+AddCSLuaFile("cl_init.lua")
+
+include("shared.lua")
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_manhack_saw/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_manhack_saw/shared.lua
new file mode 100644
index 0000000..32bfcbd
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_manhack_saw/shared.lua
@@ -0,0 +1,22 @@
+ENT.Type = "anim"
+ENT.Base = "prop_manhack"
+
+ENT.Model = "models/manhack.mdl"
+ENT.HitBoxSize = 10.5
+ENT.Mass = 80
+ENT.WeaponClass = "weapon_zs_manhack_saw"
+ENT.ControllerClass = "weapon_zs_manhackcontrol_saw"
+ENT.AmmoType = "manhack_saw"
+
+ENT.Acceleration = 140
+ENT.MaxSpeed = 200
+ENT.TurnSpeed = 30
+ENT.IdleDrag = 0.2
+
+ENT.MaxHealth = 150
+ENT.HitCooldown = 0.15
+ENT.HitDamage = 20
+ENT.BounceFleshVelocity = 30
+ENT.BounceVelocity = 75
+ENT.SelfDamageSpeed = 0.9
+ENT.SelfDamageMul = 0.08
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_meathook/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_meathook/cl_init.lua
new file mode 100644
index 0000000..82fb317
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_meathook/cl_init.lua
@@ -0,0 +1,5 @@
+include("shared.lua")
+
+function ENT:Draw()
+ self:DrawModel()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_meathook/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_meathook/init.lua
new file mode 100644
index 0000000..629128a
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_meathook/init.lua
@@ -0,0 +1,54 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+ENT.NextDamage = 0
+ENT.TicksLeft = 50
+
+function ENT:Initialize()
+ self:SetModel("models/props_junk/meathook001a.mdl")
+ self:SetSolid(SOLID_NONE)
+ self:SetMoveType(MOVETYPE_NONE)
+ self:AddEFlags(EFL_SETTING_UP_BONES)
+end
+
+function ENT:Think()
+ local parent = self:GetParent()
+ if parent:IsValid() and parent:IsPlayer() then
+ if parent:Alive() and parent:Team() == TEAM_UNDEAD and self.TicksLeft >= 1 then
+ if CurTime() >= self.NextDamage then
+ self.NextDamage = CurTime() + 0.5
+ self.TicksLeft = self.TicksLeft - 1
+
+ util.Blood((parent:NearestPoint(self:GetPos()) + parent:WorldSpaceCenter()) / 2, math.random(4, 9), Vector(0, 0, 1), 100)
+ parent:TakeDamage(6, self:GetOwner(), self)
+ end
+ else
+ local ent = ents.Create("prop_weapon")
+ if ent:IsValid() then
+ ent:SetWeaponType("weapon_zs_hook")
+ ent:SetPos(self:GetPos())
+ ent:SetAngles(self:GetAngles())
+ ent:Spawn()
+
+ local owner = self:GetOwner()
+ if owner:IsValid() and owner:IsPlayer() and owner:Team() == TEAM_HUMAN then
+ ent.NoPickupsTime = CurTime() + 3
+ ent.NoPickupsOwner = self:GetOwner()
+ end
+
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:AddAngleVelocity(VectorRand() * 200)
+ phys:SetVelocityInstantaneous(Vector(0, 0, 200) + parent:GetVelocity())
+ end
+ end
+
+ self:Remove()
+ end
+ else
+ self:Remove()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_meathook/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_meathook/shared.lua
new file mode 100644
index 0000000..2bb7b93
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_meathook/shared.lua
@@ -0,0 +1,3 @@
+ENT.Type = "anim"
+
+ENT.NoReviveFromKills = true
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_messagebeacon/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_messagebeacon/cl_init.lua
new file mode 100644
index 0000000..1927065
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_messagebeacon/cl_init.lua
@@ -0,0 +1,9 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:SetModelScale(0.333, 0)
+end
+
+function ENT:SetMessageID(id)
+ self:SetDTInt(0, id)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_messagebeacon/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_messagebeacon/init.lua
new file mode 100644
index 0000000..d00ddc7
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_messagebeacon/init.lua
@@ -0,0 +1,93 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+ENT.m_Health = 100
+
+function ENT:Initialize()
+ self:SetModel("models/props_combine/combine_mine01.mdl")
+ self:SetModelScale(0.333, 0)
+ --self:PhysicsInit(SOLID_VPHYSICS)
+ self:PhysicsInitBox(Vector(-8.29, -8.29, 0), Vector(8.29, 8.29, 10.13))
+ self:SetCollisionBounds(Vector(-8.29, -8.29, 0), Vector(8.29, 8.29, 10.13))
+ self:SetCollisionGroup(COLLISION_GROUP_WORLD)
+ self:SetUseType(SIMPLE_USE)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMaterial("metal")
+ phys:EnableMotion(false)
+ phys:Wake()
+ end
+
+ local worldhint = ents.Create("point_worldhint")
+ if worldhint:IsValid() then
+ self.WorldHint = worldhint
+ worldhint:SetPos(self:GetPos())
+ worldhint:SetParent(self)
+ worldhint:Spawn()
+ worldhint:SetViewable(TEAM_HUMAN)
+ worldhint:SetRange(7680)
+ worldhint:SetHint(self:GetMessage())
+ worldhint:SetTranslated(true)
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "messageid" then
+ value = tonumber(value)
+ if not value then return end
+ self:SetMessageID(value)
+ end
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ self:TakePhysicsDamage(dmginfo)
+
+ if not self.Destroyed then
+ local attacker = dmginfo:GetAttacker()
+ if not (attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_HUMAN) then
+ if attacker.LifeBarricadeDamage ~= nil and self:HumanNearby() then
+ attacker:AddLifeBarricadeDamage(dmginfo:GetDamage())
+ end
+
+ self.m_Health = self.m_Health - dmginfo:GetDamage()
+ if self.m_Health <= 0 then
+ self.Destroyed = true
+ local effectdata = EffectData()
+ effectdata:SetOrigin(self:LocalToWorld(self:OBBCenter()))
+ util.Effect("Explosion", effectdata, true, true)
+ end
+ end
+ end
+end
+
+function ENT:SetMessageID(id)
+ self:SetDTInt(0, id)
+ self.WorldHint:SetHint(self:GetMessage())
+end
+
+function ENT:AltUse(activator, tr)
+ self:PackUp(activator)
+end
+
+function ENT:OnPackedUp(pl)
+ pl:GiveEmptyWeapon("weapon_zs_messagebeacon")
+ pl:GiveAmmo(1, "striderminigun")
+
+ pl:PushPackedItem(self:GetClass(), self.m_Health)
+
+ self:Remove()
+end
+
+function ENT:Think()
+ if self.Destroyed then
+ self:Remove()
+ end
+end
+
+function ENT:UpdateTransmitState()
+ return TRANSMIT_ALWAYS
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_messagebeacon/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_messagebeacon/shared.lua
new file mode 100644
index 0000000..aad19e7
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_messagebeacon/shared.lua
@@ -0,0 +1,26 @@
+ENT.Type = "anim"
+
+ENT.CanPackUp = true
+ENT.PackUpTime = 3
+
+ENT.m_NoNailUnfreeze = true
+ENT.NoNails = true
+
+ENT.IsBarricadeObject = true
+ENT.AlwaysGhostable = true
+
+function ENT:GetMessageID()
+ return self:GetDTInt(0)
+end
+
+function ENT:GetMessage(id)
+ return GAMEMODE.ValidBeaconMessages[id or self:GetMessageID()] or GAMEMODE.ValidBeaconMessages[1]
+end
+
+function ENT:SetObjectOwner(owner)
+ self:SetDTEntity(0, owner)
+end
+
+function ENT:GetObjectOwner()
+ return self:GetDTEntity(0)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_nail/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_nail/cl_init.lua
new file mode 100644
index 0000000..68c5c5b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_nail/cl_init.lua
@@ -0,0 +1,122 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+function ENT:OnRemove()
+ local normal = self:GetForward() * -1
+ local pos = self:GetPos() + normal
+
+ sound.Play("physics/metal/metal_box_impact_bullet"..math.random(1, 3)..".wav", pos, 75, math.random(90, 110))
+
+ local grav = Vector(0, 0, -300)
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(22, 32)
+ for i=1, math.random(32, 48) do
+ local vNormal = (VectorRand() * 0.6 + normal):GetNormalized()
+ local particle = emitter:Add("effects/spark", pos + vNormal)
+ particle:SetVelocity(vNormal * math.Rand(16, 100))
+ particle:SetDieTime(math.Rand(0.5, 1))
+ particle:SetStartAlpha(255)
+ particle:SetEndAlpha(255)
+ particle:SetStartSize(math.Rand(0.4, 1.5))
+ particle:SetEndSize(0)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-8, 8))
+ particle:SetCollide(true)
+ particle:SetBounce(0.8)
+ particle:SetGravity(grav)
+ end
+ emitter:Finish()
+end
+
+local matOutlineWhite = Material("white_outline")
+local ScaleOutline = 1.4
+local colNail = Color(0, 0, 5, 220)
+function ENT:DrawTranslucent()
+ local drawowner = MySelf:IsValid() and MySelf:Team() == TEAM_HUMAN and (GAMEMODE.AlwaysShowNails or MySelf:KeyDown(IN_SPEED) or MySelf:TraceLine(256, MASK_SHOT).HitPos:Distance(self:GetPos()) <= 16)
+
+ if drawowner then
+ render.SuppressEngineLighting(true)
+ render.SetAmbientLight(1, 1, 1)
+
+ local health = self:GetNailHealth() / self:GetMaxNailHealth()
+ render.SetColorModulation(1 - health, health, 0)
+
+ local scale = self:GetModelScale()
+ self:SetModelScale(ScaleOutline * scale, 0)
+ render.ModelMaterialOverride(matOutlineWhite)
+
+ self:DrawModel()
+
+ render.ModelMaterialOverride()
+ self:SetModelScale(scale, 0)
+
+ render.SuppressEngineLighting(false)
+ render.SetColorModulation(1, 1, 1)
+ end
+
+ self:DrawModel()
+
+ if drawowner then
+ local displayowner = self:GetDTString(0)
+ local redname = false
+ if displayowner == "" then
+ displayowner = nil
+
+ local deployer = self:GetOwner()
+ if deployer:IsValid() then
+ displayowner = deployer:Name()
+ if deployer:Team() == TEAM_UNDEAD or not deployer:Alive() then
+ displayowner = "(DEAD) "..displayowner
+ redname = true
+ end
+ end
+ end
+
+ local ang = EyeAngles()
+ ang:RotateAroundAxis(ang:Up(), -90)
+ ang:RotateAroundAxis(ang:Forward(), 90)
+
+ cam.Start3D2D(self:GetPos(), ang, 0.05)
+ local wid, hei = 180, 5
+ local x, y = wid * -0.5 + 2, 0
+
+ if self:GetMaxRepairs() > 0 then
+ local repairs = self:GetRepairs()
+ local ru = 1 - math.Clamp(repairs / self:GetMaxRepairs(), 0, 1)
+ surface.SetDrawColor(0, 0, 0, 220)
+ surface.DrawRect(x, y, wid, hei)
+ surface.SetDrawColor(40, 40, 40, 220)
+ surface.DrawOutlinedRect(x, y, wid, hei)
+ surface.SetDrawColor(230, 5, 5, ru == 1 and (150 + math.abs(math.sin(RealTime() * 5)) * 105) or 220)
+ surface.DrawRect(x + 1, y + 1, (wid - 2) * ru, hei - 2)
+
+ draw.SimpleText(math.ceil(repairs), "ZS3D2DFont2Smaller", x + wid, y - 1, repairs <= 0 and COLOR_DARKRED or COLOR_GRAY, TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP)
+ end
+
+ if self:GetMaxNailHealth() > 0 then
+ local mu = math.Clamp(self:GetNailHealth() / self:GetMaxNailHealth(), 0, 1)
+ local green = mu * 200
+ colNail.r = 200 - green
+ colNail.g = green
+
+ y = y + hei + 3
+ hei = 8
+ x = wid * -0.5 + 2
+ surface.SetDrawColor(0, 0, 0, 220)
+ surface.DrawRect(x, y, wid, hei)
+ surface.SetDrawColor(40, 40, 40, 220)
+ surface.DrawOutlinedRect(x, y, wid, hei)
+ surface.SetDrawColor(colNail)
+ surface.DrawRect(x + 1, y + 1, (wid - 2) * mu, hei - 2)
+
+ draw.SimpleText(math.ceil(self:GetNailHealth()).." / "..math.ceil(self:GetMaxNailHealth()), "ZS3D2DFont2Smaller", x + wid / 2, y + hei + 1, colNail, TEXT_ALIGN_CENTER)
+ end
+
+ if displayowner then
+ draw.SimpleText(displayowner, "ZS3D2DFont2Smaller", 0, y + 38, redname and COLOR_DARKRED or COLOR_DARKGRAY, TEXT_ALIGN_CENTER)
+ end
+ cam.End3D2D()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_nail/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_nail/init.lua
new file mode 100644
index 0000000..1f4f9a6
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_nail/init.lua
@@ -0,0 +1,138 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+ENT.m_NextStrainSound = 0
+
+hook.Add("PlayerInitialSpawn", "NailPlayerInitialSpawn", function(pl)
+ local uid = pl:UniqueID()
+
+ for _, nail in pairs(ents.FindByClass("prop_nail")) do
+ if nail:GetOwnerUID() == uid then
+ nail:SetDeployer(pl)
+ end
+ end
+end)
+
+function ENT:Initialize()
+ self:SetModel("models/crossbow_bolt.mdl")
+end
+
+function ENT:OnDamaged(damage, attacker, inflictor, dmginfo)
+ if CurTime() >= self.m_NextStrainSound then
+ self.m_NextStrainSound = CurTime() + math.min(damage * 0.025, 1)
+ self:EmitSound("physics/metal/metal_box_impact_hard"..math.random(3)..".wav", math.Clamp(damage * 2.5, 60, 80), math.min(255, 150 + (1 - (self:GetNailHealth() / self:GetMaxNailHealth())) * 100))
+ end
+end
+
+function ENT:AttachTo(baseent, attachent, physbone, physbone2)
+ self:SetBaseEntity(baseent)
+ self:SetAttachEntity(attachent, physbone, physbone2)
+
+ if not baseent.Nails then baseent.Nails = {} end
+ if not attachent.Nails then attachent.Nails = {} end
+
+ table.insert(baseent.Nails, self)
+ table.insert(attachent.Nails, self)
+
+ self:SetParentPhysNum(physbone or 0)
+ self:SetParent(baseent)
+
+ if baseent:IsValid() then
+ baseent:CollisionRulesChanged()
+ end
+ if attachent:IsValid() then
+ attachent:CollisionRulesChanged()
+ end
+
+ if baseent:GetBarricadeHealth() == 0 then
+ local health = baseent:GetDefaultBarricadeHealth()
+ baseent:SetMaxBarricadeHealth(health)
+ baseent:SetBarricadeHealth(health)
+ baseent:SetBarricadeRepairs(baseent:GetMaxBarricadeRepairs())
+ end
+end
+
+function ENT:SetNailConstraint(const)
+ self.m_Constraint = const
+end
+
+function ENT:GetNailConstraint()
+ return self.m_Constraint or NULL
+end
+
+function ENT:SetOwnerUID(uid)
+ self.OwnerUID = uid
+end
+
+function ENT:GetOwnerUID()
+ return self.OwnerUID
+end
+
+function ENT:SetDeployer(pl)
+ if not pl then return end
+
+ if type(pl) == "string" then
+ self:SetDTString(0, pl)
+ self:SetOwner(NULL)
+ self:SetOwnerUID(nil)
+ elseif pl:IsValid() then
+ self:SetDTString(0, "")
+ self:SetOwner(pl)
+ self:SetOwnerUID(pl:UniqueID())
+ end
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ name = string.lower(name)
+ if name == "attachto" then
+ local ent = ents.FindByName(args)[1]
+ if ent and ent:IsValid() then
+ self:SetParent(ent)
+ end
+
+ return true
+ elseif name == "nailto" then
+ if self:GetParent():IsValid() then
+ local ent = args == "worldspawn" and game.GetWorld() or ents.FindByName(args)[1]
+ if ent then
+ self:AttachTo(self:GetParent(), ent)
+ end
+ end
+
+ return true
+ elseif name == "setname" or name == "setdeployer" then
+ self:SetDeployer(args)
+
+ return true
+ elseif name == "setunremoveable" or name == "setunremovable" then
+ self.m_NailUnremovable = tonumber(args) == 1
+
+ return true
+ elseif name == "toggleunremoveable" or name == "toggleunremovable" then
+ self.m_NailUnremovable = not self.m_NailRemovable
+
+ return true
+ end
+end
+
+function ENT:OnRemove()
+ if self.m_IsRemoving then return end
+
+ local baseent = self:GetBaseEntity()
+ if baseent:IsValid() and not baseent:IsWorld() then
+ baseent:RemoveNail(self, nil, nil, true)
+ end
+ local attachent = self:GetAttachEntity()
+ if attachent:IsValid() and not attachent:IsWorld() then
+ attachent:RemoveNail(self, nil, nil, true)
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "unremoveable" or key == "unremovable" then
+ self.m_NailUnremoveable = tonumber(value) == 1
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_nail/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_nail/shared.lua
new file mode 100644
index 0000000..d4ec0b9
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_nail/shared.lua
@@ -0,0 +1,109 @@
+ENT.Type = "anim"
+
+function ENT:GetDeployer()
+ return self:GetOwner()
+end
+
+function ENT:GetMaxNailHealth()
+ local ent = self:GetBaseEntity()
+ if ent:IsValid() then
+ return ent:GetMaxBarricadeHealth()
+ end
+
+ return 0
+end
+
+function ENT:GetNailHealth()
+ local ent = self:GetBaseEntity()
+ if ent:IsValid() then
+ return ent:GetBarricadeHealth()
+ end
+
+ return 0
+end
+
+function ENT:GetRepairs()
+ local ent = self:GetBaseEntity()
+ if ent:IsValid() then
+ return ent:GetBarricadeRepairs()
+ end
+
+ return 0
+end
+
+function ENT:GetMaxRepairs()
+ local ent = self:GetBaseEntity()
+ if ent:IsValid() then
+ return ent:GetMaxBarricadeRepairs()
+ end
+
+ return 0
+end
+
+function ENT:SetMaxRepairs(m)
+end
+
+function ENT:SetBaseEntity(ent)
+ self:SetDTEntity(0, ent)
+end
+
+function ENT:GetBaseEntity()
+ return self:GetDTEntity(0)
+end
+
+function ENT:SetAttachEntity(ent, physbone1, physbone2)
+ self.m_AttachEntity = ent
+
+ if not SERVER then return end
+
+ local baseent = self:GetBaseEntity()
+ if not baseent:IsValid() then return end
+
+ local cons = constraint.Weld(baseent, ent, physbone1 or 0, physbone2 or 0, 0, true)
+ if cons ~= nil then
+ for _, oldcons in pairs(constraint.FindConstraints(baseent, "Weld")) do
+ if oldcons.Ent1 == ent or oldcons.Ent2 == ent then
+ cons = oldcons.Constraint
+ break
+ end
+ end
+ end
+
+ cons:DeleteOnRemove(self)
+ self:SetNailConstraint(cons)
+
+ if baseent:IsValid() then
+ baseent:CollisionRulesChanged()
+ end
+ if ent and ent:IsValid() then
+ ent:CollisionRulesChanged()
+ end
+
+ timer.Simple(0.1, function() GAMEMODE:EvaluatePropFreeze() end)
+
+ return cons
+end
+
+function ENT:GetAttachEntity()
+ return self.m_AttachEntity or NULL
+end
+
+function ENT:GetActualPos()
+ local offset = self:GetActualOffset()
+ if offset then
+ local parent = self:GetParent()
+ if parent:IsValid() then
+ return parent:LocalToWorld(offset)
+ end
+ end
+
+ return self:GetPos()
+end
+
+function ENT:GetActualOffset()
+ return self.m_ActualOffset
+end
+
+function ENT:SetActualOffset(pos, ent)
+ self.m_ActualOffset = ent:WorldToLocal(pos)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_obj_exit/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_obj_exit/cl_init.lua
new file mode 100644
index 0000000..66c2de2
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_obj_exit/cl_init.lua
@@ -0,0 +1,199 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+function ENT:Initialize()
+ self:SetRenderBounds(Vector(-128, -128, -128), Vector(128, 128, 200))
+
+ local ent = ClientsideModel("models/props_doors/door01_dynamic.mdl", RENDERGROUP_TRANSLUCENT)
+ if ent:IsValid() then
+ ent:SetPos(self:LocalToWorld(Vector(0, 0, 52)))
+ ent:SetAngles(self:GetAngles())
+ ent:DrawShadow(false)
+ ent:SetNoDraw(true)
+ ent:SetParent(self)
+ ent:Spawn()
+ self.Door = ent
+ end
+
+ ent = ClientsideModel("models/props_debris/wood_board07a.mdl", RENDERGROUP_TRANSLUCENT)
+ if ent:IsValid() then
+ ent:SetPos(self:LocalToWorld(Vector(0, 0, 49)))
+ ent:SetAngles(self:GetAngles())
+ ent:DrawShadow(false)
+ ent:SetNoDraw(true)
+ ent:SetParent(self)
+ ent:Spawn()
+ self.LeftBoard = ent
+ end
+
+ ent = ClientsideModel("models/props_debris/wood_board07a.mdl", RENDERGROUP_TRANSLUCENT)
+ if ent:IsValid() then
+ ent:SetPos(self:LocalToWorld(Vector(-52, 0, 49)))
+ ent:SetAngles(self:GetAngles())
+ ent:DrawShadow(false)
+ ent:SetNoDraw(true)
+ ent:SetParent(self)
+ ent:Spawn()
+ self.RightBoard = ent
+ end
+
+ ent = ClientsideModel("models/props_debris/wood_board07a.mdl", RENDERGROUP_TRANSLUCENT)
+ if ent:IsValid() then
+ ent:SetPos(self:LocalToWorld(Vector(-24, 0, 109)))
+ ent:SetAngles(self:LocalToWorldAngles(Angle(90, 0, 0)))
+ ent:DrawShadow(false)
+ ent:SetNoDraw(true)
+ ent:SetParent(self)
+ ent:Spawn()
+ ent:SetModelScaleVector(Vector(1, 1, 0.38))
+ self.TopBoard = ent
+ end
+
+ ent = ClientsideModel("models/props_debris/wood_board07a.mdl", RENDERGROUP_TRANSLUCENT)
+ if ent:IsValid() then
+ ent:SetPos(self:LocalToWorld(Vector(-24, 0, 48)))
+ ent:SetAngles(self:GetAngles())
+ ent:DrawShadow(false)
+ ent:SetNoDraw(true)
+ ent:SetParent(self)
+ ent:Spawn()
+ ent:SetModelScaleVector(Vector(6, 0.001, 1))
+ self.Rift = ent
+ end
+
+ hook.Add("RenderScreenspaceEffects", self, self.RenderScreenspaceEffects)
+end
+
+local CModWhiteOut = {
+ ["$pp_colour_addr"] = 0,
+ ["$pp_colour_addg"] = 0,
+ ["$pp_colour_addb"] = 0,
+ ["$pp_colour_brightness"] = 0,
+ ["$pp_colour_contrast"] = 1,
+ ["$pp_colour_colour"] = 1,
+ ["$pp_colour_mulr"] = 0,
+ ["$pp_colour_mulg"] = 0,
+ ["$pp_colour_mulb"] = 0
+}
+
+function ENT:RenderScreenspaceEffects()
+ local eyepos = EyePos()
+ local nearest = self:NearestPoint(eyepos)
+ local dist = eyepos:Distance(nearest)
+ local power = math.Clamp(1 - dist / 300, 0, 1) ^ 2 * self:GetOpenedPercent()
+
+ if power > 0 then
+ local size = 5 + power * 10
+
+ CModWhiteOut["$pp_colour_brightness"] = power * 0.5
+ DrawBloom(1 - power, power * 4, size, size, 1, 1, 1, 1, 1)
+ DrawColorModify(CModWhiteOut)
+
+ if render.SupportsPixelShaders_2_0() then
+ local eyevec = EyeVector()
+ local pos = self:LocalToWorld(self:OBBCenter()) - eyevec * 16
+ local distance = eyepos:Distance(pos)
+ local dot = (pos - eyepos):GetNormalized():Dot(eyevec) - distance * 0.0005
+ if dot > 0 then
+ local srcpos = pos:ToScreen()
+ DrawSunbeams(0.8, dot * power, 0.1, srcpos.x / w, srcpos.y / h)
+ end
+ end
+ end
+end
+
+ENT.NextEmit = 0
+local matWhite = Material("models/debug/debugwhite")
+function ENT:DrawTranslucent()
+ local curtime = CurTime()
+ local rise = self:GetRise() ^ 2
+ local normal = self:GetUp()
+ local openedpercent = self:GetOpenedPercent()
+
+ local dlight = DynamicLight(self:EntIndex())
+ if dlight then
+ local size = 100 + openedpercent * 200
+ size = size * (1 + math.sin(curtime * math.pi) * 0.075)
+
+ dlight.Pos = self:LocalToWorld(Vector(-24, 0, 40))
+ dlight.r = 180
+ dlight.g = 200
+ dlight.b = 255
+ dlight.Brightness = 1 + openedpercent * 4
+ dlight.Size = size
+ dlight.Decay = size * 2
+ dlight.DieTime = curtime + 1
+ end
+
+ render.EnableClipping(true)
+ render.PushCustomClipPlane(normal, normal:Dot(self:GetPos()))
+
+ cam.Start3D(EyePos() + Vector(0, 0, (1 - rise) * 150), EyeAngles())
+ self.Door:SetPos(self:LocalToWorld(Vector(0, 0, 52)))
+ self.Door:SetAngles(self:LocalToWorldAngles(Angle(0, openedpercent * 80, 0)))
+ self.Door:DrawModel()
+
+ self.LeftBoard:DrawModel()
+ self.RightBoard:DrawModel()
+ self.TopBoard:DrawModel()
+ cam.End3D()
+
+ if openedpercent > 0 then
+ --[[normal = normal * -1
+ render.PushCustomClipPlane(normal, normal:Dot(self.TopBoard:GetPos()))
+
+ normal = self:GetForward()
+ render.PushCustomClipPlane(normal, normal:Dot(self.RightBoard:GetPos()))
+
+ normal = normal * -1
+ render.PushCustomClipPlane(normal, normal:Dot(self.LeftBoard:GetPos()))]]
+
+ local brightness = openedpercent ^ 0.4
+ render.SuppressEngineLighting(true)
+ render.SetColorModulation(brightness, brightness, brightness)
+ render.ModelMaterialOverride(matWhite)
+
+ self.Rift:DrawModel()
+
+ render.ModelMaterialOverride()
+ render.SetColorModulation(1, 1, 1)
+ render.SuppressEngineLighting(false)
+
+ --[[render.PopCustomClipPlane()
+ render.PopCustomClipPlane()
+ render.PopCustomClipPlane()]]
+ end
+
+ render.PopCustomClipPlane()
+ render.EnableClipping(false)
+
+ if curtime < self.NextEmit or openedpercent == 0 then return end
+ self.NextEmit = curtime + 0.01 + (1 - openedpercent) * 0.15
+
+ local dir = self:GetRight() * 2 + VectorRand()
+ dir:Normalize()
+ local startpos = self:LocalToWorld(Vector(-24, 0, 48))
+
+ local emitter = ParticleEmitter(startpos)
+ emitter:SetNearClip(24, 32)
+
+ for i=1, 4 do
+ dir = dir * -1
+
+ local particle = emitter:Add("sprites/glow04_noz", startpos + dir * 180)
+ particle:SetDieTime(0.5)
+ particle:SetVelocity(dir * -360)
+ particle:SetStartAlpha(0)
+ particle:SetEndAlpha(255 * openedpercent)
+ particle:SetStartSize(math.Rand(2, 5) * openedpercent)
+ particle:SetEndSize(0)
+ if math.random(2) == 2 then
+ particle:SetColor(220, 240, 255)
+ end
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-5, 5))
+ end
+
+ emitter:Finish()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_obj_exit/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_obj_exit/init.lua
new file mode 100644
index 0000000..61f0dda
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_obj_exit/init.lua
@@ -0,0 +1,88 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ local mins, maxs = Vector(-56, -8, -1), Vector(8, 8, 115)
+
+ self:SetModel("models/props_doors/door01_dynamic.mdl")
+ self:PhysicsInitBox(mins, maxs)
+ self:SetCollisionBounds(mins, maxs)
+ self:SetUseType(SIMPLE_USE)
+
+ self:SetTrigger(true)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:EnableMotion(false)
+ phys:Wake()
+ end
+
+ self:SetCreationTime(CurTime())
+
+ --self:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
+
+ local ent = ents.Create("point_worldhint")
+ if ent:IsValid() then
+ ent:SetPos(self:LocalToWorld(Vector(-24, 0, 2)))
+ ent:SetParent(self)
+ ent:Spawn()
+ ent:SetViewable(TEAM_HUMAN)
+ ent:SetRange(0)
+ ent:SetTranslated(true)
+ ent:SetHint("prop_obj_exit_h")
+ end
+
+ ent = ents.Create("point_worldhint")
+ if ent:IsValid() then
+ ent:SetPos(self:LocalToWorld(Vector(-24, 0, 2)))
+ ent:SetParent(self)
+ ent:Spawn()
+ ent:SetViewable(TEAM_UNDEAD)
+ ent:SetRange(0)
+ ent:SetTranslated(true)
+ ent:SetHint("prop_obj_exit_z")
+ end
+
+ --[[ent = ents.Create("env_projectedtexture")
+ if ent:IsValid() then
+ ent:SetPos(self:GetPos() + self:GetUp() * 8)
+ ent:SetAngles(self:GetRight():Angle())
+ ent:SetKeyValue("enableshadows", 0)
+ ent:SetKeyValue("farz", 600)
+ ent:SetKeyValue("nearz", 2)
+ ent:SetKeyValue("lightfov", 70)
+ ent:SetKeyValue("lightcolor", "220 240 255 255")
+ ent:SetKeyValue("appearance", 5)
+ ent:SetParent(self)
+ ent:Spawn()
+ ent:Input("SpotlightTexture", NULL, NULL, "effects/flashlight001")
+ self.SpotLight = ent
+ end]]
+end
+
+function ENT:Use(activator)
+ if activator:IsPlayer() and activator:Alive() and activator:Team() == TEAM_HUMAN and self:GetOpenStartTime() == 0 and self:GetRise() == 1 then
+ self:SetOpenStartTime(CurTime())
+ end
+end
+
+function ENT:Touch(ent)
+ if ent:IsPlayer() and ent:Team() == TEAM_HUMAN and ent:Alive() and ent:GetObserverMode() == OBS_MODE_NONE and self:IsOpened() then
+ local pos = ent:EyePos()
+
+ ent:Spectate(OBS_MODE_ROAMING)
+ ent:SpectateEntity(self)
+ ent:StripWeapons()
+ ent:GodEnable()
+
+ ent:SetPos(pos)
+
+ ent:PrintMessage(3, "You've managed to survive! Waiting for other survivors...")
+ end
+end
+
+function ENT:UpdateTransmitState()
+ return TRANSMIT_ALWAYS
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_obj_exit/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_obj_exit/shared.lua
new file mode 100644
index 0000000..55d7349
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_obj_exit/shared.lua
@@ -0,0 +1,29 @@
+ENT.Type = "anim"
+
+ENT.m_NoNailUnfreeze = true
+ENT.NoNails = true
+
+ENT.RiseTime = 4
+
+ENT.OpenTime = 10
+
+AccessorFuncDT(ENT, "OpenStartTime", "Float", 0)
+AccessorFuncDT(ENT, "CreationTime", "Float", 1)
+
+function ENT:GetOpenedPercent()
+ if not self:IsOpening() then return 0 end
+
+ return math.Clamp((CurTime() - self:GetOpenStartTime()) / self.OpenTime, 0, 1)
+end
+
+function ENT:IsOpened()
+ return self:GetOpenStartTime() ~= 0 and CurTime() >= self:GetOpenStartTime() + self.OpenTime
+end
+
+function ENT:IsOpening()
+ return self:GetOpenStartTime() ~= 0
+end
+
+function ENT:GetRise()
+ return math.Clamp((CurTime() - self:GetCreationTime()) / self.RiseTime, 0, 1)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_obj_sigil/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_obj_sigil/cl_init.lua
new file mode 100644
index 0000000..c1e11ec
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_obj_sigil/cl_init.lua
@@ -0,0 +1,160 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+local function DrawSigilHints()
+ for _, ent in pairs(ents.FindByClass("prop_obj_sigil")) do
+ ent:DrawWorldHint()
+ end
+end
+
+function ENT:Initialize()
+ self:SetRenderBounds(Vector(-128, -128, -128), Vector(128, 128, 200))
+
+ self:SetModelScaleVector(Vector(1, 1, 1) * self.ModelScale)
+
+ self.AmbientSound = CreateSound(self, "ambient/atmosphere/tunnel1.wav")
+
+ hook.Add("PostDrawTranslucentRenderables", "DrawSigilHints", DrawSigilHints)
+end
+
+function ENT:Think()
+ if EyePos():Distance(self:GetPos()) <= 700 then
+ self.AmbientSound:PlayEx(0.33, 75 + (self:GetSigilHealth() / self:GetSigilMaxHealth()) * 25)
+ else
+ self.AmbientSound:Stop()
+ end
+end
+
+function ENT:OnRemove()
+ self.AmbientSound:Stop()
+end
+
+function ENT:DrawWorldHint()
+ DrawWorldHint(math.ceil(self:GetSigilHealth()), self:GetPos(), nil, 0.75)
+end
+
+ENT.NextEmit = 0
+ENT.Rotation = math.random(360)
+
+local matWhite = Material("models/debug/debugwhite")
+local matGlow = Material("sprites/light_glow02_add")
+local cDraw = Color(255, 255, 255)
+local cDrawWhite = Color(255, 255, 255)
+function ENT:DrawTranslucent()
+ self:RemoveAllDecals()
+
+ local curtime = CurTime()
+ local sat = math.abs(math.sin(curtime))
+ local colsat = sat * 0.125
+ local eyepos = EyePos()
+ local eyeangles = EyeAngles()
+ local forwardoffset = self:GetForward() * 16
+ local rightoffset = self:GetRight() * 16
+ local healthperc = self:GetSigilHealth() / self:GetSigilMaxHealth()
+ local r, g, b = 0.15 + colsat, 0.4 + colsat, 1
+ local radius = 180 + math.cos(sat) * 40
+ local whiteradius = 122 + math.sin(sat) * 32
+ local up = self:GetUp()
+ local spritepos = self:GetPos() + up
+ local spritepos2 = self:WorldSpaceCenter()
+
+ local dlight = DynamicLight(self:EntIndex())
+ if dlight then
+ dlight.Pos = self:GetPos()
+ dlight.r = r * 255
+ dlight.g = g * 255
+ dlight.b = b * 255
+ dlight.Brightness = (2 + sat) * healthperc
+ dlight.Size = 100 + sat * 50
+ dlight.Decay = 400 + sat * 200
+ dlight.DieTime = curtime + 1
+ end
+
+ r = r * healthperc
+ g = g * healthperc
+ b = b * healthperc
+ render.SuppressEngineLighting(true)
+ render.SetColorModulation(r ^ 0.5, g ^ 0.5, b ^ 0.5)
+ self:DrawModel()
+
+ render.SetColorModulation(r, g, b)
+
+ render.ModelMaterialOverride(matWhite)
+ render.SetBlend(0.1 * healthperc)
+
+ self:DrawModel()
+
+ --[[r = r * healthperc
+ g = g * healthperc
+ b = b * healthperc]]
+ render.SetColorModulation(r, g, b)
+
+ self:SetModelScaleVector(Vector(0.1, 0.1, 0.9 * math.max(0.02, healthperc)) * self.ModelScale)
+ render.SetBlend(1)
+ cam.Start3D(eyepos + forwardoffset + rightoffset, eyeangles)
+ self:DrawModel()
+ cam.End3D()
+ cam.Start3D(eyepos + forwardoffset - rightoffset, eyeangles)
+ self:DrawModel()
+ cam.End3D()
+ cam.Start3D(eyepos - forwardoffset + rightoffset, eyeangles)
+ self:DrawModel()
+ cam.End3D()
+ cam.Start3D(eyepos - forwardoffset - rightoffset, eyeangles)
+ self:DrawModel()
+ cam.End3D()
+ self:SetModelScaleVector(Vector(1, 1, 1) * self.ModelScale)
+
+ render.SetBlend(1)
+ render.ModelMaterialOverride()
+ render.SuppressEngineLighting(false)
+ render.SetColorModulation(1, 1, 1)
+
+ self.Rotation = self.Rotation + FrameTime() * 5
+ if self.Rotation >= 360 then
+ self.Rotation = self.Rotation - 360
+ end
+
+ cDraw.r = r * 255
+ cDraw.g = g * 255
+ cDraw.b = b * 255
+ cDrawWhite.r = healthperc * 255
+ cDrawWhite.g = cDrawWhite.r
+ cDrawWhite.b = cDrawWhite.r
+
+ render.SetMaterial(matGlow)
+ render.DrawQuadEasy(spritepos, up, whiteradius, whiteradius, cDrawWhite, self.Rotation)
+ render.DrawQuadEasy(spritepos, up * -1, whiteradius, whiteradius, cDrawWhite, self.Rotation)
+ render.DrawQuadEasy(spritepos, up, radius, radius, cDraw, self.Rotation)
+ render.DrawQuadEasy(spritepos, up * -1, radius, radius, cDraw, self.Rotation)
+ --render.DrawSprite(spritepos2, whiteradius, whiteradius * 2, cDrawWhite)
+ render.DrawSprite(spritepos2, radius, radius * 2, cDraw)
+
+ if curtime < self.NextEmit then return end
+ self.NextEmit = curtime + 0.05
+
+ local offset = VectorRand()
+ offset.z = 0
+ offset:Normalize()
+ offset = offset * math.Rand(-32, 32)
+ offset.z = 1
+ local pos = self:LocalToWorld(offset)
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(24, 32)
+
+ local particle = emitter:Add("sprites/glow04_noz", pos)
+ particle:SetDieTime(math.Rand(1.5, 4))
+ particle:SetVelocity(Vector(0, 0, math.Rand(32, 64)))
+ particle:SetStartAlpha(0)
+ particle:SetEndAlpha(255)
+ particle:SetStartSize(math.Rand(2, 4))
+ particle:SetEndSize(0)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-1, 1))
+ particle:SetColor(r * 255, g * 255, b * 255)
+ particle:SetCollide(true)
+
+ emitter:Finish()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_obj_sigil/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_obj_sigil/init.lua
new file mode 100644
index 0000000..cdc1d54
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_obj_sigil/init.lua
@@ -0,0 +1,56 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+--models/props_wasteland/antlionhill.mdl
+function ENT:Initialize()
+ self:DrawShadow(false)
+
+ self:SetModel("models/props_wasteland/medbridge_post01.mdl")
+ self:PhysicsInit(SOLID_VPHYSICS)
+ self:SetUseType(SIMPLE_USE)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:EnableMotion(false)
+ phys:Wake()
+ end
+
+ self:SetSigilHealthBase(self.MaxHealth)
+ self:SetSigilHealthRegen(self.HealthRegen)
+ self:SetSigilLastDamaged(0)
+end
+
+function ENT:Think()
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ if self:GetSigilHealth() <= 0 then return end
+
+ local attacker = dmginfo:GetAttacker()
+ if not (attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_UNDEAD and dmginfo:GetDamage() > 2) then return end
+
+ local oldhealth = self:GetSigilHealth()
+ self:SetSigilLastDamaged(CurTime())
+ self:SetSigilHealthBase(oldhealth - dmginfo:GetDamage())
+
+ if self:GetSigilHealth() <= 0 then
+ self:SetSigilHealthBase(0)
+
+ gamemode.Call("OnSigilDestroyed", self, dmginfo)
+
+ self:Destroy()
+ end
+end
+
+function ENT:Destroy()
+ local effectdata = EffectData()
+ effectdata:SetOrigin(self:LocalToWorld(self:OBBCenter()))
+ util.Effect("Explosion", effectdata, true, true)
+
+ self:Fire("kill", "", 0.01)
+end
+
+function ENT:UpdateTransmitState()
+ return TRANSMIT_ALWAYS
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_obj_sigil/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_obj_sigil/shared.lua
new file mode 100644
index 0000000..480167c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_obj_sigil/shared.lua
@@ -0,0 +1,32 @@
+ENT.Type = "anim"
+
+ENT.MaxHealth = 1000
+ENT.HealthRegen = 10
+ENT.RegenDelay = 10
+
+ENT.ModelScale = 1 --ENT.ModelScale = 0.5
+
+ENT.m_NoNailUnfreeze = true
+ENT.NoNails = true
+ENT.IsBarricadeObject = true
+
+AccessorFuncDT(ENT, "SigilHealthBase", "Float", 0)
+AccessorFuncDT(ENT, "SigilHealthRegen", "Float", 1)
+AccessorFuncDT(ENT, "SigilLastDamaged", "Float", 2)
+
+function ENT:SetSigilHealth(health)
+ self:SetSigilHealthBase(health)
+
+ self:SetSigilLastDamaged(math.max(self:GetSigilLastDamaged(), self:GetSigilHealthRegen() - self.RegenDelay))
+end
+
+function ENT:GetSigilHealth()
+ local base = self:GetSigilHealthBase()
+ if base == 0 then return 0 end
+
+ return math.Clamp(base + self:GetSigilHealthRegen() * math.max(0, CurTime() - (self:GetSigilLastDamaged() + self.RegenDelay)), 0, self.MaxHealth)
+end
+
+function ENT:GetSigilMaxHealth()
+ return self.MaxHealth
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_playergib/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_playergib/cl_init.lua
new file mode 100644
index 0000000..bf9d188
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_playergib/cl_init.lua
@@ -0,0 +1,30 @@
+include("shared.lua")
+
+ENT.NextEmit = 0
+
+function ENT:Draw()
+ self:DrawModel()
+
+ if CurTime() >= self.NextEmit and self:GetVelocity():Length() >= 16 then
+ self.NextEmit = CurTime() + 0.05
+
+ local pos = self:GetPos()
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(16, 24)
+
+ local particle = emitter:Add("noxctf/sprite_bloodspray"..math.random(8), pos)
+ particle:SetVelocity(VectorRand():GetNormalized() * math.Rand(8, 16))
+ particle:SetDieTime(0.6)
+ particle:SetStartAlpha(230)
+ particle:SetEndAlpha(230)
+ particle:SetStartSize(10)
+ particle:SetEndSize(0)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-25, 25))
+ particle:SetColor(255, 0, 0)
+ particle:SetLighting(true)
+
+ emitter:Finish()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_playergib/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_playergib/init.lua
new file mode 100644
index 0000000..f9b0a1f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_playergib/init.lua
@@ -0,0 +1,88 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self.m_Health = 25
+
+ if not self.DieTime then
+ self.DieTime = CurTime() + GAMEMODE.GibLifeTime
+ end
+
+ local modelid
+ if self.m_GibType then
+ modelid = self.m_GibType
+ else
+ modelid = math.random(#GAMEMODE.HumanGibs)
+ end
+ self:SetModel(GAMEMODE.HumanGibs[modelid])
+ if 4 < modelid then
+ self:SetMaterial("models/flesh")
+ end
+ self:PhysicsInit(SOLID_VPHYSICS)
+ self:SetSolid(SOLID_VPHYSICS)
+ self:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
+ self:SetTrigger(true)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMaterial("zombieflesh")
+ phys:EnableMotion(true)
+ phys:Wake()
+ phys:ApplyForceCenter(VectorRand():GetNormalized() * math.Rand(2000, 5000))
+ phys:AddAngleVelocity(VectorRand() * 360)
+ end
+end
+
+function ENT:SetGibType(id)
+ self.m_GibType = math.Clamp(math.ceil(id), 1, #GAMEMODE.HumanGibs)
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "gibtype" then
+ value = tonumber(value)
+ if not value then return end
+
+ self:SetGibType(value)
+ elseif key == "lifetime" then
+ value = tonumber(value)
+ if not value then return end
+
+ if value <= 0 then
+ self.DieTime = -1
+ else
+ self.DieTime = CurTime() + value
+ end
+ end
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ self:TakePhysicsDamage(dmginfo)
+
+ self.m_Health = self.m_Health - dmginfo:GetDamage()
+ if self.m_Health <= 0 and not self.Destroyed then
+ self.Destroyed = true
+ self.DieTime = 0
+
+ util.Blood(self:GetPos(), math.random(1, 2), Vector(0, 0, 1), 100, self:GetDTInt(0), true)
+ end
+end
+
+function ENT:Think()
+ if self.DieTime >= 0 and self.DieTime <= CurTime() then
+ self:Remove()
+ end
+end
+
+function ENT:StartTouch(ent)
+ if self.DieTime ~= 0 and ent:IsPlayer() and ent:Alive() and ent:Team() == TEAM_UNDEAD and ent:Health() < ent:GetMaxZombieHealth() then
+ self.DieTime = 0
+
+ ent:SetHealth(math.min(ent:GetMaxZombieHealth(), ent:Health() + 10))
+
+ self:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav")
+ util.Blood(self:GetPos(), math.random(2), Vector(0, 0, 1), 100, self:GetDTInt(0), true)
+ end
+end
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_playergib/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_playergib/shared.lua
new file mode 100644
index 0000000..1a2d077
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_playergib/shared.lua
@@ -0,0 +1,7 @@
+ENT.Type = "anim"
+
+ENT.NoNails = true
+
+function ENT:HumanHoldable(pl)
+ return true
+end
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_resupplybox/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_resupplybox/cl_init.lua
new file mode 100644
index 0000000..3980359
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_resupplybox/cl_init.lua
@@ -0,0 +1,71 @@
+include("shared.lua")
+
+ENT.Dinged = true
+
+function ENT:Initialize()
+ self:SetRenderBounds(Vector(-72, -72, -72), Vector(72, 72, 128))
+end
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+end
+
+local NextUse = 0
+local vOffset = Vector(16, 0, 0)
+local vOffset2 = Vector(-16, 0, 0)
+local aOffset = Angle(0, 90, 90)
+local aOffset2 = Angle(0, 270, 90)
+local vOffsetEE = Vector(-15, 0, 8)
+
+function ENT:Think()
+ if MySelf:IsValid() and MySelf:Team() == TEAM_HUMAN then
+ if self.Dinged then
+ if CurTime() < NextUse then
+ self.Dinged = false
+ end
+ elseif CurTime() >= NextUse then
+ self.Dinged = true
+
+ self:EmitSound("zombiesurvival/ding.ogg")
+ end
+ end
+
+ self:NextThink(CurTime() + 0.5)
+ return true
+end
+
+function ENT:RenderInfo(pos, ang, owner)
+ cam.Start3D2D(pos, ang, 0.075)
+
+ draw.RoundedBox(32, -92, -50, 184, 100, color_black_alpha90)
+
+ draw.SimpleText(translate.Get("resupply_box"), "ZS3D2DFont2", 0, 0, NextUse <= CurTime() and COLOR_GREEN or COLOR_DARKRED, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+
+ if owner:IsValid() and owner:IsPlayer() then
+ draw.SimpleText("("..owner:ClippedName()..")", "ZS3D2DFont2Small", 0, 40, owner == MySelf and COLOR_BLUE or COLOR_GRAY, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM)
+ end
+
+ cam.End3D2D()
+end
+
+function ENT:Draw()
+ self:DrawModel()
+
+ if not MySelf:IsValid() then return end
+
+ local owner = self:GetObjectOwner()
+ local ang = self:LocalToWorldAngles(aOffset)
+
+ self:RenderInfo(self:LocalToWorld(vOffset), ang, owner)
+ self:RenderInfo(self:LocalToWorld(vOffset2), self:LocalToWorldAngles(aOffset2), owner)
+
+ cam.Start3D2D(self:LocalToWorld(vOffsetEE), ang, 0.01)
+
+ draw.SimpleText("ur a faget", "ZS3D2DFont2", 0, 0, color_white, TEXT_ALIGN_CENTER)
+
+ cam.End3D2D()
+end
+
+net.Receive("zs_nextresupplyuse", function(length)
+ NextUse = net.ReadFloat()
+end)
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_resupplybox/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_resupplybox/init.lua
new file mode 100644
index 0000000..9c61bd0
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_resupplybox/init.lua
@@ -0,0 +1,163 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+local function RefreshCrateOwners(pl)
+ for _, ent in pairs(ents.FindByClass("prop_resupplybox")) do
+ if ent:IsValid() and ent:GetObjectOwner() == pl then
+ ent:SetObjectOwner(NULL)
+ end
+ end
+end
+hook.Add("PlayerDisconnected", "ResupplyBox.PlayerDisconnected", RefreshCrateOwners)
+hook.Add("OnPlayerChangedTeam", "ResupplyBox.OnPlayerChangedTeam", RefreshCrateOwners)
+
+function ENT:Initialize()
+ self:SetModel("models/Items/ammocrate_ar2.mdl")
+ self:PhysicsInit(SOLID_VPHYSICS)
+ self:SetUseType(SIMPLE_USE)
+ self:SetPlaybackRate(1)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:EnableMotion(false)
+ end
+
+ self:SetMaxObjectHealth(200)
+ self:SetObjectHealth(self:GetMaxObjectHealth())
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "maxcratehealth" then
+ value = tonumber(value)
+ if not value then return end
+
+ self:SetMaxObjectHealth(value)
+ elseif key == "cratehealth" then
+ value = tonumber(value)
+ if not value then return end
+
+ self:SetObjectHealth(value)
+ end
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ if name == "setcratehealth" then
+ self:KeyValue("cratehealth", args)
+ return true
+ elseif name == "setmaxcratehealth" then
+ self:KeyValue("maxcratehealth", args)
+ return true
+ end
+end
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+ if health <= 0 and not self.Destroyed then
+ self.Destroyed = true
+
+ local ent = ents.Create("prop_physics")
+ if ent:IsValid() then
+ ent:SetModel(self:GetModel())
+ ent:SetMaterial(self:GetMaterial())
+ ent:SetAngles(self:GetAngles())
+ ent:SetPos(self:GetPos())
+ ent:SetSkin(self:GetSkin() or 0)
+ ent:SetColor(self:GetColor())
+ ent:Spawn()
+ ent:Fire("break", "", 0)
+ ent:Fire("kill", "", 0.1)
+ end
+ end
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ self:TakePhysicsDamage(dmginfo)
+
+ local attacker = dmginfo:GetAttacker()
+ if not (attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_HUMAN) then
+ self:SetObjectHealth(self:GetObjectHealth() - dmginfo:GetDamage())
+ self:ResetLastBarricadeAttacker(attacker, dmginfo)
+ end
+end
+
+function ENT:AltUse(activator, tr)
+ self:PackUp(activator)
+end
+
+function ENT:OnPackedUp(pl)
+ pl:GiveEmptyWeapon("weapon_zs_resupplybox")
+ pl:GiveAmmo(1, "helicoptergun")
+
+ pl:PushPackedItem(self:GetClass(), self:GetObjectHealth())
+
+ self:Remove()
+end
+
+function ENT:Think()
+ if self.Destroyed then
+ self:Remove()
+ elseif self.Close and CurTime() >= self.Close then
+ self.Close = nil
+ self:ResetSequence("open")
+ self:EmitSound("items/ammocrate_close.wav")
+ end
+end
+
+local NextUse = {}
+function ENT:Use(activator, caller)
+ if activator:Team() ~= TEAM_HUMAN or not activator:Alive() or GAMEMODE:GetWave() <= 0 then return end
+
+ if not self:GetObjectOwner():IsValid() then
+ self:SetObjectOwner(activator)
+ end
+
+ local owner = self:GetObjectOwner()
+ local owneruid = owner:IsValid() and owner:UniqueID() or "nobody"
+ local myuid = activator:UniqueID()
+
+ if CurTime() < (NextUse[myuid] or 0) then
+ activator:CenterNotify(COLOR_RED, translate.ClientGet(activator, "no_ammo_here"))
+ return
+ end
+
+ local ammotype
+ local wep = activator:GetActiveWeapon()
+ if not wep:IsValid() then
+ ammotype = "smg1"
+ end
+
+ if not ammotype then
+ ammotype = wep:GetPrimaryAmmoTypeString()
+ if not GAMEMODE.AmmoResupply[ammotype] then
+ ammotype = "smg1"
+ end
+ end
+
+ NextUse[myuid] = CurTime() + 120
+
+ net.Start("zs_nextresupplyuse")
+ net.WriteFloat(NextUse[myuid])
+ net.Send(activator)
+
+ activator:GiveAmmo(GAMEMODE.AmmoResupply[ammotype], ammotype)
+ if activator ~= owner and owner:IsValid() and owner:IsPlayer() and owner:Team() == TEAM_HUMAN then
+ owner.ResupplyBoxUsedByOthers = owner.ResupplyBoxUsedByOthers + 1
+
+ owner:AddPoints(1)
+
+ net.Start("zs_commission")
+ net.WriteEntity(self)
+ net.WriteEntity(activator)
+ net.WriteUInt(1, 16)
+ net.Send(owner)
+ end
+
+ if not self.Close then
+ self:ResetSequence("close")
+ self:EmitSound("items/ammocrate_open.wav")
+ end
+ self.Close = CurTime() + 3
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_resupplybox/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_resupplybox/shared.lua
new file mode 100644
index 0000000..f87ff47
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_resupplybox/shared.lua
@@ -0,0 +1,54 @@
+ENT.Type = "anim"
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+ENT.m_NoNailUnfreeze = true
+ENT.NoNails = true
+
+ENT.CanPackUp = true
+
+ENT.IsBarricadeObject = true
+ENT.AlwaysGhostable = true
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+ if health <= 0 and not self.Destroyed then
+ self.Destroyed = true
+
+ local ent = ents.Create("prop_physics")
+ if ent:IsValid() then
+ ent:SetModel(self:GetModel())
+ ent:SetMaterial(self:GetMaterial())
+ ent:SetAngles(self:GetAngles())
+ ent:SetPos(self:GetPos())
+ ent:SetSkin(self:GetSkin() or 0)
+ ent:SetColor(self:GetColor())
+ ent:Spawn()
+ ent:Fire("break", "", 0)
+ ent:Fire("kill", "", 0.1)
+ end
+ end
+end
+
+function ENT:GetObjectHealth()
+ return self:GetDTFloat(0)
+end
+
+function ENT:SetMaxObjectHealth(health)
+ self:SetDTFloat(1, health)
+end
+
+function ENT:GetMaxObjectHealth()
+ return self:GetDTFloat(1)
+end
+
+function ENT:SetObjectOwner(ent)
+ self:SetDTEntity(0, ent)
+end
+
+function ENT:GetObjectOwner()
+ return self:GetDTEntity(0)
+end
+
+function ENT:ClearObjectOwner()
+ self:SetObjectOwner(NULL)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_spotlamp/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_spotlamp/cl_init.lua
new file mode 100644
index 0000000..13580a3
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_spotlamp/cl_init.lua
@@ -0,0 +1,42 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:SetRenderBounds(Vector(-72, -72, -72), Vector(72, 72, 128))
+
+ self.PixVis = util.GetPixelVisibleHandle()
+end
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+end
+
+local matLight = Material("sprites/light_ignorez")
+function ENT:DrawTranslucent()
+ self:DrawModel()
+
+ local epos = self:GetSpotLightPos()
+ local LightNrm = self:GetSpotLightAngles():Forward()
+ local ViewNormal = epos - EyePos()
+ local Distance = ViewNormal:Length()
+ ViewNormal:Normalize()
+ local ViewDot = ViewNormal:Dot( LightNrm * -1 )
+
+ if ViewDot >= 0 then
+ local LightPos = epos + LightNrm * 5
+
+ render.SetMaterial(matLight)
+ local Visibile = util.PixelVisible( LightPos, 16, self.PixVis )
+
+ if not Visibile then return end
+
+ local Size = math.Clamp(Distance * Visibile * ViewDot * 1.8, 40, 420)
+
+ Distance = math.Clamp(Distance, 32, 800)
+ local Alpha = math.Clamp((1000 - Distance) * Visibile * ViewDot, 0, 100)
+ local Col = self:GetColor()
+ Col.a = Alpha
+
+ render.DrawSprite(LightPos, Size, Size, Col, Visibile * ViewDot)
+ render.DrawSprite(LightPos, Size*0.4, Size*0.4, Color(255, 255, 255, Alpha), Visibile * ViewDot)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_spotlamp/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_spotlamp/init.lua
new file mode 100644
index 0000000..c999a9d
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_spotlamp/init.lua
@@ -0,0 +1,107 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+local function RefreshCrateOwners(pl)
+ for _, ent in pairs(ents.FindByClass("prop_spotlamp")) do
+ if ent:IsValid() and ent:GetObjectOwner() == pl then
+ ent:SetObjectOwner(NULL)
+ end
+ end
+end
+hook.Add("PlayerDisconnected", "SpotLamp.PlayerDisconnected", RefreshCrateOwners)
+hook.Add("OnPlayerChangedTeam", "SpotLamp.OnPlayerChangedTeam", RefreshCrateOwners)
+
+function ENT:Initialize()
+ self:SetModel("models/props_combine/combine_light001a.mdl")
+ self:PhysicsInit(SOLID_VPHYSICS)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:EnableMotion(false)
+ end
+
+ self:SetMaxObjectHealth(100)
+ self:SetObjectHealth(self:GetMaxObjectHealth())
+
+ local ent = ents.Create("env_projectedtexture")
+ if ent:IsValid() then
+ ent:SetPos(self:GetSpotLightPos())
+ ent:SetAngles(self:GetSpotLightAngles())
+ ent:SetKeyValue("enableshadows", 0)
+ ent:SetKeyValue("farz", 1500)
+ ent:SetKeyValue("nearz", 8)
+ ent:SetKeyValue("lightfov", 50)
+ ent:SetKeyValue("lightcolor", "200 220 255 255")
+ ent:SetParent(self)
+ ent:Spawn()
+ ent:Input("SpotlightTexture", NULL, NULL, "effects/flashlight001")
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "maxobjecthealth" then
+ value = tonumber(value)
+ if not value then return end
+
+ self:SetMaxObjectHealth(value)
+ elseif key == "objecthealth" then
+ value = tonumber(value)
+ if not value then return end
+
+ self:SetObjectHealth(value)
+ end
+end
+
+function ENT:AcceptInput(name, activator, caller, args)
+ if name == "setobjecthealth" then
+ self:KeyValue("objecthealth", args)
+ return true
+ elseif name == "setmaxobjecthealth" then
+ self:KeyValue("maxobjecthealth", args)
+ return true
+ end
+end
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+
+ if health <= 0 and not self.Destroyed then
+ self.Destroyed = true
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(self:LocalToWorld(self:OBBCenter()))
+ util.Effect("Explosion", effectdata, true, true)
+ end
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ self:TakePhysicsDamage(dmginfo)
+
+ local attacker = dmginfo:GetAttacker()
+ if not (attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_HUMAN) then
+ self:SetObjectHealth(self:GetObjectHealth() - dmginfo:GetDamage())
+ self:ResetLastBarricadeAttacker(attacker, dmginfo)
+ end
+end
+
+function ENT:AltUse(activator, tr)
+ self:PackUp(activator)
+end
+
+function ENT:OnPackedUp(pl)
+ pl:GiveEmptyWeapon("weapon_zs_spotlamp")
+ pl:GiveAmmo(1, "spotlamp")
+
+ pl:PushPackedItem(self:GetClass(), self:GetObjectHealth())
+
+ self:Remove()
+end
+
+function ENT:Think()
+ if self.Destroyed then
+ self:Remove()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_spotlamp/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_spotlamp/shared.lua
new file mode 100644
index 0000000..2a6a85b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_spotlamp/shared.lua
@@ -0,0 +1,52 @@
+ENT.Type = "anim"
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+ENT.m_NoNailUnfreeze = true
+ENT.NoNails = true
+
+ENT.CanPackUp = true
+
+ENT.IsBarricadeObject = true
+ENT.AlwaysGhostable = true
+
+function ENT:SetObjectHealth(health)
+ self:SetDTFloat(0, health)
+
+ if health <= 0 and not self.Destroyed then
+ self.Destroyed = true
+ end
+end
+
+function ENT:GetObjectHealth()
+ return self:GetDTFloat(0)
+end
+
+function ENT:SetMaxObjectHealth(health)
+ self:SetDTFloat(1, health)
+end
+
+function ENT:GetMaxObjectHealth()
+ return self:GetDTFloat(1)
+end
+
+function ENT:SetObjectOwner(ent)
+ self:SetDTEntity(0, ent)
+end
+
+function ENT:GetObjectOwner()
+ return self:GetDTEntity(0)
+end
+
+function ENT:ClearObjectOwner()
+ self:SetObjectOwner(NULL)
+end
+
+function ENT:GetSpotLightPos()
+ return self:LocalToWorld(Vector(-2, 0, 15))
+end
+
+function ENT:GetSpotLightAngles()
+ local ang = self:GetAngles()
+ ang:RotateAroundAxis(ang:Up(), 180)
+ return ang
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_thrownbaby/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_thrownbaby/cl_init.lua
new file mode 100644
index 0000000..7187b13
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_thrownbaby/cl_init.lua
@@ -0,0 +1,9 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:SetModelScale(1.3, 0)
+end
+
+function ENT:Draw()
+ self:DrawModel()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_thrownbaby/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_thrownbaby/init.lua
new file mode 100644
index 0000000..2aa75d8
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_thrownbaby/init.lua
@@ -0,0 +1,66 @@
+AddCSLuaFile("shared.lua")
+AddCSLuaFile("cl_init.lua")
+
+include("shared.lua")
+
+ENT.m_IsProjectile = true -- Quick fix to stop people being able to use this as ammo to prop kill.
+
+function ENT:Initialize()
+ self:SetModel("models/props_c17/doll01.mdl")
+ self:PhysicsInit(SOLID_VPHYSICS) --self:PhysicsInitBox(Vector(-10.8, -10.8, -10.8), Vector(10.8, 10.8, 10.8))
+ self:SetModelScale(1.3, 0)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMass(10)
+ phys:EnableMotion(true)
+ phys:Wake()
+ end
+
+ self:Fire("kill", "", 20)
+end
+
+function ENT:Think()
+ if not self:GetSettled() and CurTime() >= self:GetCreationTime() + 0.25 and self:GetVelocity():Length() <= 16 then
+ self:SetSettled(true)
+ self:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
+ end
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ local attacker = dmginfo:GetAttacker()
+ if dmginfo:GetDamage() >= 1 and not (attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_UNDEAD) then
+ self:Destroy()
+ end
+end
+
+function ENT:Destroy()
+ if self.Destroyed then return end
+ self.Destroyed = true
+
+ util.Blood(self:GetPos(), 5, Vector(0, 0, 1), 100, true)
+
+ self:Fire("kill", "", 0.01)
+end
+
+function ENT:OnRemove()
+ if self.Destroyed then
+ self:EmitSound("ambient/voices/citizen_beaten"..math.random(5)..".wav", 70, math.random(140, 150))
+
+ local ent = ents.Create("fakedeath")
+ if ent:IsValid() then
+ ent:SetModel("models/vinrax/player/doll_player.mdl")
+ ent:SetPos(self:GetPos() + Vector(0, 0, 8))
+ ent:Spawn()
+ ent:SetModelScale(0.4, 0)
+
+ ent:SetDeathSequence(ent:LookupSequence("death_0"..math.random(4)) or 1)
+ ent:SetDeathAngles(Angle(0, math.Rand(0, 360), 0))
+ ent:SetDeathSequenceLength(1)
+ end
+ end
+end
+
+function ENT:UpdateTransmitState()
+ return TRANSMIT_ALWAYS
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_thrownbaby/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_thrownbaby/shared.lua
new file mode 100644
index 0000000..6f99f53
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_thrownbaby/shared.lua
@@ -0,0 +1,5 @@
+ENT.Type = "anim"
+
+ENT.NoNails = true
+
+AccessorFuncDT(ENT, "Settled", "Bool", 0)
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_weapon/cl_animations.lua b/gamemodes/zombiesurvival/entities/entities/prop_weapon/cl_animations.lua
new file mode 100644
index 0000000..c0357f1
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_weapon/cl_animations.lua
@@ -0,0 +1,176 @@
+function ENT:RenderModels()
+ if not self.WElements then return end
+
+ if not self.wRenderOrder then
+ self.wRenderOrder = {}
+ for k, v in pairs( self.WElements ) do
+ if (v.type == "Model") then
+ table.insert(self.wRenderOrder, 1, k)
+ elseif (v.type == "Sprite" or v.type == "Quad") then
+ table.insert(self.wRenderOrder, k)
+ end
+ end
+ end
+
+ for k, name in pairs( self.wRenderOrder ) do
+ local v = self.WElements[name]
+ if (!v) then self.wRenderOrder = nil break end
+ if (v.hide) then continue end
+
+ local pos, ang
+
+ if (v.bone) then
+ pos, ang = self:GetBoneOrientation( self.WElements, v )
+ else
+ pos, ang = self:GetBoneOrientation( self.WElements, v, "ValveBiped.Bip01_R_Hand" )
+ end
+
+ if (!pos) then continue end
+
+ local model = v.modelEnt
+ local sprite = v.spriteMaterial
+
+ if (v.type == "Model" and IsValid(model)) then
+ model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ model:SetAngles(ang)
+ //model:SetModelScale(v.size)
+ local matrix = Matrix()
+ matrix:Scale(v.size)
+ model:EnableMatrix( "RenderMultiply", matrix )
+
+ if (v.material == "") then
+ model:SetMaterial("")
+ elseif (model:GetMaterial() != v.material) then
+ model:SetMaterial( v.material )
+ end
+
+ if (v.skin and v.skin != model:GetSkin()) then
+ model:SetSkin(v.skin)
+ end
+
+ if (v.bodygroup) then
+ for k, v in pairs( v.bodygroup ) do
+ if (model:GetBodygroup(k) != v) then
+ model:SetBodygroup(k, v)
+ end
+ end
+ end
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(true)
+ end
+
+ render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
+ render.SetBlend(v.color.a/255)
+ model:DrawModel()
+ render.SetBlend(1)
+ render.SetColorModulation(1, 1, 1)
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(false)
+ end
+ elseif (v.type == "Sprite" and sprite) then
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ render.SetMaterial(sprite)
+ render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
+ elseif (v.type == "Quad" and v.draw_func) then
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ cam.Start3D2D(drawpos, ang, v.size)
+ v.draw_func( self )
+ cam.End3D2D()
+ end
+ end
+ end
+
+function ENT:GetBoneOrientation( basetab, tab, bone_override )
+ local bone, pos, ang
+ if (tab.rel and tab.rel != "") then
+
+ local v = basetab[tab.rel]
+
+ if (!v) then return end
+
+ // Technically, if there exists an element with the same name as a bone
+ // you can get in an infinite loop. Let's just hope nobody's that stupid.
+ pos, ang = self:GetBoneOrientation( basetab, v )
+
+ if (!pos) then return end
+
+ pos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ else
+
+ bone = self:LookupBone(bone_override or tab.bone)
+
+ if (!bone) then return end
+
+ pos, ang = Vector(0,0,0), Angle(0,0,0)
+ local m = self:GetBoneMatrix(bone)
+ if (m) then
+ pos, ang = m:GetTranslation(), m:GetAngles()
+ end
+ end
+
+ return pos, ang
+end
+
+function ENT:CreateModels( tab )
+ if (!tab) then return end
+
+ for k, v in pairs( tab ) do
+ if (v.type == "Model" and v.model and v.model != "" and (!IsValid(v.modelEnt) or v.createdModel != v.model) and
+ string.find(v.model, ".mdl") and file.Exists (v.model, "GAME") ) then
+
+ v.modelEnt = ClientsideModel(v.model, RENDER_GROUP_VIEW_MODEL_OPAQUE)
+ if (IsValid(v.modelEnt)) then
+ v.modelEnt:SetPos(self:GetPos())
+ v.modelEnt:SetAngles(self:GetAngles())
+ v.modelEnt:SetParent(self)
+ v.modelEnt:SetNoDraw(true)
+ v.createdModel = v.model
+ else
+ v.modelEnt = nil
+ end
+ elseif (v.type == "Sprite" and v.sprite and v.sprite != "" and (!v.spriteMaterial or v.createdSprite != v.sprite)
+ and file.Exists ("materials/"..v.sprite..".vmt", "GAME")) then
+
+ local name = v.sprite.."-"
+ local params = { ["$basetexture"] = v.sprite }
+ // make sure we create a unique name based on the selected options
+ local tocheck = { "nocull", "additive", "vertexalpha", "vertexcolor", "ignorez" }
+ for i, j in pairs( tocheck ) do
+ if (v[j]) then
+ params["$"..j] = 1
+ name = name.."1"
+ else
+ name = name.."0"
+ end
+ end
+
+ v.createdSprite = v.sprite
+ v.spriteMaterial = CreateMaterial(name,"UnlitGeneric",params)
+ end
+ end
+end
+
+function ENT:RemoveModels()
+ if (self.WElements) then
+ for k, v in pairs( self.WElements ) do
+ if (IsValid( v.modelEnt )) then
+ v.modelEnt:Remove()
+ v.modelEnt = nil
+ end
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_weapon/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/prop_weapon/cl_init.lua
new file mode 100644
index 0000000..8e9f16d
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_weapon/cl_init.lua
@@ -0,0 +1,38 @@
+include("shared.lua")
+include("cl_animations.lua")
+
+ENT.ColorModulation = Color(0.15, 0.8, 1)
+
+function ENT:Think()
+ local class = self:GetWeaponType()
+ if class ~= self.LastWeaponType then
+ self.LastWeaponType = class
+
+ self:RemoveModels()
+ self.ShowWorldModel = nil
+
+ local weptab = weapons.GetStored(class)
+ if weptab then
+ self.ShowWorldModel = not weptab.NoDroppedWorldModel
+
+ if weptab.WElements then
+ self.WElements = table.FullCopy(weptab.WElements)
+ self:CreateModels(self.WElements)
+ end
+ end
+ end
+end
+
+function ENT:DrawTranslucent()
+ if not self.NoDrawSubModels then
+ self:RenderModels()
+ end
+
+ if self.ShowWorldModel == nil or self.ShowWorldModel then
+ self.BaseClass.DrawTranslucent(self)
+ end
+end
+
+function ENT:OnRemove()
+ self:RemoveModels()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_weapon/init.lua b/gamemodes/zombiesurvival/entities/entities/prop_weapon/init.lua
new file mode 100644
index 0000000..d8ea275
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_weapon/init.lua
@@ -0,0 +1,115 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+AddCSLuaFile("cl_animations.lua")
+
+include("shared.lua")
+
+ENT.CleanupPriority = 1
+
+function ENT:Initialize()
+ self.m_Health = 200
+
+ local weptab = weapons.GetStored(self:GetWeaponType())
+ if weptab and not weptab.BoxPhysicsMax then
+ self:PhysicsInit(SOLID_VPHYSICS)
+ end
+ self:SetSolid(SOLID_VPHYSICS)
+ self:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
+
+ self:SetUseType(SIMPLE_USE)
+
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMaterial("material")
+ phys:EnableMotion(true)
+ phys:Wake()
+ end
+
+ self:ItemCreated()
+end
+
+function ENT:SetClip1(ammo)
+ self.m_Clip1 = tonumber(ammo) or self:GetClip1()
+end
+
+function ENT:GetClip1()
+ return self.m_Clip1 or 0
+end
+
+function ENT:SetClip2(ammo)
+ self.m_Clip2 = tonumber(ammo) or self:GetClip2()
+end
+
+function ENT:GetClip2()
+ return self.m_Clip2 or 0
+end
+
+function ENT:SetShouldRemoveAmmo(bool)
+ self.m_DontRemoveAmmo = not bool
+end
+
+function ENT:GetShouldRemoveAmmo()
+ return not self.m_DontRemoveAmmo
+end
+
+function ENT:Use(activator, caller)
+ if not activator:IsPlayer()
+ or not activator:Alive()
+ or activator:Team() ~= TEAM_HUMAN
+ or self.Removing
+ or activator:KeyDown(GAMEMODE.UtilityKey)
+ or self.NoPickupsTime and CurTime() < self.NoPickupsTime and self.NoPickupsOwner ~= activator then return end
+
+ local weptype = self:GetWeaponType()
+ if not weptype then return end
+
+ if activator:HasWeapon(weptype) and not GAMEMODE.MaxWeaponPickups then
+ local wep = activator:GetWeapon(weptype)
+ if wep:IsValid() then
+ local primary = wep:ValidPrimaryAmmo()
+ local secondary = wep:ValidSecondaryAmmo()
+
+ if primary then activator:GiveAmmo(self:GetClip1(), primary) self:SetClip1(0) end
+ if secondary then activator:GiveAmmo(self:GetClip2(), secondary) self:SetClip2(0) end
+
+ local stored = weapons.GetStored(weptype)
+ if stored and stored.AmmoIfHas then
+ self:RemoveNextFrame()
+ end
+
+ return
+ end
+ end
+
+ if not self.PlacedInMap or not GAMEMODE.MaxWeaponPickups or (activator.WeaponPickups or 0) < GAMEMODE.MaxWeaponPickups or team.NumPlayers(TEAM_HUMAN) <= 1 then
+ local wep = self.PlacedInMap and activator:Give(weptype) or activator:GiveEmptyWeapon(weptype)
+ if wep and wep:IsValid() and wep:GetOwner():IsValid() then
+ if self:GetShouldRemoveAmmo() then
+ wep:SetClip1(self:GetClip1())
+ wep:SetClip2(self:GetClip2())
+ end
+
+ activator.WeaponPickups = (activator.WeaponPickups or 0) + 1
+
+ self:RemoveNextFrame()
+ end
+ else
+ activator:CenterNotify(COLOR_RED, translate.ClientGet(activator, "you_decide_to_leave_some"))
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "weapontype" then
+ self:SetWeaponType(value)
+ end
+end
+
+function ENT:OnTakeDamage(dmginfo)
+ self:TakePhysicsDamage(dmginfo)
+
+ self.m_Health = self.m_Health - dmginfo:GetDamage()
+ if self.m_Health <= 0 then
+ self:RemoveNextFrame()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/prop_weapon/shared.lua b/gamemodes/zombiesurvival/entities/entities/prop_weapon/shared.lua
new file mode 100644
index 0000000..6092e67
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/prop_weapon/shared.lua
@@ -0,0 +1,39 @@
+ENT.Type = "anim"
+ENT.Base = "prop_baseoutlined"
+
+ENT.NoNails = true
+
+function ENT:HumanHoldable(pl)
+ return pl:KeyDown(GAMEMODE.UtilityKey) or (pl:HasWeapon(self:GetWeaponType()) and self:GetClip1() == 0 and self:GetClip2() == 0)
+end
+
+function ENT:SetWeaponType(class)
+ local weptab = weapons.GetStored(class)
+ if weptab then
+ if weptab.WorldModel then
+ self:SetModel(weptab.WorldModel)
+ elseif weptab.Base then
+ local weptabb = weapons.GetStored(weptab.Base)
+ if weptabb and weptabb.WorldModel then
+ self:SetModel(weptabb.WorldModel)
+ end
+ end
+
+ if SERVER and weptab.BoxPhysicsMax then
+ self:PhysicsInitBox(weptab.BoxPhysicsMin, weptab.BoxPhysicsMax)
+ self:SetCollisionBounds(weptab.BoxPhysicsMin, weptab.BoxPhysicsMax)
+ self:SetSolid(SOLID_VPHYSICS)
+ self:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
+ end
+
+ if weptab.ModelScale then
+ self:SetModelScale(weptab.ModelScale, 0)
+ end
+ end
+
+ self:SetDTString(0, class)
+end
+
+function ENT:GetWeaponType()
+ return self:GetDTString(0)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status__base/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status__base/cl_init.lua
new file mode 100644
index 0000000..4bb9f12
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status__base/cl_init.lua
@@ -0,0 +1,28 @@
+include("shared.lua")
+
+function ENT:Draw()
+end
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetRenderBounds(Vector(-40, -40, -18), Vector(40, 40, 80))
+
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ owner[self:GetClass()] = self
+ end
+
+ self:OnInitialize()
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if owner:IsValid() then self:SetPos(owner:EyePos()) end
+end
+
+function ENT:OnRemove()
+ local owner = self:GetOwner()
+ if owner:IsValid() and owner[self:GetClass()] == self then
+ owner[self:GetClass()] = nil
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status__base/init.lua b/gamemodes/zombiesurvival/entities/entities/status__base/init.lua
new file mode 100644
index 0000000..2cc5124
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status__base/init.lua
@@ -0,0 +1,69 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self.DieTime = self.DieTime or 0
+
+ self:OnInitialize()
+end
+
+function ENT:SetPlayer(pPlayer, bExists)
+ if bExists then
+ self:PlayerSet(pPlayer, bExists)
+ else
+ local bValid = pPlayer and pPlayer:IsValid()
+ if bValid then
+ self:SetPos(pPlayer:GetPos() + Vector(0,0,16))
+ end
+ self.Owner = pPlayer
+ pPlayer[self:GetClass()] = self
+ self:SetOwner(pPlayer)
+ self:SetParent(pPlayer)
+ if bValid then
+ self:PlayerSet(pPlayer)
+ end
+ end
+end
+
+function ENT:PlayerSet(pPlayer, bExists)
+end
+
+function ENT:Think()
+ -- Any kind of active effect.
+
+ if self.DieTime <= CurTime() then
+ self:Remove()
+ end
+end
+
+function ENT:KeyValue(key, value)
+ if key == "dietime" then
+ self:SetDie(tonumber(value))
+ return true
+ end
+end
+
+function ENT:PhysicsCollide(data, physobj)
+end
+
+function ENT:Touch(ent)
+end
+
+function ENT:OnRemove()
+ --[[if not self.SilentRemove and self:GetParent():IsValid() then
+ -- Emit death sound
+ end]]
+end
+
+function ENT:SetDie(fTime)
+ if fTime == 0 or not fTime then
+ self.DieTime = 0
+ elseif fTime == -1 then
+ self.DieTime = 999999999
+ else
+ self.DieTime = CurTime() + fTime
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status__base/shared.lua b/gamemodes/zombiesurvival/entities/entities/status__base/shared.lua
new file mode 100644
index 0000000..3d8694a
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status__base/shared.lua
@@ -0,0 +1,21 @@
+ENT.Type = "anim"
+
+function ENT:OnInitialize()
+end
+
+function ENT:PhysicsCollide(data, physobj)
+end
+
+function ENT:StartTouch(ent)
+end
+
+function ENT:Touch(ent)
+end
+
+function ENT:EndTouch(ent)
+end
+
+function ENT:AcceptInput(name, activator, caller)
+end
+
+ENT.GetPlayer = ENT.GetParent
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ambience_wow/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_ambience_wow/cl_init.lua
new file mode 100644
index 0000000..7e430a5
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ambience_wow/cl_init.lua
@@ -0,0 +1,71 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+ENT.NextEmit = 0
+ENT.GlowSize = 32
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+end
+
+local matGlow = Material("sprites/glow04_noz")
+local matRing = Material("Effects/splashwake3")
+function ENT:DrawTranslucent()
+ local pl = self:GetOwner()
+ if not pl:IsValid() then return end
+
+ local wep = pl:GetActiveWeapon()
+ local attackdown = wep:IsValid() and wep.GetAttackDown and wep:GetAttackDown()
+
+ self.GlowSize = math.Approach(self.GlowSize, attackdown and 28 or 16, FrameTime() * 50)
+ local basesize = self.GlowSize
+
+ local pos = pl:GetPos()
+ local time = CurTime()
+
+ local ringsize = basesize * (0.75 + math.max(0, math.sin(time * 2)) ^ 0.75 * 0.6 + math.sin(time * 4) * 0.05)
+ render.SetMaterial(matRing)
+ render.DrawSprite(pos, ringsize, ringsize, color_white)
+
+ render.SetMaterial(matGlow)
+ render.DrawSprite(pos, basesize, basesize, color_white)
+ render.DrawSprite(pos + Vector(math.sin(time * 3) * 4, 0, 0), basesize, basesize, color_white)
+ render.DrawSprite(pos + Vector(0, math.cos(time * 3.5) * 4, 0), basesize, basesize, color_white)
+ render.DrawSprite(pos + Vector(0, 0, math.sin(time * 4) * 4), basesize, basesize, color_white)
+
+ if time >= self.NextEmit then
+ self.NextEmit = time + math.Rand(0.05, 0.25)
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(16, 24)
+
+ local particle = emitter:Add("sprites/glow04_noz", pos)
+ particle:SetVelocity(VectorRand():GetNormalized() * math.Rand(-64, 64))
+ particle:SetDieTime(math.Rand(2, 4))
+ particle:SetStartSize(1)
+ particle:SetEndSize(0)
+ particle:SetStartAlpha(255)
+ particle:SetEndAlpha(255)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-4, 4))
+ particle:SetGravity(Vector(0, 0, -128))
+ particle:SetAirResistance(32)
+ particle:SetCollide(true)
+ particle:SetBounce(0.75)
+
+ emitter:Finish()
+ end
+
+ local dlight = DynamicLight(self:EntIndex())
+ if dlight then
+ dlight.Pos = pos
+ dlight.r = 255
+ dlight.g = 255
+ dlight.b = 255
+ dlight.Brightness = 1
+ dlight.Size = 150
+ dlight.Decay = 300
+ dlight.DieTime = CurTime() + 1
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ambience_wow/init.lua b/gamemodes/zombiesurvival/entities/entities/status_ambience_wow/init.lua
new file mode 100644
index 0000000..6dde495
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ambience_wow/init.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if not (owner:Alive() and owner:Team() == TEAM_UNDEAD and owner:GetZombieClassTable().Name == "Will O' Wisp") then self:Remove() end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ambience_wow/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_ambience_wow/shared.lua
new file mode 100644
index 0000000..40b3860
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ambience_wow/shared.lua
@@ -0,0 +1 @@
+ENT.Type = "anim"
diff --git a/gamemodes/zombiesurvival/entities/entities/status_bleed/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_bleed/cl_init.lua
new file mode 100644
index 0000000..4fd5083
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_bleed/cl_init.lua
@@ -0,0 +1,8 @@
+include("shared.lua")
+
+function ENT:Draw()
+end
+
+function ENT:Initialize()
+ self:GetOwner().Bleed = self
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_bleed/init.lua b/gamemodes/zombiesurvival/entities/entities/status_bleed/init.lua
new file mode 100644
index 0000000..210582d
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_bleed/init.lua
@@ -0,0 +1,29 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:PlayerSet(pPlayer, bExists)
+ pPlayer.Bleed = self
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+
+ if self:GetDamage() <= 0 or owner:Team() == TEAM_UNDEAD then
+ self:Remove()
+ return
+ end
+
+ local dmg = math.Clamp(self:GetDamage(), 1, 2)
+
+ owner:TakeDamage(dmg, self.Damager and self.Damager:IsValid() and self.Damager:IsPlayer() and self.Damager:Team() ~= owner:Team() and self.Damager or owner, self)
+ self:AddDamage(-dmg)
+
+ local dir = VectorRand()
+ dir:Normalize()
+ util.Blood(owner:WorldSpaceCenter(), 3, dir, 32)
+
+ self:NextThink(CurTime() + 1)
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_bleed/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_bleed/shared.lua
new file mode 100644
index 0000000..a5cfd65
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_bleed/shared.lua
@@ -0,0 +1,21 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ if self:GetDTFloat(1) == 0 then
+ self:SetDTFloat(1, CurTime())
+ end
+end
+
+function ENT:AddDamage(damage)
+ self:SetDamage(self:GetDamage() + damage)
+end
+
+function ENT:SetDamage(damage)
+ self:SetDTFloat(0, math.min(50, damage))
+end
+
+function ENT:GetDamage()
+ return self:GetDTFloat(0)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_bonemeshambience/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_bonemeshambience/cl_init.lua
new file mode 100644
index 0000000..b9e5db2
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_bonemeshambience/cl_init.lua
@@ -0,0 +1,29 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_NONE
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+
+ self.AmbientSound = CreateSound(self, "npc/antlion_guard/growl_idle.wav")
+ self.AmbientSound:PlayEx(0.55, 150)
+end
+
+function ENT:OnRemove()
+ self.AmbientSound:Stop()
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ local wep = owner:GetActiveWeapon()
+ if wep:IsValid() and wep.IsSwinging and wep:IsSwinging() then
+ self.AmbientSound:Stop()
+ else
+ self.AmbientSound:PlayEx(0.55, 150 + math.sin(RealTime()))
+ end
+ end
+end
+
+function ENT:Draw()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_bonemeshambience/init.lua b/gamemodes/zombiesurvival/entities/entities/status_bonemeshambience/init.lua
new file mode 100644
index 0000000..cf35381
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_bonemeshambience/init.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if not (owner:Alive() and owner:Team() == TEAM_UNDEAD and owner:GetZombieClassTable().Name == "Bonemesh") then self:Remove() end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_bonemeshambience/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_bonemeshambience/shared.lua
new file mode 100644
index 0000000..40b3860
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_bonemeshambience/shared.lua
@@ -0,0 +1 @@
+ENT.Type = "anim"
diff --git a/gamemodes/zombiesurvival/entities/entities/status_bursterambience/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_bursterambience/cl_init.lua
new file mode 100644
index 0000000..e642ac8
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_bursterambience/cl_init.lua
@@ -0,0 +1,39 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+
+ self.AmbientSound = CreateSound(self, "npc/zombie_poison/pz_breathe_loop2.wav")
+ self.AmbientSound:PlayEx(0.55, 85)
+end
+
+function ENT:OnRemove()
+ self.AmbientSound:Stop()
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ local wep = owner:GetActiveWeapon()
+ if wep:IsValid() and wep.GetCharge and wep:GetCharge() > 0 then
+ self.AmbientSound:Stop()
+ else
+ self.AmbientSound:PlayEx(0.55, 85 + math.sin(RealTime()))
+ end
+ end
+end
+
+function ENT:Draw()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ local wep = owner:GetActiveWeapon()
+ if wep:IsValid() and wep.GetCharge then
+ local charge = wep:GetCharge()
+ if charge > 0 then
+
+ end
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_bursterambience/init.lua b/gamemodes/zombiesurvival/entities/entities/status_bursterambience/init.lua
new file mode 100644
index 0000000..f8f5827
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_bursterambience/init.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if not (owner:Alive() and owner:Team() == TEAM_UNDEAD and owner:GetZombieClassTable().Name == "Burster") then self:Remove() end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_bursterambience/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_bursterambience/shared.lua
new file mode 100644
index 0000000..40b3860
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_bursterambience/shared.lua
@@ -0,0 +1 @@
+ENT.Type = "anim"
diff --git a/gamemodes/zombiesurvival/entities/entities/status_butcherambience/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_butcherambience/cl_init.lua
new file mode 100644
index 0000000..07c3d1f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_butcherambience/cl_init.lua
@@ -0,0 +1,29 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_NONE
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+
+ self.AmbientSound = CreateSound(self, "npc/antlion_guard/growl_idle.wav")
+ self.AmbientSound:PlayEx(0.55, 110)
+end
+
+function ENT:OnRemove()
+ self.AmbientSound:Stop()
+end
+
+function ENT:Think()
+ owner = self:GetOwner()
+ if owner:IsValid() then
+ local wep = owner:GetActiveWeapon()
+ if wep:IsValid() and wep.IsSwinging and wep:IsSwinging() then
+ self.AmbientSound:Stop()
+ else
+ self.AmbientSound:PlayEx(0.6, 100 + math.Rand(-30, 30) + math.sin(RealTime() * 4) * 20)
+ end
+ end
+end
+
+function ENT:Draw()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_butcherambience/init.lua b/gamemodes/zombiesurvival/entities/entities/status_butcherambience/init.lua
new file mode 100644
index 0000000..57baacb
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_butcherambience/init.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if not (owner:Alive() and owner:Team() == TEAM_UNDEAD and owner:GetZombieClassTable().Name == "The Butcher") then self:Remove() end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_butcherambience/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_butcherambience/shared.lua
new file mode 100644
index 0000000..40b3860
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_butcherambience/shared.lua
@@ -0,0 +1 @@
+ENT.Type = "anim"
diff --git a/gamemodes/zombiesurvival/entities/entities/status_chemzombieambience/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_chemzombieambience/cl_init.lua
new file mode 100644
index 0000000..5aec78f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_chemzombieambience/cl_init.lua
@@ -0,0 +1,56 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+ENT.NextEmit = 0
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetRenderBounds(Vector(-40, -40, -18), Vector(40, 40, 90))
+
+ self.AmbientSound = CreateSound(self, "npc/zombie_poison/pz_breathe_loop1.wav")
+ self.AmbientSound:PlayEx(0.67, 100)
+end
+
+function ENT:OnRemove()
+ self.AmbientSound:Stop()
+end
+
+function ENT:Think()
+ self.AmbientSound:PlayEx(0.67, 100 + math.sin(RealTime()))
+end
+
+local matGlow = Material("sprites/glow04_noz")
+local colGlow = Color(0, 255, 0, 255)
+function ENT:DrawTranslucent()
+ local owner = self:GetOwner()
+ if owner:IsValid() and (owner ~= LocalPlayer() or owner:ShouldDrawLocalPlayer()) then
+ local pos = owner:LocalToWorld(owner:OBBCenter())
+ render.SetMaterial(matGlow)
+ render.DrawSprite(pos, math.Rand(64, 72), math.Rand(64, 72), colGlow)
+
+ if self.NextEmit <= CurTime() then
+ self.NextEmit = CurTime() + 0.15
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(32, 48)
+
+ local particle = emitter:Add("particle/smokestack", pos)
+ particle:SetVelocity(owner:GetVelocity() * 0.8)
+ particle:SetDieTime(math.Rand(1, 1.35))
+ particle:SetStartAlpha(220)
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(math.Rand(30, 44))
+ particle:SetEndSize(20)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-3, 3))
+ particle:SetGravity(Vector(0, 0, 125))
+ particle:SetCollide(true)
+ particle:SetBounce(0.45)
+ particle:SetAirResistance(12)
+ particle:SetColor(0, 200, 0)
+
+ emitter:Finish()
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_chemzombieambience/init.lua b/gamemodes/zombiesurvival/entities/entities/status_chemzombieambience/init.lua
new file mode 100644
index 0000000..527b949
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_chemzombieambience/init.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if not (owner:Alive() and owner:Team() == TEAM_UNDEAD and owner:GetZombieClassTable().Name == "Chem Zombie") then self:Remove() end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_chemzombieambience/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_chemzombieambience/shared.lua
new file mode 100644
index 0000000..40b3860
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_chemzombieambience/shared.lua
@@ -0,0 +1 @@
+ENT.Type = "anim"
diff --git a/gamemodes/zombiesurvival/entities/entities/status_confusion/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_confusion/cl_init.lua
new file mode 100644
index 0000000..569d2a8
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_confusion/cl_init.lua
@@ -0,0 +1,42 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ owner.Confusion = self
+ end
+
+ if self:GetStartTime() == 0 then
+ self:SetStartTime(CurTime())
+ end
+
+ if self:GetEndTime() == 0 then
+ self:SetEndTime(CurTime() + 10)
+ end
+end
+
+function ENT:Draw()
+end
+
+function ENT:CalcView(pl, pos, ang, fov, znear, zfar)
+ ang.roll = ang.roll + math.sin(CurTime() * 0.5) * 50 * self:GetPower()
+end
+
+function ENT:RenderScreenSpaceEffects()
+ local power = self:GetPower()
+
+ local time = CurTime() * 1.5
+ local sharpenpower = power * 0.4
+ DrawSharpen(sharpenpower, math.sin(time) * 128)
+ DrawSharpen(sharpenpower, math.cos(time) * 128)
+ DrawMotionBlur(0.1 * power, 4 * power, 0.05)
+end
+
+function ENT:OnRemove()
+ local owner = self:GetOwner()
+ if owner.Confusion == self then
+ owner.Confusion = nil
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_confusion/init.lua b/gamemodes/zombiesurvival/entities/entities/status_confusion/init.lua
new file mode 100644
index 0000000..01668ec
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_confusion/init.lua
@@ -0,0 +1,32 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:PlayerSet(pPlayer, bExists)
+ pPlayer.Confusion = self
+ pPlayer:SetDSP(7)
+
+ if self:GetStartTime() == 0 then
+ self:SetStartTime(CurTime())
+ end
+
+ if self:GetEndTime() == 0 then
+ self:SetEndTime(CurTime() + 10)
+ end
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if CurTime() >= self:GetEndTime() or self.EyeEffect and owner:IsValid() and owner:WaterLevel() >= 3 then
+ self:Remove()
+ end
+end
+
+function ENT:OnRemove()
+ local owner = self:GetOwner()
+ if owner.Confusion == self then
+ owner.Confusion = nil
+ owner:SetDSP(0)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_confusion/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_confusion/shared.lua
new file mode 100644
index 0000000..e34d268
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_confusion/shared.lua
@@ -0,0 +1,28 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+function ENT:SetEndTime(time)
+ self:SetDTFloat(0, time)
+end
+
+function ENT:GetEndTime()
+ return self:GetDTFloat(0)
+end
+
+function ENT:SetStartTime(time)
+ self:SetDTFloat(1, time)
+end
+
+function ENT:GetStartTime()
+ return self:GetDTFloat(1)
+end
+
+function ENT:GetPower()
+ local curtime = CurTime()
+ local power = math.min(1, curtime - self:GetStartTime())
+ if power == 1 then
+ power = math.min(1, self:GetEndTime() - curtime)
+ end
+
+ return power
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_disorientation.lua b/gamemodes/zombiesurvival/entities/entities/status_disorientation.lua
new file mode 100644
index 0000000..a6e07a8
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_disorientation.lua
@@ -0,0 +1,52 @@
+AddCSLuaFile()
+
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+ENT.LifeTime = 3
+
+function ENT:Initialize()
+ self.BaseClass.Initialize(self)
+
+ if CLIENT then
+ hook.Add("CreateMove", self, self.CreateMove)
+ hook.Add("RenderScreenspaceEffects", self, self.RenderScreenspaceEffects)
+
+ self.Seed = math.Rand(0, 10)
+ end
+
+ local parent = self:GetParent()
+ if parent:IsValid() and (SERVER or CLIENT and LocalPlayer() == parent) then
+ parent:SetDSP(35)
+ end
+
+ self.DieTime = CurTime() + self.LifeTime
+end
+
+if SERVER then return end
+
+function ENT:GetPower()
+ return math.Clamp(self.DieTime - CurTime(), 0, 1)
+end
+
+function ENT:CreateMove(cmd)
+ if LocalPlayer() ~= self:GetOwner() then return end
+
+ local curtime = CurTime()
+ local frametime = FrameTime()
+ local power = self:GetPower()
+
+ local ang = cmd:GetViewAngles()
+ ang.pitch = math.Clamp(ang.pitch + math.sin(curtime) * 40 * frametime * power, -89, 89)
+ ang.yaw = math.NormalizeAngle(ang.yaw + math.cos(curtime + self.Seed) * 50 * frametime * power)
+
+ cmd:SetViewAngles(ang)
+end
+
+function ENT:RenderScreenspaceEffects()
+ if LocalPlayer() ~= self:GetOwner() then return end
+
+ local power = self:GetPower()
+
+ DrawMotionBlur(0.1, power, 0.05)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_drown/init.lua b/gamemodes/zombiesurvival/entities/entities/status_drown/init.lua
new file mode 100644
index 0000000..d3360f6
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_drown/init.lua
@@ -0,0 +1,27 @@
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if not owner:IsValid() or not owner:Alive() then return end
+
+ if owner:Team() == TEAM_UNDEAD then self:Remove() return end
+
+ if self:IsUnderwater() then
+ if owner:WaterLevel() < 3 and not (owner.NoAirBrush and owner.NoAirBrush:IsValid()) then
+ self:SetUnderwater(false)
+ end
+ elseif owner:WaterLevel() >= 3 or owner.NoAirBrush and owner.NoAirBrush:IsValid() then
+ self:SetUnderwater(true)
+ end
+
+ if self:IsDrowning() then
+ owner:TakeSpecialDamage(10, DMG_DROWN, game.GetWorld())
+
+ self:NextThink(CurTime() + 1)
+ return true
+ elseif not self:IsUnderwater() and self:GetDrown() == 0 then
+ self:Remove()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_drown/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_drown/shared.lua
new file mode 100644
index 0000000..3896c2d
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_drown/shared.lua
@@ -0,0 +1,48 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+function ENT:SetDrown(drownamount)
+ self:SetDTFloat(0, CurTime())
+ self:SetDTFloat(1, drownamount)
+end
+
+function ENT:SetUnderwater(underwater)
+ self:SetDrown(self:GetDrown())
+
+ self:SetDTBool(0, underwater)
+end
+
+function ENT:GetUnderwater()
+ return self:GetDTBool(0)
+end
+ENT.IsUnderwater = ENT.GetUnderwater
+
+function ENT:GetDrown()
+ if self:IsUnderwater() then
+ return math.Clamp(self:GetDTFloat(1) + (CurTime() - self:GetDTFloat(0)) / self:GetDrownTime(), 0, 1)
+ else
+ return math.Clamp(self:GetDTFloat(1) - (CurTime() - self:GetDTFloat(0)) / self:GetRecoverTime(), 0, 1)
+ end
+end
+
+function ENT:GetDrownTime()
+ local owner = self:GetOwner()
+ if owner:IsValid() and owner:HasWeapon("weapon_zs_oxygentank") then
+ return 300
+ end
+
+ return 30
+end
+
+function ENT:GetRecoverTime()
+ local owner = self:GetOwner()
+ if owner:IsValid() and owner:HasWeapon("weapon_zs_oxygentank") then
+ return 20
+ end
+
+ return 10
+end
+
+function ENT:IsDrowning()
+ return self:GetDrown() == 1 and self:GetUnderwater()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_fastzombieambience/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_fastzombieambience/cl_init.lua
new file mode 100644
index 0000000..b823430
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_fastzombieambience/cl_init.lua
@@ -0,0 +1,29 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_NONE
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+
+ self.AmbientSound = CreateSound(self, "npc/fast_zombie/breathe_loop1.wav")
+ self.AmbientSound:PlayEx(0.55, 100)
+end
+
+function ENT:OnRemove()
+ self.AmbientSound:Stop()
+end
+
+function ENT:Think()
+ owner = self:GetOwner()
+ if owner:IsValid() then
+ local wep = owner:GetActiveWeapon()
+ if wep:IsValid() and (wep.IsSwinging and wep:IsSwinging() or wep.IsRoaring and wep:IsRoaring() or wep.IsClimbing and wep:IsClimbing() or wep.IsPouncing and wep:IsPouncing()) then
+ self.AmbientSound:Stop()
+ else
+ self.AmbientSound:PlayEx(0.55, math.min(60 + owner:GetVelocity():Length2D() * 0.15, 100) + math.sin(RealTime()))
+ end
+ end
+end
+
+function ENT:Draw()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_fastzombieambience/init.lua b/gamemodes/zombiesurvival/entities/entities/status_fastzombieambience/init.lua
new file mode 100644
index 0000000..14cc71f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_fastzombieambience/init.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if not (owner:Alive() and owner:Team() == TEAM_UNDEAD and owner:GetZombieClassTable().Name == "Fast Zombie") then self:Remove() end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_fastzombieambience/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_fastzombieambience/shared.lua
new file mode 100644
index 0000000..40b3860
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_fastzombieambience/shared.lua
@@ -0,0 +1 @@
+ENT.Type = "anim"
diff --git a/gamemodes/zombiesurvival/entities/entities/status_feigndeath/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_feigndeath/cl_init.lua
new file mode 100644
index 0000000..80144a4
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_feigndeath/cl_init.lua
@@ -0,0 +1,70 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+function ENT:OnInitialize()
+ hook.Add("Move", self, self.Move)
+ hook.Add("CreateMove", self, self.CreateMove)
+ hook.Add("ShouldDrawLocalPlayer", self, self.ShouldDrawLocalPlayer)
+
+ self:SetRenderBounds(Vector(-40, -40, -18), Vector(40, 40, 80))
+
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ owner.FeignDeath = self
+ owner.NoCollideAll = true
+
+ self.CommandYaw = owner:GetAngles().yaw
+
+ owner:CallWeaponFunction("KnockedDown", self, false)
+ owner:CallZombieFunction("KnockedDown", self, false)
+ end
+end
+
+function ENT:CreateMove(cmd)
+ if LocalPlayer() ~= self:GetOwner() then return end
+
+ local ang = cmd:GetViewAngles()
+ ang.yaw = self.CommandYaw or ang.yaw
+ cmd:SetViewAngles(ang)
+
+ if bit.band(cmd:GetButtons(), IN_JUMP) ~= 0 then
+ cmd:SetButtons(cmd:GetButtons() - IN_JUMP)
+ end
+end
+
+function ENT:ShouldDrawLocalPlayer(pl)
+ if pl ~= self:GetOwner() then return end
+
+ return true
+end
+
+function ENT:OnRemove()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ owner.FeignDeath = nil
+ owner.NoCollideAll = owner:Team() == TEAM_UNDEAD and owner:GetZombieClassTable().NoCollideAll
+ end
+end
+
+function ENT:DrawTranslucent()
+ local owner = self:GetOwner()
+ if LocalPlayer() ~= owner then return end
+
+ local pos = owner:GetPos() + EyeAngles():Right() * 32
+ local col = table.Copy(COLOR_GRAY)
+ if self:GetState() == 1 then
+ col.a = math.max(self:GetStateEndTime() - CurTime(), 0) * 80
+ else
+ col.a = (1 - math.max(self:GetStateEndTime() - CurTime(), 0)) * 80
+ end
+ local ang = owner:GetAngles()
+ ang.pitch = 0
+ ang.roll = 0
+
+ cam.IgnoreZ(true)
+ cam.Start3D2D(pos, ang, 0.1)
+ draw.SimpleTextBlur(translate.Get("press_sprint_to_get_up"), "ZS3D2DFont2Small", 0, 0, col, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+ cam.End3D2D()
+ cam.IgnoreZ(false)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_feigndeath/init.lua b/gamemodes/zombiesurvival/entities/entities/status_feigndeath/init.lua
new file mode 100644
index 0000000..7f9f8c7
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_feigndeath/init.lua
@@ -0,0 +1,57 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+ENT.NextHeal = 0
+
+function ENT:OnInitialize()
+ hook.Add("Move", self, self.Move)
+end
+
+function ENT:PlayerSet(pPlayer, bExists)
+ pPlayer.FeignDeath = self
+ pPlayer:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
+ pPlayer:AnimResetGestureSlot(GESTURE_SLOT_ATTACK_AND_RELOAD)
+
+ if pPlayer:KeyDown(IN_BACK) then
+ self:SetDirection(DIR_BACK)
+ elseif pPlayer:KeyDown(IN_MOVERIGHT) then
+ self:SetDirection(DIR_RIGHT)
+ elseif pPlayer:KeyDown(IN_MOVELEFT) then
+ self:SetDirection(DIR_LEFT)
+ else
+ self:SetDirection(DIR_FORWARD)
+ end
+end
+
+function ENT:Think()
+ local fCurTime = CurTime()
+ local owner = self:GetOwner()
+
+ if owner:IsValid() then
+ if self:GetStateEndTime() <= fCurTime and self:GetState() == 1 or not owner:Alive() or owner:Team() ~= TEAM_UNDEAD or not owner:GetZombieClassTable().CanFeignDeath then
+ self:Remove()
+ return
+ end
+
+ if fCurTime >= self.NextHeal then
+ self.NextHeal = fCurTime + 0.25
+
+ if owner:Health() < owner:GetMaxHealth() then
+ owner:SetHealth(owner:Health() + 1)
+ end
+ end
+ end
+
+ self:NextThink(fCurTime)
+ return true
+end
+
+function ENT:OnRemove()
+ local parent = self:GetOwner()
+ if parent:IsValid() then
+ parent.FeignDeath = nil
+ parent:TemporaryNoCollide(true)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_feigndeath/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_feigndeath/shared.lua
new file mode 100644
index 0000000..4336829
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_feigndeath/shared.lua
@@ -0,0 +1,33 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+function ENT:Move(pl, move)
+ if pl ~= self:GetOwner() then return end
+
+ move:SetMaxSpeed(0)
+ move:SetMaxClientSpeed(0)
+end
+
+function ENT:SetState(state)
+ self:SetDTInt(0, state)
+end
+
+function ENT:GetState()
+ return self:GetDTInt(0)
+end
+
+function ENT:SetStateEndTime(time)
+ self:SetDTFloat(0, time)
+end
+
+function ENT:GetStateEndTime()
+ return self:GetDTFloat(0)
+end
+
+function ENT:SetDirection(m)
+ self:SetDTInt(1, m)
+end
+
+function ENT:GetDirection()
+ return self:GetDTInt(1)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_arsenalcrate/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_arsenalcrate/cl_init.lua
new file mode 100644
index 0000000..c787a7b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_arsenalcrate/cl_init.lua
@@ -0,0 +1,29 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+function ENT:Think()
+ self:RecalculateValidity()
+
+ self:NextThink(CurTime())
+ return true
+end
+
+function ENT:DrawTranslucent()
+ cam.Start3D(EyePos(), EyeAngles())
+ render.SuppressEngineLighting(true)
+ if self:GetValidPlacement() then
+ render.SetBlend(0.75)
+ render.SetColorModulation(0, 1, 0)
+ else
+ render.SetBlend(0.5)
+ render.SetColorModulation(1, 0, 0)
+ end
+
+ self:DrawModel()
+
+ render.SetBlend(1)
+ render.SetColorModulation(1, 1, 1)
+ render.SuppressEngineLighting(false)
+ cam.End3D()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_arsenalcrate/init.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_arsenalcrate/init.lua
new file mode 100644
index 0000000..8ef309e
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_arsenalcrate/init.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Think()
+ self:RecalculateValidity()
+
+ local owner = self:GetOwner()
+ if not (owner:IsValid() and owner:GetActiveWeapon():IsValid() and owner:GetActiveWeapon():GetClass() == "weapon_zs_arsenalcrate") then
+ self:Remove()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_arsenalcrate/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_arsenalcrate/shared.lua
new file mode 100644
index 0000000..3662a60
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_arsenalcrate/shared.lua
@@ -0,0 +1,87 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+ENT.Model = Model("models/Items/item_item_crate.mdl")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetMaterial("models/wireframe")
+ self:SetModel(self.Model)
+
+ self:RecalculateValidity()
+end
+
+function ENT:IsInsideProp()
+ for _, ent in pairs(ents.FindInBox(self:WorldSpaceAABB())) do
+ if ent ~= self and ent:IsValid() and ent:GetMoveType() == MOVETYPE_VPHYSICS and ent:GetSolid() > 0 then return true end
+ end
+
+ return false
+end
+
+function ENT:RecalculateValidity()
+ local owner = self:GetOwner()
+ if not owner:IsValid() then return end
+
+ if SERVER or MySelf == owner then
+ self:SetRotation(math.NormalizeAngle(owner:GetInfoNum("_zs_ghostrotation", 0)))
+ end
+
+ local rotation = self:GetRotation()
+ local eyeangles = owner:EyeAngles()
+ local shootpos = owner:GetShootPos()
+ local tr = util.TraceLine({start = shootpos, endpos = shootpos + owner:GetAimVector() * 48, mask = MASK_SOLID, filter = owner})
+
+ if tr.HitWorld and not tr.HitSky and tr.HitNormal.z >= 0.75 then
+ eyeangles = tr.HitNormal:Angle()
+ eyeangles:RotateAroundAxis(eyeangles:Right(), 270)
+
+ local valid = true
+ if self:IsInsideProp() then
+ valid = false
+ else
+ for _, ent in pairs(ents.FindInSphere(tr.HitPos, 128)) do
+ if ent:IsValid() and ent:GetClass() == "prop_arsenalcrate" then
+ valid = false
+ break
+ end
+ end
+ end
+
+ if valid and SERVER and GAMEMODE:EntityWouldBlockSpawn(self) then
+ valid = false
+ end
+
+ self:SetValidPlacement(valid)
+ else
+ self:SetValidPlacement(false)
+ end
+
+ if tr.HitNormal.z >= 0.75 then
+ eyeangles:RotateAroundAxis(eyeangles:Up(), owner:GetAngles().yaw + rotation)
+ else
+ eyeangles:RotateAroundAxis(eyeangles:Up(), rotation)
+ end
+
+ local pos, ang = tr.HitPos, eyeangles
+ self:SetPos(pos)
+ self:SetAngles(ang)
+
+ return pos, ang
+end
+
+function ENT:GetValidPlacement()
+ return self:GetDTBool(0)
+end
+
+function ENT:SetValidPlacement(onoff)
+ self:SetDTBool(0, onoff)
+end
+
+function ENT:GetRotation()
+ return self:GetDTFloat(0)
+end
+
+function ENT:SetRotation(rotation)
+ self:SetDTFloat(0, rotation)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_barricadekit/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_barricadekit/cl_init.lua
new file mode 100644
index 0000000..c787a7b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_barricadekit/cl_init.lua
@@ -0,0 +1,29 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+function ENT:Think()
+ self:RecalculateValidity()
+
+ self:NextThink(CurTime())
+ return true
+end
+
+function ENT:DrawTranslucent()
+ cam.Start3D(EyePos(), EyeAngles())
+ render.SuppressEngineLighting(true)
+ if self:GetValidPlacement() then
+ render.SetBlend(0.75)
+ render.SetColorModulation(0, 1, 0)
+ else
+ render.SetBlend(0.5)
+ render.SetColorModulation(1, 0, 0)
+ end
+
+ self:DrawModel()
+
+ render.SetBlend(1)
+ render.SetColorModulation(1, 1, 1)
+ render.SuppressEngineLighting(false)
+ cam.End3D()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_barricadekit/init.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_barricadekit/init.lua
new file mode 100644
index 0000000..864fd6b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_barricadekit/init.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Think()
+ self:RecalculateValidity()
+
+ local owner = self:GetOwner()
+ if not (owner:IsValid() and owner:GetActiveWeapon():IsValid() and owner:GetActiveWeapon():GetClass() == "weapon_zs_barricadekit") then
+ self:Remove()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_barricadekit/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_barricadekit/shared.lua
new file mode 100644
index 0000000..452183b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_barricadekit/shared.lua
@@ -0,0 +1,75 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+ENT.Model = Model("models/props_debris/wood_board05a.mdl")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetMaterial("models/wireframe")
+ self:SetModel(self.Model)
+
+ self:RecalculateValidity()
+end
+
+function ENT:RecalculateValidity()
+ local owner = self:GetOwner()
+ if not owner:IsValid() then
+ self:SetValidPlacement(false)
+ return
+ end
+
+ if SERVER or MySelf == owner then
+ self:SetRotation(math.NormalizeAngle(owner:GetInfoNum("zs_barricadekityaw", 0)))
+ end
+
+ local rotation = self:GetRotation()
+ local eyeangles = owner:EyeAngles()
+ local shootpos = owner:GetShootPos()
+ local tr = util.TraceLine({start = shootpos, endpos = shootpos + owner:GetAimVector() * 32, mask = MASK_SOLID, filter = owner})
+
+ local valid = false
+ if tr.HitWorld and not tr.HitSky then
+ eyeangles = tr.HitNormal:Angle()
+ eyeangles:RotateAroundAxis(eyeangles:Right(), 180)
+
+ valid = true
+ else
+ local vRight = eyeangles:Right() * self:BoundingRadius()
+ local trRight = util.TraceLine({start = tr.HitPos, endpos = tr.HitPos + vRight, mask = MASK_SOLID, filter = owner})
+ local trLeft = util.TraceLine({start = tr.HitPos, endpos = tr.HitPos - vRight, mask = MASK_SOLID, filter = owner})
+
+ valid = trLeft.HitWorld and trRight.HitWorld and not trLeft.HitSky and not trRight.HitSky
+ end
+
+ eyeangles:RotateAroundAxis(eyeangles:Forward(), rotation)
+
+ local pos, ang = tr.HitPos + tr.HitNormal, eyeangles
+ if CLIENT then
+ self:SetPos(pos)
+ self:SetAngles(ang)
+ end
+
+ if valid and SERVER and GAMEMODE:EntityWouldBlockSpawn(self) then
+ valid = false
+ end
+
+ self:SetValidPlacement(valid)
+
+ return pos, ang
+end
+
+function ENT:GetValidPlacement()
+ return self:GetDTBool(0)
+end
+
+function ENT:SetValidPlacement(onoff)
+ self:SetDTBool(0, onoff)
+end
+
+function ENT:GetRotation()
+ return self:GetDTFloat(0)
+end
+
+function ENT:SetRotation(rotation)
+ self:SetDTFloat(0, rotation)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_base/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_base/cl_init.lua
new file mode 100644
index 0000000..dd25212
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_base/cl_init.lua
@@ -0,0 +1,31 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+function ENT:Think()
+ self:RecalculateValidity()
+
+ self:NextThink(CurTime())
+ return true
+end
+
+function ENT:DrawTranslucent()
+ cam.Start3D(EyePos(), EyeAngles())
+ render.SuppressEngineLighting(true)
+ if self:GetValidPlacement() then
+ render.SetBlend(0.75)
+ render.SetColorModulation(0, 1, 0)
+ else
+ render.SetBlend(0.5)
+ render.SetColorModulation(1, 0, 0)
+ end
+
+ self:DrawModel()
+
+ render.SetBlend(1)
+ render.SetColorModulation(1, 1, 1)
+ render.SuppressEngineLighting(false)
+ cam.End3D()
+end
+
+CreateClientConVar("_zs_ghostrotation", 0, false, true)
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_base/init.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_base/init.lua
new file mode 100644
index 0000000..990bb97
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_base/init.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Think()
+ self:RecalculateValidity()
+
+ local owner = self:GetOwner()
+ if not (owner:IsValid() and owner:GetActiveWeapon():IsValid() and owner:GetActiveWeapon():GetClass() == self.GhostWeapon) then
+ self:Remove()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_base/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_base/shared.lua
new file mode 100644
index 0000000..3d2c7ef
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_base/shared.lua
@@ -0,0 +1,119 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+ENT.GhostModel = Model("models/Combine_turrets/Floor_turret.mdl")
+ENT.GhostRotation = Angle(270, 0, 0)
+ENT.GhostEntity = "prop_gunturret"
+ENT.GhostWeapon = "weapon_zs_gunturret"
+ENT.GhostDistance = 64
+ENT.GhostFlatGround = true
+ENT.GhostRotateFunction = "Up"
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetMaterial("models/wireframe") --self:SetMaterial("models/debug/debugwhite")
+ self:SetModel(self.GhostModel)
+
+ self:RecalculateValidity()
+end
+
+function ENT:IsInsideProp()
+ for _, ent in pairs(ents.FindInBox(self:WorldSpaceAABB())) do
+ if ent ~= self and ent:IsValid() and ent:GetMoveType() == MOVETYPE_VPHYSICS and ent:GetSolid() > 0 then return true end
+ end
+
+ return false
+end
+
+-- TODO: Rewrite this so it sets pos before the validation...
+function ENT:RecalculateValidity()
+ local owner = self:GetOwner()
+ if not owner:IsValid() then return end
+
+ if SERVER or MySelf == owner then
+ self:SetRotation(math.NormalizeAngle(owner:GetInfoNum("_zs_ghostrotation", 0)))
+ end
+
+ local rotation = self.GhostNoRotation and 0 or self:GetRotation()
+ local eyeangles = owner:EyeAngles()
+ local shootpos = owner:GetShootPos()
+ local entity
+ local tr = util.TraceLine({start = shootpos, endpos = shootpos + owner:GetAimVector() * 48, mask = MASK_SOLID, filter = owner})
+
+ if tr.HitWorld and not tr.HitSky or tr.HitNonWorld and self.GhostPlaceOnEntities then
+ if self.GhostHitNormalOffset then
+ tr.HitPos = tr.HitPos + tr.HitNormal * self.GhostHitNormalOffset
+ end
+
+ local rot = self.GhostRotation
+ eyeangles = tr.HitNormal:Angle()
+ eyeangles:RotateAroundAxis(eyeangles:Right(), rot.pitch)
+ eyeangles:RotateAroundAxis(eyeangles:Up(), rot.yaw)
+ eyeangles:RotateAroundAxis(eyeangles:Forward(), rot.roll)
+
+ local valid = true
+ if self.GhostLimitedNormal and tr.HitNormal.z < self.GhostLimitedNormal or self:IsInsideProp() then
+ valid = false
+ elseif self.GhostDistance then
+ for _, ent in pairs(ents.FindInSphere(tr.HitPos, self.GhostDistance)) do
+ if ent:IsValid() and ent:GetClass() == self.GhostEntity then
+ valid = false
+ break
+ end
+ end
+ end
+
+ if valid and self.GhostFlatGround and math.abs(tr.HitNormal.z) < 0.75 then
+ local start = tr.HitPos + tr.HitNormal
+ if not util.TraceLine({start = start, endpos = start + Vector(0, 0, -128), mask = MASK_SOLID_BRUSHONLY}).Hit then
+ valid = false
+ end
+ end
+
+ if valid and SERVER and GAMEMODE:EntityWouldBlockSpawn(self) then -- This isn't predicted but why would they be in the zombie spawn...
+ valid = false
+ end
+
+ if valid then
+ valid = self:CustomValidate(tr)
+ end
+
+ entity = tr.Entity
+
+ self:SetValidPlacement(valid)
+ else
+ self:SetValidPlacement(false)
+ end
+
+ if tr.HitNormal.z >= 0.75 then
+ eyeangles:RotateAroundAxis(eyeangles[self.GhostRotateFunction](eyeangles), owner:GetAngles().yaw + rotation)
+ else
+ eyeangles:RotateAroundAxis(eyeangles[self.GhostRotateFunction](eyeangles), rotation)
+ end
+
+ local pos, ang = tr.HitPos, eyeangles
+ self:SetPos(pos)
+ self:SetAngles(ang)
+
+ return pos, ang, entity
+end
+
+function ENT:CustomValidate(tr)
+ return true
+end
+
+function ENT:GetValidPlacement()
+ return self:GetDTBool(0)
+end
+
+function ENT:SetValidPlacement(onoff)
+ self:SetDTBool(0, onoff)
+end
+
+function ENT:GetRotation()
+ return self:GetDTFloat(0)
+end
+
+function ENT:SetRotation(rotation)
+ self:SetDTFloat(0, rotation)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_detpack.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_detpack.lua
new file mode 100644
index 0000000..a69dcc2
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_detpack.lua
@@ -0,0 +1,20 @@
+AddCSLuaFile()
+
+ENT.Type = "anim"
+ENT.Base = "status_ghost_base"
+
+ENT.GhostModel = Model("models/weapons/w_c4_planted.mdl")
+ENT.GhostRotation = Angle(270, 0, 0)
+ENT.GhostEntity = "prop_detpack"
+ENT.GhostWeapon = "weapon_zs_detpack"
+ENT.GhostFlatGround = false
+ENT.GhostDistance = 8
+
+function ENT:CustomValidate(tr)
+ local hitent = tr.Entity
+ if hitent and hitent:IsValid() and hitent:GetClass() ~= "func_tracktrain" and hitent:GetClass() ~= "func_movelinear" then
+ return false
+ end
+
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_ffemitter.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_ffemitter.lua
new file mode 100644
index 0000000..3a152f0
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_ffemitter.lua
@@ -0,0 +1,12 @@
+AddCSLuaFile()
+
+ENT.Type = "anim"
+ENT.Base = "status_ghost_base"
+
+ENT.GhostModel = Model("models/props_lab/lab_flourescentlight002b.mdl")
+ENT.GhostRotation = Angle(0, 0, 0)
+ENT.GhostEntity = "prop_ffemitter"
+ENT.GhostWeapon = "weapon_zs_ffemitter"
+ENT.GhostDistance = 80
+ENT.GhostHitNormalOffset = 2.9
+ENT.GhostRotateFunction = "Forward"
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_gunturret.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_gunturret.lua
new file mode 100644
index 0000000..55bab8c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_gunturret.lua
@@ -0,0 +1,10 @@
+AddCSLuaFile()
+
+ENT.Type = "anim"
+ENT.Base = "status_ghost_base"
+
+ENT.GhostModel = Model("models/Combine_turrets/Floor_turret.mdl")
+ENT.GhostRotation = Angle(270, 0, 0)
+ENT.GhostEntity = "prop_gunturret"
+ENT.GhostWeapon = "weapon_zs_gunturret"
+ENT.GhostDistance = 140
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_messagebeacon/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_messagebeacon/cl_init.lua
new file mode 100644
index 0000000..add2cf4
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_messagebeacon/cl_init.lua
@@ -0,0 +1,31 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+function ENT:Think()
+ self:RecalculateValidity()
+
+ self:NextThink(CurTime())
+ return true
+end
+
+function ENT:DrawTranslucent()
+ self:SetModelScale(0.333, 0)
+
+ cam.Start3D(EyePos(), EyeAngles())
+ render.SuppressEngineLighting(true)
+ if self:GetValidPlacement() then
+ render.SetBlend(0.75)
+ render.SetColorModulation(0, 1, 0)
+ else
+ render.SetBlend(0.5)
+ render.SetColorModulation(1, 0, 0)
+ end
+
+ self:DrawModel()
+
+ render.SetBlend(1)
+ render.SetColorModulation(1, 1, 1)
+ render.SuppressEngineLighting(false)
+ cam.End3D()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_messagebeacon/init.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_messagebeacon/init.lua
new file mode 100644
index 0000000..b53dbfc
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_messagebeacon/init.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Think()
+ self:RecalculateValidity()
+
+ local owner = self:GetOwner()
+ if not (owner:IsValid() and owner:GetActiveWeapon():IsValid() and owner:GetActiveWeapon():GetClass() == "weapon_zs_messagebeacon") then
+ self:Remove()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_messagebeacon/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_messagebeacon/shared.lua
new file mode 100644
index 0000000..d1d81da
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_messagebeacon/shared.lua
@@ -0,0 +1,69 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+ENT.Model = Model("models/props_combine/combine_mine01.mdl")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetMaterial("models/wireframe")
+ self:SetModel(self.Model)
+ self:SetCollisionBounds(Vector(-8.29, -8.29, 0), Vector(8.29, 8.29, 10.13))
+
+ self:RecalculateValidity()
+end
+
+function ENT:IsInsideProp()
+ for _, ent in pairs(ents.FindInBox(self:WorldSpaceAABB())) do
+ if ent ~= self and ent:IsValid() and ent:GetMoveType() == MOVETYPE_VPHYSICS and ent:GetSolid() > 0 then return true end
+ end
+
+ return false
+end
+
+function ENT:RecalculateValidity()
+ local owner = self:GetOwner()
+ if not owner:IsValid() then return end
+
+ local eyeangles = owner:EyeAngles()
+ local shootpos = owner:GetShootPos()
+ local tr = util.TraceLine({start = shootpos, endpos = shootpos + owner:GetAimVector() * 48, mask = MASK_SOLID, filter = owner})
+
+ if tr.HitWorld and not tr.HitSky and tr.HitNormal.z >= 0 then
+ eyeangles = tr.HitNormal:Angle()
+ eyeangles:RotateAroundAxis(eyeangles:Right(), 270)
+
+ local valid = true
+ if self:IsInsideProp() then
+ valid = false
+ else
+ for _, ent in pairs(ents.FindInSphere(tr.HitPos, 48)) do
+ if ent:IsValid() and ent:GetClass() == "prop_messagebeacon" then
+ valid = false
+ break
+ end
+ end
+ end
+
+ if valid and SERVER and GAMEMODE:EntityWouldBlockSpawn(self) then
+ valid = false
+ end
+
+ self:SetValidPlacement(valid)
+ else
+ self:SetValidPlacement(false)
+ end
+
+ local pos, ang = tr.HitPos, eyeangles
+ self:SetPos(pos)
+ self:SetAngles(ang)
+
+ return pos, ang
+end
+
+function ENT:GetValidPlacement()
+ return self:GetDTBool(0)
+end
+
+function ENT:SetValidPlacement(onoff)
+ self:SetDTBool(0, onoff)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_resupplybox.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_resupplybox.lua
new file mode 100644
index 0000000..90ed33a
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_resupplybox.lua
@@ -0,0 +1,12 @@
+AddCSLuaFile()
+
+ENT.Type = "anim"
+ENT.Base = "status_ghost_base"
+
+ENT.GhostModel = Model("models/Items/ammocrate_ar2.mdl")
+ENT.GhostRotation = Angle(270, 0, 0)
+ENT.GhostHitNormalOffset = 12
+ENT.GhostEntity = "prop_resupplybox"
+ENT.GhostWeapon = "weapon_zs_resupplybox"
+ENT.GhostDistance = 64
+ENT.GhostLimitedNormal = 0.75
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ghost_spotlamp.lua b/gamemodes/zombiesurvival/entities/entities/status_ghost_spotlamp.lua
new file mode 100644
index 0000000..a5134bb
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ghost_spotlamp.lua
@@ -0,0 +1,12 @@
+AddCSLuaFile()
+
+ENT.Type = "anim"
+ENT.Base = "status_ghost_base"
+
+ENT.GhostModel = Model("models/props_combine/combine_light001a.mdl")
+ENT.GhostRotation = Angle(270, 180, 0)
+ENT.GhostHitNormalOffset = 0
+ENT.GhostEntity = "prop_spotlamp"
+ENT.GhostWeapon = "weapon_zs_spotlamp"
+ENT.GhostDistance = 200
+ENT.GhostLimitedNormal = 0.75
diff --git a/gamemodes/zombiesurvival/entities/entities/status_headcrabcouple/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_headcrabcouple/cl_init.lua
new file mode 100644
index 0000000..9cca3ce
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_headcrabcouple/cl_init.lua
@@ -0,0 +1,14 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+
+ self:GetOwner().m_Couple = self
+end
+
+function ENT:OnRemove()
+ local owner = self:GetOwner()
+ if owner:IsValid() and owner.m_Couple == self then
+ owner.m_Couple = nil
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_headcrabcouple/init.lua b/gamemodes/zombiesurvival/entities/entities/status_headcrabcouple/init.lua
new file mode 100644
index 0000000..bc0196b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_headcrabcouple/init.lua
@@ -0,0 +1,19 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:PlayerSet(pPlayer, bExists)
+ pPlayer.m_Couple = self
+end
+
+function ENT:Remove()
+ local owner = self:GetOwner()
+ if owner:IsValid() and owner.m_Couple == self then
+ owner:SetBodyGroup(1, 0)
+ owner.m_Couple = nil
+ end
+end
+
+function ENT:Think()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_headcrabcouple/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_headcrabcouple/shared.lua
new file mode 100644
index 0000000..741a7bb
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_headcrabcouple/shared.lua
@@ -0,0 +1,17 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+function ENT:SetPartner(partner)
+ partner = partner or NULL
+
+ self:SetDTEntity(0, partner)
+
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ owner:SetBodyGroup(1, partner:IsValid() and 1 or 0)
+ end
+end
+
+function ENT:GetPartner()
+ return self:GetDTEntity(0)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_healdartboost.lua b/gamemodes/zombiesurvival/entities/entities/status_healdartboost.lua
new file mode 100644
index 0000000..4d1946b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_healdartboost.lua
@@ -0,0 +1,17 @@
+AddCSLuaFile()
+
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+function ENT:Initialize()
+ self.BaseClass.Initialize(self)
+
+ hook.Add("Move", self, self.Move)
+end
+
+function ENT:Move(pl, move)
+ if pl ~= self:GetOwner() then return end
+
+ move:SetMaxSpeed(move:GetMaxSpeed() + 50)
+ move:SetMaxClientSpeed(move:GetMaxSpeed())
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_human_holding/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_human_holding/cl_init.lua
new file mode 100644
index 0000000..fbc32bb
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_human_holding/cl_init.lua
@@ -0,0 +1,67 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+
+ENT.AnimTime = 0.25
+
+function ENT:OnRemove()
+ local owner = self:GetOwner()
+ if owner == MySelf then
+ if self.Rotating then
+ hook.Remove("CreateMove", "HoldingCreateMove")
+ end
+
+ local wep = owner:GetActiveWeapon()
+ if wep:IsValid() then
+ if wep.NoHolsterOnCarry then
+ self.NoHolster = true
+ else
+ wep:SendWeaponAnim(ACT_VM_DRAW)
+ end
+ end
+ end
+
+ self.BaseClass.OnRemove(self)
+end
+
+function ENT:Initialize()
+ hook.Add("Move", self, self.Move)
+
+ self.Created = CurTime()
+
+ if not self.NoHolster then
+ local owner = self:GetOwner()
+ if owner == MySelf then
+ local wep = owner:GetActiveWeapon()
+ if wep:IsValid() then
+ wep:SendWeaponAnim(ACT_VM_HOLSTER)
+ end
+ end
+ end
+
+ self.BaseClass.Initialize(self)
+end
+
+function ENT:Think()
+ if self:GetOwner() ~= MySelf then return end
+
+ if not self.NoHolster then
+ self:SetSequence(2)
+ self:SetCycle(0.68 + math.sin(CurTime() * math.pi) * 0.01)
+ end
+
+ self.BaseClass.Think(self)
+end
+
+function ENT:Draw()
+ if self:GetOwner() ~= MySelf or self.NoHolster or MySelf:ShouldDrawLocalPlayer() then return end
+
+ local pos = EyePos()
+ local ang = EyeAngles()
+
+ pos = pos + -16 * (1 - math.Clamp((CurTime() - self.Created) / self.AnimTime, 0, 1) ^ 0.5) * ang:Up()
+
+ self:SetPos(pos)
+ self:SetAngles(ang)
+ self:DrawModel()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_human_holding/init.lua b/gamemodes/zombiesurvival/entities/entities/status_human_holding/init.lua
new file mode 100644
index 0000000..dcd9268
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_human_holding/init.lua
@@ -0,0 +1,205 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ hook.Add("Move", self, self.Move)
+
+ self:DrawShadow(false)
+
+ local owner = self:GetOwner()
+ if owner:IsValid() and owner:IsPlayer() then
+ owner.status_human_holding = self
+
+ owner:DrawWorldModel(false)
+
+ local info = GAMEMODE:GetHandsModel(owner)
+ if info then
+ self:SetModel(info.model)
+ self:SetSkin(info.skin)
+ self:SetBodyGroups(info.body)
+ end
+
+ local wep = owner:GetActiveWeapon()
+ if wep:IsValid() then
+ wep:SendWeaponAnim(ACT_VM_HOLSTER)
+ if wep.SetIronsights then
+ wep:SetIronsights(false)
+ end
+ end
+ else
+ self:SetModel("models/weapons/c_arms_citizen.mdl")
+ end
+
+ local object = self:GetObject()
+ if object:IsValid() then
+ for _, ent in pairs(ents.FindByClass("logic_pickupdrop")) do
+ if ent.EntityToWatch == object:GetName() and ent:IsValid() then
+ ent:Input("onpickedup", owner, object, "")
+ end
+ end
+
+ local objectphys = object:GetPhysicsObject()
+ if objectphys:IsValid() then
+ objectphys:AddGameFlag(FVPHYSICS_NO_IMPACT_DMG)
+ objectphys:AddGameFlag(FVPHYSICS_NO_NPC_IMPACT_DMG)
+
+ self:SetObjectMass(objectphys:GetMass())
+
+ if owner.BuffMuscular or (objectphys:GetMass() < CARRY_DRAG_MASS and (object:OBBMins():Length() + object:OBBMaxs():Length() < CARRY_DRAG_VOLUME or object.NoVolumeCarryCheck)) then
+ objectphys:AddGameFlag(FVPHYSICS_PLAYER_HELD)
+ object._OriginalMass = objectphys:GetMass()
+
+ objectphys:EnableGravity(false)
+ objectphys:SetMass(2)
+
+ object:SetOwner(owner)
+ else
+ self:SetIsHeavy(true)
+ self:SetHingePos(object:NearestPoint(self:GetPullPos()))
+ end
+
+ object:CollisionRulesChanged()
+ end
+ end
+end
+
+function ENT:OnRemove()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ --owner.status_human_holding = nil
+
+ owner:DrawWorldModel(true)
+
+ if owner:Alive() and owner:Team() ~= TEAM_UNDEAD then
+ local wep = owner:GetActiveWeapon()
+ if wep:IsValid() then
+ wep:SendWeaponAnim(ACT_VM_DRAW)
+ end
+ end
+ end
+
+ local object = self:GetObject()
+ if object:IsValid() then
+ local objectphys = object:GetPhysicsObject()
+ if objectphys:IsValid() then
+ objectphys:ClearGameFlag(FVPHYSICS_PLAYER_HELD)
+ objectphys:ClearGameFlag(FVPHYSICS_NO_IMPACT_DMG)
+ objectphys:ClearGameFlag(FVPHYSICS_NO_NPC_IMPACT_DMG)
+ objectphys:EnableGravity(true)
+ if object._OriginalMass then
+ objectphys:SetMass(object._OriginalMass)
+ object._OriginalMass = nil
+ end
+
+ if not self:GetIsHeavy() then
+ object:GhostAllPlayersInMe(2.5, true)
+ end
+
+ object:SetOwner(NULL)
+ object:CollisionRulesChanged()
+ end
+
+ for _, ent in pairs(ents.FindByClass("logic_pickupdrop")) do
+ if ent.EntityToWatch == object:GetName() and ent:IsValid() then
+ ent:Input("ondropped", owner, object, "")
+ end
+ end
+ end
+end
+
+concommand.Add("_zs_rotateang", function(sender, command, arguments)
+ local x = tonumbersafe(arguments[1])
+ local y = tonumbersafe(arguments[2])
+
+ if x and y then
+ sender.InputMouseX = math.Clamp(x * 0.2, -180, 180)
+ sender.InputMouseY = math.Clamp(y * 0.2, -180, 180)
+ end
+end)
+
+local ShadowParams = {secondstoarrive = 0.01, maxangular = 1000, maxangulardamp = 10000, maxspeed = 500, maxspeeddamp = 1000, dampfactor = 0.65, teleportdistance = 0}
+function ENT:Think()
+ local ct = CurTime()
+
+ local frametime = ct - (self.LastThink or ct)
+ self.LastThink = ct
+
+ local object = self:GetObject()
+ local owner = self:GetOwner()
+ if not object:IsValid() or object:IsNailed() or not owner:IsValid() or not owner:Alive() then
+ self:Remove()
+ return
+ end
+
+ local shootpos = owner:GetShootPos()
+ local nearestpoint = object:NearestPoint(shootpos)
+
+ local objectphys = object:GetPhysicsObject()
+ if object:GetMoveType() ~= MOVETYPE_VPHYSICS or not objectphys:IsValid() or owner:GetGroundEntity() == object then
+ self:Remove()
+ return
+ end
+
+ if self:GetIsHeavy() then
+ if 64 < self:GetHingePos():Distance(self:GetPullPos()) then
+ self:Remove()
+ return
+ end
+ elseif 64 < nearestpoint:Distance(shootpos) then
+ self:Remove()
+ return
+ end
+
+ objectphys:Wake()
+
+ if owner:KeyPressed(IN_ATTACK) then
+ object:SetPhysicsAttacker(owner)
+
+ self:Remove()
+ return
+ elseif self:GetIsHeavy() then
+ local pullpos = self:GetPullPos()
+ local hingepos = self:GetHingePos()
+ objectphys:ApplyForceOffset(objectphys:GetMass() * frametime * 450 * (pullpos - hingepos):GetNormalized(), hingepos)
+ elseif owner:KeyDown(IN_ATTACK2) and not owner:GetActiveWeapon().NoPropThrowing then
+ owner:ConCommand("-attack2")
+ objectphys:ApplyForceCenter(objectphys:GetMass() * math.Clamp(1.25 - math.min(1, (object:OBBMins():Length() + object:OBBMaxs():Length()) / CARRY_DRAG_VOLUME), 0.25, 1) * 500 * owner:GetAimVector())
+ object:SetPhysicsAttacker(owner)
+
+ self:Remove()
+ return
+ else
+ if not self.ObjectPosition or not owner:KeyDown(IN_SPEED) then
+ local obbcenter = object:OBBCenter()
+ local objectpos = shootpos + owner:GetAimVector() * 48
+ objectpos = objectpos - obbcenter.z * object:GetUp()
+ objectpos = objectpos - obbcenter.y * object:GetRight()
+ objectpos = objectpos - obbcenter.x * object:GetForward()
+ self.ObjectPosition = objectpos
+ if not self.ObjectAngles then
+ self.ObjectAngles = object:GetAngles()
+ end
+ end
+
+ if owner:KeyDown(IN_SPEED) then
+ if owner:KeyPressed(IN_SPEED) then
+ self.ObjectAngles = object:GetAngles()
+ end
+ elseif owner:KeyDown(IN_WALK) then
+ self.ObjectAngles:RotateAroundAxis(owner:EyeAngles():Up(), owner.InputMouseX or 0)
+ self.ObjectAngles:RotateAroundAxis(owner:EyeAngles():Right(), owner.InputMouseY or 0)
+ end
+
+ ShadowParams.pos = self.ObjectPosition
+ ShadowParams.angle = self.ObjectAngles
+ ShadowParams.deltatime = frametime
+ objectphys:ComputeShadowControl(ShadowParams)
+ end
+
+ object:SetPhysicsAttacker(owner)
+
+ self:NextThink(ct)
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_human_holding/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_human_holding/shared.lua
new file mode 100644
index 0000000..79df7f6
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_human_holding/shared.lua
@@ -0,0 +1,77 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+AccessorFuncDT(ENT, "ObjectMass", "Int", 0)
+
+function ENT:Move(pl, mv)
+ if pl ~= self:GetOwner() then return end
+
+ local object = self:GetObject()
+ if object:IsValid() then
+ --local objectphys = object:GetPhysicsObject()
+ --if objectphys:IsValid() then
+ mv:SetMaxSpeed(math.max(mv:GetMaxSpeed() / 4, mv:GetMaxSpeed() - self:GetObjectMass() * CARRY_SPEEDLOSS_PERKG))
+ mv:SetMaxClientSpeed(mv:GetMaxSpeed())
+ --end
+ end
+end
+
+local defaultcolor = Vector( 62.0/255.0, 88.0/255.0, 106.0/255.0 )
+function ENT:GetPlayerColor()
+ local owner = self:GetOwner()
+ if owner and owner:IsValid() and owner.GetPlayerColor then
+ return owner:GetPlayerColor()
+ end
+
+ return defaultcolor
+end
+
+function ENT:GetObject()
+ return self:GetDTEntity(0)
+end
+
+function ENT:SetObject(object)
+ self:SetDTEntity(0, object)
+end
+
+function ENT:SetIsHeavy(heavy)
+ self:SetDTBool(0, heavy)
+end
+
+function ENT:GetIsHeavy()
+ return self:GetDTBool(0)
+end
+
+function ENT:GetPullPos()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ return owner:EyePos() + owner:GetAimVector() * 48
+ end
+
+ return self:GetObjectPos()
+end
+
+function ENT:GetObjectPos()
+ local object = self:GetObject()
+ if object:IsValid() then
+ return object:GetPos()
+ end
+
+ return self:GetPos()
+end
+
+function ENT:SetHingePos(pos)
+ local object = self:GetObject()
+ if object:IsValid() then
+ self:SetDTVector(0, object:WorldToLocal(pos))
+ end
+end
+
+function ENT:GetHingePos()
+ local object = self:GetObject()
+ if object:IsValid() then
+ return object:LocalToWorld(self:GetDTVector(0))
+ end
+
+ return self:GetObjectPos()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_knockdown/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_knockdown/cl_init.lua
new file mode 100644
index 0000000..5f6cc13
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_knockdown/cl_init.lua
@@ -0,0 +1,59 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetRenderBounds(Vector(-40, -40, -18), Vector(40, 40, 80))
+
+ local owner = self:GetOwner()
+ if owner:IsPlayer() then
+ owner.KnockedDown = self
+ owner:SetNoDraw(true)
+ end
+end
+
+function ENT:OnRemove()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ owner.KnockedDown = nil
+ owner:SetNoDraw(false)
+ end
+end
+
+function ENT:Think()
+ local ct = CurTime()
+ local owner = self:GetOwner()
+ if owner:IsValid() and 0 < owner:Health() then
+ local rag = owner:GetRagdollEntity()
+ if rag and rag:IsValid() then
+ local endtime = self:GetDTFloat(0)
+ if endtime - 0.65 <= ct then
+ local delta = math.max(0.01, endtime - ct)
+ for i = 0, rag:GetPhysicsObjectCount() do
+ local translate = owner:TranslatePhysBoneToBone(i)
+ if translate and 0 < translate then
+ local pos, ang = owner:GetBonePosition(translate)
+ if pos and ang then
+ local phys = rag:GetPhysicsObjectNum(i)
+ if phys and phys:IsValid() then
+ phys:Wake()
+ phys:ComputeShadowControl({secondstoarrive = delta, pos = pos, angle = ang, maxangular = 1000, maxangulardamp = 10000, maxspeed = 5000, maxspeeddamp = 1000, dampfactor = 0.85, teleportdistance = 100, deltatime = FrameTime()})
+ end
+ end
+ end
+ end
+ else
+ local phys = rag:GetPhysicsObject()
+ if phys and phys:IsValid() then
+ phys:Wake()
+ phys:ComputeShadowControl({secondstoarrive = 0.05, pos = owner:GetPos() + Vector(0,0,16), angle = rag:GetPhysicsObject():GetAngles(), maxangular = 2000, maxangulardamp = 10000, maxspeed = 5000, maxspeeddamp = 1000, dampfactor = 0.85, teleportdistance = 200, deltatime = FrameTime()})
+ end
+ end
+ end
+ end
+
+ self:NextThink(ct)
+ return true
+end
+
+function ENT:Draw()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_knockdown/init.lua b/gamemodes/zombiesurvival/entities/entities/status_knockdown/init.lua
new file mode 100644
index 0000000..11ca7e2
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_knockdown/init.lua
@@ -0,0 +1,35 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:PlayerSet(pPlayer, bExists)
+ pPlayer.KnockedDown = self
+ pPlayer:Freeze(true)
+
+ pPlayer:DrawWorldModel(false)
+ pPlayer:DrawViewModel(false)
+
+ self:SetDTFloat(0, self.DieTime)
+ if not bExists then
+ pPlayer:CreateRagdoll()
+ end
+end
+
+function ENT:OnRemove()
+ local parent = self:GetParent()
+ if parent:IsValid() then
+ parent:Freeze(false)
+ parent.KnockedDown = nil
+
+ if parent:Alive() then
+ parent:DrawViewModel(true)
+ parent:DrawWorldModel(true)
+
+ local rag = parent:GetRagdollEntity()
+ if rag and rag:IsValid() then
+ rag:Remove()
+ end
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_knockdown/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_knockdown/shared.lua
new file mode 100644
index 0000000..2f44d2c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_knockdown/shared.lua
@@ -0,0 +1,2 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
diff --git a/gamemodes/zombiesurvival/entities/entities/status_nightmareambience/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_nightmareambience/cl_init.lua
new file mode 100644
index 0000000..0f82f63
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_nightmareambience/cl_init.lua
@@ -0,0 +1,29 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_NONE
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+
+ self.AmbientSound = CreateSound(self, "npc/antlion_guard/growl_idle.wav")
+ self.AmbientSound:PlayEx(0.55, 110)
+end
+
+function ENT:OnRemove()
+ self.AmbientSound:Stop()
+end
+
+function ENT:Think()
+ owner = self:GetOwner()
+ if owner:IsValid() then
+ local wep = owner:GetActiveWeapon()
+ if wep:IsValid() and wep.IsSwinging and wep:IsSwinging() then
+ self.AmbientSound:Stop()
+ else
+ self.AmbientSound:PlayEx(0.55, 110 + math.sin(RealTime()))
+ end
+ end
+end
+
+function ENT:Draw()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_nightmareambience/init.lua b/gamemodes/zombiesurvival/entities/entities/status_nightmareambience/init.lua
new file mode 100644
index 0000000..9afd15d
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_nightmareambience/init.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if not (owner:Alive() and owner:Team() == TEAM_UNDEAD and owner:GetZombieClassTable().Name == "The Tickle Monster") then self:Remove() end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_nightmareambience/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_nightmareambience/shared.lua
new file mode 100644
index 0000000..40b3860
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_nightmareambience/shared.lua
@@ -0,0 +1 @@
+ENT.Type = "anim"
diff --git a/gamemodes/zombiesurvival/entities/entities/status_overridemodel.lua b/gamemodes/zombiesurvival/entities/entities/status_overridemodel.lua
new file mode 100644
index 0000000..895bcaf
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_overridemodel.lua
@@ -0,0 +1,42 @@
+AddCSLuaFile()
+
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+function ENT:Initialize()
+ self:SetSolid(SOLID_NONE)
+ self:SetMoveType(MOVETYPE_NONE)
+ self:AddEffects(bit.bor(EF_BONEMERGE, EF_BONEMERGE_FASTCULL, EF_PARENT_ANIMATES))
+
+ local pPlayer = self:GetOwner()
+ if pPlayer:IsValid() then
+ pPlayer.status_overridemodel = self
+ pPlayer:SetRenderMode(RENDERMODE_NONE)
+ end
+end
+
+function ENT:PlayerSet(pPlayer, bExists)
+ pPlayer:SetRenderMode(RENDERMODE_NONE)
+end
+
+function ENT:OnRemove()
+ local pPlayer = self:GetOwner()
+ if pPlayer:IsValid() then
+ pPlayer:SetRenderMode(RENDERMODE_NORMAL)
+ end
+end
+
+function ENT:Think()
+end
+
+if CLIENT then
+ function ENT:Draw()
+ local owner = self:GetOwner()
+ if owner:IsValid() and owner:Alive() then
+ local col = owner:GetColor()
+ col.a = 255
+ self:SetColor(col)
+ self:DrawModel()
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_oxygentank/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_oxygentank/cl_init.lua
new file mode 100644
index 0000000..5c38184
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_oxygentank/cl_init.lua
@@ -0,0 +1,26 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetModelScale(0.5, 0)
+end
+
+function ENT:Draw()
+ local owner = self:GetOwner()
+ if not owner:IsValid() or owner == LocalPlayer() and not owner:ShouldDrawLocalPlayer() then return end
+
+ local wep = owner:GetActiveWeapon()
+ if wep:IsValid() and wep:GetClass() == "weapon_zs_oxygentank" then return end
+
+ local boneid = owner:LookupBone("ValveBiped.Bip01_Spine2")
+ if not boneid or boneid <= 0 then return end
+
+ local bonepos, boneang = owner:GetBonePositionMatrixed(boneid)
+
+ self:SetPos(bonepos + boneang:Forward() + boneang:Right() * 4)
+ boneang:RotateAroundAxis(boneang:Right(), 270)
+ boneang:RotateAroundAxis(boneang:Up(), 180)
+ self:SetAngles(boneang)
+
+ self:DrawModel()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_oxygentank/init.lua b/gamemodes/zombiesurvival/entities/entities/status_oxygentank/init.lua
new file mode 100644
index 0000000..a149a8f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_oxygentank/init.lua
@@ -0,0 +1,18 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetModelScale(0.5, 0)
+
+ self:SetModel("models/props_c17/canister01a.mdl")
+ self:SetSolid(SOLID_NONE)
+ self:SetMoveType(MOVETYPE_NONE)
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if not (owner:IsValid() and owner:Alive() and owner:HasWeapon("weapon_zs_oxygentank")) then self:Remove() end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_oxygentank/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_oxygentank/shared.lua
new file mode 100644
index 0000000..40b3860
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_oxygentank/shared.lua
@@ -0,0 +1 @@
+ENT.Type = "anim"
diff --git a/gamemodes/zombiesurvival/entities/entities/status_packup/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_packup/cl_init.lua
new file mode 100644
index 0000000..3929a2c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_packup/cl_init.lua
@@ -0,0 +1,21 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetRenderBounds(Vector(-40, -40, -18), Vector(40, 40, 80))
+
+ if self:GetStartTime() == 0 then
+ self:SetStartTime(CurTime())
+ end
+
+ self:GetOwner().PackUp = self
+end
+
+function ENT:OnRemove()
+end
+
+function ENT:Think()
+end
+
+function ENT:Draw()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_packup/init.lua b/gamemodes/zombiesurvival/entities/entities/status_packup/init.lua
new file mode 100644
index 0000000..9d2b24c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_packup/init.lua
@@ -0,0 +1,70 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:PlayerSet(pPlayer, bExists)
+ pPlayer:EmitSound("items/ammocrate_open.wav")
+
+ pPlayer.PackUp = pPlayer
+
+ if self:GetStartTime() == 0 then
+ self:SetStartTime(CurTime())
+ end
+end
+
+function ENT:Think()
+ if self.Removing then return end
+
+ local packer = self:GetOwner()
+ local owner = packer
+ local pack = self:GetPackUpEntity()
+ if pack:IsValid() and owner:TraceLine(64, MASK_SOLID, owner:GetMeleeFilter()).Entity == pack then
+ if not self:GetNotOwner() and pack.GetObjectOwner then
+ local packowner = pack:GetObjectOwner()
+ if packowner:IsValid() and packowner:Team() == TEAM_HUMAN and packowner ~= packer and not gamemode.Call("PlayerIsAdmin", packer) then
+ self:SetNotOwner(true)
+ end
+ end
+
+ if CurTime() >= self:GetEndTime() then
+ if self:GetNotOwner() then
+ local count = 0
+ for _, ent in pairs(ents.FindByClass("status_packup")) do
+ if ent:GetPackUpEntity() == pack then
+ count = count + 1
+ end
+ end
+
+ if count < self.PackUpOverride then
+ self:NextThink(CurTime())
+ return true
+ end
+
+ if pack.GetObjectOwner then
+ local objowner = pack:GetObjectOwner()
+ if objowner:IsValid() and objowner:Team() == TEAM_HUMAN and objowner:IsValid() then
+ owner = objowner
+ end
+ end
+ end
+
+ if pack.OnPackedUp and not pack:OnPackedUp(owner) then
+ owner:EmitSound("items/ammocrate_close.wav")
+ self.Removing = true
+
+ gamemode.Call("ObjectPackedUp", pack, packer, owner)
+
+ self:Remove()
+ end
+ end
+ else
+ owner:EmitSound("items/medshotno1.wav")
+
+ self:Remove()
+ self.Removing = true
+ end
+
+ self:NextThink(CurTime())
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_packup/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_packup/shared.lua
new file mode 100644
index 0000000..7dca17e
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_packup/shared.lua
@@ -0,0 +1,54 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+ENT.PackUpOverride = 4
+
+function ENT:GetTimeRemaining()
+ return math.max(0, self:GetEndTime() - CurTime())
+end
+
+function ENT:RefreshMaxTime()
+ self:SetMaxTime(math.max(self:GetMaxTime(), self:GetEndTime() - self:GetStartTime()))
+end
+
+function ENT:SetMaxTime(time)
+ self:SetDTFloat(2, time)
+end
+
+function ENT:GetMaxTime()
+ return self:GetDTFloat(2)
+end
+
+function ENT:SetEndTime(time)
+ self:SetDTFloat(0, time)
+ self:RefreshMaxTime()
+end
+
+function ENT:GetEndTime()
+ return self:GetDTFloat(0)
+end
+
+function ENT:GetStartTime()
+ return self:GetDTFloat(1)
+end
+
+function ENT:SetStartTime(time)
+ self:SetDTFloat(1, time)
+ self:RefreshMaxTime()
+end
+
+function ENT:SetPackUpEntity(ent)
+ self:SetDTEntity(0, ent)
+end
+
+function ENT:GetPackUpEntity()
+ return self:GetDTEntity(0)
+end
+
+function ENT:SetNotOwner(notowner)
+ self:SetDTBool(0, notowner)
+end
+
+function ENT:GetNotOwner()
+ return self:GetDTBool(0)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_poisonrecovery/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_poisonrecovery/cl_init.lua
new file mode 100644
index 0000000..11a5e13
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_poisonrecovery/cl_init.lua
@@ -0,0 +1,8 @@
+include("shared.lua")
+
+function ENT:Draw()
+end
+
+function ENT:Initialize()
+ self:GetOwner().PoisonRecovery = self
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_poisonrecovery/init.lua b/gamemodes/zombiesurvival/entities/entities/status_poisonrecovery/init.lua
new file mode 100644
index 0000000..268294d
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_poisonrecovery/init.lua
@@ -0,0 +1,24 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:PlayerSet(pPlayer, bExists)
+ pPlayer.PoisonRecovery = self
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+
+ if self:GetDamage() <= 0 or owner:Team() == TEAM_UNDEAD then
+ self:Remove()
+ return
+ end
+
+ owner:SetHealth(math.min(owner:GetMaxHealth(), owner:Health() + 1))
+ self:AddDamage(-1)
+
+ self:NextThink(CurTime() + 0.75)
+ --self:NextThink(CurTime() + (owner.BuffResistant and 0.375 or 0.75))
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_poisonrecovery/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_poisonrecovery/shared.lua
new file mode 100644
index 0000000..a5cfd65
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_poisonrecovery/shared.lua
@@ -0,0 +1,21 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ if self:GetDTFloat(1) == 0 then
+ self:SetDTFloat(1, CurTime())
+ end
+end
+
+function ENT:AddDamage(damage)
+ self:SetDamage(self:GetDamage() + damage)
+end
+
+function ENT:SetDamage(damage)
+ self:SetDTFloat(0, math.min(50, damage))
+end
+
+function ENT:GetDamage()
+ return self:GetDTFloat(0)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_pukepusambience/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_pukepusambience/cl_init.lua
new file mode 100644
index 0000000..4ac2871
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_pukepusambience/cl_init.lua
@@ -0,0 +1,29 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_NONE
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+
+ self.AmbientSound = CreateSound(self, "npc/zombie_poison/pz_breathe_loop2.wav")
+ self.AmbientSound:PlayEx(0.55, 85)
+end
+
+function ENT:OnRemove()
+ self.AmbientSound:Stop()
+end
+
+function ENT:Think()
+ owner = self:GetOwner()
+ if owner:IsValid() then
+ local wep = owner:GetActiveWeapon()
+ if wep:IsValid() and wep.IsSwinging and wep:IsSwinging() then
+ self.AmbientSound:Stop()
+ else
+ self.AmbientSound:PlayEx(0.55, 85 + math.sin(RealTime()))
+ end
+ end
+end
+
+function ENT:Draw()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_pukepusambience/init.lua b/gamemodes/zombiesurvival/entities/entities/status_pukepusambience/init.lua
new file mode 100644
index 0000000..c27d382
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_pukepusambience/init.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if not (owner:Alive() and owner:Team() == TEAM_UNDEAD and owner:GetZombieClassTable().Name == "Puke Pus") then self:Remove() end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_pukepusambience/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_pukepusambience/shared.lua
new file mode 100644
index 0000000..40b3860
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_pukepusambience/shared.lua
@@ -0,0 +1 @@
+ENT.Type = "anim"
diff --git a/gamemodes/zombiesurvival/entities/entities/status_revive/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_revive/cl_init.lua
new file mode 100644
index 0000000..9094db4
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_revive/cl_init.lua
@@ -0,0 +1,59 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetRenderBounds(Vector(-40, -40, -18), Vector(40, 40, 80))
+
+ local owner = self:GetOwner()
+ if owner:IsPlayer() then
+ owner.Revive = self
+ end
+end
+
+function ENT:OnRemove()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ owner.Revive = nil
+ end
+end
+
+function ENT:Think()
+ local endtime = self:GetReviveTime()
+ if endtime <= 0 then return end
+
+ local ct = CurTime()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ local rag = owner:GetRagdollEntity()
+ if rag and rag:IsValid() then
+ if endtime - 1 <= ct then
+ local delta = math.max(0.01, endtime - ct)
+ for i = 0, rag:GetPhysicsObjectCount() do
+ local translate = owner:TranslatePhysBoneToBone(i)
+ if translate and 0 < translate then
+ local pos, ang = owner:GetBonePosition(translate)
+ if pos and ang then
+ local phys = rag:GetPhysicsObjectNum(i)
+ if phys and phys:IsValid() then
+ phys:Wake()
+ phys:ComputeShadowControl({secondstoarrive = delta, pos = pos, angle = ang, maxangular = 1000, maxangulardamp = 10000, maxspeed = 5000, maxspeeddamp = 1000, dampfactor = 0.85, teleportdistance = 100, deltatime = FrameTime()})
+ end
+ end
+ end
+ end
+ else
+ local phys = rag:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:ComputeShadowControl({secondstoarrive = 0.05, pos = owner:GetPos() + Vector(0,0,16), angle = phys:GetAngles(), maxangular = 2000, maxangulardamp = 10000, maxspeed = 5000, maxspeeddamp = 1000, dampfactor = 0.85, teleportdistance = 200, deltatime = FrameTime()})
+ end
+ end
+ end
+ end
+
+ self:NextThink(ct)
+ return true
+end
+
+function ENT:Draw()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_revive/init.lua b/gamemodes/zombiesurvival/entities/entities/status_revive/init.lua
new file mode 100644
index 0000000..2126505
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_revive/init.lua
@@ -0,0 +1,25 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:PlayerSet(pPlayer, bExists)
+ pPlayer.Revive = self
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if owner:IsValid() and (owner:Alive() or self:GetReviveTime() <= CurTime()) then
+ self:Remove()
+ end
+end
+
+function ENT:OnRemove()
+ local parent = self:GetParent()
+ if parent:IsValid() then
+ parent.Revive = nil
+ if not parent:Alive() then
+ parent:SecondWind()
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_revive/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_revive/shared.lua
new file mode 100644
index 0000000..0a9a6d5
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_revive/shared.lua
@@ -0,0 +1,14 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+function ENT:IsRising()
+ return self:GetReviveTime() - 2.5 <= CurTime()
+end
+
+function ENT:SetReviveTime(tim)
+ self:SetDTFloat(0, tim)
+end
+
+function ENT:GetReviveTime()
+ return self:GetDTFloat(0)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_revive2/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_revive2/cl_init.lua
new file mode 100644
index 0000000..f3cb9ff
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_revive2/cl_init.lua
@@ -0,0 +1,63 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetRenderBounds(Vector(-40, -40, -18), Vector(40, 40, 80))
+
+ local owner = self:GetOwner()
+ if owner:IsPlayer() then
+ owner.Revive = self
+ end
+end
+
+function ENT:OnRemove()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ owner.Revive = nil
+ end
+end
+
+function ENT:Think()
+ local endtime = self:GetReviveTime()
+ if endtime <= 0 then return end
+
+ local ct = CurTime()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ local rag = owner:GetRagdollEntity()
+ if rag and rag:IsValid() then
+ if endtime - 1 <= ct then
+ if not self.m_DidSetModel then
+ self.m_DidSetModel = true
+ rag:SetModel(GAMEMODE.ZombieClasses["Zombie"].Model)
+ end
+ local delta = math.max(0.01, endtime - ct)
+ for i = 0, rag:GetPhysicsObjectCount() do
+ local translate = owner:TranslatePhysBoneToBone(i)
+ if translate and 0 < translate then
+ local pos, ang = owner:GetBonePosition(translate)
+ if pos and ang then
+ local phys = rag:GetPhysicsObjectNum(i)
+ if phys and phys:IsValid() then
+ phys:Wake()
+ phys:ComputeShadowControl({secondstoarrive = delta, pos = pos, angle = ang, maxangular = 1000, maxangulardamp = 10000, maxspeed = 5000, maxspeeddamp = 1000, dampfactor = 0.85, teleportdistance = 100, deltatime = FrameTime()})
+ end
+ end
+ end
+ end
+ else
+ local phys = rag:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:ComputeShadowControl({secondstoarrive = 0.05, pos = owner:GetPos() + Vector(0,0,16), angle = phys:GetAngles(), maxangular = 2000, maxangulardamp = 10000, maxspeed = 5000, maxspeeddamp = 1000, dampfactor = 0.85, teleportdistance = 200, deltatime = FrameTime()})
+ end
+ end
+ end
+ end
+
+ self:NextThink(ct)
+ return true
+end
+
+function ENT:Draw()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_revive2/init.lua b/gamemodes/zombiesurvival/entities/entities/status_revive2/init.lua
new file mode 100644
index 0000000..2126505
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_revive2/init.lua
@@ -0,0 +1,25 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:PlayerSet(pPlayer, bExists)
+ pPlayer.Revive = self
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if owner:IsValid() and (owner:Alive() or self:GetReviveTime() <= CurTime()) then
+ self:Remove()
+ end
+end
+
+function ENT:OnRemove()
+ local parent = self:GetParent()
+ if parent:IsValid() then
+ parent.Revive = nil
+ if not parent:Alive() then
+ parent:SecondWind()
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_revive2/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_revive2/shared.lua
new file mode 100644
index 0000000..0a9a6d5
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_revive2/shared.lua
@@ -0,0 +1,14 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+function ENT:IsRising()
+ return self:GetReviveTime() - 2.5 <= CurTime()
+end
+
+function ENT:SetReviveTime(tim)
+ self:SetDTFloat(0, tim)
+end
+
+function ENT:GetReviveTime()
+ return self:GetDTFloat(0)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_revive_slump/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_revive_slump/cl_init.lua
new file mode 100644
index 0000000..af63d09
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_revive_slump/cl_init.lua
@@ -0,0 +1,44 @@
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetRenderBounds(Vector(-40, -40, -18), Vector(40, 40, 80))
+
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ owner.Revive = self
+
+ owner:CallWeaponFunction("KnockedDown", self, false)
+ owner:CallZombieFunction("KnockedDown", self, false)
+ end
+end
+
+function ENT:OnRemove()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ owner.Revive = nil
+ end
+end
+
+function ENT:Think()
+ local endtime = self:GetReviveTime()
+ if endtime == 0 then return end
+
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ local rag = owner:GetRagdollEntity()
+ if rag and rag:IsValid() then
+ local phys = rag:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:ComputeShadowControl({secondstoarrive = 0.05, pos = owner:GetPos() + Vector(0,0,16), angle = phys:GetAngles(), maxangular = 2000, maxangulardamp = 10000, maxspeed = 5000, maxspeeddamp = 1000, dampfactor = 0.85, teleportdistance = 200, deltatime = FrameTime()})
+ end
+ end
+ end
+
+ self:NextThink(CurTime())
+ return true
+end
+
+function ENT:Draw()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_revive_slump/init.lua b/gamemodes/zombiesurvival/entities/entities/status_revive_slump/init.lua
new file mode 100644
index 0000000..c28bbb3
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_revive_slump/init.lua
@@ -0,0 +1,53 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:PlayerSet(pPlayer, bExists)
+ self.HealCarryOver = self.HealCarryOver or 0
+
+ pPlayer.Revive = self
+ pPlayer:Freeze(true)
+ if not bExists then
+ pPlayer:GodEnable()
+ self.GodDisableTime = CurTime() + 0.1
+ end
+
+ pPlayer:CallWeaponFunction("KnockedDown", self, bExists)
+ pPlayer:CallZombieFunction("KnockedDown", self, bExists)
+end
+
+function ENT:Think()
+ local fCurTime = CurTime()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ if self:GetReviveTime() <= fCurTime or not owner:Alive() then
+ self:Remove()
+ return
+ end
+
+ if self.GodDisableTime and fCurTime >= self.GodDisableTime then
+ owner:GodDisable()
+ self.GodDisableTime = nil
+ end
+
+ self.HealCarryOver = self.HealCarryOver + FrameTime() * 10
+ if self.HealCarryOver >= 1 then
+ local toheal = math.floor(self.HealCarryOver)
+ owner:SetHealth(math.min(owner:GetMaxHealth(), owner:Health() + toheal))
+ self.HealCarryOver = self.HealCarryOver - toheal
+ end
+ end
+
+ self:NextThink(fCurTime)
+ return true
+end
+
+function ENT:OnRemove()
+ local parent = self:GetOwner()
+ if parent:IsValid() then
+ parent.Revive = nil
+ parent:Freeze(false)
+ parent:GodDisable()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_revive_slump/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_revive_slump/shared.lua
new file mode 100644
index 0000000..a1f4b01
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_revive_slump/shared.lua
@@ -0,0 +1,26 @@
+ENT.Type = "anim"
+ENT.Base = "status__base"
+
+ENT.AnimTime = 1.9
+
+function ENT:GetRagdollEyes(pl)
+ local attachid = pl:LookupAttachment("head")
+ if attachid then
+ local attach = pl:GetAttachment(attachid)
+ if attach then
+ return attach.Pos, attach.Ang
+ end
+ end
+end
+
+function ENT:IsRising()
+ return self:GetReviveTime() - self.AnimTime <= CurTime()
+end
+
+function ENT:SetReviveTime(tim)
+ self:SetDTFloat(0, tim)
+end
+
+function ENT:GetReviveTime()
+ return self:GetDTFloat(0)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_revive_slump_human/init.lua b/gamemodes/zombiesurvival/entities/entities/status_revive_slump_human/init.lua
new file mode 100644
index 0000000..50bc19a
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_revive_slump_human/init.lua
@@ -0,0 +1,35 @@
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Think()
+ local fCurTime = CurTime()
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ local zombietime = self:GetZombieInitializeTime()
+ if zombietime > 0 and CurTime() >= zombietime then
+ self:SetZombieInitializeTime(0)
+
+ if not owner:Alive() then
+ owner:SecondWind()
+ owner:Freeze(true)
+ owner:TemporaryNoCollide()
+ end
+ end
+
+ if self:GetReviveTime() <= fCurTime then
+ self:Remove()
+ return
+ end
+
+ self.HealCarryOver = self.HealCarryOver + FrameTime() * 15
+ if self.HealCarryOver >= 1 then
+ local toheal = math.floor(self.HealCarryOver)
+ owner:SetHealth(math.min(owner:GetMaxHealth(), owner:Health() + toheal))
+ self.HealCarryOver = self.HealCarryOver - toheal
+ end
+ end
+
+ self:NextThink(fCurTime)
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_revive_slump_human/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_revive_slump_human/shared.lua
new file mode 100644
index 0000000..6e4b9a5
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_revive_slump_human/shared.lua
@@ -0,0 +1,10 @@
+ENT.Type = "anim"
+ENT.Base = "status_revive_slump"
+
+function ENT:SetZombieInitializeTime(time)
+ self:SetDTFloat(1, time)
+end
+
+function ENT:GetZombieInitializeTime()
+ return self:GetDTFloat(1)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_shadeambience/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_shadeambience/cl_init.lua
new file mode 100644
index 0000000..ffd05cd
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_shadeambience/cl_init.lua
@@ -0,0 +1,52 @@
+include("shared.lua")
+
+ENT.NextEmit = 0
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+
+ self.AmbientSound = CreateSound(self, "npc/antlion_guard/growl_idle.wav")
+ self.AmbientSound:PlayEx(0.55, 130)
+
+ self:GetOwner().status_shadeambience = self
+end
+
+function ENT:OnRemove()
+ self.AmbientSound:Stop()
+end
+
+function ENT:Think()
+ self.AmbientSound:PlayEx(0.55, 130 + math.sin(RealTime()))
+end
+
+function ENT:Draw()
+ if CurTime() < self.NextEmit then return end
+
+ local delta = CurTime() - self:GetLastDamaged()
+ if delta < 1 then
+ local power = (1 - delta) * math.min(1, self:GetLastDamage() / 12)
+ self.NextEmit = CurTime() + 0.02 + (1 - power) * 0.3
+
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ local radius = owner:BoundingRadius() / 2
+
+ local pos = owner:LocalToWorld(owner:OBBCenter()) + VectorRand():GetNormalized() * math.Rand(-radius, radius)
+
+ local emitter = ParticleEmitter(pos)
+ emitter:SetNearClip(24, 32)
+
+ local particle = emitter:Add("sprites/glow04_noz", pos)
+ particle:SetDieTime(math.Rand(0.2, 0.4))
+ particle:SetStartSize(1)
+ particle:SetEndSize(power * 16)
+ particle:SetStartAlpha(200)
+ particle:SetEndAlpha(0)
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-5, 5))
+ particle:SetColor(255, 255, 190)
+
+ emitter:Finish()
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_shadeambience/init.lua b/gamemodes/zombiesurvival/entities/entities/status_shadeambience/init.lua
new file mode 100644
index 0000000..dfa2683
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_shadeambience/init.lua
@@ -0,0 +1,64 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+ENT.NextFlashlightCheck = 0
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if not (owner:Alive() and owner:Team() == TEAM_UNDEAD and owner:GetZombieClassTable().Name == "Shade") then
+ self:Remove()
+ elseif CurTime() >= self.NextFlashlightCheck then
+ self.NextFlashlightCheck = CurTime() + 0.33
+
+ local totaldamage = 0
+ for _, pl in pairs(team.GetPlayers(TEAM_HUMAN)) do
+ if pl:Alive() and pl:FlashlightIsOn() then
+ local eyepos = pl:GetShootPos()
+ local nearest = owner:NearestPoint(eyepos)
+ local dist = eyepos:Distance(nearest)
+ if dist <= 300 and TrueVisible(eyepos, nearest) then
+ local dot = (nearest - eyepos):GetNormalized():Dot(pl:GetAimVector())
+ if dot >= 0.85 then
+ local damage = (1 - dist / 300) * dot * 7
+ totaldamage = totaldamage + damage
+
+ SHADEFLASHLIGHTDAMAGE = true
+ owner:TakeDamage(damage, pl, self)
+ SHADEFLASHLIGHTDAMAGE = false
+ end
+ end
+ end
+ end
+
+ for _, ent in pairs(ents.FindByClass("prop_spotlamp")) do
+ local eyepos = ent:GetSpotLightPos()
+ local nearest = owner:NearestPoint(eyepos)
+ local dist = eyepos:Distance(nearest)
+ if dist <= 500 and TrueVisibleFilters(eyepos, nearest, owner, ent) then
+ local dot = (nearest - eyepos):GetNormalized():Dot(ent:GetSpotLightAngles():Forward())
+ if dot >= 0.85 then
+ local damage = (1 - dist / 500) * dot * 8
+ totaldamage = totaldamage + damage
+
+ SHADEFLASHLIGHTDAMAGE = true
+ owner:TakeDamage(damage, ent, self)
+ SHADEFLASHLIGHTDAMAGE = false
+ end
+ end
+ end
+
+ if totaldamage > 0 then
+ self:SetLastDamaged(CurTime())
+ end
+
+ if self:GetLastDamage() ~= totaldamage then
+ self:SetLastDamage(totaldamage)
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_shadeambience/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_shadeambience/shared.lua
new file mode 100644
index 0000000..c6ccdbb
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_shadeambience/shared.lua
@@ -0,0 +1,25 @@
+ENT.Type = "anim"
+
+function ENT:SetLastDamaged(time)
+ self:SetDTFloat(0, time)
+end
+
+function ENT:GetLastDamaged()
+ return self:GetDTFloat(0)
+end
+
+function ENT:SetLastDamage(damage)
+ self:SetDTFloat(1, damage)
+end
+
+function ENT:GetLastDamage()
+ return self:GetDTFloat(1)
+end
+
+function ENT:SetLastReflect(time)
+ self:SetDTFloat(2, time)
+end
+
+function ENT:GetLastReflect()
+ return self:GetDTFloat(2)
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ticklemonsterambience/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/status_ticklemonsterambience/cl_init.lua
new file mode 100644
index 0000000..0f82f63
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ticklemonsterambience/cl_init.lua
@@ -0,0 +1,29 @@
+include("shared.lua")
+
+ENT.RenderGroup = RENDERGROUP_NONE
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+
+ self.AmbientSound = CreateSound(self, "npc/antlion_guard/growl_idle.wav")
+ self.AmbientSound:PlayEx(0.55, 110)
+end
+
+function ENT:OnRemove()
+ self.AmbientSound:Stop()
+end
+
+function ENT:Think()
+ owner = self:GetOwner()
+ if owner:IsValid() then
+ local wep = owner:GetActiveWeapon()
+ if wep:IsValid() and wep.IsSwinging and wep:IsSwinging() then
+ self.AmbientSound:Stop()
+ else
+ self.AmbientSound:PlayEx(0.55, 110 + math.sin(RealTime()))
+ end
+ end
+end
+
+function ENT:Draw()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ticklemonsterambience/init.lua b/gamemodes/zombiesurvival/entities/entities/status_ticklemonsterambience/init.lua
new file mode 100644
index 0000000..9afd15d
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ticklemonsterambience/init.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+end
+
+function ENT:Think()
+ local owner = self:GetOwner()
+ if not (owner:Alive() and owner:Team() == TEAM_UNDEAD and owner:GetZombieClassTable().Name == "The Tickle Monster") then self:Remove() end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/status_ticklemonsterambience/shared.lua b/gamemodes/zombiesurvival/entities/entities/status_ticklemonsterambience/shared.lua
new file mode 100644
index 0000000..40b3860
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/status_ticklemonsterambience/shared.lua
@@ -0,0 +1 @@
+ENT.Type = "anim"
diff --git a/gamemodes/zombiesurvival/entities/entities/trigger_zombieclass/init.lua b/gamemodes/zombiesurvival/entities/entities/trigger_zombieclass/init.lua
new file mode 100644
index 0000000..99d7088
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/trigger_zombieclass/init.lua
@@ -0,0 +1,107 @@
+ENT.Type = "brush"
+
+function ENT:Initialize()
+ self:SetTrigger(true)
+
+ if self.On == nil then self.On = true end
+ if self.InstantChange == nil then self.InstantChange = true end
+end
+
+function ENT:Think()
+end
+
+function ENT:AcceptInput(name, caller, activator, arg)
+ name = string.lower(name)
+ if name == "seton" then
+ self.On = tonumber(arg) == 1
+ return true
+ elseif name == "enable" then
+ self.On = true
+ return true
+ elseif name == "disable" then
+ self.On = false
+ return true
+ elseif name == "settouchclass" or name == "setendtouchclass" or name == "settouchdeathclass" or name == "setendtouchdeathclass" or name == "setonetime" or name == "setinstantchange" then
+ self:KeyValue(string.sub(name, 4), arg)
+ end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "enabled" then
+ self.On = tonumber(value) == 1
+ elseif key == "touchclass" then
+ self.TouchClass = string.lower(value)
+ elseif key == "endtouchclass" then
+ self.EndTouchClass = string.lower(value)
+ elseif key == "touchdeathclass" then
+ self.TouchDeathClass = string.lower(value)
+ elseif key == "endtouchdeathclass" then
+ self.EndTouchDeathClass = string.lower(value)
+ elseif key == "onetime" then
+ self.OneTime = tonumber(value) == 1
+ elseif key == "instantchange" then
+ self.InstantChange = tonumber(value) == 1
+ end
+end
+
+function ENT:Touch(ent)
+ if self.On and ent:IsPlayer() and ent:Alive() and ent:Team() == TEAM_UNDEAD then
+ if self.TouchClass and self.TouchClass ~= string.lower(ent:GetZombieClassTable().Name) then
+ for k, v in ipairs(GAMEMODE.ZombieClasses) do
+ if string.lower(v.Name) == self.TouchClass then
+ local prev = ent:GetZombieClass()
+ local prevpos = ent:GetPos()
+ ent:SetZombieClass(k)
+ ent:UnSpectateAndSpawn()
+ if self.OneTime then
+ ent.DeathClass = prev
+ end
+ if self.InstantChange then
+ ent:SetPos(prevpos)
+ end
+
+ break
+ end
+ end
+ elseif self.TouchDeathClass and self.TouchDeathClass ~= string.lower(ent:GetZombieClassTable().Name) then
+ for k, v in ipairs(GAMEMODE.ZombieClasses) do
+ if string.lower(v.Name) == self.TouchDeathClass then
+ ent.DeathClass = k
+ break
+ end
+ end
+ end
+ end
+end
+ENT.StartTouch = ENT.Touch
+
+function ENT:EndTouch(ent)
+ if self.On and ent:IsPlayer() and ent:Alive() and ent:Team() == TEAM_UNDEAD then
+ if self.EndTouchClass and self.EndTouchClass ~= string.lower(ent:GetZombieClassTable().Name) then
+ for k, v in ipairs(GAMEMODE.ZombieClasses) do
+ if string.lower(v.Name) == self.EndTouchClass then
+ local prev = ent:GetZombieClass()
+ local prevpos = ent:GetPos()
+ ent:SetZombieClass(k)
+ ent:UnSpectateAndSpawn()
+ if self.OneTime then
+ ent.DeathClass = prev
+ end
+ if self.InstantChange then
+ ent:SetPos(prevpos)
+ end
+
+ break
+ end
+ end
+ elseif self.EndTouchDeathClass and self.EndTouchDeathClass ~= string.lower(ent:GetZombieClassTable().Name) then
+ for k, v in ipairs(GAMEMODE.ZombieClasses) do
+ if string.lower(v.Name) == self.EndTouchDeathClass then
+ ent.DeathClass = k
+ break
+ end
+ end
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/zombiegasses/cl_init.lua b/gamemodes/zombiesurvival/entities/entities/zombiegasses/cl_init.lua
new file mode 100644
index 0000000..1fe6cd7
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/zombiegasses/cl_init.lua
@@ -0,0 +1,49 @@
+include("shared.lua")
+
+ENT.NextGas = 0
+ENT.NextSound = 0
+
+function ENT:Think()
+ if GAMEMODE.ZombieEscape then return end
+
+ if self.NextSound <= CurTime() then
+ self.NextSound = CurTime() + math.Rand(4, 6)
+
+ if 0 < GAMEMODE:GetWave() and MySelf:IsValid() and MySelf:Team() == TEAM_HUMAN and MySelf:Alive() then
+ local mypos = self:GetPos()
+ local eyepos = MySelf:NearestPoint(mypos)
+ if eyepos:Distance(mypos) <= self:GetRadius() + 72 and WorldVisible(eyepos, mypos) then
+ MySelf:EmitSound("ambient/voices/cough"..math.random(4)..".wav")
+ end
+ end
+ end
+end
+
+function ENT:Draw()
+ if GAMEMODE.ZombieEscape or CurTime() < self.NextGas then return end
+ self.NextGas = CurTime() + math.Rand(0.08, 0.2)
+
+ local radius = self:GetRadius()
+
+ local randdir = VectorRand()
+ randdir.z = math.abs(randdir.z)
+ randdir:Normalize()
+ local emitpos = self:GetPos() + randdir * math.Rand(0, radius / 2)
+
+ local emitter = ParticleEmitter(emitpos)
+ emitter:SetNearClip(48, 64)
+
+ local particle = emitter:Add("particles/smokey", emitpos)
+ particle:SetVelocity(randdir * math.Rand(8, 256))
+ particle:SetAirResistance(64)
+ particle:SetDieTime(math.Rand(1.2, 2.5))
+ particle:SetStartAlpha(math.Rand(70, 90))
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(1)
+ particle:SetEndSize(radius * math.Rand(0.25, 0.45))
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-1, 1))
+ particle:SetColor(0, math.Rand(40, 70), 0)
+
+ emitter:Finish()
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/zombiegasses/init.lua b/gamemodes/zombiesurvival/entities/entities/zombiegasses/init.lua
new file mode 100644
index 0000000..6cd1b85
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/zombiegasses/init.lua
@@ -0,0 +1,53 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function ENT:Initialize()
+ self.Heal = self.Heal or 25
+ self:DrawShadow(false)
+ self:Fire("attack", "", 1.5)
+
+ if self:GetRadius() == 0 then self:SetRadius(400) end
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "radius" then
+ self:SetRadius(tonumber(value))
+ elseif key == "heal" then
+ self.Heal = tonumber(value) or self.Heal
+ end
+end
+
+local function TrueVisible(posa, posb)
+ local filt = ents.FindByClass("projectile_*")
+ filt = table.Add(filt, ents.FindByClass("npc_*"))
+ filt = table.Add(filt, ents.FindByClass("prop_*"))
+ filt = table.Add(filt, player.GetAll())
+
+ return not util.TraceLine({start = posa, endpos = posb, filter = filt}).Hit
+end
+
+function ENT:AcceptInput(name, activator, caller, arg)
+ if name ~= "attack" then return end
+ self:Fire("attack", "", 1.5)
+
+ if GAMEMODE:GetWave() <= 0 or GAMEMODE.ZombieEscape then return end
+
+ local vPos = self:GetPos()
+ for _, ent in pairs(ents.FindInSphere(vPos, self:GetRadius())) do
+ if ent:IsPlayer() and ent:Alive() and WorldVisible(vPos, ent:NearestPoint(vPos)) then
+ if ent:Team() == TEAM_UNDEAD then
+ if ent:Health() < ent:GetMaxHealth() and not ent:GetZombieClassTable().Boss then
+ ent:SetHealth(math.min(ent:GetMaxZombieHealth(), ent:Health() + self.Heal))
+ ent.m_LastGasHeal = CurTime()
+ end
+ elseif 1 < ent:Health() then
+ ent:PoisonDamage(math.min(10, ent:Health() - 1), self, self)
+ end
+ end
+ end
+
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/entities/zombiegasses/shared.lua b/gamemodes/zombiesurvival/entities/entities/zombiegasses/shared.lua
new file mode 100644
index 0000000..0cc68c0
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/zombiegasses/shared.lua
@@ -0,0 +1,3 @@
+ENT.Type = "anim"
+
+AccessorFuncDT(ENT, "Radius", "Float", 0)
diff --git a/gamemodes/zombiesurvival/entities/entities/zs_hands.lua b/gamemodes/zombiesurvival/entities/entities/zs_hands.lua
new file mode 100644
index 0000000..8274485
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/entities/zs_hands.lua
@@ -0,0 +1,69 @@
+
+AddCSLuaFile()
+
+ENT.Type = "anim"
+ENT.RenderGroup = RENDERGROUP_OTHER
+
+
+function ENT:Initialize()
+
+ hook.Add( "OnViewModelChanged", self, self.ViewModelChanged )
+
+ self:SetNotSolid( true )
+ self:DrawShadow( false )
+ self:SetTransmitWithParent( true ) -- Transmit only when the viewmodel does!
+
+end
+
+function ENT:DoSetup( ply )
+
+ -- Set these hands to the player
+ ply:SetHands( self )
+ self:SetOwner( ply )
+
+ -- Which hands should we use?
+ local info = GAMEMODE:GetHandsModel( ply )
+ if ( info ) then
+ self:SetModel( info.model )
+ self:SetSkin( info.skin )
+ self:SetBodyGroups( info.body )
+ end
+
+ -- Attach them to the viewmodel
+ local vm = ply:GetViewModel( 0 )
+ self:AttachToViewmodel( vm )
+
+ vm:DeleteOnRemove( self )
+ ply:DeleteOnRemove( self )
+
+end
+
+local defaultcolor = Vector( 62.0/255.0, 88.0/255.0, 106.0/255.0 )
+function ENT:GetPlayerColor()
+ local owner = self:GetOwner()
+ if owner and owner:IsValid() and owner.GetPlayerColor then
+ return owner:GetPlayerColor()
+ end
+
+ return defaultcolor
+end
+
+function ENT:ViewModelChanged( vm, old, new )
+
+ -- Ignore other peoples viewmodel changes!
+ if ( vm:GetOwner() != self:GetOwner() ) then return end
+
+ self:AttachToViewmodel( vm )
+
+end
+
+function ENT:AttachToViewmodel( vm )
+
+ self:AddEffects( EF_BONEMERGE )
+ self:SetParent( vm )
+ self:SetMoveType( MOVETYPE_NONE )
+
+ self:SetPos( Vector( 0, 0, 0 ) )
+ self:SetAngles( Angle( 0, 0, 0 ) )
+
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/base_code.lua b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/base_code.lua
new file mode 100644
index 0000000..981f9ca
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/base_code.lua
@@ -0,0 +1,498 @@
+/********************************************************
+ SWEP Construction Kit base code
+ Created by Clavus
+ Available for public use, thread at:
+ facepunch.com/threads/1032378
+
+
+ DESCRIPTION:
+ This script is meant for experienced scripters
+ that KNOW WHAT THEY ARE DOING. Don't come to me
+ with basic Lua questions.
+
+ Just copy into your SWEP or SWEP base of choice
+ and merge with your own code.
+
+ The SWEP.VElements, SWEP.WElements and
+ SWEP.ViewModelBoneMods tables are all optional
+ and only have to be visible to the client.
+********************************************************/
+
+function SWEP:Initialize()
+
+ // other initialize code goes here
+
+ if CLIENT then
+
+ // Create a new table for every weapon instance
+ self.VElements = table.FullCopy( self.VElements )
+ self.WElements = table.FullCopy( self.WElements )
+ self.ViewModelBoneMods = table.FullCopy( self.ViewModelBoneMods )
+
+ self:CreateModels(self.VElements) // create viewmodels
+ self:CreateModels(self.WElements) // create worldmodels
+
+ // init view model bone build function
+ if IsValid(self.Owner) then
+ local vm = self.Owner:GetViewModel()
+ if IsValid(vm) then
+ self:ResetBonePositions(vm)
+
+ // Init viewmodel visibility
+ if (self.ShowViewModel == nil or self.ShowViewModel) then
+ vm:SetColor(Color(255,255,255,255))
+ else
+ // we set the alpha to 1 instead of 0 because else ViewModelDrawn stops being called
+ vm:SetColor(Color(255,255,255,1))
+ // ^ stopped working in GMod 13 because you have to do Entity:SetRenderMode(1) for translucency to kick in
+ // however for some reason the view model resets to render mode 0 every frame so we just apply a debug material to prevent it from drawing
+ vm:SetMaterial("Debug/hsv")
+ end
+ end
+ end
+
+ end
+
+end
+
+function SWEP:Holster()
+
+ if CLIENT and IsValid(self.Owner) then
+ local vm = self.Owner:GetViewModel()
+ if IsValid(vm) then
+ self:ResetBonePositions(vm)
+ end
+ end
+
+ return true
+end
+
+function SWEP:OnRemove()
+ self:Holster()
+end
+
+if CLIENT then
+
+ SWEP.vRenderOrder = nil
+ function SWEP:ViewModelDrawn()
+
+ local vm = self.Owner:GetViewModel()
+ if !IsValid(vm) then return end
+
+ if (!self.VElements) then return end
+
+ self:UpdateBonePositions(vm)
+
+ if (!self.vRenderOrder) then
+
+ // we build a render order because sprites need to be drawn after models
+ self.vRenderOrder = {}
+
+ for k, v in pairs( self.VElements ) do
+ if (v.type == "Model") then
+ table.insert(self.vRenderOrder, 1, k)
+ elseif (v.type == "Sprite" or v.type == "Quad") then
+ table.insert(self.vRenderOrder, k)
+ end
+ end
+
+ end
+
+ for k, name in ipairs( self.vRenderOrder ) do
+
+ local v = self.VElements[name]
+ if (!v) then self.vRenderOrder = nil break end
+ if (v.hide) then continue end
+
+ local model = v.modelEnt
+ local sprite = v.spriteMaterial
+
+ if (!v.bone) then continue end
+
+ local pos, ang = self:GetBoneOrientation( self.VElements, v, vm )
+
+ if (!pos) then continue end
+
+ if (v.type == "Model" and IsValid(model)) then
+
+ model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ model:SetAngles(ang)
+ //model:SetModelScale(v.size)
+ local matrix = Matrix()
+ matrix:Scale(v.size)
+ model:EnableMatrix( "RenderMultiply", matrix )
+
+ if (v.material == "") then
+ model:SetMaterial("")
+ elseif (model:GetMaterial() != v.material) then
+ model:SetMaterial( v.material )
+ end
+
+ if (v.skin and v.skin != model:GetSkin()) then
+ model:SetSkin(v.skin)
+ end
+
+ if (v.bodygroup) then
+ for k, v in pairs( v.bodygroup ) do
+ if (model:GetBodygroup(k) != v) then
+ model:SetBodygroup(k, v)
+ end
+ end
+ end
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(true)
+ end
+
+ render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
+ render.SetBlend(v.color.a/255)
+ model:DrawModel()
+ render.SetBlend(1)
+ render.SetColorModulation(1, 1, 1)
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(false)
+ end
+
+ elseif (v.type == "Sprite" and sprite) then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ render.SetMaterial(sprite)
+ render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
+
+ elseif (v.type == "Quad" and v.draw_func) then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ cam.Start3D2D(drawpos, ang, v.size)
+ v.draw_func( self )
+ cam.End3D2D()
+
+ end
+
+ end
+
+ end
+
+ SWEP.wRenderOrder = nil
+ function SWEP:DrawWorldModel()
+
+ if (self.ShowWorldModel == nil or self.ShowWorldModel) then
+ self:DrawModel()
+ end
+
+ if (!self.WElements) then return end
+
+ if (!self.wRenderOrder) then
+
+ self.wRenderOrder = {}
+
+ for k, v in pairs( self.WElements ) do
+ if (v.type == "Model") then
+ table.insert(self.wRenderOrder, 1, k)
+ elseif (v.type == "Sprite" or v.type == "Quad") then
+ table.insert(self.wRenderOrder, k)
+ end
+ end
+
+ end
+
+ if (IsValid(self.Owner)) then
+ bone_ent = self.Owner
+ else
+ // when the weapon is dropped
+ bone_ent = self
+ end
+
+ for k, name in pairs( self.wRenderOrder ) do
+
+ local v = self.WElements[name]
+ if (!v) then self.wRenderOrder = nil break end
+ if (v.hide) then continue end
+
+ local pos, ang
+
+ if (v.bone) then
+ pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent )
+ else
+ pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent, "ValveBiped.Bip01_R_Hand" )
+ end
+
+ if (!pos) then continue end
+
+ local model = v.modelEnt
+ local sprite = v.spriteMaterial
+
+ if (v.type == "Model" and IsValid(model)) then
+
+ model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ model:SetAngles(ang)
+ //model:SetModelScale(v.size)
+ local matrix = Matrix()
+ matrix:Scale(v.size)
+ model:EnableMatrix( "RenderMultiply", matrix )
+
+ if (v.material == "") then
+ model:SetMaterial("")
+ elseif (model:GetMaterial() != v.material) then
+ model:SetMaterial( v.material )
+ end
+
+ if (v.skin and v.skin != model:GetSkin()) then
+ model:SetSkin(v.skin)
+ end
+
+ if (v.bodygroup) then
+ for k, v in pairs( v.bodygroup ) do
+ if (model:GetBodygroup(k) != v) then
+ model:SetBodygroup(k, v)
+ end
+ end
+ end
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(true)
+ end
+
+ render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
+ render.SetBlend(v.color.a/255)
+ model:DrawModel()
+ render.SetBlend(1)
+ render.SetColorModulation(1, 1, 1)
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(false)
+ end
+
+ elseif (v.type == "Sprite" and sprite) then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ render.SetMaterial(sprite)
+ render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
+
+ elseif (v.type == "Quad" and v.draw_func) then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ cam.Start3D2D(drawpos, ang, v.size)
+ v.draw_func( self )
+ cam.End3D2D()
+
+ end
+
+ end
+
+ end
+
+ function SWEP:GetBoneOrientation( basetab, tab, ent, bone_override )
+
+ local bone, pos, ang
+ if (tab.rel and tab.rel != "") then
+
+ local v = basetab[tab.rel]
+
+ if (!v) then return end
+
+ // Technically, if there exists an element with the same name as a bone
+ // you can get in an infinite loop. Let's just hope nobody's that stupid.
+ pos, ang = self:GetBoneOrientation( basetab, v, ent )
+
+ if (!pos) then return end
+
+ pos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ else
+
+ bone = ent:LookupBone(bone_override or tab.bone)
+
+ if (!bone) then return end
+
+ pos, ang = Vector(0,0,0), Angle(0,0,0)
+ local m = ent:GetBoneMatrix(bone)
+ if (m) then
+ pos, ang = m:GetTranslation(), m:GetAngles()
+ end
+
+ if (IsValid(self.Owner) and self.Owner:IsPlayer() and
+ ent == self.Owner:GetViewModel() and self.ViewModelFlip) then
+ ang.r = -ang.r // Fixes mirrored models
+ end
+
+ end
+
+ return pos, ang
+ end
+
+ function SWEP:CreateModels( tab )
+
+ if (!tab) then return end
+
+ // Create the clientside models here because Garry says we can't do it in the render hook
+ for k, v in pairs( tab ) do
+ if (v.type == "Model" and v.model and v.model != "" and (!IsValid(v.modelEnt) or v.createdModel != v.model) and
+ string.find(v.model, ".mdl") and file.Exists (v.model, "GAME") ) then
+
+ v.modelEnt = ClientsideModel(v.model, RENDER_GROUP_VIEW_MODEL_OPAQUE)
+ if (IsValid(v.modelEnt)) then
+ v.modelEnt:SetPos(self:GetPos())
+ v.modelEnt:SetAngles(self:GetAngles())
+ v.modelEnt:SetParent(self)
+ v.modelEnt:SetNoDraw(true)
+ v.createdModel = v.model
+ else
+ v.modelEnt = nil
+ end
+
+ elseif (v.type == "Sprite" and v.sprite and v.sprite != "" and (!v.spriteMaterial or v.createdSprite != v.sprite)
+ and file.Exists ("materials/"..v.sprite..".vmt", "GAME")) then
+
+ local name = v.sprite.."-"
+ local params = { ["$basetexture"] = v.sprite }
+ // make sure we create a unique name based on the selected options
+ local tocheck = { "nocull", "additive", "vertexalpha", "vertexcolor", "ignorez" }
+ for i, j in pairs( tocheck ) do
+ if (v[j]) then
+ params["$"..j] = 1
+ name = name.."1"
+ else
+ name = name.."0"
+ end
+ end
+
+ v.createdSprite = v.sprite
+ v.spriteMaterial = CreateMaterial(name,"UnlitGeneric",params)
+
+ end
+ end
+
+ end
+
+ local allbones
+ local hasGarryFixedBoneScalingYet = false
+
+ function SWEP:UpdateBonePositions(vm)
+
+ if self.ViewModelBoneMods then
+
+ if (!vm:GetBoneCount()) then return end
+
+ // !! WORKAROUND !! //
+ // We need to check all model names :/
+ local loopthrough = self.ViewModelBoneMods
+ if (!hasGarryFixedBoneScalingYet) then
+ allbones = {}
+ for i=0, vm:GetBoneCount() do
+ local bonename = vm:GetBoneName(i)
+ if (self.ViewModelBoneMods[bonename]) then
+ allbones[bonename] = self.ViewModelBoneMods[bonename]
+ else
+ allbones[bonename] = {
+ scale = Vector(1,1,1),
+ pos = Vector(0,0,0),
+ angle = Angle(0,0,0)
+ }
+ end
+ end
+
+ loopthrough = allbones
+ end
+ // !! ----------- !! //
+
+ for k, v in pairs( loopthrough ) do
+ local bone = vm:LookupBone(k)
+ if (!bone) then continue end
+
+ // !! WORKAROUND !! //
+ local s = Vector(v.scale.x,v.scale.y,v.scale.z)
+ local p = Vector(v.pos.x,v.pos.y,v.pos.z)
+ local ms = Vector(1,1,1)
+ if (!hasGarryFixedBoneScalingYet) then
+ local cur = vm:GetBoneParent(bone)
+ while(cur >= 0) do
+ local pscale = loopthrough[vm:GetBoneName(cur)].scale
+ ms = ms * pscale
+ cur = vm:GetBoneParent(cur)
+ end
+ end
+
+ s = s * ms
+ // !! ----------- !! //
+
+ if vm:GetManipulateBoneScale(bone) != s then
+ vm:ManipulateBoneScale( bone, s )
+ end
+ if vm:GetManipulateBoneAngles(bone) != v.angle then
+ vm:ManipulateBoneAngles( bone, v.angle )
+ end
+ if vm:GetManipulateBonePosition(bone) != p then
+ vm:ManipulateBonePosition( bone, p )
+ end
+ end
+ else
+ self:ResetBonePositions(vm)
+ end
+
+ end
+
+ function SWEP:ResetBonePositions(vm)
+ -- New code
+ vm:SetColor(color_white)
+ vm:SetMaterial("")
+ --------
+
+ if (!vm:GetBoneCount()) then return end
+ for i=0, vm:GetBoneCount() do
+ vm:ManipulateBoneScale( i, Vector(1, 1, 1) )
+ vm:ManipulateBoneAngles( i, Angle(0, 0, 0) )
+ vm:ManipulateBonePosition( i, Vector(0, 0, 0) )
+ end
+
+ end
+
+ /**************************
+ Global utility code
+ **************************/
+
+ // Fully copies the table, meaning all tables inside this table are copied too and so on (normal table.Copy copies only their reference).
+ // Does not copy entities of course, only copies their reference.
+ // WARNING: do not use on tables that contain themselves somewhere down the line or you'll get an infinite loop
+ function table.FullCopy( tab )
+
+ if (!tab) then return nil end
+
+ local res = {}
+ for k, v in pairs( tab ) do
+ if (type(v) == "table") then
+ res[k] = table.FullCopy(v) // recursion ho!
+ elseif (type(v) == "Vector") then
+ res[k] = Vector(v.x, v.y, v.z)
+ elseif (type(v) == "Angle") then
+ res[k] = Angle(v.p, v.y, v.r)
+ else
+ res[k] = v
+ end
+ end
+
+ return res
+
+ end
+
+end
+
diff --git a/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/client.lua b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/client.lua
new file mode 100644
index 0000000..40d72ea
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/client.lua
@@ -0,0 +1,1250 @@
+
+include('glon.lua')
+
+surface.CreateFont("12ptFont", {font = "Arial", size = 12, width = 500, antialias = true, additive = false})
+surface.CreateFont("24ptFont", {font = "Arial", size = 24, width = 500, antialias = true, additive = false})
+
+SWEP.useThirdPerson = false
+SWEP.thirdPersonAngle = Angle(0,-90,0)
+SWEP.thirdPersonDis = 100
+SWEP.mlast_x = ScrW()/2
+SWEP.mlast_y = ScrH()/2
+
+local playerBones = {
+ "ValveBiped.Bip01_Head1",
+ "ValveBiped.Bip01_Pelvis",
+ "ValveBiped.Bip01_Spine",
+ "ValveBiped.Bip01_Spine1",
+ "ValveBiped.Bip01_Spine2",
+ "ValveBiped.Bip01_Spine4",
+ "ValveBiped.Anim_Attachment_RH",
+ "ValveBiped.Bip01_R_Hand",
+ "ValveBiped.Bip01_R_Forearm",
+ "ValveBiped.Bip01_R_UpperArm",
+ "ValveBiped.Bip01_R_Clavicle",
+ "ValveBiped.Bip01_R_Foot",
+ "ValveBiped.Bip01_R_Toe0",
+ "ValveBiped.Bip01_R_Thigh",
+ "ValveBiped.Bip01_R_Calf",
+ "ValveBiped.Bip01_R_Shoulder",
+ "ValveBiped.Bip01_R_Elbow",
+ "ValveBiped.Bip01_Neck1",
+ "ValveBiped.Anim_Attachment_LH",
+ "ValveBiped.Bip01_L_Hand",
+ "ValveBiped.Bip01_L_Forearm",
+ "ValveBiped.Bip01_L_UpperArm",
+ "ValveBiped.Bip01_L_Clavicle",
+ "ValveBiped.Bip01_L_Foot",
+ "ValveBiped.Bip01_L_Toe0",
+ "ValveBiped.Bip01_L_Thigh",
+ "ValveBiped.Bip01_L_Calf",
+ "ValveBiped.Bip01_L_Shoulder",
+ "ValveBiped.Bip01_L_Elbow"
+ }
+
+SWEP.v_models = {}
+SWEP.v_panelCache = {}
+SWEP.v_modelListing = nil
+SWEP.v_bonemods = {}
+SWEP.v_modelbonebox = nil
+
+SWEP.w_models = {}
+SWEP.w_panelCache = {}
+SWEP.w_modelListing = nil
+
+SWEP.world_model = nil
+SWEP.cur_wmodel = nil
+
+SWEP.browser_callback = nil
+SWEP.modelbrowser = nil
+SWEP.modelbrowser_list = nil
+SWEP.matbrowser = nil
+SWEP.matbrowser_list = nil
+
+SWEP.tpsfocusbone = "ValveBiped.Bip01_R_Hand"
+
+SWEP.save_data = {}
+local save_data_template = {
+ ViewModel = SWEP.ViewModel,
+ CurWorldModel = SWEP.CurWorldModel,
+ w_models = {},
+ v_models = {},
+ v_bonemods = {},
+ ViewModelFOV = SWEP.ViewModelFOV,
+ HoldType = SWEP.HoldType,
+ ViewModelFlip = SWEP.ViewModelFlip,
+ IronSightsEnabled = true,
+ IronSightsPos = SWEP.IronSightsPos,
+ IronSightsAng = SWEP.IronSightsAng,
+ ShowViewModel = true,
+ ShowWorldModel = true
+}
+
+SWEP.ir_drag = {
+ x = { true, "-x", 25 },
+ y = { false, "y", 25 },
+ z = { true, "y", 25 },
+ pitch = { false, "y", 10 },
+ yaw = { false, "x", 10 },
+ roll = { false, "y", 10 }
+}
+
+SWEP.Frame = nil
+SWEP.cur_drag_mode = "x / z"
+SWEP.basecode = "FAILED TO READ BASE CODE"
+
+function SWEP:ClientInit()
+
+ SCKDebug("Client init start")
+
+ if (IsValid(self.Owner)) then
+ // init view model bone mods
+ local vm = self.Owner:GetViewModel()
+ if IsValid(vm) then
+ self:ResetBonePositions(vm)
+ end
+ end
+
+ local basecodepath = "lua/weapons/swep_construction_kit/base_code.lua"
+ self.basecode = file.Read(basecodepath, "GAME")
+
+ SCKDebug("Loaded base code")
+
+end
+
+function SimplePanel( parent )
+
+ local p = vgui.Create("DPanel", parent)
+ p.Paint = function() end
+ return p
+
+end
+
+function PrintVec( vec )
+ local px, py, pz = math.floor(vec.x*1000)/1000,math.floor(vec.y*1000)/1000,math.floor(vec.z*1000)/1000
+ return "Vector("..px..", "..py..", "..pz..")"
+end
+
+function PrintAngle( angle )
+ local pp, py, pr = math.floor(angle.p*1000)/1000,math.floor(angle.y*1000)/1000,math.floor(angle.r*1000)/1000
+ return "Angle("..pp..", "..py..", "..pr..")"
+end
+
+function PrintColor( col )
+ return "Color("..col.r..", "..col.g..", "..col.b..", "..col.a..")"
+end
+
+// Populates a DChoiceList with all the bones of the specified entity
+// returns if it has a first option
+function PopulateBoneList( choicelist, ent )
+ if (!IsValid(choicelist)) then return false end
+ if (!IsValid(ent)) then return end
+
+ SCKDebug("Populating bone list for entity "..tostring(ent))
+
+ if (ent == LocalPlayer()) then
+ // if the local player is in third person, his bone lookup is all messed up so
+ // we just use the predefined playerBones table
+ for k, v in pairs(playerBones) do
+ choicelist:AddChoice(v)
+ end
+
+ return true
+ else
+ local hasfirstoption
+ for i = 0, ent:GetBoneCount() - 1 do
+ local name = ent:GetBoneName(i)
+ if (ent:LookupBone(name)) then // filter out invalid bones
+ choicelist:AddChoice(name)
+ if (!firstoption) then hasfirstoption = true end
+ end
+ end
+
+ return hasfirstoption
+ end
+end
+
+function SWEP:CreateWeaponWorldModel()
+
+ local model = self.CurWorldModel
+ SCKDebug("Creating weapon world model")
+
+ if ((!self.world_model or (IsValid(self.world_model) and self.cur_wmodel != model)) and
+ string.find(model, ".mdl") and file.Exists(model,"GAME") ) then
+
+ if IsValid(self.world_model) then self.world_model:Remove() end
+ self.world_model = ClientsideModel(model, RENDERGROUP_TRANSLUCENT)
+ if (IsValid(self.world_model)) then
+ self.world_model:SetParent(self.Owner)
+ self.world_model:SetNoDraw(true)
+ self.cur_wmodel = model
+ if (self.world_model:LookupBone( "ValveBiped.Bip01_R_Hand" )) then
+ self.world_model:AddEffects(EF_BONEMERGE)
+ end
+ else
+ self.world_model = nil
+ self.cur_wmodel = nil
+ end
+
+ end
+
+end
+
+function SWEP:CreateModels( tab )
+
+ //if true then return end
+
+ // Create the clientside models here because Garry says we can't do it in the render hook
+ for k, v in pairs( tab ) do
+ if (v.type == "Model" and v.model and v.model != "" and (!IsValid(v.modelEnt) or v.createdModel != v.model) and
+ string.find(v.model, ".mdl") and file.Exists(v.model,"GAME") ) then
+
+ SCKDebug("Creating new ClientSideModel "..v.model)
+
+ v.modelEnt = ClientsideModel(v.model, RENDERGROUP_TRANSLUCENT)
+ if (IsValid(v.modelEnt)) then
+ v.modelEnt:SetPos(self:GetPos())
+ v.modelEnt:SetAngles(self:GetAngles())
+ v.modelEnt:SetParent(self)
+ v.modelEnt:SetNoDraw(true)
+ v.createdModel = v.model
+ else
+ v.modelEnt = nil
+ end
+
+ elseif (v.type == "Sprite" and v.sprite and v.sprite != "" and (!v.spriteMaterial or v.createdSprite != v.sprite) and file.Exists("materials/"..v.sprite..".vmt", "GAME")) then
+
+ SCKDebug("Creating new sprite "..v.sprite)
+
+ local name = v.sprite.."-"
+ local params = { ["$basetexture"] = v.sprite }
+ // make sure we create a unique name based on the selected options
+ local tocheck = { "nocull", "additive", "vertexalpha", "vertexcolor", "ignorez" }
+ for i, j in pairs( tocheck ) do
+ if (v[j]) then
+ params["$"..j] = 1
+ name = name.."1"
+ else
+ name = name.."0"
+ end
+ end
+
+ v.createdSprite = v.sprite
+ v.spriteMaterial = CreateMaterial(name,"UnlitGeneric",params)
+
+ end
+ end
+
+end
+
+function SWEP:Think()
+
+ self:CreateModels( self.v_models )
+ self:CreateModels( self.w_models )
+
+ // Some hacky shit to get 3rd person view compatible with
+ // other addons that override CalcView
+ self:CalcViewHookManagement()
+
+ /************************
+ Camera fiddling
+ ************************/
+ self.useThirdPerson = self:GetThirdPerson()
+
+ local mx, my = gui.MousePos()
+ local diffx, diffy = (mx - self.mlast_x), (my - self.mlast_y)
+
+ if (input.IsMouseDown(MOUSE_RIGHT) and !(diffx > 40 or diffy > 40) and self.Frame and self.Frame:IsVisible()) then // right mouse press without sudden jumps
+
+ if (self.useThirdPerson) then
+
+ if (input.IsKeyDown(KEY_E)) then
+ self.thirdPersonDis = math.Clamp( self.thirdPersonDis + diffy, 10, 500 )
+ else
+ self.thirdPersonAngle = self.thirdPersonAngle + Angle( diffy/2, diffx/2, 0 )
+ end
+
+ else
+ // ironsight adjustment
+ for k, v in pairs( self.ir_drag ) do
+ if (v[1]) then
+ local temp = GetConVar( "_sp_ironsight_"..k ):GetFloat()
+ if (v[2] == "x") then
+ local add = -(diffx/v[3])
+ if (self.ViewModelFlip) then add = add*-1 end
+ RunConsoleCommand( "_sp_ironsight_"..k, temp + add )
+ elseif (v[2] == "-x") then
+ local add = diffx/v[3]
+ if (self.ViewModelFlip) then add = add*-1 end
+ RunConsoleCommand( "_sp_ironsight_"..k, temp + add )
+ elseif (v[2] == "y") then
+ RunConsoleCommand( "_sp_ironsight_"..k, temp - diffy/v[3] )
+ end
+ end
+ end
+
+ end
+
+ end
+
+ self.mlast_x, self.mlast_y = mx, my
+end
+
+function SWEP:RemoveModels()
+
+ SCKDebug("Removing models")
+
+ for k, v in pairs( self.v_models ) do
+ if (IsValid( v.modelEnt )) then v.modelEnt:Remove() end
+ end
+ for k, v in pairs( self.w_models ) do
+ if (IsValid( v.modelEnt )) then v.modelEnt:Remove() end
+ end
+ self.v_models = {}
+ self.w_models = {}
+
+ if (IsValid(self.world_model)) then
+ self.world_model:Remove()
+ self.world_model = nil
+ self.cur_wmodel = nil
+ end
+end
+
+function SWEP:GetBoneOrientation( basetab, name, ent, bone_override, buildup )
+
+ local bone, pos, ang
+ local tab = basetab[name]
+
+ if (tab.rel and tab.rel != "") then
+
+ local v = basetab[tab.rel]
+
+ if (!v) then return end
+
+ if (!buildup) then
+ buildup = {}
+ end
+
+ table.insert(buildup, name)
+ if (table.HasValue(buildup, tab.rel)) then return end
+
+ // Technically, if there exists an element with the same name as a bone
+ // you can get in an infinite loop. Let's just hope nobody's that stupid.
+ pos, ang = self:GetBoneOrientation( basetab, tab.rel, ent, nil, buildup )
+
+ if (!pos) then return end
+
+ pos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ if (v.angle) then
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+ end
+
+ else
+
+ bone = ent:LookupBone(bone_override or tab.bone)
+
+ if (!bone) then return end
+
+ pos, ang = Vector(0,0,0), Angle(0,0,0)
+ local m = ent:GetBoneMatrix(bone)
+ if (m) then
+ pos, ang = m:GetTranslation(), m:GetAngles()
+ end
+
+ if (IsValid(self.Owner) and self.Owner:IsPlayer() and
+ ent == self.Owner:GetViewModel() and self.ViewModelFlip) then
+ ang.r = -ang.r // Fixes mirrored models
+ end
+
+ end
+
+ return pos, ang
+end
+
+local allbones
+local hasGarryFixedBoneScalingYet = false
+
+function SWEP:UpdateBonePositions(vm)
+
+ if self.v_bonemods then
+
+ if (!vm:GetBoneCount()) then return end
+
+ // !! WORKAROUND !! //
+ // We need to check all model names :/
+ local loopthrough = self.v_bonemods
+ if (!hasGarryFixedBoneScalingYet) then
+ allbones = {}
+ for i=0, vm:GetBoneCount() do
+ local bonename = vm:GetBoneName(i)
+ if (self.v_bonemods[bonename]) then
+ allbones[bonename] = self.v_bonemods[bonename]
+ else
+ allbones[bonename] = {
+ scale = Vector(1,1,1),
+ pos = Vector(0,0,0),
+ angle = Angle(0,0,0)
+ }
+ end
+ end
+
+ loopthrough = allbones
+ end
+ // !! ----------- !! //
+
+ for k, v in pairs( loopthrough ) do
+ local bone = vm:LookupBone(k)
+ if (!bone) then continue end
+
+ // !! WORKAROUND !! //
+ local s = Vector(v.scale.x,v.scale.y,v.scale.z)
+ local p = Vector(v.pos.x,v.pos.y,v.pos.z)
+ local ms = Vector(1,1,1)
+ if (!hasGarryFixedBoneScalingYet) then
+ local cur = vm:GetBoneParent(bone)
+ while(cur >= 0) do
+ local pscale = loopthrough[vm:GetBoneName(cur)].scale
+ ms = ms * pscale
+ cur = vm:GetBoneParent(cur)
+ end
+ end
+
+ //local bpos = vm:GetBonePosition(bone)
+ //local par = vm:GetBoneParent(bone)
+ s = s * ms
+
+ //SCKDebug("Bone ("..bone..") "..vm:GetBoneName(bone).." rel to p ("..par.."): "..tostring(bpos - (vm:GetBonePosition(vm:GetBoneParent(bone)) or bpos)))
+ //local relp = bpos - (vm:GetBonePosition(vm:GetBoneParent(bone)) or bpos)
+ //p = relp * ms - relp
+ //SCKDebug("Bone ("..bone..") scale = "..tostring(ms).." | newpos = "..tostring(p))
+
+ // !! ----------- !! //
+
+ if vm:GetManipulateBoneScale(bone) != s then
+ vm:ManipulateBoneScale( bone, s )
+ end
+ if vm:GetManipulateBoneAngles(bone) != v.angle then
+ vm:ManipulateBoneAngles( bone, v.angle )
+ end
+ if vm:GetManipulateBonePosition(bone) != p then
+ vm:ManipulateBonePosition( bone, p )
+ end
+ end
+ else
+ self:ResetBonePositions(vm)
+ end
+
+end
+
+function SWEP:ResetBonePositions(vm)
+
+ if (!vm:GetBoneCount()) then return end
+
+ for i=0, vm:GetBoneCount() do
+ vm:ManipulateBoneScale( i, Vector(1, 1, 1) )
+ vm:ManipulateBoneAngles( i, Angle(0, 0, 0) )
+ vm:ManipulateBonePosition( i, Vector(0, 0, 0) )
+ end
+
+end
+
+/********************************
+ All viewmodel drawing magic
+*********************************/
+SWEP.vRenderOrder = nil
+function SWEP:ViewModelDrawn()
+
+ //if true then return end
+ //SCKDebugRepeat( "SWEP:VMD", "Drawing viewmodel!" )
+
+ local vm = self.Owner:GetViewModel()
+ if !IsValid(vm) then return end
+
+ self:UpdateBonePositions(vm)
+ /*if vm.BuildBonePositions ~= self.BuildViewModelBones then
+ vm.BuildBonePositions = self.BuildViewModelBones
+ end*/
+
+ if (!self.vRenderOrder) then
+
+ // we build a render order because sprites need to be drawn after models
+ self.vRenderOrder = {}
+
+ for k, v in pairs( self.v_models ) do
+ if (v.type == "Model") then
+ table.insert(self.vRenderOrder, 1, k)
+ elseif (v.type == "Sprite" or v.type == "Quad") then
+ table.insert(self.vRenderOrder, k)
+ end
+ end
+
+ end
+
+ for k, name in ipairs( self.vRenderOrder ) do
+
+ local v = self.v_models[name]
+ if (!v) then self.vRenderOrder = nil break end
+
+ local model = v.modelEnt
+ local sprite = v.spriteMaterial
+
+ if (!v.bone) then continue end
+
+ local pos, ang = self:GetBoneOrientation( self.v_models, name, vm )
+
+ if (!pos) then continue end
+
+ if (v.type == "Model" and IsValid(model)) then
+
+ model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ model:SetAngles(ang)
+ //model:SetModelScale(v.size)
+ local matrix = Matrix()
+ matrix:Scale(v.size)
+ model:EnableMatrix( "RenderMultiply", matrix )
+
+ if (v.material == "") then
+ model:SetMaterial("")
+ elseif (model:GetMaterial() != v.material) then
+ model:SetMaterial( v.material )
+ end
+
+ if (v.skin != model:GetSkin()) then
+ model:SetSkin(v.skin)
+ end
+
+ for k, v in pairs( v.bodygroup ) do
+ if (model:GetBodygroup(k) != v) then
+ model:SetBodygroup(k, v)
+ end
+ end
+
+ // Ain't working :/
+ /*halo.Render({
+ Ents = {model},
+ Color = Color(255,0,0,200),
+ BlurX = 2,
+ BlurY = 2,
+ DrawPasses = 1,
+ Additive = true,
+ IgnoreZ = true
+ })*/
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(true)
+ end
+
+ render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
+ render.SetBlend(v.color.a/255)
+ model:DrawModel()
+ render.SetBlend(1)
+ render.SetColorModulation(1, 1, 1)
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(false)
+ end
+
+ elseif (v.type == "Sprite" and sprite) then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ render.SetMaterial(sprite)
+ render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
+
+ elseif (v.type == "Quad") then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ cam.Start3D2D(drawpos, ang, v.size)
+ draw.RoundedBox( 0, -20, -20, 40, 40, Color(200,0,0,100) )
+ surface.SetDrawColor( 255, 255, 255, 100 )
+ surface.DrawOutlinedRect( -20, -20, 40, 40 )
+ draw.SimpleTextOutlined("12pt arial","12ptFont",0, -12, Color(255,255,255,255), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 1, Color(0,0,0,255))
+ draw.SimpleTextOutlined("40x40 box","12ptFont",0, 2, Color(255,255,255,255), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 1, Color(0,0,0,255))
+ surface.SetDrawColor( 0, 255, 0, 230 )
+ surface.DrawLine( 0, 0, 0, 8 )
+ surface.DrawLine( 0, 0, 8, 0 )
+ cam.End3D2D()
+
+ end
+
+ end
+
+end
+
+/********************************
+ All worldmodel drawing science
+*********************************/
+SWEP.wRenderOrder = nil
+function SWEP:DrawWorldModel()
+
+ //if true then return end
+ //SCKDebugRepeat( "SWEP:WMD", "Drawing worldmodel!" )
+
+ local wm = self.world_model
+ if !IsValid(wm) then return end
+
+ if (!self.wRenderOrder) then
+
+ self.wRenderOrder = {}
+
+ for k, v in pairs( self.w_models ) do
+ if (v.type == "Model") then
+ table.insert(self.wRenderOrder, 1, k)
+ elseif (v.type == "Sprite" or v.type == "Quad") then
+ table.insert(self.wRenderOrder, k)
+ end
+ end
+
+ end
+
+ local bone_ent
+
+ if (IsValid(self.Owner)) then
+ self:SetColor(Color(255,255,255,255))
+ self:SetRenderMode(0)
+ wm:SetNoDraw(true)
+ if (self.Owner:GetActiveWeapon() != self.Weapon) then return end
+ wm:SetParent(self.Owner)
+ if (self.ShowWorldModel) then
+ wm:DrawModel()
+ end
+ bone_ent = self.Owner
+ else
+ // this only happens if the weapon is dropped, which shouldn't happen normally.
+ self:SetColor(Color(255,0,0,0))
+ self:SetRenderMode(1)
+ wm:SetNoDraw(false) // else DrawWorldModel stops being called for some reason
+ wm:SetParent(self)
+ //wm:SetPos(opos)
+ //wm:SetAngles(oang)
+ if (self.ShowWorldModel) then
+ wm:DrawModel()
+ end
+
+ // the reason that we don't always use this bone is because it lags 1 frame behind the player's right hand bone when held
+ bone_ent = wm
+ end
+
+ /* BASE CODE FOR NEW SWEPS */
+ /*self:DrawModel()
+ if (IsValid(self.Owner)) then
+ bone_ent = self.Owner
+ else
+ // when the weapon is dropped
+ bone_ent = self
+ end*/
+
+ for k, name in pairs( self.wRenderOrder ) do
+
+ local v = self.w_models[name]
+ if (!v) then self.wRenderOrder = nil break end
+
+ local pos, ang
+
+ if (v.bone) then
+ pos, ang = self:GetBoneOrientation( self.w_models, name, bone_ent )
+ else
+ pos, ang = self:GetBoneOrientation( self.w_models, name, bone_ent, "ValveBiped.Bip01_R_Hand" )
+ end
+
+ if (!pos) then continue end
+
+ local model = v.modelEnt
+ local sprite = v.spriteMaterial
+
+ if (v.type == "Model" and IsValid(model)) then
+
+ model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ model:SetAngles(ang)
+ //model:SetModelScale(v.size)
+ local matrix = Matrix()
+ matrix:Scale(v.size)
+ model:EnableMatrix( "RenderMultiply", matrix )
+
+ if (v.material == "") then
+ model:SetMaterial("")
+ elseif (model:GetMaterial() != v.material) then
+ model:SetMaterial( v.material )
+ end
+
+ if (v.skin != model:GetSkin()) then
+ model:SetSkin(v.skin)
+ end
+
+ for k, v in pairs( v.bodygroup ) do
+ if (model:GetBodygroup(k) != v) then
+ model:SetBodygroup(k, v)
+ end
+ end
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(true)
+ end
+
+ render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
+ render.SetBlend(v.color.a/255)
+ model:DrawModel()
+ render.SetBlend(1)
+ render.SetColorModulation(1, 1, 1)
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(false)
+ end
+
+ elseif (v.type == "Sprite" and sprite) then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ render.SetMaterial(sprite)
+ render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
+
+ elseif (v.type == "Quad") then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ cam.Start3D2D(drawpos, ang, v.size)
+ draw.RoundedBox( 0, -20, -20, 40, 40, Color(200,0,0,100) )
+ surface.SetDrawColor( 255, 255, 255, 100 )
+ surface.DrawOutlinedRect( -20, -20, 40, 40 )
+ draw.SimpleTextOutlined("12pt arial","12ptFont",0, -12, Color(255,255,255,255), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 1, Color(0,0,0,255))
+ draw.SimpleTextOutlined("40x40 box","12ptFont",0, 2, Color(255,255,255,255), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 1, Color(0,0,0,255))
+ surface.SetDrawColor( 0, 255, 0, 230 )
+ surface.DrawLine( 0, 0, 0, 8 )
+ surface.DrawLine( 0, 0, 8, 0 )
+ cam.End3D2D()
+
+ end
+
+ end
+
+end
+
+function SWEP:Holster()
+ self.useThirdPerson = false
+
+ local vm = self.Owner:GetViewModel()
+ if IsValid(vm) then
+ self:ResetBonePositions(vm)
+ end
+
+ return true
+end
+
+local function DrawDot( x, y )
+
+ surface.SetDrawColor(100, 100, 100, 255)
+ surface.DrawRect(x - 2, y - 2, 4, 4)
+
+ surface.SetDrawColor(255, 255, 255, 255)
+ surface.DrawRect(x - 1, y - 1, 2, 2)
+
+end
+
+SWEP.FirstTimeOpen = true
+
+function SWEP:DrawHUD()
+
+ DrawDot( ScrW()/2, ScrH()/2 )
+ DrawDot( ScrW()/2 + 10, ScrH()/2 )
+ DrawDot( ScrW()/2 - 10, ScrH()/2 )
+ DrawDot( ScrW()/2, ScrH()/2 + 10 )
+ DrawDot( ScrW()/2, ScrH()/2 - 10 )
+
+ if (self.Frame and self.Frame:IsVisible()) then
+
+ self.FirstTimeOpen = false
+ local text = ""
+ if (self.useThirdPerson) then
+ text = "Hold right mouse and drag to rotate. Additionally hold E key to zoom."
+ else
+ text = "Hold right mouse and drag to adjust ironsights (mode: "..self.cur_drag_mode..")"
+ end
+ draw.SimpleTextOutlined(text, "default", ScrW()/2, ScrH()/4, Color(255,255,255,255), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 1, Color(20,20,20,255))
+
+ elseif (self.FirstTimeOpen) then
+ draw.SimpleTextOutlined("Press right mouse to open menu", "default", ScrW()/2, ScrH()/4, Color(255,255,255,255), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 1, Color(20,20,20,255))
+ end
+
+end
+
+/****** Create model browser *****/
+// callback = function( selected_model )
+function SWEP:OpenBrowser( current, browse_type, callback )
+
+ local wep = self
+ wep.browser_callback = callback
+ wep.Frame:SetVisible( false )
+
+ if (browse_type == "model" and wep.modelbrowser) then
+ wep.modelbrowser:SetVisible(true)
+ wep.modelbrowser:MakePopup()
+ wep.modelbrowser_list.OnRowSelected(nil,nil,current)
+ return
+ elseif (browse_type == "material" and wep.matbrowser) then
+ wep.matbrowser:SetVisible(true)
+ wep.matbrowser:MakePopup()
+ wep.matbrowser_list.OnRowSelected(nil,nil,current)
+ return
+ end
+
+ local browser = vgui.Create("DFrame")
+ browser:SetSize( 480, ScrH()*0.8 )
+ browser:SetPos( 50, 50 )
+ browser:SetDraggable( true )
+ browser:ShowCloseButton( false )
+ browser:SetSizable( true )
+ browser:SetDeleteOnClose( false )
+
+ if (browse_type == "model") then
+ browser:SetTitle( "Model browser" )
+ wep.modelbrowser = browser
+ elseif (browse_type == "material") then
+ browser:SetTitle( "Material browser" )
+ wep.matbrowser = browser
+ end
+
+ local tree = vgui.Create( "DTree", browser )
+ //tree:SetPos( 5, 30 )
+ //tree:SetSize( browser:GetWide() - 10, browser:GetTall()-355 )
+ tree:SetTall(300)
+ tree:DockPadding(5,5,5,5)
+ tree:Dock(TOP)
+
+ local nodelist = {}
+ local filecache = {}
+ local checked = {}
+
+ local modlist = vgui.Create("DListView", browser)
+ modlist:SetMultiSelect(false)
+ modlist:SetDrawBackground(true)
+ if (browse_type == "model") then
+ modlist:AddColumn("Model")
+ elseif (browse_type == "material") then
+ modlist:AddColumn("Material")
+ end
+ modlist:DockPadding(5,5,5,0)
+ modlist:Dock(FILL)
+
+ local bpanel = vgui.Create("DPanel", browser)
+ bpanel:SetTall(200)
+ bpanel:SetDrawBackground(false)
+ bpanel:DockMargin(5,5,5,5)
+ bpanel:Dock(BOTTOM)
+
+ local modzoom = 30
+ local modview
+
+ if (browse_type == "model") then
+ modview = vgui.Create("DModelPanel", bpanel)
+ modview:SetModel("")
+ modview:SetCamPos( Vector(modzoom,modzoom,modzoom/2) )
+ modview:SetLookAt( Vector( 0, 0, 0 ) )
+ elseif (browse_type == "material") then
+ modview = vgui.Create("DImage", bpanel)
+ //modview:SetImage("")
+ end
+
+ modview:SetSize(200, 200)
+ modview:Dock(LEFT)
+
+ local rpanel = vgui.Create("DPanel", bpanel)
+ rpanel:SetDrawBackground(false)
+ rpanel:DockPadding(5,0,0,0)
+ rpanel:Dock(FILL)
+
+ local mdlabel = vgui.Create("DLabel", rpanel)
+ mdlabel:SetText( current )
+ mdlabel:SizeToContents()
+ mdlabel:Dock(TOP)
+
+ if (browse_type == "model") then
+
+ local zoomslider = vgui.Create( "DNumSlider", rpanel)
+ zoomslider:SetText( "Zoom" )
+ zoomslider:SetMin( 8 )
+ zoomslider:SetMax( 256 )
+ zoomslider:SetDecimals( 0 )
+ zoomslider:SetValue( modzoom )
+ zoomslider.Wang.ConVarChanged = function( panel, value )
+ local modzoom = tonumber(value)
+ modview:SetCamPos( Vector(modzoom,modzoom,modzoom/2) )
+ modview:SetLookAt( Vector( 0, 0, 0 ) )
+ end
+ zoomslider:Dock(FILL)
+
+ end
+
+ local selected = ""
+
+ modlist.OnRowSelected = function( panel, line, override )
+ if (type(override) != "string") then override = nil end // for some reason the list itself throws a panel at it in the callback
+ local path = override or modlist:GetLine(line):GetValue(1)
+
+ if (browse_type == "model") then
+ modview:SetModel(path)
+ elseif (browse_type == "material") then
+ if (path:sub( 1, 10 ) == "materials/") then
+ path = path:sub( 11 ) // removes the "materials/" part
+ end
+ path = path:gsub( "%.vmt", "" )
+ if (file.Exists( "materials/"..path..".vmt", "GAME" )) then
+ modview:SetImage(path)
+ end
+ end
+
+ mdlabel:SetText(path)
+ selected = path
+ end
+
+ // set the default
+ modlist.OnRowSelected(nil,nil,current)
+ if (browse_type == "model") then
+ wep.modelbrowser_list = modlist
+ elseif (browse_type == "material") then
+ wep.matbrowser_list = modlist
+ end
+
+ local cancelbtn = vgui.Create("DButton", rpanel)
+ cancelbtn:SetTall(20)
+ cancelbtn:SetText("cancel")
+ cancelbtn.DoClick = function()
+ if (wep.Frame) then
+ wep.Frame:SetVisible(true)
+ end
+ browser:Close()
+ end
+ cancelbtn:Dock(BOTTOM)
+
+ local choosebtn = vgui.Create("DButton", rpanel)
+ choosebtn:SetTall(20)
+ if (browse_type == "model") then
+ choosebtn:SetText("DO WANT THIS MODEL")
+ elseif (browse_type == "material") then
+ choosebtn:SetText("DO WANT THIS MATERIAL")
+ end
+
+ choosebtn.DoClick = function()
+ if (wep.browser_callback) then
+ pcall(wep.browser_callback, selected)
+ end
+ if (wep.Frame) then
+ wep.Frame:SetVisible(true)
+ end
+ browser:Close()
+ end
+ choosebtn:DockMargin(0,0,0,5)
+ choosebtn:Dock(BOTTOM)
+
+
+
+ local LoadDirectories
+ local AddNode = function( base, dir, tree_override )
+
+ local newpath = base.."/"..dir
+ local basenode = nodelist[base]
+
+ if (tree_override) then
+ newpath = dir
+ basenode = tree_override
+ end
+
+ if (!basenode) then
+ print("No base node for \""..tostring(base).."\", \""..tostring(dir).."\", "..tostring(tree_override))
+ end
+
+ nodelist[newpath] = basenode:AddNode( dir )
+ nodelist[newpath].DoClick = function()
+ LoadDirectories( newpath )
+ modlist:Clear()
+ modlist:SetVisible(true)
+
+ if (filecache[newpath]) then
+ for k, f in pairs(filecache[newpath]) do
+ modlist:AddLine(f)
+ end
+ else
+ filecache[newpath] = {}
+ local files, folders
+ if (newpath:sub(1,9) == "materials") then
+ files, folders = file.Find(newpath.."/*.vmt", "GAME")
+ else
+ files, folders = file.Find(newpath.."/*.mdl", "GAME")
+ end
+ table.sort(files)
+ for k, f in pairs(files) do
+ local newfilepath = newpath.."/"..f
+ modlist:AddLine(newfilepath)
+ table.insert(filecache[newpath], newfilepath)
+ end
+ end
+ end
+
+ end
+
+ if (browse_type == "model") then
+ AddNode( "", "models", tree )
+ elseif (browse_type == "material") then
+ AddNode( "", "materials", tree )
+ end
+
+ LoadDirectories = function( v )
+
+ if (table.HasValue(checked,v)) then return end
+ local files
+ files, newdirs = file.Find(v.."/*", "GAME")
+ table.insert(checked, v)
+
+ table.sort(newdirs)
+
+ for _, dir in pairs(newdirs) do
+ AddNode( v, dir )
+ end
+
+ end
+
+ if (browse_type == "model") then
+ LoadDirectories( "models" )
+ elseif (browse_type == "material") then
+ LoadDirectories( "materials" )
+ end
+
+ browser:SetVisible( true )
+ browser:MakePopup()
+
+end
+
+/***************************
+ Menu
+***************************/
+local function CreateMenu( preset )
+
+ local wep = GetSCKSWEP( LocalPlayer() )
+ if !IsValid(wep) then return nil end
+
+ wep.save_data = table.Copy(save_data_template)
+
+ if (preset) then
+ // use the preset
+ for k, v in pairs( preset ) do
+ wep.save_data[k] = v
+ end
+ end
+
+ // Now for the actual menu:
+ local f = vgui.Create("DFrame")
+ f:SetSize( 480, ScrH()*0.8 )
+ f:SetPos( 50, 50 )
+ f:SetTitle( "SWEP Construction Kit" )
+ f:SetDraggable( true )
+ f:ShowCloseButton( true )
+ f:SetSizable( true )
+ f:SetDeleteOnClose( false )
+
+ local tpanel= vgui.Create( "DPanel", f )
+ tpanel:SetDrawBackground(false)
+ tpanel:SetTall(20)
+ tpanel:DockMargin(0,0,0,5)
+ tpanel:Dock(TOP)
+
+ local tpsbonelist = vgui.Create( "DComboBox", tpanel )
+ tpsbonelist:SetWide(150)
+ tpsbonelist:SetToolTip("Bone to focus third person view on")
+ tpsbonelist.OnSelect = function( p, index, value )
+ wep.tpsfocusbone = value
+ end
+ tpsbonelist:SetText( wep.tpsfocusbone )
+ tpsbonelist:DockMargin(5,0,0,0)
+ tpsbonelist:Dock(RIGHT)
+
+ local tlabel = vgui.Create( "DLabel", tpanel )
+ tlabel:SetText( "Focus:" )
+ tlabel:SizeToContents()
+ tlabel:SetTall(20)
+ tlabel:DockMargin(10,0,0,0)
+ tlabel:Dock(RIGHT)
+
+ PopulateBoneList( tpsbonelist, LocalPlayer() )
+
+ local tbtn = vgui.Create( "DButton", tpanel )
+ tbtn:SetText( "Toggle thirdperson" )
+ tbtn.DoClick = function()
+ RunConsoleCommand("swepck_togglethirdperson")
+ end
+
+ tbtn:Dock(FILL)
+
+ local tab = vgui.Create( "DPropertySheet", f )
+
+ wep.ptool = vgui.Create("DPanel", tab)
+ wep.ptool.Paint = function() surface.SetDrawColor(70,70,70,255) surface.DrawRect(0,0,wep.ptool:GetWide(),wep.ptool:GetTall()) end
+ wep.pweapon = vgui.Create("DPanel", tab)
+ wep.pweapon.Paint = function() surface.SetDrawColor(70,70,70,255) surface.DrawRect(0,0,wep.pweapon:GetWide(),wep.pweapon:GetTall()) end
+ wep.pironsight = vgui.Create("DPanel", tab)
+ wep.pironsight.Paint = function() surface.SetDrawColor(70,70,70,255) surface.DrawRect(0,0,wep.pironsight:GetWide(),wep.pironsight:GetTall()) end
+ wep.pmodels = vgui.Create("DPanel", tab)
+ wep.pmodels.Paint = function() surface.SetDrawColor(70,70,70,255) surface.DrawRect(0,0,wep.pmodels:GetWide(),wep.pmodels:GetTall()) end
+ wep.pwmodels = vgui.Create("DPanel", tab)
+ wep.pwmodels.Paint = function() surface.SetDrawColor(70,70,70,255) surface.DrawRect(0,0,wep.pwmodels:GetWide(),wep.pwmodels:GetTall()) end
+
+ tab:AddSheet( "Tool", wep.ptool, nil, false, false, "Modify tool settings" )
+ tab:AddSheet( "Weapon", wep.pweapon, nil, false, false, "Modify weapon settings" )
+ tab:AddSheet( "Ironsights", wep.pironsight, nil, false, false, "Modify ironsights" )
+ tab:AddSheet( "View Models", wep.pmodels, nil, false, false, "Modify view models" )
+ tab:AddSheet( "World Models", wep.pwmodels, nil, false, false, "Modify world models" )
+
+ wep.ptool:DockPadding(5, 5, 5, 5)
+ wep.pweapon:DockPadding(5, 5, 5, 5)
+ wep.pironsight:DockPadding(5, 5, 5, 5)
+ wep.pmodels:DockPadding(5, 5, 5, 5)
+ wep.pwmodels:DockPadding(5, 5, 5, 5)
+
+ tab:Dock(FILL)
+
+ /*****************
+ Tool page
+ *****************/
+ include("weapons/"..wep:GetClass().."/menu/tool.lua")
+
+ /*****************
+ Weapon page
+ *****************/
+ include("weapons/"..wep:GetClass().."/menu/weapon.lua")
+
+ /*********************
+ Ironsights page
+ *********************/
+ include("weapons/"..wep:GetClass().."/menu/ironsights.lua")
+
+ /****************************************
+ View models and World models page
+ ****************************************/
+ include("weapons/"..wep:GetClass().."/menu/models.lua")
+
+ // finally, return the frame!
+ return f
+
+end
+
+function SWEP:OpenMenu( preset )
+ if (!self.Frame) then
+ self.Frame = CreateMenu( preset )
+ end
+
+ if (IsValid(self.Frame)) then
+ self.Frame:SetVisible(true)
+ self.Frame:MakePopup()
+ else
+ self.Frame = nil
+ end
+
+end
+
+function SWEP:OnRemove()
+ self:CleanMenu()
+end
+
+function SWEP:OnDropWeapon()
+ self.useThirdPerson = false
+ self.LastOwner = nil
+ if (!self.Frame) then return end
+ self.Frame:Close()
+end
+
+function SWEP:CleanMenu()
+ self:RemoveModels()
+ if (!self.Frame) then return end
+
+ self.v_modelListing = nil
+ self.w_modelListing = nil
+ self.v_panelCache = {}
+ self.w_panelCache = {}
+ self.Frame:Remove()
+ self.Frame = nil
+end
+
+function SWEP:HUDShouldDraw( el )
+ return el != "CHudAmmo" and el != "CHudSecondaryAmmo"
+end
+
+/***************************
+ Third person view
+***************************/
+function TPCalcView(pl, pos, angles, fov)
+
+ local wep = pl:GetActiveWeapon()
+ if (!IsValid(wep) or !wep.IsSCK or !wep.useThirdPerson) then
+ wep.useThirdPerson = false
+ return
+ end
+
+ local look_pos = pos
+ local rhand_bone = pl:LookupBone(wep.tpsfocusbone)
+ if (rhand_bone) then
+ look_pos = pl:GetBonePosition( rhand_bone )
+ end
+
+ local view = {}
+ view.origin = look_pos + ((pl:GetAngles()+wep.thirdPersonAngle):Forward()*wep.thirdPersonDis)
+ view.angles = (look_pos - view.origin):Angle()
+ view.fov = fov
+
+ return view
+end
+
+oldCVHooks = {}
+hooksCleared = false
+local function CVHookReset()
+
+ //print("Hook reset")
+ hook.Remove( "CalcView", "TPCalcView" )
+ for k, v in pairs( oldCVHooks ) do
+ hook.Add("CalcView", k, v)
+ end
+ oldCVHooks = {}
+ hooksCleared = false
+
+end
+
+function SWEP:CalcViewHookManagement()
+
+ if (!hooksCleared) then
+
+ local CVHooks = hook.GetTable()["CalcView"]
+ if CVHooks then
+
+ for k, v in pairs( CVHooks ) do
+ oldCVHooks[k] = v
+ hook.Remove( "CalcView", k )
+ end
+
+ end
+
+ hook.Add("CalcView", "TPCalcView", TPCalcView)
+ hooksCleared = true
+ else
+ timer.Create("CVHookReset", 2, 1, CVHookReset)
+ end
+
+end
+
+hook.Add("ShouldDrawLocalPlayer", "ThirdPerson", function(pl)
+ local wep = pl:GetActiveWeapon()
+ if (wep.useThirdPerson) then
+ return true
+ end
+end)
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/glon.lua b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/glon.lua
new file mode 100644
index 0000000..1005106
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/glon.lua
@@ -0,0 +1,414 @@
+// NOTE by Clavus: glon was removed from GMod 13, replaced by the util.TableToJSON etc functions
+// In order to maintain compatability and not rewrite all that shit, I'm including it with the SCK.
+
+-- GLON: Garry's Mod Lua Object Notation
+-- A extension of LON: Lua Object Notation
+-- Made entirely by Deco Da Man
+-- Types:
+ -- 2: table
+ -- 3: array
+ -- 4: fasle boolean
+ -- 5: true boolean
+ -- 6: number (NOT COMPRESSED, it isn't worth it)
+ -- 7: string
+ ---- non-LON types start here!
+ -- 8: Vector (NOT COMPRESSED, it isn't worth it)
+ -- 9: Angle (NOT COMPRESSED, it isn't worth it)
+ -- 10: Entity (Can do players, vehicles, npcs, weapons and any other type of entity (-1 for null entity))
+ -- 11: Player (By UserID)
+ -- 12: CEffectData
+ -- 13: ConVar (Not ClientConVar)
+ -- 15: Color
+ -- 254: The number equal to -math.huge (tostring(math.huge) == "-1.#INF")
+ -- 254: The number equal to math.huge (tostring(math.huge) == "1.#INF")
+ -- 255: reference (Sends the ID of the table to use (for "local t = {} t.a=t"))
+/*local pairs = pairs
+local type = type
+local string = string
+local math = math
+local tostring = tostring
+local ValidEntity = ValidEntity
+local error = error
+local print = print
+local setmetatable = setmetatable
+local Vector = Vector
+local Angle = Angle
+local Entity = Entity
+local EffectData = EffectData
+local GetConVar = GetConVar
+local tonumber = tonumber
+local player = player
+local IsValid = IsValid
+module("glon")*/
+glon = {}
+local encode_types
+local decode_types
+local Write
+local Read
+
+local function InDataEscape(s)
+ s = string.gsub(s, "([\1\2])", "\2%1")
+ s = string.gsub(s, "%z", "\2\3")
+ s = string.gsub(s, "\"", "\4") // escape the " character to simplify client commands
+ return s
+end
+
+encode_types = {
+ ["nil"] = {nil, function()
+ return "", nil
+ end},
+ table = {2, function(o, rtabs)
+ for k,v in pairs(rtabs) do
+ if v == o then
+ return tostring(k).."\1", 255
+ end
+ end
+ rtabs[#rtabs+1] = o
+ local is_array = true
+ local i = 0
+ for k,v in pairs(o) do
+ i = i + 1
+ if k ~= i or type(k) ~= "number" or math.floor(k) ~= k then
+ is_array = false
+ break end
+ end
+ local s = ""
+ for k,v in pairs(o) do
+
+ if ( !encode_types[type(v)] ) then continue end
+
+ if not is_array then
+ s = s..Write(k, rtabs)
+ end
+ s = s..Write(v, rtabs)
+ end
+ return s.."\1", is_array and 3
+ end},
+ boolean = {4, function(o)
+ return "", o and 5
+ end},
+ number = {6, function(o)
+ o = o == 0 and "" or o
+ return o == ((o == math.huge or o == -math.huge) and "") or tostring(o).."\1", (o == math.huge and 254) or (o == -math.huge and 253)
+ end},
+ string = {7, function(o)
+ return InDataEscape(o).."\1"
+ end},
+ -- non-LON types start here!
+ Vector = {8, function(o)
+ return o.x.."\1"..o.y.."\1"..o.z.."\1"
+ end},
+ Angle = {9, function(o)
+ return o.p.."\1"..o.y.."\1"..o.r.."\1"
+ end},
+ Entity = {10, function(o)
+ return (ValidEntity(o) and o:EntIndex() or -1).."\1"
+ end},
+ NPC = {10, function(o)
+ return (ValidEntity(o) and o:EntIndex() or -1).."\1"
+ end},
+ Weapon = {10, function(o)
+ return (ValidEntity(o) and o:EntIndex() or -1).."\1"
+ end},
+ Player = {11, function(o)
+ return o:EntIndex().."\1"
+ end},
+ CEffectData = {12, function(o, rtabs)
+ local t = {}
+ if o:GetAngle() ~= Angle(0,0,0) then
+ t.a = o:GetAngle()
+ end
+ if o:GetAttachment() ~= 0 then
+ t.h = o:GetAttachment()
+ end
+ if o:GetEntity():IsValid() then
+ t.e = o:GetEntity()
+ end
+ if o:GetMagnitude() ~= 0 then
+ t.m = o:GetMagnitude()
+ end
+ if o:GetNormal() ~= Vector(0,0,0) then
+ t.n = o:GetNormal()
+ end
+ if o:GetOrigin() ~= Vector(0,0,0) then
+ t.o = o:GetOrigin()
+ end
+ if o:GetRadius() ~= 0 then
+ t.r = o:GetRadius()
+ end
+ if o:GetScale() ~= 0 then
+ t.c = o:GetScale()
+ end
+ if o:GetStart() ~= 0 then
+ t.s = o:GetStart()
+ end
+ if o:GetSurfaceProp() ~= 0 then
+ t.p = o:GetSurfaceProp()
+ end
+ return encode_types.table[2](t, rtabs)
+ end},
+ ConVar = {13, function(o)
+ return InDataEscape(o:GetName()).."\1"
+ end},
+ PhysObj = {14, function(o)
+ local parent, obj, id = o:GetEntity()
+ for i = 1, parent:GetPhysicsObjectCount() do
+ obj = parent:GetPhysicsObjectNum()
+ if obj == o then
+ id = i
+ break end
+ end
+ return parent:EntIndex().."\1"..id.."\1"
+ end},
+ Color = {15, function(o)
+ return o.r.."\1"..o.g.."\1"..o.b.."\1"..o.a.."\1"
+ end},
+}
+
+Write = function(data, rtabs)
+ local t = encode_types[type(data)]
+ if t then
+ local data, id_override = t[2](data, rtabs)
+ local char = id_override or t[1] or ""
+ if char ~= "" then char = string.char(char) end
+ return char..(data or "")
+ else
+ error(string.format("Tried to write unwriteable type: %s",
+ type(data)))
+ end
+end
+
+local CEffectDataTranslation = {
+ a = "Angle",
+ h = "Attachment",
+ e = "Entity",
+ m = "Magnitude",
+ n = "Normal",
+ o = "Origin",
+ r = "Radius",
+ c = "Scale",
+ s = "Start",
+ p = "SurfaceProp",
+}
+decode_types = {
+ -- \2\6omg\1\6omgavalue\1\1
+ [2 ] = function(reader, rtabs) -- table
+ local t, c, pos = {}, reader:Next()
+ rtabs[#rtabs+1] = t
+ local stage = false
+ local key
+ while true do
+ c, pos = reader:Peek()
+ if c == "\1" then
+ if stage then
+ error(string.format("Expected value to match key at %s! (Got EO Table)",
+ pos))
+ else
+ reader:Next()
+ return t
+ end
+ else
+ if stage then
+ t[key] = Read(reader, rtabs)
+ else
+ key = Read(reader, rtabs)
+ end
+ stage = not stage
+ end
+ end
+ end,
+ [3 ] = function(reader, rtabs) -- array
+ local t, i, c, pos = {}, 1, reader:Next()
+ rtabs[#rtabs+1] = t
+ while true do
+ c, pos = reader:Peek()
+ if c == "\1" then
+ reader:Next()
+ return t
+ else
+ t[i] = Read(reader, rtabs)
+ i = i+1
+ end
+ end
+ end,
+ [4 ] = function(reader) -- false boolean
+ reader:Next()
+ return false
+ end,
+ [5 ] = function(reader) -- true boolean
+ reader:Next()
+ return true
+ end,
+ [6 ] = function(reader) -- number
+ local s, c, pos, e = "", reader:Next()
+ while true do
+ c = reader:Next()
+ if not c then
+ error(string.format("Expected \1 to end number at %s! (Got EOF!)",
+ pos))
+ elseif c == "\1" then
+ break
+ else
+ s = s..c
+ end
+ end
+ if s == "" then s = "0" end
+ local n = tonumber(s)
+ if not n then
+ error(string.format("Invalid number at %s! (%q)",
+ pos, s))
+ end
+ return n
+ end,
+ [7 ] = function(reader) -- string
+ local s, c, pos, e = "", reader:Next()
+ while true do
+ c = reader:Next()
+ if not c then
+ error(string.format("Expected unescaped \1 to end string at position %s! (Got EOF)",
+ pos))
+ elseif e then
+ if c == "\3" then
+ s = s.."\0"
+ else
+ s = s..c
+ end
+ e = false
+ elseif c == "\2" then
+ e = true
+ elseif c == "\1" then
+ s = string.gsub(s, "\4", "\"") // unescape quotes
+ return s
+ else
+ s = s..c
+ end
+ end
+ end,
+ [8 ] = function(reader) -- Vector
+ local x = decode_types[6](reader)
+ reader:StepBack()
+ local y = decode_types[6](reader)
+ reader:StepBack()
+ local z = decode_types[6](reader)
+ return Vector(x, y, z)
+ end,
+ [9 ] = function(reader) -- Angle
+ local p = decode_types[6](reader)
+ reader:StepBack()
+ local y = decode_types[6](reader)
+ reader:StepBack()
+ local r = decode_types[6](reader)
+ return Angle(p, y, r)
+ end,
+ [10 ] = function(reader) -- Entity
+ return Entity(decode_types[6](reader))
+ end,
+ [11 ] = function(reader) -- Player
+ local num = decode_types[6](reader)
+ return player.GetByID(num)
+ end,
+ [12 ] = function(reader, rtabs) -- CEffectData
+ local t = decode_types[2](reader, rtabs)
+ local d = EffectData()
+ for k,v in pairs(t) do
+ d["Set"..CEffectDataTranslation[k]](d, v)
+ end
+ return d
+ end,
+ [13 ] = function(reader) -- ConVar
+ return GetConVar(decode_types[7](reader))
+ end,
+ [14 ] = function(reader) -- PhysicsObject
+
+ local ent = Entity(decode_types[6](reader))
+ local bone = decode_types[6](reader)
+
+ if ( !IsValid( ent ) ) then return nil end;
+ return ent:GetPhysicsObjectNum( bone )
+ end,
+ [15 ] = function(reader) -- Color
+ local r = decode_types[6](reader)
+ reader:StepBack()
+ local g = decode_types[6](reader)
+ reader:StepBack()
+ local b = decode_types[6](reader)
+ reader:StepBack()
+ local a = decode_types[6](reader)
+ return Color(r, g, b, a)
+ end,
+ [253] = function(reader) -- -math.huge
+ reader:Next()
+ return -math.huge
+ end,
+ [254] = function(reader) -- math.huge
+ reader:Next()
+ return math.huge
+ end,
+ [255] = function(reader, rtabs) -- Reference
+ return rtabs[decode_types[6](reader) - 1]
+ end,
+}
+
+Read = function(reader, rtabs)
+ local t, pos = reader:Peek()
+ if not t then
+ error(string.format("Expected type ID at %s! (Got EOF)",
+ pos))
+ else
+ local dt = decode_types[string.byte(t)]
+ if not dt then
+ error(string.format("Unknown type ID, %s!",
+ string.byte(t)))
+ else
+ return dt(reader, rtabs or {0})
+ end
+ end
+end
+
+local reader_meta = {}
+reader_meta.__index = reader_meta
+reader_meta.Next = function(self)
+ self.i = self.i+1
+ self.c = string.sub(self.s, self.i, self.i)
+ if self.c == "" then self.c = nil end
+ self.p = string.sub(self.s, self.i+1, self.i+1)
+ if self.p == "" then self.p = nil end
+ return self.c, self.i
+end
+
+reader_meta.StepBack = function(self)
+ self.i = self.i-1
+ self.c = string.sub(self.s, self.i, self.i)
+ if self.c == "" then self.c = nil end
+ self.p = string.sub(self.s, self.i+1, self.i+1)
+ if self.p == "" then self.p = nil end
+ return self.c, self.i
+end
+
+reader_meta.Peek = function(self)
+ return self.p, self.i+1
+end
+
+function glon.decode(data)
+ if type(data) == "nil" then
+ return nil
+ elseif type(data) ~= "string" then
+ error(string.format("Expected string to decode! (Got type %s)",
+ type(data)
+ ))
+ elseif data:len() == 0 then
+ return nil
+ end
+
+
+ return Read(setmetatable({
+ s = data,
+ i = 0,
+ c = string.sub(data, 0, 0),
+ p = string.sub(data, 1, 1),
+ }, reader_meta), {})
+end
+
+function glon.encode(data)
+ return Write(data, {0}) -- to use the first key, to prevent it from interfereing with \1s. You can have up to 254 unique tables (including arrays)
+end
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/menu/ironsights.lua b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/menu/ironsights.lua
new file mode 100644
index 0000000..d341e3f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/menu/ironsights.lua
@@ -0,0 +1,159 @@
+
+local drag_modes = {
+ ["x / z"] = { "x", "z" },
+ ["y"] = { "y" },
+ ["pitch / yaw"] = { "pitch", "yaw" },
+ ["roll"] = { "roll" }
+}
+
+local function GetIronSightPrintText( vec, ang )
+ return "SWEP.IronSightsPos = "..PrintVec( vec ).."\nSWEP.IronSightsAng = "..PrintVec( ang )
+end
+
+local wep = GetSCKSWEP( LocalPlayer() )
+local pironsight = wep.pironsight
+local pironsight_enable = SimplePanel( pironsight )
+
+ local icbox = vgui.Create( "DCheckBoxLabel", pironsight_enable )
+ icbox:SetSize( 150, 20 )
+ icbox:SetText( "Enable ironsights" )
+ icbox.OnChange = function()
+ if (wep:GetIronSights() != icbox:GetChecked()) then
+ RunConsoleCommand("swepck_toggleironsights")
+ end
+ end
+ if (wep.save_data.IronSightsEnabled) then icbox:SetValue(1)
+ else icbox:SetValue(0) end
+ icbox:Dock(LEFT)
+
+ local ribtn = vgui.Create( "DButton", pironsight_enable )
+ ribtn:SetTall( 20 )
+ ribtn:SetText( "Reset ironsights" )
+ ribtn.DoClick = function()
+ wep:ResetIronSights()
+ end
+ ribtn:Dock(FILL)
+
+pironsight_enable:DockMargin(0,0,0,5)
+pironsight_enable:Dock(TOP)
+
+local pironsight_drag = SimplePanel( pironsight )
+
+ local modlabel = vgui.Create( "DLabel", pironsight_drag )
+ modlabel:SetSize( 150, 20 )
+ modlabel:SetText( "Drag mode:" )
+ modlabel:Dock(LEFT)
+
+ local drbox = vgui.Create( "DComboBox", pironsight_drag )
+ drbox:SetTall( 20 )
+ drbox:SetText( wep.cur_drag_mode )
+ for k, v in pairs( drag_modes ) do
+ drbox:AddChoice( k )
+ end
+ drbox.OnSelect = function(panel,index,value)
+ local modes = drag_modes[value]
+ wep.cur_drag_mode = value
+ for k, v in pairs( wep.ir_drag ) do
+ v[1] = table.HasValue( modes, k ) // set the drag modus
+ end
+ end
+ drbox:Dock(FILL)
+
+pironsight_drag:DockMargin(0,0,0,10)
+pironsight_drag:Dock(TOP)
+
+local ixslider = vgui.Create( "DNumSlider", pironsight )
+ ixslider:SetText( "Translate x" )
+ ixslider:SetMinMax( -20, 20 )
+ ixslider:SetDecimals( 3 )
+ ixslider:SetConVar( "_sp_ironsight_x" )
+ ixslider:SetValue( wep.save_data.IronSightsPos.x )
+ ixslider.ConVarChanged = function( p, value )
+ RunConsoleCommand("_sp_ironsight_x",value)
+ end
+ixslider:DockMargin(0,0,0,10)
+ixslider:Dock(TOP)
+
+local iyslider = vgui.Create( "DNumSlider", pironsight )
+ iyslider:SetText( "Translate y" )
+ iyslider:SetMinMax( -20, 20 )
+ iyslider:SetDecimals( 3 )
+ iyslider:SetConVar( "_sp_ironsight_y" )
+ iyslider:SetValue( wep.save_data.IronSightsPos.y )
+ iyslider.ConVarChanged = function( p, value )
+ RunConsoleCommand("_sp_ironsight_y",value)
+ end
+iyslider:DockMargin(0,0,0,10)
+iyslider:Dock(TOP)
+
+local izslider = vgui.Create( "DNumSlider", pironsight )
+ izslider:SetText( "Translate z" )
+ izslider:SetMinMax( -20, 20 )
+ izslider:SetDecimals( 3 )
+ izslider:SetConVar( "_sp_ironsight_z" )
+ izslider:SetValue( wep.save_data.IronSightsPos.z )
+ izslider.ConVarChanged = function( p, value )
+ RunConsoleCommand("_sp_ironsight_z",value)
+ end
+izslider:DockMargin(0,0,0,10)
+izslider:Dock(TOP)
+
+local ipslider = vgui.Create( "DNumSlider", pironsight )
+ ipslider:SetText( "Rotate pitch" )
+ ipslider:SetMinMax( -70, 70 )
+ ipslider:SetDecimals( 3 )
+ ipslider:SetConVar( "_sp_ironsight_pitch" )
+ ipslider:SetValue( wep.save_data.IronSightsAng.x )
+ ipslider.ConVarChanged = function( p, value )
+ RunConsoleCommand("_sp_ironsight_pitch",value)
+ end
+ipslider:DockMargin(0,0,0,10)
+ipslider:Dock(TOP)
+
+local iyaslider = vgui.Create( "DNumSlider", pironsight )
+ iyaslider:SetText( "Rotate yaw" )
+ iyaslider:SetMinMax( -70, 70 )
+ iyaslider:SetDecimals( 3 )
+ iyaslider:SetConVar( "_sp_ironsight_yaw" )
+ iyaslider:SetValue( wep.save_data.IronSightsAng.y )
+ iyaslider.ConVarChanged = function( p, value )
+ RunConsoleCommand("_sp_ironsight_yaw",value)
+ end
+iyaslider:DockMargin(0,0,0,10)
+iyaslider:Dock(TOP)
+
+local irslider = vgui.Create( "DNumSlider", pironsight )
+ irslider:SetText( "Rotate roll" )
+ irslider:SetMinMax( -70, 70 )
+ irslider:SetDecimals( 3 )
+ irslider:SetConVar( "_sp_ironsight_roll" )
+ irslider:SetValue( wep.save_data.IronSightsAng.z )
+ irslider.ConVarChanged = function( p, value )
+ RunConsoleCommand("_sp_ironsight_roll",value)
+ end
+irslider:DockMargin(0,0,0,10)
+irslider:Dock(TOP)
+
+local pcbtn = vgui.Create( "DButton", pironsight )
+ pcbtn:SetTall( 30 )
+ pcbtn:SetText( "Copy ironsights code to clipboard" )
+ pcbtn.DoClick = function()
+ local vec, ang = wep:GetIronSightCoordination()
+ SetClipboardText(GetIronSightPrintText( vec, ang ))
+ LocalPlayer():ChatPrint("Code copied to clipboard!")
+ end
+pcbtn:DockMargin(0,5,0,0)
+pcbtn:Dock(BOTTOM)
+
+local prbtn = vgui.Create( "DButton", pironsight )
+ prbtn:SetTall( 30 )
+ prbtn:SetText( "Print ironsights code to console" )
+ prbtn.DoClick = function()
+ local vec, ang = wep:GetIronSightCoordination()
+ MsgN("*********************************************")
+ MsgN(GetIronSightPrintText( vec, ang ))
+ MsgN("*********************************************")
+ LocalPlayer():ChatPrint("Code printed to console!")
+ end
+prbtn:DockMargin(0,5,0,0)
+prbtn:Dock(BOTTOM)
diff --git a/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/menu/models.lua b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/menu/models.lua
new file mode 100644
index 0000000..a029bd7
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/menu/models.lua
@@ -0,0 +1,1618 @@
+
+local function GetVModelsText()
+
+ local wep = GetSCKSWEP( LocalPlayer() )
+ if (!IsValid(wep)) then return "" end
+
+ local str = ("SWEP.VElements = {\n")
+ local i = 0
+ local num = table.Count(wep.v_models)
+ for k, v in pairs( wep.v_models ) do
+
+ if (v.type == "Model") then
+ str = str.."\t[\""..k.."\"] = { type = \"Model\", model = \""..v.model.."\", bone = \""..v.bone.."\", rel = \""..v.rel.."\", pos = "..PrintVec(v.pos)
+ str = str..", angle = "..PrintAngle( v.angle )..", size = "..PrintVec(v.size)..", color = "..PrintColor( v.color )
+ str = str..", surpresslightning = "..tostring(v.surpresslightning)..", material = \""..v.material.."\", skin = "..v.skin
+ str = str..", bodygroup = {"
+ local i = 0
+ for k, v in pairs( v.bodygroup ) do
+ if (v <= 0) then continue end
+ if ( i != 0 ) then str = str..", " end
+ i = 1
+ str = str.."["..k.."] = "..v
+ end
+ str = str.."} }"
+ elseif (v.type == "Sprite") then
+ str = str.."\t[\""..k.."\"] = { type = \"Sprite\", sprite = \""..v.sprite.."\", bone = \""..v.bone.."\", rel = \""..v.rel.."\", pos = "..PrintVec(v.pos)
+ str = str..", size = { x = "..v.size.x..", y = "..v.size.y.." }, color = "..PrintColor( v.color )..", nocull = "..tostring(v.nocull)
+ str = str..", additive = "..tostring(v.additive)..", vertexalpha = "..tostring(v.vertexalpha)..", vertexcolor = "..tostring(v.vertexcolor)
+ str = str..", ignorez = "..tostring(v.ignorez).."}"
+ elseif (v.type == "Quad") then
+ str = str.."\t[\""..k.."\"] = { type = \"Quad\", bone = \""..v.bone.."\", rel = \""..v.rel.."\", pos = "..PrintVec(v.pos)..", angle = "..PrintAngle( v.angle )
+ str = str..", size = "..v.size..", draw_func = nil}"
+ end
+
+ if (v.type) then
+ i = i + 1
+ if (i < num) then str = str.."," end
+ str = str.."\n"
+ end
+ end
+ str = str.."}"
+
+ return str
+end
+
+local function GetWModelsText()
+
+ local wep = GetSCKSWEP( LocalPlayer() )
+ if (!IsValid(wep)) then return "" end
+
+ local str = ("SWEP.WElements = {\n")
+ local i = 0
+ local num = table.Count(wep.w_models)
+ for k, v in pairs( wep.w_models ) do
+
+ if (v.type == "Model") then
+ str = str.."\t[\""..k.."\"] = { type = \"Model\", model = \""..v.model.."\", bone = \""..v.bone.."\", rel = \""..v.rel.."\", pos = "..PrintVec(v.pos)
+ str = str..", angle = "..PrintAngle( v.angle )..", size = "..PrintVec(v.size)..", color = "..PrintColor( v.color )
+ str = str..", surpresslightning = "..tostring(v.surpresslightning)..", material = \""..v.material.."\", skin = "..v.skin
+ str = str..", bodygroup = {"
+ local i = 0
+ for k, v in pairs( v.bodygroup ) do
+ if (v <= 0) then continue end
+ if ( i != 0 ) then str = str..", " end
+ i = 1
+ str = str.."["..k.."] = "..v
+ end
+ str = str.."} }"
+ elseif (v.type == "Sprite") then
+ str = str.."\t[\""..k.."\"] = { type = \"Sprite\", sprite = \""..v.sprite.."\", bone = \""..v.bone.."\", rel = \""..v.rel.."\", pos = "..PrintVec(v.pos)
+ str = str..", size = { x = "..v.size.x..", y = "..v.size.y.." }, color = "..PrintColor( v.color )..", nocull = "..tostring(v.nocull)
+ str = str..", additive = "..tostring(v.additive)..", vertexalpha = "..tostring(v.vertexalpha)..", vertexcolor = "..tostring(v.vertexcolor)
+ str = str..", ignorez = "..tostring(v.ignorez).."}"
+ elseif (v.type == "Quad") then
+ str = str.."\t[\""..k.."\"] = { type = \"Quad\", bone = \""..v.bone.."\", rel = \""..v.rel.."\", pos = "..PrintVec(v.pos)..", angle = "..PrintAngle( v.angle )
+ str = str..", size = "..v.size..", draw_func = nil}"
+ end
+
+ if (v.type) then
+ i = i + 1
+ if (i < num) then str = str.."," end
+ str = str.."\n"
+ end
+ end
+ str = str.."}"
+
+ str = str.."\n\n"
+
+ local i = 0
+ for k, v in pairs( wep.w_models ) do
+ if (v.type == "Model") then
+ i = i + 1
+ str = str.."c:AddModel(\""..v.model.."\", "..PrintVec(v.pos)..", "..PrintAngle(v.angle)..", ".. ((not v.rel or #v.rel == 0) and "\""..v.bone.."\"" or "nil") ..", "..(v.size.x == 1 and v.size.y == 1 and v.size.z == 1 and "nil" or v.size.x == v.size.y and v.size.x == v.size.z and math.Round(v.size.x, 4) or PrintVec(v.size))..", ".. (v.material and #v.material > 0 and "\""..v.material.."\"" or "nil") ..", "..(v.color.r == 255 and v.color.g == 255 and v.color.b == 255 and v.color.a == 255 and "nil" or PrintColor( v.color ))
+ if v.rel and #v.rel > 0 then
+ str = str..", 1"
+ end
+ str = str..")\n"
+ end
+ end
+
+ return str
+end
+
+local function PopulateRelative( sourcetab, box, startchoice, ignore )
+
+ box:Clear()
+ local choose = box:AddChoice("")
+ for k, v in pairs( sourcetab ) do
+ if (v == ignore) then continue end
+ local id = box:AddChoice(v)
+ if (v == startchoice) then
+ choose = id
+ end
+ end
+ box:ChooseOptionID( choose )
+
+end
+
+// Some hacky shit to keep the relative DComboBoxes updated
+local v_relelements = {}
+local w_relelements = {}
+local boxes_to_update = {}
+local function RegisterRelBox( elementname, box, w_or_v, preset_choice )
+ table.insert(boxes_to_update, { box, w_or_v, elementname, preset_choice })
+end
+
+local function RemoveRelBox( w_or_v, elementname )
+ for k, v in pairs( boxes_to_update ) do
+ if (v[2] == w_or_v and v[3] == elementname) then
+ table.remove(boxes_to_update, k)
+ break
+ end
+ end
+end
+
+local function UpdateRelBoxes( w_or_v )
+ local source = v_relelements
+ if (w_or_v == "w") then
+ source = w_relelements
+ end
+
+ for k, v in pairs( boxes_to_update ) do
+ if (IsValid(v[1]) and v[2] == w_or_v) then
+ local choose = v[1]:GetValue()
+ if (v[4]) then // preset choice
+ choose = v[4]
+ v[4] = nil
+ end
+ PopulateRelative( source, v[1], choose, v[3] )
+ end
+ end
+end
+
+local wep = GetSCKSWEP( LocalPlayer() )
+local pmodels = wep.pmodels
+local pwmodels = wep.pwmodels
+local lastVisible = ""
+
+local mlabel = vgui.Create( "DLabel", pmodels )
+ mlabel:SetTall( 20 )
+ mlabel:SetText( "New viewmodel element:" )
+mlabel:Dock(TOP)
+
+local function CreateNote( text )
+ local templabel = vgui.Create( "DLabel" )
+ templabel:SetText( text )
+ templabel:SizeToContents()
+
+ local x, y = mlabel:GetPos()
+ local notif = vgui.Create( "DNotify" , pmodels )
+ notif:SetPos( x + 160, y )
+ notif:SetSize( templabel:GetWide(), 20 )
+ notif:SetLife( 5 )
+ notif:AddItem(templabel)
+end
+
+local pnewelement = SimplePanel( pmodels )
+pnewelement:SetTall(20)
+
+ local mntext = vgui.Create("DTextEntry", pnewelement )
+ mntext:SetTall( 20 )
+ mntext:SetMultiline(false)
+ mntext:SetText( "element_name" )
+ mntext:Dock(FILL)
+
+ local mnbtn = vgui.Create( "DButton", pnewelement )
+ mnbtn:SetSize( 50, 20 )
+ mnbtn:SetText( "Add" )
+ mnbtn:DockMargin(5,0,0,0)
+ mnbtn:Dock(RIGHT)
+
+ local tpbox = vgui.Create( "DComboBox", pnewelement )
+ tpbox:SetSize( 100, 20 )
+ tpbox:SetText( "Model" )
+ tpbox:AddChoice( "Model" )
+ tpbox:AddChoice( "Sprite" )
+ tpbox:AddChoice( "Quad" )
+ local boxselected = "Model"
+ tpbox.OnSelect = function( p, index, value )
+ boxselected = value
+ end
+ tpbox:DockMargin(5,0,0,0)
+ tpbox:Dock(RIGHT)
+
+pnewelement:DockMargin(0,5,0,5)
+pnewelement:Dock(TOP)
+
+local mlist = vgui.Create( "DListView", pmodels)
+ wep.v_modelListing = mlist
+
+ mlist:SetTall( 160 )
+ mlist:SetMultiSelect(false)
+ mlist:SetDrawBackground(true)
+ mlist:AddColumn("Name")
+ mlist:AddColumn("Type")
+ // cache the created panels
+ mlist.OnRowSelected = function( panel, line )
+ local name = mlist:GetLine(line):GetValue(1)
+
+ if (wep.v_panelCache[lastVisible]) then
+ wep.v_panelCache[lastVisible]:SetVisible(false)
+ end
+ wep.v_panelCache[name]:SetVisible(true)
+
+ lastVisible = name
+ end
+
+mlist:Dock(TOP)
+
+local pbuttons = SimplePanel( pmodels )
+
+ local rmbtn = vgui.Create( "DButton", pbuttons )
+ rmbtn:SetSize( 160, 25 )
+ rmbtn:SetText( "Remove selected" )
+ rmbtn:Dock(LEFT)
+
+ local copybtn = vgui.Create( "DButton", pbuttons )
+ copybtn:SetSize( 160, 25 )
+ copybtn:SetText( "Copy selected" )
+ copybtn:Dock(RIGHT)
+
+pbuttons:DockMargin(0,5,0,5)
+pbuttons:Dock(TOP)
+
+// Print buttons
+local pctbtn = vgui.Create( "DButton", pmodels)
+ pctbtn:SetTall( 30 )
+ pctbtn:SetText("Copy view model table to clipboard")
+ pctbtn.DoClick = function()
+ SetClipboardText(GetVModelsText())
+ LocalPlayer():ChatPrint("Code copied to clipboard!")
+ end
+pctbtn:DockMargin(0,5,0,0)
+pctbtn:Dock(BOTTOM)
+
+local prtbtn = vgui.Create( "DButton", pmodels)
+ prtbtn:SetTall( 30 )
+ prtbtn:SetText("Print view model table to console")
+ prtbtn.DoClick = function()
+ MsgN("*********************************************")
+ for k, v in pairs(string.Explode("\n",GetVModelsText())) do
+ MsgN(v)
+ end
+ MsgN("*********************************************")
+ LocalPlayer():ChatPrint("Code printed to console!")
+ end
+prtbtn:Dock(BOTTOM)
+
+local pCol = 0
+local function PanelBackgroundReset()
+ pCol = 0
+end
+
+local function PanelApplyBackground(panel)
+
+ if (pCol == 1) then
+ panel:SetPaintBackground(true)
+ panel.Paint = function() surface.SetDrawColor( 85, 85, 85, 255 ) surface.DrawRect( 0, 0, panel:GetWide(), panel:GetTall() ) end
+ end
+
+ pCol = (pCol + 1) % 2
+end
+
+local function CreatePositionModifiers( data, panel )
+
+ panel:SetTall(32*3)
+ PanelApplyBackground(panel)
+
+ local trlabel = vgui.Create( "DLabel", panel )
+ trlabel:SetText( "Position:" )
+ trlabel:SizeToContents()
+ trlabel:SetWide(45)
+ trlabel:Dock(LEFT)
+
+ local mxwang = vgui.Create( "DNumSlider", panel )
+ mxwang:SetText("x")
+ mxwang:SetMinMax( -80, 80 )
+ mxwang:SetDecimals( 3 )
+ mxwang.Wang.ConVarChanged = function( p, value ) data.pos.x = tonumber(value) end
+ mxwang:SetValue( data.pos.x )
+ mxwang:DockMargin(10,0,0,0)
+
+ local mywang = vgui.Create( "DNumSlider", panel )
+ mywang:SetText("y")
+ mywang:SetMinMax( -80, 80 )
+ mywang:SetDecimals( 3 )
+ mywang.Wang.ConVarChanged = function( p, value ) data.pos.y = tonumber(value) end
+ mywang:SetValue( data.pos.y )
+ mywang:DockMargin(10,0,0,0)
+
+ local mzwang = vgui.Create( "DNumSlider", panel )
+ mzwang:SetText("z")
+ mzwang:SetMinMax( -80, 80 )
+ mzwang:SetDecimals( 3 )
+ mzwang.Wang.ConVarChanged = function( p, value ) data.pos.z = tonumber(value) end
+ mzwang:SetValue( data.pos.z )
+ mzwang:DockMargin(10,0,0,0)
+
+ panel.PerformLayout = function()
+ mxwang:SetWide(panel:GetWide()*4/15)
+ mywang:SetWide(panel:GetWide()*4/15)
+ mzwang:SetWide(panel:GetWide()*4/15)
+ end
+
+ mxwang:Dock(TOP)
+ mywang:Dock(TOP)
+ mzwang:Dock(TOP)
+
+ return panel
+end
+
+local function CreateAngleModifiers( data, panel )
+
+ panel:SetTall(32*3)
+ PanelApplyBackground(panel)
+
+ local anlabel = vgui.Create( "DLabel", panel )
+ anlabel:SetText( "Angle:" )
+ anlabel:SizeToContents()
+ anlabel:SetWide(45)
+ anlabel:Dock(LEFT)
+
+ local mpitchwang = vgui.Create( "DNumSlider", panel )
+ mpitchwang:SetText("pitch")
+ mpitchwang:SetMinMax( -180, 180 )
+ mpitchwang:SetDecimals( 3 )
+ mpitchwang.Wang.ConVarChanged = function( p, value ) data.angle.p = tonumber(value) end
+ mpitchwang:SetValue( data.angle.p )
+ mpitchwang:DockMargin(10,0,0,0)
+
+ local myawwang = vgui.Create( "DNumSlider", panel )
+ myawwang:SetText("yaw")
+ myawwang:SetMinMax( -180, 180 )
+ myawwang:SetDecimals( 3 )
+ myawwang.Wang.ConVarChanged = function( p, value ) data.angle.y = tonumber(value) end
+ myawwang:SetValue( data.angle.y )
+ myawwang:DockMargin(10,0,0,0)
+
+ local mrollwang = vgui.Create( "DNumSlider", panel )
+ mrollwang:SetText("roll")
+ mrollwang:SetMinMax( -180, 180 )
+ mrollwang:SetDecimals( 3 )
+ mrollwang.Wang.ConVarChanged = function( p, value ) data.angle.r = tonumber(value) end
+ mrollwang:SetValue( data.angle.r )
+ mrollwang:DockMargin(10,0,0,0)
+
+ panel.PerformLayout = function()
+ mrollwang:SetWide(panel:GetWide()*4/15)
+ myawwang:SetWide(panel:GetWide()*4/15)
+ mpitchwang:SetWide(panel:GetWide()*4/15)
+ end
+
+ mpitchwang:Dock(TOP)
+ myawwang:Dock(TOP)
+ mrollwang:Dock(TOP)
+
+ return panel
+end
+
+local function CreateSizeModifiers( data, panel, dimensions )
+
+ panel:SetTall(32*dimensions)
+ PanelApplyBackground(panel)
+
+ local sizelabel = vgui.Create( "DLabel", panel )
+ sizelabel:SetText( "Size:" )
+ sizelabel:SizeToContents()
+ sizelabel:SetWide(45)
+ sizelabel:Dock(LEFT)
+
+ local msywang, mszwang
+
+ local msxwang = vgui.Create( "DNumSlider", panel )
+ msxwang:SetMinMax( 0.01, 10 )
+ msxwang:SetDecimals( 3 )
+
+ if (dimensions > 1 ) then
+
+ msywang = vgui.Create( "DNumSlider", panel )
+ msywang:SetText("y")
+ msywang:SetMinMax( 0.01, 10 )
+ msywang:SetDecimals( 3 )
+ msywang.Wang.ConVarChanged = function( p, value ) data.size.y = tonumber(value) end
+ msywang:DockMargin(10,0,0,0)
+ msywang:Dock(TOP)
+
+ if (dimensions > 2) then
+ mszwang = vgui.Create( "DNumSlider", panel )
+ mszwang:SetText("z")
+ mszwang:SetMinMax( 0.01, 10 )
+ mszwang:SetDecimals( 3 )
+ mszwang.Wang.ConVarChanged = function( p, value ) data.size.z = tonumber(value) end
+ mszwang:DockMargin(10,0,0,0)
+ mszwang:Dock(TOP)
+ end
+
+ end
+
+ // make the x numberwang set the total size
+ msxwang.Wang.ConVarChanged = function( p, value )
+ if (mszwang) then
+ mszwang:SetValue( value )
+ end
+ if (msywang) then
+ msywang:SetValue( value )
+ end
+
+ if (dimensions > 1) then
+ data.size.x = tonumber(value)
+ else
+ data.size = tonumber(value)
+ end
+ end
+
+ msxwang:DockMargin(10,0,0,0)
+ msxwang:Dock(TOP)
+
+ /*panel.PerformLayout = function()
+ msxwang:SetWide(panel:GetWide()*4/5/dimensions)
+ if (dimensions > 1) then
+ msywang:SetWide(panel:GetWide()*4/5/dimensions)
+ if (dimensions > 2) then
+ mszwang:SetWide(panel:GetWide()*4/15)
+ end
+ end
+ end*/
+
+ if (dimensions == 1) then
+
+ msxwang:SetText("factor")
+ msxwang:SetValue( data.size )
+
+ else
+
+ local new_y = data.size.y
+ local new_z = data.size.z
+
+ msxwang:SetText("x / y")
+ msxwang:SetValue( data.size.x )
+ msywang:SetValue( new_y )
+
+ if (mszwang) then
+ msxwang:SetText("x / y / z")
+ mszwang:SetValue( new_z )
+ end
+
+ end
+
+ return panel
+end
+
+local function CreateColorModifiers( data, panel )
+
+ panel:SetTall(32*4)
+ PanelApplyBackground(panel)
+
+ local collabel = vgui.Create( "DLabel", panel )
+ collabel:SetText( "Color:" )
+ collabel:SizeToContents()
+ collabel:SetWide(45)
+ collabel:Dock(LEFT)
+
+ local colrwang = vgui.Create( "DNumSlider", panel )
+ colrwang:SetText("red")
+ colrwang:SetMinMax( 0, 255 )
+ colrwang:SetDecimals( 0 )
+ colrwang.Wang.ConVarChanged = function( p, value ) data.color.r = tonumber(value) end
+ colrwang:SetValue(data.color.r)
+ colrwang:DockMargin(10,0,0,0)
+
+ local colgwang = vgui.Create( "DNumSlider", panel )
+ colgwang:SetText("green")
+ colgwang:SetMinMax( 0, 255 )
+ colgwang:SetDecimals( 0 )
+ colgwang.Wang.ConVarChanged = function( p, value ) data.color.g = tonumber(value) end
+ colgwang:SetValue(data.color.g)
+ colgwang:DockMargin(10,0,0,0)
+
+ local colbwang = vgui.Create( "DNumSlider", panel )
+ colbwang:SetText("blue")
+ colbwang:SetMinMax( 0, 255 )
+ colbwang:SetDecimals( 0 )
+ colbwang.Wang.ConVarChanged = function( p, value ) data.color.b = tonumber(value) end
+ colbwang:SetValue(data.color.b)
+ colbwang:DockMargin(10,0,0,0)
+
+ local colawang = vgui.Create( "DNumSlider", panel )
+ colawang:SetText("alpha")
+ colawang:SetMinMax( 0, 255 )
+ colawang:SetDecimals( 0 )
+ colawang.Wang.ConVarChanged = function( p, value ) data.color.a = tonumber(value) end
+ colawang:SetValue(data.color.a)
+ colawang:DockMargin(10,0,0,0)
+
+ panel.PerformLayout = function()
+ colawang:SetWide(panel:GetWide()/5)
+ colbwang:SetWide(panel:GetWide()/5)
+ colgwang:SetWide(panel:GetWide()/5)
+ colrwang:SetWide(panel:GetWide()/5)
+ end
+
+ colrwang:Dock(TOP)
+ colgwang:Dock(TOP)
+ colbwang:Dock(TOP)
+ colawang:Dock(TOP)
+
+ return panel
+end
+
+local function CreateModelModifier( data, panel )
+
+ panel:SetTall(20)
+
+ local pmolabel = vgui.Create( "DLabel", panel )
+ pmolabel:SetText( "Model:" )
+ pmolabel:SetWide(60)
+ pmolabel:SizeToContentsY()
+ pmolabel:Dock(LEFT)
+
+ local wtbtn = vgui.Create( "DButton", panel )
+ wtbtn:SetSize( 25, 20 )
+ wtbtn:SetText("...")
+ wtbtn:Dock(RIGHT)
+
+ local pmmtext = vgui.Create( "DTextEntry", panel )
+ pmmtext:SetMultiline(false)
+ pmmtext:SetToolTip("Path to the model file")
+ pmmtext.OnTextChanged = function()
+ local newmod = pmmtext:GetValue()
+ if file.Exists(newmod, "GAME") then
+ util.PrecacheModel(newmod)
+ data.model = newmod
+ end
+ end
+ pmmtext:SetText( data.model )
+ pmmtext.OnTextChanged()
+ pmmtext:DockMargin(10,0,0,0)
+ pmmtext:Dock(FILL)
+
+ wtbtn.DoClick = function()
+ wep:OpenBrowser( data.model, "model", function( val ) pmmtext:SetText(val) pmmtext:OnTextChanged() end )
+ end
+
+ return panel
+end
+
+local function CreateSpriteModifier( data, panel )
+
+ panel:SetTall(20)
+
+ local pmolabel = vgui.Create( "DLabel", panel )
+ pmolabel:SetText( "Sprite:" )
+ pmolabel:SetWide(60)
+ pmolabel:SizeToContentsY()
+ pmolabel:Dock(LEFT)
+
+ local wtbtn = vgui.Create( "DButton", panel )
+ wtbtn:SetSize( 25, 20 )
+ wtbtn:SetText("...")
+ wtbtn:Dock(RIGHT)
+
+ local pmmtext = vgui.Create( "DTextEntry", panel )
+ pmmtext:SetMultiline(false)
+ pmmtext:SetToolTip("Path to the sprite material")
+ pmmtext.OnTextChanged = function()
+ local newsprite = pmmtext:GetValue()
+ if file.Exists("materials/"..newsprite..".vmt", "GAME") then
+ data.sprite = newsprite
+ end
+ end
+ pmmtext:SetText( data.sprite )
+ pmmtext.OnTextChanged()
+ pmmtext:DockMargin(10,0,0,0)
+ pmmtext:Dock(FILL)
+
+ wtbtn.DoClick = function()
+ wep:OpenBrowser( data.sprite, "material", function( val ) pmmtext:SetText(val) pmmtext:OnTextChanged() end )
+ end
+
+ return panel
+end
+
+local function CreateNameLabel( name, panel )
+
+ panel:SetTall(20)
+
+ local pnmlabel = vgui.Create( "DLabel", panel )
+ pnmlabel:SetText( "Name: "..name )
+ pnmlabel:SizeToContents()
+ pnmlabel:Dock(LEFT)
+
+ /*local pnmtext = vgui.Create( "DTextEntry", panel )
+ pnmtext:SetMultiline(false)
+ pnmtext:SetText( name )
+ pnmtext:SetEditable( false )
+ pnmtext:Dock(FILL)*/
+
+ return panel
+end
+
+local function CreateParamModifiers( data, panel )
+
+ panel:SetTall(45)
+
+ local strip1 = SimplePanel( panel )
+ strip1:SetTall(20)
+
+ local ncchbox = vgui.Create( "DCheckBoxLabel", strip1 )
+ ncchbox:SetText("$nocull")
+ ncchbox:SizeToContents()
+ ncchbox:SetValue( 0 )
+ ncchbox.OnChange = function()
+ data.nocull = ncchbox:GetChecked()
+ data.spriteMaterial = nil // dump old material
+ end
+ if (data.nocull) then ncchbox:SetValue( 1 ) end
+ ncchbox:DockMargin(0,0,10,0)
+ ncchbox:Dock(LEFT)
+
+ local adchbox = vgui.Create( "DCheckBoxLabel", strip1 )
+ adchbox:SetText("$additive")
+ adchbox:SizeToContents()
+ adchbox:SetValue( 0 )
+ adchbox.OnChange = function()
+ data.additive = adchbox:GetChecked()
+ data.spriteMaterial = nil // dump old material
+ end
+ if (data.additive) then adchbox:SetValue( 1 ) end
+ adchbox:DockMargin(0,0,10,0)
+ adchbox:Dock(LEFT)
+
+ local vtachbox = vgui.Create( "DCheckBoxLabel", strip1 )
+ vtachbox:SetText("$vertexalpha")
+ vtachbox:SizeToContents()
+ vtachbox:SetValue( 0 )
+ vtachbox.OnChange = function()
+ data.vertexalpha = vtachbox:GetChecked()
+ data.spriteMaterial = nil // dump old material
+ end
+ if (data.vertexalpha) then vtachbox:SetValue( 1 ) end
+ vtachbox:DockMargin(0,0,10,0)
+ vtachbox:Dock(LEFT)
+
+ strip1:DockMargin(0,0,0,5)
+ strip1:Dock(TOP)
+
+ local strip2 = SimplePanel( panel )
+ strip2:SetTall(20)
+
+ local vtcchbox = vgui.Create( "DCheckBoxLabel", strip2 )
+ vtcchbox:SetText("$vertexcolor")
+ vtcchbox:SizeToContents()
+ vtcchbox:SetValue( 0 )
+ vtcchbox.OnChange = function()
+ data.vertexcolor = vtcchbox:GetChecked()
+ data.spriteMaterial = nil // dump old material
+ end
+ if (data.vertexcolor) then vtcchbox:SetValue( 1 ) end
+ vtcchbox:DockMargin(0,0,10,0)
+ vtcchbox:Dock(LEFT)
+
+ local izchbox = vgui.Create( "DCheckBoxLabel", strip2 )
+ izchbox:SetText("$ignorez")
+ izchbox:SizeToContents()
+ izchbox:SetValue( 0 )
+ izchbox.OnChange = function()
+ data.ignorez = izchbox:GetChecked()
+ data.spriteMaterial = nil // dump old material
+ end
+ if (data.ignorez) then izchbox:SetValue( 1 ) end
+ izchbox:DockMargin(0,0,10,0)
+ izchbox:Dock(LEFT)
+
+ strip2:Dock(TOP)
+
+ return panel
+end
+
+local function CreateMaterialModifier( data, panel )
+
+ panel:SetTall(20)
+
+ local matlabel = vgui.Create( "DLabel", panel )
+ matlabel:SetText( "Material:" )
+ matlabel:SetWide(60)
+ matlabel:SizeToContentsY()
+ matlabel:Dock(LEFT)
+
+ local wtbtn = vgui.Create( "DButton", panel )
+ wtbtn:SetSize( 25, 20 )
+ wtbtn:SetText("...")
+ wtbtn:Dock(RIGHT)
+
+ local mattext = vgui.Create("DTextEntry", panel )
+ mattext:SetMultiline(false)
+ mattext:SetToolTip("Path to the material file")
+ mattext.OnTextChanged = function()
+ local newmat = mattext:GetValue()
+ if file.Exists("materials/"..newmat..".vmt", "GAME") then
+ data.material = newmat
+ else
+ data.material = ""
+ end
+ end
+ mattext:SetText( data.material )
+ mattext:DockMargin(10,0,0,0)
+ mattext:Dock(FILL)
+
+ wtbtn.DoClick = function()
+ wep:OpenBrowser( data.material, "material", function( val ) mattext:SetText(val) mattext:OnTextChanged() end )
+ end
+
+ return panel
+end
+
+local function CreateSLightningModifier( data, panel )
+
+ local lschbox = vgui.Create( "DCheckBoxLabel", panel )
+ lschbox:SetText("Surpress engine lightning")
+ lschbox:SizeToContents()
+ lschbox.OnChange = function()
+ data.surpresslightning = lschbox:GetChecked()
+ end
+ if (data.surpresslightning) then
+ lschbox:SetValue( 1 )
+ else
+ lschbox:SetValue( 0 )
+ end
+ lschbox:Dock(LEFT)
+
+ return panel
+end
+
+local function CreateBoneModifier( data, panel, ent )
+
+ local pbonelabel = vgui.Create( "DLabel", panel )
+ pbonelabel:SetText( "Bone:" )
+ pbonelabel:SetWide(60)
+ pbonelabel:SizeToContentsY()
+ pbonelabel:Dock(LEFT)
+
+ local bonebox = vgui.Create( "DComboBox", panel )
+ bonebox:SetToolTip("Bone to parent the selected element to. Is ignored if the 'Relative' field is not empty")
+ bonebox.OnSelect = function( p, index, value )
+ data.bone = value
+ end
+ bonebox:SetText( data.bone )
+ bonebox:DockMargin(10,0,0,0)
+ bonebox:Dock(FILL)
+
+ local delay = 0
+ // we have to call it later when loading settings because the viewmodel needs to be changed first
+ if (data.bone != "") then delay = 2 end
+
+ timer.Simple(delay, function()
+ local option = PopulateBoneList( bonebox, ent )
+ if (option and data.bone == "") then
+ bonebox:ChooseOptionID(1)
+ end
+ end)
+
+ return panel
+end
+
+local function CreateVRelativeModifier( name, data, panel )
+
+ local prellabel = vgui.Create( "DLabel", panel )
+ prellabel:SetText( "Relative:" )
+ prellabel:SetWide(60)
+ prellabel:SizeToContentsY()
+ prellabel:Dock(LEFT)
+
+ local relbox = vgui.Create( "DComboBox", panel )
+ relbox:SetToolTip("Element you want to parent this element to (position and angle become relative). Overrides parenting to a bone if not blank.")
+ relbox.OnSelect = function( p, index, value )
+ data.rel = value
+ end
+ relbox:DockMargin(10,0,0,0)
+ relbox:Dock(FILL)
+
+ RegisterRelBox(name, relbox, "v", data.rel)
+
+ return panel
+end
+
+local function CreateWRelativeModifier( name, data, panel )
+
+ local prellabel = vgui.Create( "DLabel", panel )
+ prellabel:SetText( "Relative:" )
+ prellabel:SetWide(60)
+ prellabel:SizeToContentsY()
+ prellabel:Dock(LEFT)
+
+ local relbox = vgui.Create( "DComboBox", panel )
+ relbox:SetToolTip("Element you want to parent this element to (position and angle become relative). Overrides parenting to a bone if not blank.")
+ relbox.OnSelect = function( p, index, value )
+ data.rel = value
+ end
+ relbox:DockMargin(10,0,0,0)
+ relbox:Dock(FILL)
+
+ RegisterRelBox(name, relbox, "w", data.rel)
+
+ return panel
+end
+
+local function CreateBodygroupSkinModifier( data, panel )
+
+ local bdlabel = vgui.Create( "DLabel", panel )
+ bdlabel:SetText( "Bodygroup:" )
+ bdlabel:SizeToContents()
+ bdlabel:Dock(LEFT)
+
+ local bdwang = vgui.Create( "DNumberWang", panel )
+ bdwang:SetSize( 30, 20 )
+ bdwang:SetMinMax( 1, 9 )
+ bdwang:SetDecimals( 0 )
+ bdwang:SetToolTip("Bodygroup number")
+ bdwang:DockMargin(10,0,0,0)
+ bdwang:Dock(LEFT)
+
+ local islabel = vgui.Create( "DLabel", panel )
+ islabel:SetSize( 10, 20 )
+ islabel:SetText( "=" )
+ islabel:DockMargin(1,0,1,0)
+ islabel:Dock(LEFT)
+
+ local bdvwang = vgui.Create( "DNumberWang", panel )
+ bdvwang:SetSize( 30, 20 )
+ bdvwang:SetMinMax( 0, 9 )
+ bdvwang:SetDecimals( 0 )
+ bdvwang:SetToolTip("State number")
+ bdvwang:Dock(LEFT)
+
+ bdvwang.ConVarChanged = function( p, value )
+ local group = tonumber(bdwang:GetValue())
+ local val = tonumber(value)
+ data.bodygroup[group] = val
+ end
+ bdvwang:SetValue(0)
+
+ bdwang.ConVarChanged = function( p, value )
+ local group = tonumber(value)
+ if (group < 1) then return end
+ local setval = data.bodygroup[group] or 0
+ bdvwang:SetValue(setval)
+ end
+ bdwang:SetValue(1)
+
+ local sklabel = vgui.Create( "DLabel", panel )
+ sklabel:SetText( "Skin:" )
+ sklabel:SizeToContents()
+ sklabel:DockMargin(50,0,0,0)
+ sklabel:Dock(LEFT)
+
+ local skwang = vgui.Create( "DNumberWang", panel )
+ skwang:SetSize( 30, 20 )
+ skwang:SetMin( 0 )
+ skwang:SetMax( 9 )
+ skwang:SetDecimals( 0 )
+ skwang.ConVarChanged = function( p, value ) data.skin = tonumber(value) end
+ skwang:SetValue(data.skin)
+ skwang:DockMargin(10,0,0,0)
+ skwang:Dock(LEFT)
+
+ return panel
+end
+
+/*** Model panel for adjusting models ***
+Name:
+Model:
+Bone name:
+Translation x / y / z
+Rotation pitch / yaw / role
+Model size x / y / z
+Material
+Color modulation
+*/
+local function CreateModelPanel( name, preset_data )
+
+ local data = wep.v_models[name]
+ if (!preset_data) then preset_data = {} end
+
+ // default data
+ data.type = preset_data.type or "Model"
+ data.model = preset_data.model or ""
+ data.bone = preset_data.bone or ""
+ data.rel = preset_data.rel or ""
+ data.pos = preset_data.pos or Vector(0,0,0)
+ data.angle = preset_data.angle or Angle(0,0,0)
+ data.size = preset_data.size or Vector(0.5,0.5,0.5)
+ data.color = preset_data.color or Color(255,255,255,255)
+ data.surpresslightning = preset_data.surpresslightning or false
+ data.material = preset_data.material or ""
+ data.bodygroup = preset_data.bodygroup or {}
+ data.skin = preset_data.skin or 0
+
+ wep.vRenderOrder = nil // force viewmodel render order to recache
+
+ local panellist = vgui.Create("DPanelList", pmodels )
+ panellist:SetPaintBackground( true )
+ panellist.Paint = function() surface.SetDrawColor( 90, 90, 90, 255 ) surface.DrawRect( 0, 0, panellist:GetWide(), panellist:GetTall() ) end
+ panellist:EnableVerticalScrollbar( true )
+ panellist:SetSpacing(5)
+ panellist:SetPadding(5)
+ panellist:DockMargin(0,0,0,5)
+ panellist:Dock(FILL)
+
+ PanelBackgroundReset()
+
+ panellist:AddItem(CreateNameLabel( name, SimplePanel(panellist) ))
+ panellist:AddItem(CreateModelModifier( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateBoneModifier( data, SimplePanel(panellist), LocalPlayer():GetViewModel() ))
+ panellist:AddItem(CreateVRelativeModifier( name, data, SimplePanel(panellist) ))
+ panellist:AddItem(CreatePositionModifiers( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateAngleModifiers( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateSizeModifiers( data, SimplePanel(panellist), 3 ))
+ panellist:AddItem(CreateColorModifiers( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateSLightningModifier( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateMaterialModifier( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateBodygroupSkinModifier( data, SimplePanel(panellist) ))
+
+ return panellist
+
+end
+
+/*** Sprite panel for adjusting sprites ***
+Name:
+Sprite:
+Bone name:
+Translation x / y / z
+Sprite x / y size
+Color
+*/
+local function CreateSpritePanel( name, preset_data )
+
+ local data = wep.v_models[name]
+ if (!preset_data) then preset_data = {} end
+
+ // default data
+ data.type = preset_data.type or "Sprite"
+ data.sprite = preset_data.sprite or ""
+ data.bone = preset_data.bone or ""
+ data.rel = preset_data.rel or ""
+ data.pos = preset_data.pos or Vector(0,0,0)
+ data.size = preset_data.size or { x = 1, y = 1 }
+ data.color = preset_data.color or Color(255,255,255,255)
+ data.nocull = preset_data.nocull or true
+ data.additive = preset_data.additive or true
+ data.vertexalpha = preset_data.vertexalpha or true
+ data.vertexcolor = preset_data.vertexcolor or true
+ data.ignorez = preset_data.ignorez or false
+
+ wep.vRenderOrder = nil
+
+ local panellist = vgui.Create("DPanelList", pmodels )
+ panellist:SetPaintBackground( true )
+ panellist.Paint = function() surface.SetDrawColor( 90, 90, 90, 255 ) surface.DrawRect( 0, 0, panellist:GetWide(), panellist:GetTall() ) end
+ panellist:EnableVerticalScrollbar( true )
+ panellist:SetSpacing(5)
+ panellist:SetPadding(5)
+ panellist:DockMargin(0,0,0,5)
+ panellist:Dock(FILL)
+
+ PanelBackgroundReset()
+
+ panellist:AddItem(CreateNameLabel( name,SimplePanel(panellist) ))
+ panellist:AddItem(CreateSpriteModifier( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateBoneModifier( data, SimplePanel(panellist), LocalPlayer():GetViewModel() ))
+ panellist:AddItem(CreateVRelativeModifier( name, data, SimplePanel(panellist) ))
+ panellist:AddItem(CreatePositionModifiers( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateSizeModifiers( data, SimplePanel(panellist), 2 ))
+ panellist:AddItem(CreateColorModifiers( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateParamModifiers( data, SimplePanel(panellist) ))
+
+ return panellist
+
+end
+
+/*** Model panel for adjusting models ***
+Name:
+Model:
+Bone name:
+Translation x / y / z
+Rotation pitch / yaw / role
+Size
+*/
+local function CreateQuadPanel( name, preset_data )
+
+ local data = wep.v_models[name]
+ if (!preset_data) then preset_data = {} end
+
+ // default data
+ data.type = preset_data.type or "Quad"
+ data.model = preset_data.model or ""
+ data.bone = preset_data.bone or ""
+ data.rel = preset_data.rel or ""
+ data.pos = preset_data.pos or Vector(0,0,0)
+ data.angle = preset_data.angle or Angle(0,0,0)
+ data.size = preset_data.size or 0.05
+
+ wep.vRenderOrder = nil // force viewmodel render order to recache
+
+ local panellist = vgui.Create("DPanelList", pmodels )
+ panellist:SetPaintBackground( true )
+ panellist.Paint = function() surface.SetDrawColor( 90, 90, 90, 255 ) surface.DrawRect( 0, 0, panellist:GetWide(), panellist:GetTall() ) end
+ panellist:EnableVerticalScrollbar( true )
+ panellist:SetSpacing(5)
+ panellist:SetPadding(5)
+ panellist:DockMargin(0,0,0,5)
+ panellist:Dock(FILL)
+
+ PanelBackgroundReset()
+
+ panellist:AddItem(CreateNameLabel( name, SimplePanel(panellist) ))
+ panellist:AddItem(CreateBoneModifier( data, SimplePanel(panellist), LocalPlayer():GetViewModel() ))
+ panellist:AddItem(CreateVRelativeModifier( name, data, SimplePanel(panellist) ))
+ panellist:AddItem(CreatePositionModifiers( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateAngleModifiers( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateSizeModifiers( data, SimplePanel(panellist), 1 ))
+
+ return panellist
+
+end
+
+// adding button DoClick
+mnbtn.DoClick = function()
+ local new = string.Trim( mntext:GetValue() )
+ if (new) then
+ if (new == "") then CreateNote("Empty name field!") return end
+ if (wep.v_models[new] != nil) then CreateNote("Name already exists!") return end
+ wep.v_models[new] = {}
+
+ if (!wep.v_panelCache[new]) then
+ if (boxselected == "Model") then
+ wep.v_panelCache[new] = CreateModelPanel( new )
+ elseif (boxselected == "Sprite") then
+ wep.v_panelCache[new] = CreateSpritePanel( new )
+ elseif (boxselected == "Quad") then
+ wep.v_panelCache[new] = CreateQuadPanel( new )
+ else
+ Error("wtf are u doing")
+ end
+ end
+
+ wep.v_panelCache[new]:SetVisible(false)
+
+ table.insert(v_relelements, new)
+ UpdateRelBoxes("v")
+
+ mlist:AddLine(new,boxselected)
+ end
+end
+
+for k, v in pairs( wep.save_data.v_models ) do
+ wep.v_models[k] = {}
+ if (v.type == "Model") then
+ wep.v_panelCache[k] = CreateModelPanel( k, v )
+ elseif (v.type == "Sprite") then
+ wep.v_panelCache[k] = CreateSpritePanel( k, v )
+ elseif (v.type == "Quad") then
+ wep.v_panelCache[k] = CreateQuadPanel( k, v )
+ end
+ wep.v_panelCache[k]:SetVisible(false)
+
+ table.insert(v_relelements, k)
+ mlist:AddLine(k,v.type)
+
+end
+UpdateRelBoxes("v")
+
+// remove a line
+rmbtn.DoClick = function()
+ local line = mlist:GetSelectedLine()
+ if (line) then
+ local name = mlist:GetLine(line):GetValue(1)
+ wep.v_models[name] = nil
+ // clear from panel cache
+ if (wep.v_panelCache[name]) then
+ wep.v_panelCache[name]:Remove()
+ wep.v_panelCache[name] = nil
+
+ table.RemoveByValue( v_relelements, name )
+ RemoveRelBox( "v", name )
+ UpdateRelBoxes( "v" )
+ end
+ mlist:RemoveLine(line)
+ end
+end
+
+// duplicate line
+copybtn.DoClick = function()
+ local line = mlist:GetSelectedLine()
+ if (line) then
+ local name = mlist:GetLine(line):GetValue(1)
+ local to_copy = wep.v_models[name]
+ local new_preset = table.Copy(to_copy)
+
+ // quickly generate a new unique name
+ while(wep.v_models[name]) do
+ name = name.."+"
+ end
+
+ // have to fix every sub-table as well because table.Copy copies references
+ new_preset.pos = Vector(to_copy.pos.x, to_copy.pos.y, to_copy.pos.z)
+ if (to_copy.angle) then
+ new_preset.angle = Angle(to_copy.angle.p, to_copy.angle.y, to_copy.angle.r)
+ end
+ if (to_copy.color) then
+ new_preset.color = Color(to_copy.color.r,to_copy.color.g,to_copy.color.b,to_copy.color.a)
+ end
+ if (type(to_copy.size) == "table") then
+ new_preset.size = table.Copy(to_copy.size)
+ elseif (type(to_copy.size) == "Vector") then
+ new_preset.size = Vector(to_copy.size.x, to_copy.size.y, to_copy.size.z)
+ end
+ if (to_copy.bodygroup) then
+ new_preset.bodygroup = table.Copy(to_copy.bodygroup)
+ end
+
+ wep.v_models[name] = {}
+
+ if (new_preset.type == "Model") then
+ wep.v_panelCache[name] = CreateModelPanel( name, new_preset )
+ elseif (new_preset.type == "Sprite") then
+ wep.v_panelCache[name] = CreateSpritePanel( name, new_preset )
+ elseif (new_preset.type == "Quad") then
+ wep.v_panelCache[name] = CreateQuadPanel( name, new_preset )
+ end
+
+ wep.v_panelCache[name]:SetVisible(false)
+
+ table.insert(v_relelements, name)
+ UpdateRelBoxes("v")
+
+ mlist:AddLine(name,new_preset.type)
+ end
+end
+
+
+
+/*//////////////////////////////////////////////////////////////
+
+ World Models
+
+/////////////////////////////////////////////////////////////*/
+
+local lastVisible = ""
+
+local mlabel = vgui.Create( "DLabel", pwmodels )
+ mlabel:SetTall( 20 )
+ mlabel:SetText( "New worldmodel element:" )
+mlabel:Dock(TOP)
+
+local function CreateWNote( text )
+ local templabel = vgui.Create( "DLabel" )
+ templabel:SetText( text )
+ templabel:SizeToContents()
+
+ local x, y = mlabel:GetPos()
+ local notif = vgui.Create( "DNotify" , pwmodels )
+ notif:SetPos( x + 160, y )
+ notif:SetSize( templabel:GetWide(), 20 )
+ notif:SetLife( 5 )
+ notif:AddItem(templabel)
+end
+
+local pnewelement = SimplePanel( pwmodels )
+pnewelement:SetTall(20)
+
+ local mnwtext = vgui.Create("DTextEntry", pnewelement )
+ mnwtext:SetTall( 20 )
+ mnwtext:SetMultiline(false)
+ mnwtext:SetText( "element_name" )
+ mnwtext:Dock(FILL)
+
+ local mnwbtn = vgui.Create( "DButton", pnewelement )
+ mnwbtn:SetSize( 50, 20 )
+ mnwbtn:SetText( "Add" )
+ mnwbtn:DockMargin(5,0,0,0)
+ mnwbtn:Dock(RIGHT)
+
+ local tpbox = vgui.Create( "DComboBox", pnewelement )
+ tpbox:SetSize( 100, 20 )
+ tpbox:SetText( "Model" )
+ tpbox:AddChoice( "Model" )
+ tpbox:AddChoice( "Sprite" )
+ tpbox:AddChoice( "Quad" )
+ local wboxselected = "Model"
+ tpbox.OnSelect = function( p, index, value )
+ wboxselected = value
+ end
+ tpbox:DockMargin(5,0,0,0)
+ tpbox:Dock(RIGHT)
+
+pnewelement:DockMargin(0,5,0,5)
+pnewelement:Dock(TOP)
+
+local mwlist = vgui.Create( "DListView", pwmodels)
+ wep.w_modelListing = mwlist
+
+ mwlist:SetTall( 160 )
+ mwlist:SetMultiSelect(false)
+ mwlist:SetDrawBackground(true)
+ mwlist:AddColumn("Name")
+ mwlist:AddColumn("Type")
+ // cache the created panels
+ mwlist.OnRowSelected = function( panel, line )
+ local name = mwlist:GetLine(line):GetValue(1)
+
+ if (wep.w_panelCache[lastVisible]) then
+ wep.w_panelCache[lastVisible]:SetVisible(false)
+ end
+ wep.w_panelCache[name]:SetVisible(true)
+
+ lastVisible = name
+ end
+
+mwlist:Dock(TOP)
+
+local pwbuttons = SimplePanel( pwmodels )
+
+ local rmbtn = vgui.Create( "DButton", pwbuttons )
+ rmbtn:SetSize( 140, 25 )
+ rmbtn:SetText( "Remove selected" )
+ rmbtn:Dock(LEFT)
+
+ local copybtn = vgui.Create( "DButton", pwbuttons )
+ copybtn:SetSize( 140, 25 )
+ copybtn:SetText( "Copy selected" )
+ copybtn:Dock(RIGHT)
+
+ local importbtn = vgui.Create( "DButton", pwbuttons )
+ importbtn:SetTall( 25 )
+ importbtn:SetText( "Import viewmodels" )
+ importbtn:Dock(FILL)
+
+pwbuttons:DockMargin(0,5,0,5)
+pwbuttons:Dock(TOP)
+
+// Print buttons
+local pctbtn = vgui.Create( "DButton", pwmodels)
+ pctbtn:SetTall( 30 )
+ pctbtn:SetText("Copy world model table to clipboard")
+ pctbtn.DoClick = function()
+ SetClipboardText(GetWModelsText())
+ LocalPlayer():ChatPrint("Code copied to clipboard!")
+ end
+pctbtn:DockMargin(0,5,0,0)
+pctbtn:Dock(BOTTOM)
+
+local prtbtn = vgui.Create( "DButton", pwmodels)
+ prtbtn:SetTall( 30 )
+ prtbtn:SetText("Print world model table to console")
+ prtbtn.DoClick = function()
+ MsgN("*********************************************")
+ for k, v in pairs(string.Explode("\n",GetWModelsText())) do
+ MsgN(v)
+ end
+ MsgN("*********************************************")
+ LocalPlayer():ChatPrint("Code printed to console!")
+ end
+prtbtn:Dock(BOTTOM)
+
+/*** Model panel for adjusting models ***
+Name:
+Model:
+Translation x / y / z
+Rotation pitch / yaw / role
+Model size x / y / z
+Material
+Color modulation
+*/
+local function CreateWorldModelPanel( name, preset_data )
+
+ local data = wep.w_models[name]
+ if (!preset_data) then preset_data = {} end
+
+ // default data
+ data.type = preset_data.type or "Model"
+ data.model = preset_data.model or ""
+ data.bone = preset_data.bone or "ValveBiped.Bip01_R_Hand"
+ data.rel = preset_data.rel or ""
+ data.pos = preset_data.pos or Vector(0,0,0)
+ data.angle = preset_data.angle or Angle(0,0,0)
+ data.size = preset_data.size or Vector(0.5,0.5,0.5)
+ data.color = preset_data.color or Color(255,255,255,255)
+ data.surpresslightning = preset_data.surpresslightning or false
+ data.material = preset_data.material or ""
+ data.bodygroup = preset_data.bodygroup or {}
+ data.skin = preset_data.skin or 0
+
+ wep.wRenderOrder = nil
+
+ local panellist = vgui.Create("DPanelList", pwmodels )
+ panellist:SetPaintBackground( true )
+ panellist.Paint = function() surface.SetDrawColor( 90, 90, 90, 255 ) surface.DrawRect( 0, 0, panellist:GetWide(), panellist:GetTall() ) end
+ panellist:EnableVerticalScrollbar( true )
+ panellist:SetSpacing(5)
+ panellist:SetPadding(5)
+ panellist:DockMargin(0,0,0,5)
+ panellist:Dock(FILL)
+
+ PanelBackgroundReset()
+
+ panellist:AddItem(CreateNameLabel( name, SimplePanel(panellist) ))
+ panellist:AddItem(CreateModelModifier( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateBoneModifier( data, SimplePanel(panellist), LocalPlayer() ))
+ panellist:AddItem(CreateWRelativeModifier( name, data, SimplePanel(panellist) ))
+ panellist:AddItem(CreatePositionModifiers( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateAngleModifiers( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateSizeModifiers( data, SimplePanel(panellist), 3 ))
+ panellist:AddItem(CreateColorModifiers( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateSLightningModifier( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateMaterialModifier( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateBodygroupSkinModifier( data, SimplePanel(panellist) ))
+
+ return panellist
+
+end
+
+/*** Sprite panel for adjusting sprites ***
+Name:
+Sprite:
+Translation x / y / z
+Sprite x / y size
+Color
+*/
+local function CreateWorldSpritePanel( name, preset_data )
+
+ local data = wep.w_models[name]
+ if (!preset_data) then preset_data = {} end
+
+ // default data
+ data.type = preset_data.type or "Sprite"
+ data.sprite = preset_data.sprite or ""
+ data.bone = preset_data.bone or "ValveBiped.Bip01_R_Hand"
+ data.rel = preset_data.rel or ""
+ data.pos = preset_data.pos or Vector(0,0,0)
+ data.size = preset_data.size or { x = 1, y = 1 }
+ data.color = preset_data.color or Color(255,255,255,255)
+ data.nocull = preset_data.nocull or true
+ data.additive = preset_data.additive or true
+ data.vertexalpha = preset_data.vertexalpha or true
+ data.vertexcolor = preset_data.vertexcolor or true
+ data.ignorez = preset_data.ignorez or false
+
+ wep.wRenderOrder = nil
+
+ local panellist = vgui.Create("DPanelList", pwmodels )
+ panellist:SetPaintBackground( true )
+ panellist.Paint = function() surface.SetDrawColor( 90, 90, 90, 255 ) surface.DrawRect( 0, 0, panellist:GetWide(), panellist:GetTall() ) end
+ panellist:EnableVerticalScrollbar( true )
+ panellist:SetSpacing(5)
+ panellist:SetPadding(5)
+ panellist:DockMargin(0,0,0,5)
+ panellist:Dock(FILL)
+
+ PanelBackgroundReset()
+
+ panellist:AddItem(CreateNameLabel( name, SimplePanel(panellist) ))
+ panellist:AddItem(CreateSpriteModifier( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateBoneModifier( data, SimplePanel(panellist), LocalPlayer() ))
+ panellist:AddItem(CreateWRelativeModifier( name, data, SimplePanel(panellist) ))
+ panellist:AddItem(CreatePositionModifiers( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateSizeModifiers( data, SimplePanel(panellist), 2 ))
+ panellist:AddItem(CreateColorModifiers( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateParamModifiers( data, SimplePanel(panellist) ))
+
+ return panellist
+
+end
+
+/*** Model panel for adjusting models ***
+Name:
+Model:
+Bone name:
+Translation x / y / z
+Rotation pitch / yaw / role
+Size
+*/
+local function CreateWorldQuadPanel( name, preset_data )
+
+ local data = wep.w_models[name]
+ if (!preset_data) then preset_data = {} end
+
+ // default data
+ data.type = preset_data.type or "Quad"
+ data.model = preset_data.model or ""
+ data.bone = preset_data.bone or "ValveBiped.Bip01_R_Hand"
+ data.rel = preset_data.rel or ""
+ data.pos = preset_data.pos or Vector(0,0,0)
+ data.angle = preset_data.angle or Angle(0,0,0)
+ data.size = preset_data.size or 0.05
+
+ wep.vRenderOrder = nil // force viewmodel render order to recache
+
+ local panellist = vgui.Create("DPanelList", pwmodels )
+ panellist:SetPaintBackground( true )
+ panellist.Paint = function() surface.SetDrawColor( 90, 90, 90, 255 ) surface.DrawRect( 0, 0, panellist:GetWide(), panellist:GetTall() ) end
+ panellist:EnableVerticalScrollbar( true )
+ panellist:SetSpacing(5)
+ panellist:SetPadding(5)
+ panellist:DockMargin(0,0,0,5)
+ panellist:Dock(FILL)
+
+ PanelBackgroundReset()
+
+ panellist:AddItem(CreateNameLabel( name, SimplePanel(panellist) ))
+ panellist:AddItem(CreateBoneModifier( data, SimplePanel(panellist), LocalPlayer() ))
+ panellist:AddItem(CreateWRelativeModifier( name, data, SimplePanel(panellist) ))
+ panellist:AddItem(CreatePositionModifiers( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateAngleModifiers( data, SimplePanel(panellist) ))
+ panellist:AddItem(CreateSizeModifiers( data, SimplePanel(panellist), 1 ))
+
+ return panellist
+
+end
+
+// adding button DoClick
+mnwbtn.DoClick = function()
+ local new = string.Trim( mnwtext:GetValue() )
+ if (new) then
+ if (new == "") then CreateWNote("Empty name field!") return end
+ if (wep.w_models[new] != nil) then CreateWNote("Name already exists!") return end
+ wep.w_models[new] = {}
+
+ if (!wep.w_panelCache[new]) then
+ if (wboxselected == "Model") then
+ wep.w_panelCache[new] = CreateWorldModelPanel( new )
+ elseif (wboxselected == "Sprite") then
+ wep.w_panelCache[new] = CreateWorldSpritePanel( new )
+ elseif (wboxselected == "Quad") then
+ wep.w_panelCache[new] = CreateWorldQuadPanel( new )
+ else
+ Error("wtf are u doing")
+ end
+ end
+
+ wep.w_panelCache[new]:SetVisible(false)
+
+ table.insert(w_relelements, new)
+ UpdateRelBoxes("w")
+
+ mwlist:AddLine(new,wboxselected)
+ end
+end
+
+for k, v in pairs( wep.save_data.w_models ) do
+ wep.w_models[k] = {}
+
+ // backwards compatability
+ if (!v.bone or v.bone == "") then
+ v.bone = "ValveBiped.Bip01_R_Hand"
+ end
+
+ if (v.type == "Model") then
+ wep.w_panelCache[k] = CreateWorldModelPanel( k, v )
+ elseif (v.type == "Sprite") then
+ wep.w_panelCache[k] = CreateWorldSpritePanel( k, v )
+ elseif (v.type == "Quad") then
+ wep.w_panelCache[k] = CreateWorldQuadPanel( k, v )
+ end
+ wep.w_panelCache[k]:SetVisible(false)
+ table.insert(w_relelements, k)
+
+ mwlist:AddLine(k,v.type)
+
+end
+UpdateRelBoxes("w")
+
+// import viewmodels
+importbtn.DoClick = function()
+ local num = 0
+ for k, v in pairs( wep.v_models ) do
+ local name = k
+ local i = 1
+ while(wep.w_models[name] != nil) do
+ name = k..""..i
+ i = i + 1
+
+ // changing names might mess up the relative transitions of some stuff
+ // but whatever.
+ end
+
+ local new_preset = table.Copy(v)
+ new_preset.bone = "ValveBiped.Bip01_R_Hand" // switch to hand bone by default
+
+ if (new_preset.rel and new_preset.rel != "") then
+ new_preset.pos = Vector(v.pos.x, v.pos.y, v.pos.z)
+ if (v.angle) then
+ new_preset.angle = Angle(v.angle.p, v.angle.y, v.angle.r)
+ end
+ else
+ new_preset.pos = Vector(num*5,0,-10)
+ if (v.angle) then
+ new_preset.angle = Angle(0,0,0)
+ end
+ end
+
+ if (v.color) then
+ new_preset.color = Color(v.color.r,v.color.g,v.color.b,v.color.a)
+ end
+ if (type(v.size) == "table") then
+ new_preset.size = table.Copy(v.size)
+ elseif (type(v.size) == "Vector") then
+ new_preset.size = Vector(v.size.x, v.size.y, v.size.z)
+ end
+ if (v.bodygroup) then
+ new_preset.bodygroup = table.Copy(v.bodygroup)
+ end
+
+ wep.w_models[name] = {}
+ if (v.type == "Model") then
+ wep.w_panelCache[name] = CreateWorldModelPanel( name, new_preset )
+ elseif (v.type == "Sprite") then
+ wep.w_panelCache[name] = CreateWorldSpritePanel( name, new_preset )
+ elseif (v.type == "Quad") then
+ wep.w_panelCache[name] = CreateWorldQuadPanel( name, new_preset )
+ end
+ wep.w_panelCache[name]:SetVisible(false)
+
+ table.insert(w_relelements, name)
+ UpdateRelBoxes("w")
+
+ mwlist:AddLine(name,v.type)
+
+ num = num + 1
+ end
+end
+
+// remove a line
+rmbtn.DoClick = function()
+ local line = mwlist:GetSelectedLine()
+ if (line) then
+ local name = mwlist:GetLine(line):GetValue(1)
+ wep.w_models[name] = nil
+ // clear from panel cache
+ if (wep.w_panelCache[name]) then
+ wep.w_panelCache[name]:Remove()
+ wep.w_panelCache[name] = nil
+
+ table.RemoveByValue( w_relelements, name )
+ RemoveRelBox( "w", name )
+ UpdateRelBoxes( "w" )
+ end
+ mwlist:RemoveLine(line)
+ end
+end
+
+// duplicate line
+copybtn.DoClick = function()
+ local line = mwlist:GetSelectedLine()
+ if (line) then
+ local name = mwlist:GetLine(line):GetValue(1)
+ local to_copy = wep.w_models[name]
+ local new_preset = table.Copy(to_copy)
+
+ // quickly generate a new unique name
+ while(wep.w_models[name]) do
+ name = name.."+"
+ end
+
+ // have to fix every sub-table as well because table.Copy copies references
+ new_preset.pos = Vector(to_copy.pos.x, to_copy.pos.y, to_copy.pos.z)
+ if (to_copy.angle) then
+ new_preset.angle = Angle(to_copy.angle.p, to_copy.angle.y, to_copy.angle.r)
+ end
+ if (to_copy.color) then
+ new_preset.color = Color(to_copy.color.r,to_copy.color.g,to_copy.color.b,to_copy.color.a)
+ end
+ if (type(to_copy.size) == "table") then
+ new_preset.size = table.Copy(to_copy.size)
+ elseif (type(to_copy.size) == "Vector") then
+ new_preset.size = Vector(to_copy.size.x, to_copy.size.y, to_copy.size.z)
+ end
+ if (to_copy.bodygroup) then
+ new_preset.bodygroup = table.Copy(to_copy.bodygroup)
+ end
+
+ wep.w_models[name] = {}
+
+ if (new_preset.type == "Model") then
+ wep.w_panelCache[name] = CreateWorldModelPanel( name, new_preset )
+ elseif (new_preset.type == "Sprite") then
+ wep.w_panelCache[name] = CreateWorldSpritePanel( name, new_preset )
+ elseif (new_preset.type == "Quad") then
+ wep.w_panelCache[name] = CreateWorldQuadPanel( name, new_preset )
+ end
+
+ wep.w_panelCache[name]:SetVisible(false)
+
+ table.insert(w_relelements, name)
+ UpdateRelBoxes("w")
+
+ mwlist:AddLine(name,new_preset.type)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/menu/tool.lua b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/menu/tool.lua
new file mode 100644
index 0000000..79f2079
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/menu/tool.lua
@@ -0,0 +1,201 @@
+
+local tutorialURL = "http://www.facepunch.com/threads/1032378-SWEP-Construction-Kit-developer-tool-for-modifying-viewmodels-ironsights/"
+local wep = GetSCKSWEP( LocalPlayer() )
+local ptool = wep.ptool
+
+local panim = SimplePanel(ptool)
+ // ***** Animations *****
+
+ local alabel = vgui.Create( "DLabel", panim )
+ alabel:SetTall( 18 )
+ alabel:SetText( "Play animation (only works properly in third person):" )
+ alabel:Dock( TOP )
+
+ local cols = 4
+ local agrid = vgui.Create( "DGrid", panim )
+ agrid:SetCols(cols)
+ agrid:SetColWide( 106 )
+ agrid:SetRowHeight( 24 )
+
+ local animations = {
+ { "Primary attack", ACT_VM_PRIMARYATTACK, PLAYER_ATTACK1 },
+ { "Reload", ACT_VM_RELOAD, PLAYER_RELOAD },
+ { "Melee 1", ACT_VM_MISSCENTER, PLAYER_ATTACK1 },
+ { "Melee 2", ACT_VM_HITCENTER, PLAYER_ATTACK1 },
+ { "Grenade pull (CSS)", ACT_VM_PULLPIN, nil },
+ { "Grenade pull (HL2)", ACT_VM_PULLBACK_HIGH, nil },
+ { "Draw", ACT_VM_PULLBACK_HIGH, nil },
+ { "Throw grenade", ACT_VM_THROW, PLAYER_ATTACK1 },
+ { "Throw grenade", ACT_VM_IDLE, nil }
+ }
+
+ for k, anim in pairs( animations ) do
+
+ local abtn = vgui.Create( "DButton", agrid )
+ abtn:SetSize( 100, 18 )
+ abtn:SetText( anim[1] )
+ abtn.DoClick = function()
+ RunConsoleCommand("swepck_playanimation", anim[2])
+ wep:ResetSequenceInfo()
+ if (anim[2] != nil) then wep:SendWeaponAnim(anim[2]) end
+ if (anim[3] != nil) then LocalPlayer():SetAnimation(anim[3]) end
+ end
+ agrid:AddItem(abtn)
+
+ end
+
+ agrid:SetTall( math.ceil(#animations / cols) * 24 )
+ agrid:DockMargin(0,5,0,0)
+ agrid:Dock(TOP)
+
+panim:SetTall(alabel:GetTall() + agrid:GetTall() + 5)
+panim:DockPadding(0,5,0,5)
+panim:Dock( TOP )
+
+local psettings = SimplePanel(ptool)
+
+ // ***** Settings saving / loading *****
+ local function CreateSettingsNote( text )
+ local notiflabel = vgui.Create( "DLabel", psettings )
+ notiflabel:SetTall( 20 )
+ notiflabel:SetText( text )
+ notiflabel:SizeToContentsX()
+
+ local notif = vgui.Create( "DNotify" , psettings )
+ notif:SetPos( 150, 5 ) // just hack it in
+ notif:SetSize( notiflabel:GetWide(), 20 )
+ notif:SetLife( 5 )
+ notif:AddItem(notiflabel)
+
+ end
+
+ local selabel = vgui.Create( "DLabel", psettings )
+ selabel:SetTall( 20 )
+ selabel:SetText( "Configuration:" )
+ selabel:Dock(TOP)
+
+ local psave = SimplePanel(psettings)
+
+ local satext = vgui.Create( "DTextEntry", psave )
+ satext:SetTall( 20 )
+ satext:SetMultiline(false)
+ if (wep.save_data._savename) then
+ satext:SetText( wep.save_data._savename )
+ else
+ satext:SetText( "save1" )
+ end
+ satext:DockMargin(5,0,0,0)
+ satext:Dock(FILL)
+
+ local sabtn = vgui.Create( "DButton", psave )
+ sabtn:SetTall( 16 )
+ sabtn:SetText( "Save as:" )
+ sabtn.DoClick = function()
+
+ if !IsValid(wep) then return end
+
+ local text = string.Trim(satext:GetValue())
+ if (text == "") then return end
+
+ local save_data = wep.save_data
+
+ // collect all save data
+ save_data.v_models = table.Copy(wep.v_models)
+ save_data.w_models = table.Copy(wep.w_models)
+ save_data.v_bonemods = table.Copy(wep.v_bonemods)
+ // remove caches
+ for k, v in pairs(save_data.v_models) do
+ v.createdModel = nil
+ v.createdSprite = nil
+ end
+ for k, v in pairs(save_data.w_models) do
+ v.createdModel = nil
+ v.createdSprite = nil
+ end
+ save_data.ViewModelFlip = wep.ViewModelFlip
+ save_data.ViewModel = wep.ViewModel
+ save_data.CurWorldModel = wep.CurWorldModel
+ save_data.ViewModelFOV = wep.ViewModelFOV
+ save_data.HoldType = wep.HoldType
+ save_data.IronSightsEnabled = wep:GetIronSights()
+ save_data.IronSightsPos, save_data.IronSightsAng = wep:GetIronSightCoordination()
+ save_data.ShowViewModel = wep.ShowViewModel
+ save_data.ShowWorldModel = wep.ShowWorldModel
+
+ local filename = "swep_construction_kit/"..text..".txt"
+
+ local succ, val = pcall(glon.encode, save_data)
+ if (!succ || !val) then LocalPlayer():ChatPrint("Failed to encode settings!") return end
+
+ file.Write(filename, val)
+ LocalPlayer():ChatPrint("Saved file \""..text.."\"!")
+ end
+
+ sabtn:Dock(LEFT)
+
+ psave:DockMargin(0,5,0,5)
+ psave:Dock(TOP)
+
+ local pload = SimplePanel(psettings)
+
+ local lftext = vgui.Create( "DTextEntry", pload )
+ lftext:SetTall( 20 )
+ lftext:SetMultiline(false)
+ lftext:SetText( "save1" )
+
+ lftext:DockMargin(5,0,0,0)
+ lftext:Dock(FILL)
+
+ local lfbtn = vgui.Create( "DButton", pload )
+ lfbtn:SetTall( 16 )
+ lfbtn:SetText( "Load file:" )
+ lfbtn.DoClick = function()
+ local text = string.Trim(lftext:GetValue())
+ if (text == "") then return end
+
+ local filename = "swep_construction_kit/"..text..".txt"
+
+ if (!file.Exists(filename, "DATA")) then
+ CreateSettingsNote( "No such file exists!" )
+ return
+ end
+
+ local glondata = file.Read(filename)
+ local succ, new_preset = pcall(glon.decode, glondata)
+ if (!succ || !new_preset) then LocalPlayer():ChatPrint("Failed to load settings!") return end
+
+ new_preset._savename = text
+
+ wep:CleanMenu()
+ wep:OpenMenu( new_preset )
+ LocalPlayer():ChatPrint("Loaded file \""..text.."\"!")
+ end
+ lfbtn:Dock(LEFT)
+
+ pload:Dock(TOP)
+
+psettings:SetTall(selabel:GetTall() + lftext:GetTall() + satext:GetTall() + 30)
+psettings:DockPadding(0,5,0,5)
+psettings:Dock(TOP)
+
+// link to FP thread
+local threadbtn = vgui.Create( "DButton", ptool )
+ threadbtn:SetTall( 30 )
+ threadbtn:SetText( "Open Tutorial (Facepunch thread)" )
+ threadbtn.DoClick = function()
+ gui.OpenURL(tutorialURL) // Removed in Gmod 13
+ //SetClipboardText(tutorialURL)
+ end
+threadbtn:DockMargin(0,15,0,5)
+threadbtn:Dock(TOP)
+
+// base code
+local basecbtn = vgui.Create( "DButton", ptool )
+ basecbtn:SetTall( 30 )
+ basecbtn:SetText( "Copy SWEP base code to clipboard" )
+ basecbtn.DoClick = function()
+ SetClipboardText(wep.basecode)
+ LocalPlayer():ChatPrint("Base code copied to clipboard!")
+ end
+basecbtn:DockMargin(0,5,0,0)
+basecbtn:Dock(TOP)
diff --git a/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/menu/weapon.lua b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/menu/weapon.lua
new file mode 100644
index 0000000..7c88bf0
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/menu/weapon.lua
@@ -0,0 +1,581 @@
+
+local function GetWeaponPrintText( wep )
+
+ str = ""
+ str = str.."SWEP.HoldType = \""..wep.HoldType.."\"\n"
+ str = str.."SWEP.ViewModelFOV = "..wep.ViewModelFOV.."\n"
+ str = str.."SWEP.ViewModelFlip = "..tostring(wep.ViewModelFlip).."\n"
+ str = str.."SWEP.ViewModel = \""..wep.ViewModel.."\"\n"
+ str = str.."SWEP.WorldModel = \""..wep.CurWorldModel.."\"\n"
+ str = str.."SWEP.ShowViewModel = "..tostring(wep.ShowViewModel).."\n"
+ str = str.."SWEP.ShowWorldModel = "..tostring(wep.ShowWorldModel).."\n"
+ str = str.."SWEP.ViewModelBoneMods = {"
+ local i = 0
+ local num = table.Count( wep.v_bonemods )
+ for k, v in pairs( wep.v_bonemods ) do
+ if !(v.scale == Vector(1,1,1) and v.pos == Vector(0,0,0) and v.angle == Angle(0,0,0)) then
+ if (i == 0) then str = str.."\n" end
+ i = i + 1
+ str = str.."\t[\""..k.."\"] = { scale = "..PrintVec( v.scale )..", pos = "..PrintVec( v.pos )..", angle = "..PrintAngle( v.angle ).." }"
+
+ if (i < num) then str = str.."," end
+ str = str.."\n"
+ end
+ end
+ str = str.."}"
+
+ str = string.Replace(str,",\n}","\n}") // remove the last comma
+
+ return str
+
+end
+
+local function ClearViewModels()
+
+ local wep = GetSCKSWEP( LocalPlayer() )
+
+ wep.v_models = {}
+ if (wep.v_modelListing) then wep.v_modelListing:Clear() end
+ for k, v in pairs( wep.v_panelCache ) do
+ if (v) then
+ v:Remove()
+ end
+ end
+ wep.v_panelCache = {}
+end
+
+local function ClearWorldModels()
+
+ local wep = GetSCKSWEP( LocalPlayer() )
+ if (!IsValid(wep)) then return end
+
+ wep.w_models = {}
+ if (wep.w_modelListing) then wep.w_modelListing:Clear() end
+ for k, v in pairs( wep.w_panelCache ) do
+ if (v) then
+ v:Remove()
+ end
+ end
+ wep.w_panelCache = {}
+end
+
+local function RefreshViewModelBoneMods()
+
+ local wep = GetSCKSWEP( LocalPlayer() )
+ if (!IsValid(wep)) then return end
+
+ if (!IsValid(wep.v_modelbonebox)) then return end
+ wep.v_bonemods = {}
+
+ wep.v_modelbonebox:Clear()
+
+ timer.Destroy("repop")
+
+ timer.Create("repop", 1, 1, function()
+ local option = PopulateBoneList( wep.v_modelbonebox, LocalPlayer():GetViewModel() )
+ if (option) then
+ wep.v_modelbonebox:ChooseOptionID(1)
+ end
+ end)
+
+end
+
+local wep = GetSCKSWEP( LocalPlayer() )
+local pweapon = wep.pweapon
+local next_v_model = ""
+
+// Weapon model
+local pweapon_vmodel = SimplePanel( pweapon )
+
+ local vlabel = vgui.Create( "DLabel", pweapon_vmodel )
+ vlabel:SetTall( 20 )
+ vlabel:SetText( "View model:" )
+ vlabel:Dock(LEFT)
+
+ local vtext = vgui.Create( "DTextEntry", pweapon_vmodel)
+ vtext:SetTall( 20 )
+ vtext:SetMultiline(false)
+ vtext.OnTextChanged = function()
+ local newmod = string.gsub(vtext:GetValue(), ".mdl", "")
+ RunConsoleCommand("swepck_viewmodel", newmod)
+
+ // clear view model additions
+ if (newmod != next_v_model and file.Exists(newmod..".mdl", "GAME")) then
+ next_v_model = newmod
+ ClearViewModels()
+ RefreshViewModelBoneMods()
+ end
+
+ end
+ vtext:SetText( wep.save_data.ViewModel )
+ vtext:OnTextChanged()
+ vtext:Dock(FILL)
+
+ local vtbtn = vgui.Create( "DButton", pweapon_vmodel )
+ vtbtn:SetSize( 25, 20 )
+ vtbtn:SetText("...")
+ vtbtn.DoClick = function()
+ wep:OpenBrowser( wep.ViewModel, "model", function( val ) vtext:SetText(val) vtext:OnTextChanged() end )
+ end
+ vtbtn:Dock(RIGHT)
+
+pweapon_vmodel:DockMargin(0,0,0,5)
+pweapon_vmodel:Dock(TOP)
+
+local pweapon_wmodel = SimplePanel( pweapon )
+
+ local wlabel = vgui.Create( "DLabel", pweapon_wmodel )
+ wlabel:SetTall( 20 )
+ wlabel:SetText( "World model:" )
+ wlabel:Dock(LEFT)
+
+ local wtext = vgui.Create( "DTextEntry", pweapon_wmodel)
+ wtext:SetTall( 20 )
+ wtext:SetMultiline(false)
+ wtext.OnTextChanged = function()
+ local newmod = string.gsub(wtext:GetValue(), ".mdl", "")
+ RunConsoleCommand("swepck_worldmodel", newmod)
+
+ // clear world model additions
+ if (newmod != wep.cur_wmodel) then
+ ClearWorldModels()
+ end
+
+ end
+ wtext:SetText( wep.save_data.CurWorldModel )
+ wtext:OnTextChanged()
+ wtext:Dock(FILL)
+
+ local wtbtn = vgui.Create( "DButton", pweapon_wmodel )
+ wtbtn:SetSize( 25, 20 )
+ wtbtn:SetText("...")
+ wtbtn.DoClick = function()
+ wep:OpenBrowser( wep.CurWorldModel, "model", function( val ) wtext:SetText(val) wtext:OnTextChanged() end )
+ end
+ wtbtn:Dock(RIGHT)
+
+pweapon_wmodel:DockMargin(0,0,0,5)
+pweapon_wmodel:Dock(TOP)
+
+local pweapon_holdtype = SimplePanel( pweapon )
+
+ // Weapon hold type
+ local hlabel = vgui.Create( "DLabel", pweapon_holdtype )
+ hlabel:SetSize( 150, 20 )
+ hlabel:SetText( "Hold type (3rd person):" )
+ hlabel:Dock(LEFT)
+
+ local hbox = vgui.Create( "DComboBox", pweapon_holdtype )
+ hbox:SetTall( 20 )
+ for k, v in pairs( wep:GetHoldTypes() ) do
+ hbox:AddChoice( v )
+ end
+ hbox.OnSelect = function(panel,index,value)
+ if (!value) then return end
+ wep:SetWeaponHoldType( value )
+ wep.HoldType = value
+ RunConsoleCommand("swepck_setholdtype", value)
+ end
+ hbox:SetText( wep.save_data.HoldType )
+ hbox.OnSelect( nil, nil, wep.save_data.HoldType )
+ hbox:Dock(FILL)
+
+pweapon_holdtype:DockMargin(0,0,0,5)
+pweapon_holdtype:Dock(TOP)
+
+
+// Show viewmodel
+local vhbox = vgui.Create( "DCheckBoxLabel", pweapon )
+ vhbox:SetTall( 20 )
+ vhbox:SetText( "Show view model" )
+ vhbox.OnChange = function()
+ wep.ShowViewModel = vhbox:GetChecked()
+ if (wep.ShowViewModel) then
+ LocalPlayer():GetViewModel():SetColor(Color(255,255,255,255))
+ LocalPlayer():GetViewModel():SetMaterial("")
+ else
+ LocalPlayer():GetViewModel():SetColor(Color(255,0,0,255))
+ // This should prevent the model from drawing, without stopping ViewModelDrawn from being called
+ // I tried Entity:SetRenderMode(1) with color alpha on 1 but the view model resets to render mode 0 every frame :/
+ LocalPlayer():GetViewModel():SetMaterial("Debug/hsv")
+ end
+ end
+ if (wep.save_data.ShowViewModel) then vhbox:SetValue(1)
+ else vhbox:SetValue(0) end
+vhbox:DockMargin(0,0,0,5)
+vhbox:Dock(TOP)
+
+// Show worldmodel
+local whbox = vgui.Create( "DCheckBoxLabel", pweapon )
+ whbox:SetTall( 20 )
+ whbox:SetText( "Show world model" )
+ whbox.OnChange = function()
+ wep.ShowWorldModel = whbox:GetChecked()
+ end
+ if (wep.save_data.ShowWorldModel) then whbox:SetValue(1)
+ else whbox:SetValue(0) end
+whbox:DockMargin(0,0,0,5)
+whbox:Dock(TOP)
+
+// Flip viewmodel
+local fcbox = vgui.Create( "DCheckBoxLabel", pweapon )
+ fcbox:SetTall( 20 )
+ fcbox:SetText( "Flip viewmodel" )
+ fcbox.OnChange = function()
+ wep.ViewModelFlip = fcbox:GetChecked()
+ end
+ if (wep.save_data.ViewModelFlip) then fcbox:SetValue(1)
+ else fcbox:SetValue(0) end
+fcbox:DockMargin(0,0,0,5)
+fcbox:Dock(TOP)
+
+// View model FOV slider
+local fovslider = vgui.Create( "DNumSlider", pweapon )
+ fovslider:SetText( "View model FOV" )
+ fovslider:SetMin( 20 )
+ fovslider:SetMax( 140 )
+ fovslider:SetDecimals( 0 )
+ fovslider.OnValueChanged = function( panel, value )
+ wep.ViewModelFOV = tonumber(value)
+ RunConsoleCommand("swepck_viewmodelfov", value)
+ end
+ fovslider:SetValue( wep.save_data.ViewModelFOV )
+fovslider:DockMargin(0,5,0,10)
+fovslider:Dock(TOP)
+
+local pweapon_bone = SimplePanel( pweapon )
+ pweapon_bone:SetTall( 50 )
+
+ local pbone_left = SimplePanel( pweapon_bone )
+ pbone_left:SetWide( 200 )
+
+ // View model bone scaling
+ local vsbonelabel = vgui.Create( "DLabel", pbone_left )
+ vsbonelabel:SetText( "Viewmodel bone mods:" )
+ vsbonelabel:SizeToContentsX()
+ vsbonelabel:SetTall( 20 )
+ vsbonelabel:Dock(TOP)
+
+ local vsbonebox = vgui.Create( "DComboBox", pbone_left )
+ vsbonebox:SetTall( 20 )
+ vsbonebox:Dock(BOTTOM)
+
+ pbone_left:Dock(LEFT)
+
+ local pbone_right = SimplePanel( pweapon_bone )
+
+ local resbtn = vgui.Create( "DButton", pbone_right )
+ resbtn:SetTall( 20 )
+ resbtn:SetText("Reset all bone mods")
+ resbtn:DockMargin(10,0,0,0)
+ resbtn:Dock(TOP)
+
+ local resselbtn = vgui.Create( "DButton", pbone_right )
+ resselbtn:SetTall( 20 )
+ resselbtn:SetText("Reset selected bone mod")
+ resselbtn:DockMargin(10,0,0,0)
+ resselbtn:Dock(BOTTOM)
+
+ pbone_right:Dock(FILL)
+
+pweapon_bone:Dock(TOP)
+
+if (!wep.save_data.v_bonemods) then
+ wep.save_data.v_bonemods = {}
+end
+
+// backwards compatability with old bone scales
+if (wep.save_data.v_bonescales) then
+ for k, v in pairs(wep.save_data.v_bonescales) do
+ if (v == Vector(1,1,1)) then continue end
+ wep.save_data.v_bonemods[k] = { scale = v, pos = Vector(0,0,0), angle = Angle(0,0,0) }
+ end
+end
+wep.save_data.v_bonescales = nil
+
+local curbone = table.GetFirstKey(wep.save_data.v_bonemods)
+if (curbone) then
+ wep.v_bonemods = table.Copy(wep.save_data.v_bonemods)
+else
+ curbone = ""
+ wep.v_bonemods = {}
+end
+
+local bonepanel = vgui.Create( "DPanel", pweapon )
+ bonepanel:SetVisible( true )
+ bonepanel:SetPaintBackground( true )
+ bonepanel.Paint = function() surface.SetDrawColor( 80, 80, 80, 255 ) surface.DrawRect( 0, 0, bonepanel:GetWide(), bonepanel:GetTall() ) end
+bonepanel:DockMargin( 0, 5, 0, 5 )
+bonepanel:DockPadding( 5, 5, 5, 5 )
+bonepanel:Dock(FILL)
+
+local function CreateBoneMod( selbone, preset_data )
+
+ local data = wep.v_bonemods[selbone]
+ if (!preset_data) then preset_data = {} end
+
+ data.scale = preset_data.scale or Vector(1,1,1)
+ data.pos = preset_data.pos or Vector(0,0,0)
+ data.angle = preset_data.angle or Angle(0,0,0)
+
+ local sliderw = 110
+
+ local pscale = SimplePanel( bonepanel )
+ pscale:SetTall(32*3)
+
+ local vslabel = vgui.Create( "DLabel", pscale )
+ vslabel:SetText( "Scale" )
+ vslabel:SizeToContents()
+ vslabel:SetWide(45)
+ vslabel:Dock(LEFT)
+
+ local vsxwang = vgui.Create( "DNumSlider", pscale )
+ vsxwang:SetText("x / y / z")
+ vsxwang:SetWide(sliderw)
+ vsxwang:SetMinMax( 0.01, 3 )
+ vsxwang:SetDecimals( 3 )
+
+ local vsywang = vgui.Create( "DNumSlider", pscale )
+ vsywang:SetText("y")
+ vsywang:SetWide(sliderw)
+ vsywang:SetMinMax( 0.01, 3 )
+ vsywang:SetDecimals( 3 )
+ vsywang.Wang.ConVarChanged = function( p, value )
+ if (selbone != "") then wep.v_bonemods[selbone].scale.y = tonumber(value) end
+ end
+ vsywang:DockMargin(10,0,0,0)
+
+ local vszwang = vgui.Create( "DNumSlider", pscale )
+ vszwang:SetText("z")
+ vszwang:SetWide(sliderw)
+ vszwang:SetMinMax( 0.01, 3 )
+ vszwang:SetDecimals( 3 )
+ vszwang.Wang.ConVarChanged = function( p, value )
+ if (selbone != "") then wep.v_bonemods[selbone].scale.z = tonumber(value) end
+ end
+ vszwang:DockMargin(10,0,0,0)
+
+ // make the x numberwang set the total size
+ vsxwang.Wang.ConVarChanged = function( p, value )
+ if (selbone == "") then return end
+ vszwang:SetValue( value )
+ vsywang:SetValue( value )
+ wep.v_bonemods[selbone].scale.x = tonumber(value)
+ end
+ vsxwang:DockMargin(10,0,0,0)
+
+ pscale.PerformLayout = function() // scales the sliders with the panel
+ vszwang:SetWide(pscale:GetWide()*4/15)
+ vsywang:SetWide(pscale:GetWide()*4/15)
+ vsxwang:SetWide(pscale:GetWide()*4/15)
+ end
+
+ vsxwang:Dock(TOP)
+ vsywang:Dock(TOP)
+ vszwang:Dock(TOP)
+
+ pscale:DockMargin(0,0,0, 5)
+ pscale:Dock(TOP)
+
+ local ppos = SimplePanel( bonepanel )
+ ppos:SetTall(32*3)
+
+ local vposlabel = vgui.Create( "DLabel", ppos )
+ vposlabel:SetText( "Pos" )
+ vposlabel:SizeToContents()
+ vposlabel:SetWide(45)
+ vposlabel:Dock(LEFT)
+
+ local vposxwang = vgui.Create( "DNumSlider", ppos )
+ vposxwang:SetText("x")
+ vposxwang:SetWide(sliderw)
+ vposxwang:SetMinMax( -30, 30 )
+ vposxwang:SetDecimals( 3 )
+ vposxwang.Wang.ConVarChanged = function( p, value )
+ if (selbone != "") then wep.v_bonemods[selbone].pos.x = tonumber(value) end
+ end
+ vposxwang:DockMargin(10,0,0,0)
+
+ local vposywang = vgui.Create( "DNumSlider", ppos )
+ vposywang:SetText("y")
+ vposywang:SetWide(sliderw)
+ vposywang:SetMinMax( -30, 30 )
+ vposywang:SetDecimals( 3 )
+ vposywang.Wang.ConVarChanged = function( p, value )
+ if (selbone != "") then wep.v_bonemods[selbone].pos.y = tonumber(value) end
+ end
+ vposywang:DockMargin(10,0,0,0)
+
+ local vposzwang = vgui.Create( "DNumSlider", ppos )
+ vposzwang:SetText("z")
+ vposzwang:SetWide(sliderw)
+ vposzwang:SetMinMax( -30, 30 )
+ vposzwang:SetDecimals( 3 )
+ vposzwang.Wang.ConVarChanged = function( p, value )
+ if (selbone != "") then wep.v_bonemods[selbone].pos.z = tonumber(value) end
+ end
+ vposzwang:DockMargin(10,0,0,0)
+
+ ppos.PerformLayout = function()
+ vposzwang:SetWide(ppos:GetWide()*4/15)
+ vposywang:SetWide(ppos:GetWide()*4/15)
+ vposxwang:SetWide(ppos:GetWide()*4/15)
+ end
+
+ vposxwang:Dock(TOP)
+ vposywang:Dock(TOP)
+ vposzwang:Dock(TOP)
+
+ ppos:DockMargin(0,0,0, 5)
+ ppos:Dock(TOP)
+
+ local pang = SimplePanel( bonepanel )
+ pang:SetTall(32*3)
+
+ local vanglabel = vgui.Create( "DLabel", pang )
+ vanglabel:SetText( "Angle" )
+ vanglabel:SizeToContents()
+ vanglabel:SetWide(45)
+ vanglabel:Dock(LEFT)
+
+ local vangxwang = vgui.Create( "DNumSlider", pang )
+ vangxwang:SetText("pitch")
+ vangxwang:SetWide(sliderw)
+ vangxwang:SetMinMax( -180, 180 )
+ vangxwang:SetDecimals( 3 )
+ vangxwang.Wang.ConVarChanged = function( p, value )
+ if (selbone != "") then wep.v_bonemods[selbone].angle.p = tonumber(value) end
+ end
+ vangxwang:DockMargin(10,0,0,0)
+
+ local vangywang = vgui.Create( "DNumSlider", pang )
+ vangywang:SetText("yaw")
+ vangywang:SetWide(sliderw)
+ vangywang:SetMinMax( -180, 180 )
+ vangywang:SetDecimals( 3 )
+ vangywang.Wang.ConVarChanged = function( p, value )
+ if (selbone != "") then wep.v_bonemods[selbone].angle.y = tonumber(value) end
+ end
+ vangywang:DockMargin(10,0,0,0)
+
+ local vangzwang = vgui.Create( "DNumSlider", pang )
+ vangzwang:SetText("roll")
+ vangzwang:SetWide(sliderw)
+ vangzwang:SetMinMax( -180, 180 )
+ vangzwang:SetDecimals( 3 )
+ vangzwang.Wang.ConVarChanged = function( p, value )
+ if (selbone != "") then wep.v_bonemods[selbone].angle.r = tonumber(value) end
+ end
+ vangzwang:DockMargin(10,0,0,0)
+
+ pang.PerformLayout = function()
+ vangzwang:SetWide(pang:GetWide()*4/15)
+ vangywang:SetWide(pang:GetWide()*4/15)
+ vangxwang:SetWide(pang:GetWide()*4/15)
+ end
+
+ vangxwang:Dock(TOP)
+ vangywang:Dock(TOP)
+ vangzwang:Dock(TOP)
+
+ pang:DockMargin(0,0,0, 5)
+ pang:Dock(TOP)
+
+ vsxwang:SetValue( data.scale.x )
+ vsywang:SetValue( data.scale.y )
+ vszwang:SetValue( data.scale.z )
+
+ vposxwang:SetValue( data.pos.x )
+ vposywang:SetValue( data.pos.y )
+ vposzwang:SetValue( data.pos.z )
+
+ vangxwang:SetValue( data.angle.p )
+ vangywang:SetValue( data.angle.y )
+ vangzwang:SetValue( data.angle.r )
+
+end
+
+vsbonebox.OnSelect = function( p, index, value )
+ local selbone = value
+ if (!selbone or selbone == "") then return end
+
+ if (!wep.v_bonemods[selbone]) then
+ wep.v_bonemods[selbone] = { scale = Vector(1,1,1), pos = Vector(0,0,0), angle = Angle(0,0,0) }
+ end
+
+ for k, v in pairs( bonepanel:GetChildren() ) do
+ v:Remove()
+ end
+
+ CreateBoneMod( selbone, wep.v_bonemods[selbone])
+ curbone = selbone
+end
+vsbonebox:SetText( curbone )
+vsbonebox.OnSelect( vsbonebox, 1, curbone )
+
+timer.Simple(1, function()
+ local option = PopulateBoneList( vsbonebox, LocalPlayer():GetViewModel() )
+ if (option and curbone == "") then
+ vsbonebox:ChooseOptionID(1)
+ end
+end)
+
+resbtn.DoClick = function()
+ wep.v_bonemods = {}
+ if (curbone == "") then return end
+
+ wep.v_bonemods[curbone] = { scale = Vector(1,1,1), pos = Vector(0,0,0), angle = Angle(0,0,0) }
+
+ for k, v in pairs( bonepanel:GetChildren() ) do
+ v:Remove()
+ end
+
+ CreateBoneMod( curbone, wep.v_bonemods[curbone])
+end
+
+resselbtn.DoClick = function()
+
+ if (curbone == "") then return end
+ wep.v_bonemods[curbone] = { scale = Vector(1,1,1), pos = Vector(0,0,0), angle = Angle(0,0,0) }
+
+ for k, v in pairs( bonepanel:GetChildren() ) do
+ v:Remove()
+ end
+
+ CreateBoneMod( curbone, wep.v_bonemods[curbone])
+end
+
+wep.v_modelbonebox = vsbonebox
+
+local wpdbtn = vgui.Create( "DButton", pweapon )
+ wpdbtn:SetTall( 30 )
+ wpdbtn:SetText( "Drop weapon (hold reload key to pick back up)" )
+ wpdbtn.DoClick = function()
+ RunConsoleCommand("swepck_dropwep")
+ end
+wpdbtn:DockMargin(0,5,0,0)
+wpdbtn:Dock(BOTTOM)
+
+local wpcbtn = vgui.Create( "DButton", pweapon )
+ wpcbtn:SetTall( 30 )
+ wpcbtn:SetText( "Copy weapon code to clipboard" )
+ wpcbtn.DoClick = function()
+ SetClipboardText(GetWeaponPrintText(wep))
+ LocalPlayer():ChatPrint("Code copied to clipboard!")
+ end
+wpcbtn:DockMargin(0,5,0,0)
+wpcbtn:Dock(BOTTOM)
+
+local wpbtn = vgui.Create( "DButton", pweapon )
+ wpbtn:SetTall( 30 )
+ wpbtn:SetText( "Print weapon code to console" )
+ wpbtn.DoClick = function()
+ MsgN("*********************************************")
+ for k, v in pairs(string.Explode("\n",GetWeaponPrintText(wep))) do
+ MsgN(v)
+ end
+ MsgN("*********************************************")
+ LocalPlayer():ChatPrint("Code printed to console!")
+ end
+wpbtn:DockMargin(0,5,0,0)
+wpbtn:Dock(BOTTOM)
diff --git a/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/server.lua b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/server.lua
new file mode 100644
index 0000000..4fe4246
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/server.lua
@@ -0,0 +1,143 @@
+local function CanPickup( pl, wep )
+
+ if (wep:GetClass() == sck_class) then
+ return pl:KeyDown(IN_RELOAD) or !wep.Dropped
+ end
+
+end
+hook.Add("PlayerCanPickupWeapon","SCKPickup",CanPickup)
+
+function SWEP:Deploy()
+ self.LastOwner = self.Owner
+end
+
+function SWEP:Holster()
+ self:SetThirdPerson( false )
+ return true
+end
+
+function SWEP:OnDrop()
+ self:SetThirdPerson( false )
+ if (IsValid(self.LastOwner)) then
+ self.LastOwner:SendLua("Entity("..self:EntIndex().."):OnDropWeapon()")
+ end
+ self.LastOwner = nil
+end
+
+local function Cmd_SetHoldType( pl, cmd, args )
+
+ local holdtype = args[1]
+ local wep = GetSCKSWEP( pl )
+ if (IsValid(wep) and holdtype and table.HasValue( wep:GetHoldTypes(), holdtype )) then
+ wep:SetWeaponHoldType( holdtype )
+ wep.HoldType = holdtype
+ end
+
+end
+concommand.Add("swepck_setholdtype", Cmd_SetHoldType)
+
+local function Cmd_ToggleThirdPerson( pl, cmd, args )
+
+ local wep = GetSCKSWEP( pl )
+ if (IsValid(wep)) then
+ wep:ToggleThirdPerson()
+ end
+
+end
+concommand.Add("swepck_togglethirdperson", Cmd_ToggleThirdPerson)
+
+local function Cmd_PlayAnimation( pl, cmd, args )
+
+ local wep = GetSCKSWEP( pl )
+ if (IsValid(wep)) then
+ local anim = tonumber(args[1] or 0)
+ wep:ResetSequenceInfo()
+ wep:SendWeaponAnim( anim )
+ end
+
+end
+concommand.Add("swepck_playanimation", Cmd_PlayAnimation)
+
+local function Cmd_ToggleSights( pl, cmd, args )
+
+ local wep = GetSCKSWEP( pl )
+ if (IsValid(wep)) then
+ wep:ToggleIronSights()
+ end
+
+end
+concommand.Add("swepck_toggleironsights", Cmd_ToggleSights)
+
+local function Cmd_ViewModelFOV( pl, cmd, args )
+
+ local wep = GetSCKSWEP( pl )
+ if (IsValid(wep)) then
+ wep.ViewModelFOV = tonumber(args[1] or wep.ViewModelFOV)
+ end
+
+end
+concommand.Add("swepck_viewmodelfov", Cmd_ViewModelFOV)
+
+local function Cmd_ViewModel( pl, cmd, args )
+
+ local wep = GetSCKSWEP( pl )
+ if (!IsValid(wep)) then return end
+ local newmod = args[1] or wep.ViewModel
+ newmod = newmod..".mdl"
+ if !file.Exists(newmod, "GAME") then return end
+
+ //util.PrecacheModel(newmod)
+ wep.ViewModel = newmod
+ pl:GetViewModel():SetWeaponModel(Model(newmod), wep)
+ pl:SendLua([[LocalPlayer():GetActiveWeapon().ViewModel = "]]..newmod..[["]])
+ //pl:SendLua([[LocalPlayer():GetViewModel():SetModel("]]..newmod..[[")]])
+ pl:SendLua([[LocalPlayer():GetViewModel():SetWeaponModel(Model("]]..newmod..[["), Entity(]]..wep:EntIndex()..[[))]])
+
+ local quickswitch = nil
+ for k, v in pairs( pl:GetWeapons() ) do
+ if (v:GetClass() != wep:GetClass()) then
+ quickswitch = v:GetClass()
+ break
+ end
+ end
+
+ if (quickswitch) then
+ pl:SelectWeapon( quickswitch )
+ pl:SelectWeapon( wep:GetClass() )
+ else
+ pl:ChatPrint("Switch weapons to make the new viewmodel show up")
+ end
+
+ //print("Changed viewmodel to \""..wep.ViewModel.."\"")
+
+end
+concommand.Add("swepck_viewmodel", Cmd_ViewModel)
+
+local function Cmd_WorldModel( pl, cmd, args )
+
+ local wep = GetSCKSWEP( pl )
+ if (!IsValid(wep)) then return end
+ local newmod = args[1] or wep.CurWorldModel
+ newmod = newmod..".mdl"
+ if !file.Exists(newmod, "GAME") then return end
+
+ util.PrecacheModel(newmod)
+ wep.CurWorldModel = newmod
+ wep:SetModel(newmod)
+ pl:SendLua([[LocalPlayer():GetActiveWeapon().CurWorldModel = "]]..newmod..[["]])
+ pl:SendLua([[LocalPlayer():GetActiveWeapon():CreateWeaponWorldModel()]])
+ //print("Changed worldmodel to \""..wep.CurWorldModel.."\"")
+
+end
+concommand.Add("swepck_worldmodel", Cmd_WorldModel)
+
+local function Cmd_DropWep( pl, cmd, args )
+
+ local wep = GetSCKSWEP( pl )
+ if (IsValid(wep)) then
+ wep.Dropped = true
+ pl:DropWeapon(wep)
+ end
+
+end
+concommand.Add("swepck_dropwep", Cmd_DropWep)
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/shared.lua b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/shared.lua
new file mode 100644
index 0000000..e8fd247
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/swep_construction_kit/shared.lua
@@ -0,0 +1,264 @@
+
+if SERVER then
+ AddCSLuaFile("shared.lua")
+ AddCSLuaFile("client.lua")
+ AddCSLuaFile("glon.lua")
+ AddCSLuaFile("menu/tool.lua")
+ AddCSLuaFile("menu/weapon.lua")
+ AddCSLuaFile("menu/ironsights.lua")
+ AddCSLuaFile("menu/models.lua")
+ AddCSLuaFile("base_code.lua")
+end
+
+if CLIENT then
+
+ SWEP.PrintName = "SWEP Construction Kit"
+ SWEP.Author = "Clavus"
+ SWEP.Contact = "clavus@clavusstudios.com"
+ SWEP.Purpose = "Design SWEP ironsights and clientside models"
+ SWEP.Instructions = "http://tinyurl.com/swepkit"
+ SWEP.Slot = 5
+ SWEP.SlotPos = 10
+ SWEP.ViewModelFlip = false
+
+ SWEP.DrawCrosshair = false
+
+ SWEP.ShowViewModel = true
+ SWEP.ShowWorldModel = true
+
+end
+
+local debugging = false
+
+function SCKDebug( msg )
+ if !debugging then return end
+ MsgN("[SCK] "..msg)
+end
+
+local repmsg = {}
+function SCKDebugRepeat( tag, msg )
+ if !debugging then return end
+ if !repmsg[tag] then repmsg[tag] = { last = 0, num = 0 } end
+ repmsg[tag].num = repmsg[tag].num + 1
+ if (CurTime() - repmsg[tag].last >= 1) then
+ MsgN("[SCK][Repeated "..repmsg[tag].num.." times in last sec] "..msg)
+ repmsg[tag].num = 0
+ repmsg[tag].last = CurTime()
+ end
+end
+
+
+SWEP.HoldType = "pistol"
+SWEP.HoldTypes = { "normal", "melee", "melee2", "fist",
+"knife", "smg", "ar2", "pistol", "revolver", "rpg", "physgun",
+"grenade", "shotgun", "crossbow", "slam", "duel", "passive",
+"camera" }
+
+SWEP.Spawnable = true
+SWEP.AdminSpawnable = true
+
+SWEP.ViewModel = "models/weapons/v_pistol.mdl"
+SWEP.WorldModel = "models/weapons/w_pistol.mdl"
+SWEP.CurWorldModel = "models/weapons/w_pistol.mdl" // this is where shit gets hacky
+
+SWEP.ViewModelFOV = 70
+SWEP.BobScale = 0
+SWEP.SwayScale = 0
+
+SWEP.Primary.Automatic = false
+
+SWEP.IronsightTime = 0.2
+
+SWEP.IronSightsPos = Vector(0, 0, 0)
+SWEP.IronSightsAng = Vector(0, 0, 0)
+
+local sck_class = ""
+
+function SWEP:Initialize()
+
+ self:SetWeaponHoldType(self.HoldType)
+
+ self:SetIronSights( true )
+ self:ResetIronSights()
+
+ if CLIENT then
+ self:CreateWeaponWorldModel()
+ self:ClientInit()
+ if (not file.IsDir("swep_construction_kit", "DATA")) then
+ file.CreateDir("swep_construction_kit")
+ end
+ end
+
+ self.Dropped = false
+
+ sck_class = self:GetClass()
+
+end
+
+function SWEP:Equip()
+
+ self.Dropped = false
+
+end
+
+function SWEP:PrimaryAttack()
+
+ self.Weapon:SetNextPrimaryFire(CurTime() + 0.2)
+
+ if CLIENT then
+ self:OpenMenu()
+ end
+ if game.SinglePlayer() then
+ self.Owner:SendLua("LocalPlayer():GetActiveWeapon():OpenMenu()")
+ end
+
+end
+
+function SWEP:SecondaryAttack()
+
+ self.Weapon:SetNextSecondaryFire(CurTime() + 0.2)
+
+ if CLIENT then
+ self:OpenMenu()
+ end
+ if game.SinglePlayer() then
+ self.Owner:SendLua("LocalPlayer():GetActiveWeapon():OpenMenu()")
+ end
+
+end
+
+
+function SWEP:SetupDataTables()
+
+ self:DTVar( "Bool", 0, "ironsights" )
+ self:DTVar( "Bool", 1, "thirdperson" )
+
+end
+
+function SWEP:ToggleIronSights()
+ self.dt.ironsights = !self.dt.ironsights
+end
+
+function SWEP:SetIronSights( b )
+ self.dt.ironsights = b
+end
+
+function SWEP:GetIronSights()
+ return self.dt.ironsights
+end
+
+function SWEP:ResetIronSights()
+ RunConsoleCommand("_sp_ironsight_x", 0)
+ RunConsoleCommand("_sp_ironsight_y", 0)
+ RunConsoleCommand("_sp_ironsight_z", 0)
+ RunConsoleCommand("_sp_ironsight_pitch", 0)
+ RunConsoleCommand("_sp_ironsight_yaw", 0)
+ RunConsoleCommand("_sp_ironsight_roll", 0)
+end
+
+function SWEP:ToggleThirdPerson()
+ self:SetThirdPerson( !self.dt.thirdperson )
+end
+
+function SWEP:SetThirdPerson( b )
+ self.dt.thirdperson = b
+
+ local owner = self.Owner
+ if (!IsValid(owner)) then owner = self.LastOwner end
+ if (!IsValid(owner)) then return end
+
+ if (self.dt.thirdperson) then
+ owner:SetViewEntity(game.GetWorld())
+ owner:CrosshairDisable()
+ else
+ owner:SetViewEntity(owner)
+ owner:CrosshairEnable()
+ end
+end
+
+function SWEP:GetThirdPerson()
+ return self.dt.thirdperson
+end
+
+function SWEP:GetViewModelPosition(pos, ang)
+
+ //if true then return pos, ang end
+ //SCKDebugRepeat( "SWEP:VMPos", "Getting viewmodel pos" )
+
+ local bIron = self.dt.ironsights
+ local fIronTime = self.fIronTime or 0
+
+ if (not bIron and fIronTime < CurTime() - self.IronsightTime) then
+ return pos, ang
+ end
+
+ self.IronSightsPos, self.IronSightsAng = self:GetIronSightCoordination()
+
+ local Mul = 1.0
+
+ if (fIronTime > CurTime() - self.IronsightTime) then
+ Mul = math.Clamp((CurTime() - fIronTime) / self.IronsightTime, 0, 1)
+
+ if not bIron then Mul = 1 - Mul end
+ end
+
+ local Offset = self.IronSightsPos
+
+ if (self.IronSightsAng) then
+ ang = ang * 1
+ ang:RotateAroundAxis(ang:Right(), self.IronSightsAng.x * Mul)
+ ang:RotateAroundAxis(ang:Up(), self.IronSightsAng.y * Mul)
+ ang:RotateAroundAxis(ang:Forward(), self.IronSightsAng.z * Mul)
+ end
+
+ local Right = ang:Right()
+ local Up = ang:Up()
+ local Forward = ang:Forward()
+
+ pos = pos + Offset.x * Right * Mul
+ pos = pos + Offset.y * Forward * Mul
+ pos = pos + Offset.z * Up * Mul
+
+ return pos, ang
+end
+
+SWEP.ir_x = CreateConVar( "_sp_ironsight_x", 0.0 )
+SWEP.ir_y = CreateConVar( "_sp_ironsight_y", 0.0 )
+SWEP.ir_z = CreateConVar( "_sp_ironsight_z", 0.0 )
+SWEP.ir_p = CreateConVar( "_sp_ironsight_pitch", 0.0 )
+SWEP.ir_yw = CreateConVar( "_sp_ironsight_yaw", 0.0 )
+SWEP.ir_r = CreateConVar( "_sp_ironsight_roll", 0.0 )
+
+function SWEP:GetIronSightCoordination()
+
+ local vec = Vector( self.ir_x:GetFloat(), self.ir_y:GetFloat(), self.ir_z:GetFloat() )
+ local ang = Vector( self.ir_p:GetFloat(), self.ir_yw:GetFloat(), self.ir_r:GetFloat() )
+ return vec, ang
+
+end
+
+function SWEP:GetHoldTypes()
+ return self.HoldTypes
+end
+
+SWEP.LastOwner = nil
+/***************************
+ Helper functions
+***************************/
+SWEP.IsSCK = true
+function GetSCKSWEP( pl )
+ local wep = pl:GetActiveWeapon()
+ if (IsValid(wep) and wep.IsSCK) then
+ return wep
+ end
+ //Error("Not holding SWEP Construction Kit!")
+ return NULL
+end
+
+if SERVER then
+ include("server.lua")
+end
+
+if CLIENT then
+ include("client.lua")
+end
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_hegrenade.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_hegrenade.lua
new file mode 100644
index 0000000..0ac3365
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_hegrenade.lua
@@ -0,0 +1,3 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_zegrenade"
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_akbar.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_akbar.lua
new file mode 100644
index 0000000..dd09d51
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_akbar.lua
@@ -0,0 +1,41 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Akbar' Assault Rifle"
+ SWEP.Slot = 2
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 50
+
+ SWEP.HUD3DBone = "v_weapon.AK47_Parent"
+ SWEP.HUD3DPos = Vector(-1, -4.5, -4)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+ SWEP.HUD3DScale = 0.015
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "ar2"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_rif_ak47.mdl"
+SWEP.WorldModel = "models/weapons/w_rif_ak47.mdl"
+SWEP.UseHands = true
+
+SWEP.ReloadSound = Sound("Weapon_AK47.Clipout")
+SWEP.Primary.Sound = Sound("Weapon_AK47.Single")
+SWEP.Primary.Damage = 18
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.12
+
+SWEP.Primary.ClipSize = 25
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "ar2"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.ConeMax = 0.055
+SWEP.ConeMin = 0.0275
+
+SWEP.WalkSpeed = SPEED_SLOW
+
+SWEP.IronSightsPos = Vector(-6.6, 20, 3.1)
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_annabelle.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_annabelle.lua
new file mode 100644
index 0000000..548599f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_annabelle.lua
@@ -0,0 +1,161 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Annabelle' Rifle"
+ SWEP.Description = "This modified hunting rifle's bullets will explode in to smaller bullets upon hitting a hard surface."
+ SWEP.Slot = 3
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+
+ SWEP.HUD3DBone = "ValveBiped.Gun"
+ SWEP.HUD3DPos = Vector(1.75, 1, -5)
+ SWEP.HUD3DAng = Angle(180, 0, 0)
+ SWEP.HUD3DScale = 0.015
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "ar2"
+
+SWEP.ViewModel = "models/weapons/v_annabelle.mdl"
+SWEP.WorldModel = "models/weapons/w_annabelle.mdl"
+
+SWEP.CSMuzzleFlashes = false
+
+SWEP.Primary.Sound = Sound("Weapon_Shotgun.Single")
+SWEP.Primary.Damage = 90
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 1
+SWEP.ReloadDelay = 0.4
+
+SWEP.Primary.ClipSize = 4
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "357"
+SWEP.Primary.DefaultClip = 24
+
+SWEP.ConeMax = 0.1
+SWEP.ConeMin = 0.015
+
+SWEP.WalkSpeed = SPEED_SLOW
+
+SWEP.reloadtimer = 0
+SWEP.nextreloadfinish = 0
+
+SWEP.IronSightsPos = Vector(-8.8, 10, 4.32)
+SWEP.IronSightsAng = Vector(1.4,0.1,5)
+
+function SWEP:Reload()
+ if self.reloading then return end
+
+ if self:Clip1() < self.Primary.ClipSize and 0 < self.Owner:GetAmmoCount(self.Primary.Ammo) then
+ self:SetNextPrimaryFire(CurTime() + self.ReloadDelay)
+ self.reloading = true
+ self.reloadtimer = CurTime() + self.ReloadDelay
+ self:SendWeaponAnim(ACT_SHOTGUN_RELOAD_START)
+ self.Owner:DoReloadEvent()
+ end
+end
+
+if SERVER then
+function SWEP:Think()
+ if self.reloading and self.reloadtimer < CurTime() then
+ self.reloadtimer = CurTime() + self.ReloadDelay
+ self:SendWeaponAnim(ACT_VM_RELOAD)
+
+ self.Owner:RemoveAmmo(1, self.Primary.Ammo, false)
+ self:SetClip1(self:Clip1() + 1)
+ self:EmitSound("Weapon_Shotgun.Reload")
+
+ if self.Primary.ClipSize <= self:Clip1() or self.Owner:GetAmmoCount(self.Primary.Ammo) <= 0 then
+ self.nextreloadfinish = CurTime() + self.ReloadDelay
+ self.reloading = false
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ end
+ end
+
+ local nextreloadfinish = self.nextreloadfinish
+ if nextreloadfinish ~= 0 and nextreloadfinish < CurTime() then
+ self:SendWeaponAnim(ACT_SHOTGUN_PUMP)
+ self:EmitSound("Weapon_Shotgun.Special1")
+ self.nextreloadfinish = 0
+ end
+
+ if self.IdleAnimation and self.IdleAnimation <= CurTime() then
+ self.IdleAnimation = nil
+ self:SendWeaponAnim(ACT_VM_IDLE)
+ end
+
+ if self:GetIronsights() and not self.Owner:KeyDown(IN_ATTACK2) then
+ self:SetIronsights(false)
+ end
+end
+end
+
+if CLIENT then
+function SWEP:Think()
+ if self.reloading and self.reloadtimer < CurTime() then
+ self.reloadtimer = CurTime() + self.ReloadDelay
+ self:SendWeaponAnim(ACT_VM_RELOAD)
+
+ self.Owner:RemoveAmmo(1, self.Primary.Ammo, false)
+ self:SetClip1(self:Clip1() + 1)
+ self:EmitSound("Weapon_Shotgun.Reload")
+
+ if self.Primary.ClipSize <= self:Clip1() or self.Owner:GetAmmoCount(self.Primary.Ammo) <= 0 then
+ self.nextreloadfinish = CurTime() + self.ReloadDelay
+ self.reloading = false
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ end
+ end
+
+ local nextreloadfinish = self.nextreloadfinish
+ if nextreloadfinish ~= 0 and nextreloadfinish < CurTime() then
+ self:SendWeaponAnim(ACT_SHOTGUN_PUMP)
+ self:EmitSound("Weapon_Shotgun.Special1")
+ self.nextreloadfinish = 0
+ end
+
+ if self:GetIronsights() and not self.Owner:KeyDown(IN_ATTACK2) then
+ self:SetIronsights(false)
+ end
+end
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:Clip1() <= 0 then
+ self:EmitSound("Weapon_Shotgun.Empty")
+ self:SetNextPrimaryFire(CurTime() + 0.25)
+ return false
+ end
+
+ if self.reloading then
+ if 0 < self:Clip1() then
+ self:SendWeaponAnim(ACT_SHOTGUN_PUMP)
+ self:EmitSound("Weapon_Shotgun.Special1")
+ else
+ self:SendWeaponAnim(ACT_SHOTGUN_RELOAD_FINISH)
+ end
+ self.reloading = false
+ self:SetNextPrimaryFire(CurTime() + 0.25)
+ return false
+ end
+
+ return true
+end
+
+local function DoRicochet(attacker, hitpos, hitnormal, normal, damage)
+ attacker.RicochetBullet = true
+ attacker:FireBullets({Num = 8, Src = hitpos, Dir = hitnormal, Spread = Vector(0.2, 0.2, 0), Tracer = 1, TracerName = "rico_trace", Force = damage * 0.15, Damage = damage, Callback = GenericBulletCallback})
+ attacker.RicochetBullet = nil
+end
+function SWEP.BulletCallback(attacker, tr, dmginfo)
+ if SERVER and tr.HitWorld and not tr.HitSky then
+ local hitpos, hitnormal, normal, dmg = tr.HitPos, tr.HitNormal, tr.Normal, dmginfo:GetDamage() / 5
+ timer.Simple(0, function() DoRicochet(attacker, hitpos, hitnormal, normal, dmg) end)
+ end
+
+ GenericBulletCallback(attacker, tr, dmginfo)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_arsenalcrate/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_arsenalcrate/cl_init.lua
new file mode 100644
index 0000000..822844c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_arsenalcrate/cl_init.lua
@@ -0,0 +1,45 @@
+include("shared.lua")
+
+SWEP.PrintName = "Arsenal Crate"
+SWEP.Description = "This crate is invaluable to survival. It allows people to purchase new weapons, tools, ammunition, etc.\nThe deployer gets a 7% commission on purchases not made by themselves.\nPress PRIMARY ATTACK to deploy the crate.\nPress SECONDARY ATTACK and RELOAD to rotate the crate."
+SWEP.DrawCrosshair = false
+
+SWEP.Slot = 4
+SWEP.SlotPos = 0
+
+function SWEP:DrawHUD()
+ if GetConVarNumber("crosshair") ~= 1 then return end
+ self:DrawCrosshairDot()
+end
+
+function SWEP:PrimaryAttack()
+end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
+
+function SWEP:Think()
+ if self.Owner:KeyDown(IN_ATTACK2) then
+ self:RotateGhost(FrameTime() * 60)
+ end
+ if self.Owner:KeyDown(IN_RELOAD) then
+ self:RotateGhost(FrameTime() * -60)
+ end
+end
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ return true
+end
+
+local nextclick = 0
+function SWEP:RotateGhost(amount)
+ if nextclick <= RealTime() then
+ surface.PlaySound("npc/headcrab_poison/ph_step4.wav")
+ nextclick = RealTime() + 0.3
+ end
+
+ RunConsoleCommand("_zs_ghostrotation", math.NormalizeAngle(GetConVarNumber("_zs_ghostrotation") + amount))
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_arsenalcrate/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_arsenalcrate/init.lua
new file mode 100644
index 0000000..2ba7f1c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_arsenalcrate/init.lua
@@ -0,0 +1,83 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self:SpawnGhost()
+
+ return true
+end
+
+function SWEP:OnRemove()
+ self:RemoveGhost()
+end
+
+function SWEP:Holster()
+ self:RemoveGhost()
+ return true
+end
+
+function SWEP:SpawnGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:GiveStatus("ghost_arsenalcrate")
+ end
+end
+
+function SWEP:RemoveGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:RemoveStatus("ghost_arsenalcrate", false, true)
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+
+ local owner = self.Owner
+
+ local status = owner.status_ghost_arsenalcrate
+ if not (status and status:IsValid()) then return end
+ status:RecalculateValidity()
+ if not status:GetValidPlacement() then return end
+
+ local pos, ang = status:RecalculateValidity()
+ if not pos or not ang then return end
+
+ self:SetNextPrimaryAttack(CurTime() + self.Primary.Delay)
+
+ local ent = ents.Create("prop_arsenalcrate")
+ if ent:IsValid() then
+ ent:SetPos(pos)
+ ent:SetAngles(ang)
+ ent:Spawn()
+
+ ent:SetObjectOwner(owner)
+
+ ent:EmitSound("npc/dog/dog_servo12.wav")
+
+ ent:GhostAllPlayersInMe(5)
+
+ self:TakePrimaryAmmo(1)
+
+ local stored = owner:PopPackedItem(ent:GetClass())
+ if stored then
+ ent:SetObjectHealth(stored[1])
+ end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ owner:StripWeapon(self:GetClass())
+ end
+ end
+end
+
+function SWEP:Think()
+ local count = self:GetPrimaryAmmoCount()
+ if count ~= self:GetReplicatedAmmo() then
+ self:SetReplicatedAmmo(count)
+ self.Owner:ResetSpeed()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_arsenalcrate/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_arsenalcrate/shared.lua
new file mode 100644
index 0000000..6a5401e
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_arsenalcrate/shared.lua
@@ -0,0 +1,59 @@
+SWEP.ViewModel = "models/weapons/v_pistol.mdl"
+SWEP.WorldModel = Model("models/Items/item_item_crate.mdl")
+
+SWEP.AmmoIfHas = true
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.DefaultClip = 1
+SWEP.Primary.Ammo = "airboatgun"
+SWEP.Primary.Delay = 1
+SWEP.Primary.Automatic = true
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_NORMAL
+SWEP.FullWalkSpeed = SPEED_SLOWEST
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType("slam")
+ self:SetDeploySpeed(1.1)
+ self:HideViewAndWorldModel()
+end
+
+function SWEP:SetReplicatedAmmo(count)
+ self:SetDTInt(0, count)
+end
+
+function SWEP:GetReplicatedAmmo()
+ return self:GetDTInt(0)
+end
+
+function SWEP:GetWalkSpeed()
+ if self:GetPrimaryAmmoCount() > 0 then
+ return self.FullWalkSpeed
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ return false
+ end
+
+ return true
+end
+
+function SWEP:Holster()
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_axe.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_axe.lua
new file mode 100644
index 0000000..16bd1ee
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_axe.lua
@@ -0,0 +1,51 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Axe"
+
+ SWEP.ViewModelFOV = 55
+ SWEP.ViewModelFlip = false
+
+ SWEP.ShowViewModel = false
+ SWEP.ShowWorldModel = false
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props/cs_militia/axe.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(3, 1.299, -4), angle = Angle(0, 0, 90), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props/cs_militia/axe.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(3, 1.399, -4), angle = Angle(0, 0, 90), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.ViewModel = "models/weapons/c_stunstick.mdl"
+SWEP.WorldModel = "models/props/cs_militia/axe.mdl"
+SWEP.UseHands = true
+
+SWEP.HoldType = "melee2"
+
+SWEP.MeleeDamage = 45
+SWEP.MeleeRange = 55
+SWEP.MeleeSize = 1.5
+SWEP.MeleeKnockBack = SWEP.MeleeDamage * 1.5
+
+SWEP.WalkSpeed = SPEED_FAST
+
+SWEP.SwingTime = 0.6
+SWEP.SwingRotation = Angle(0, -20, -40)
+SWEP.SwingOffset = Vector(10, 0, 0)
+SWEP.SwingHoldType = "melee"
+
+SWEP.HitDecal = "Manhackcut"
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("weapons/iceaxe/iceaxe_swing1.wav", 75, math.random(65, 70))
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("weapons/melee/golf club/golf_hit-0"..math.random(4)..".ogg")
+end
+
+function SWEP:PlayHitFleshSound()
+ self:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav")
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_barricadekit/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_barricadekit/cl_init.lua
new file mode 100644
index 0000000..a1d662f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_barricadekit/cl_init.lua
@@ -0,0 +1,52 @@
+include("shared.lua")
+
+SWEP.PrintName = "'Aegis' Barricade Kit"
+SWEP.Description = "A ready-to-go, all-in-one board deployer.\nIt automatically deploys the board and then firmly attaches it to almost any surface.\nUse PRIMARY FIRE to deploy boards.\nUse SECONADRY FIRE and RELOAD to rotate the board.\nA ghost of the board shows you if placement is valid or not."
+SWEP.DrawCrosshair = false
+SWEP.ViewModelFOV = 70
+SWEP.ViewModelFlip = false
+
+SWEP.Slot = 4
+ SWEP.SlotPos = 0
+
+
+function SWEP:DrawHUD()
+ if GetConVarNumber("crosshair") ~= 1 then return end
+ self:DrawCrosshairDot()
+end
+
+function SWEP:Deploy()
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ return true
+end
+
+function SWEP:GetViewModelPosition(pos, ang)
+ return pos, ang
+end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
+
+function SWEP:PrimaryAttack()
+end
+
+function SWEP:Think()
+ if self.Owner:KeyDown(IN_ATTACK2) then
+ self:RotateGhost(FrameTime() * 60)
+ end
+ if self.Owner:KeyDown(IN_RELOAD) then
+ self:RotateGhost(FrameTime() * -60)
+ end
+end
+
+local nextclick = 0
+local kityaw = CreateClientConVar("zs_barricadekityaw", 90, false, true)
+function SWEP:RotateGhost(amount)
+ if nextclick <= RealTime() then
+ surface.PlaySound("npc/headcrab_poison/ph_step4.wav")
+ nextclick = RealTime() + 0.3
+ end
+ RunConsoleCommand("zs_barricadekityaw", math.NormalizeAngle(kityaw:GetFloat() + amount))
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_barricadekit/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_barricadekit/init.lua
new file mode 100644
index 0000000..b2387cf
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_barricadekit/init.lua
@@ -0,0 +1,80 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ self:SpawnGhost()
+
+ return true
+end
+
+function SWEP:OnRemove()
+ self:RemoveGhost()
+end
+
+function SWEP:Holster()
+ self:RemoveGhost()
+ return true
+end
+
+function SWEP:SpawnGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:GiveStatus("ghost_barricadekit")
+ end
+end
+
+function SWEP:RemoveGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:RemoveStatus("ghost_barricadekit", false, true)
+ end
+end
+
+function SWEP:Think()
+ if self.IdleAnimation and self.IdleAnimation <= CurTime() then
+ self.IdleAnimation = nil
+ self:SendWeaponAnim(ACT_VM_IDLE)
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+
+ local owner = self.Owner
+
+ local status = owner.status_ghost_barricadekit
+ if not (status and status:IsValid()) then return end
+ status:RecalculateValidity()
+ if not status:GetValidPlacement() then return end
+
+ local pos, ang = status:RecalculateValidity()
+ if not pos or not ang then return end
+
+ self:SetNextPrimaryAttack(CurTime() + self.Primary.Delay)
+
+ local ent = ents.Create("prop_aegisboard")
+ if ent:IsValid() then
+ ent:SetPos(pos)
+ ent:SetAngles(ang)
+ ent:Spawn()
+
+ ent:EmitSound("npc/dog/dog_servo12.wav")
+
+ ent:GhostAllPlayersInMe(5)
+
+ ent:SetObjectOwner(owner)
+
+ local stored = owner:PopPackedItem(ent:GetClass())
+ if stored then
+ ent:SetObjectHealth(stored[1])
+ end
+
+ self:TakePrimaryAmmo(1)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_barricadekit/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_barricadekit/shared.lua
new file mode 100644
index 0000000..4cb9099
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_barricadekit/shared.lua
@@ -0,0 +1,47 @@
+SWEP.ViewModel = "models/weapons/c_rpg.mdl"
+SWEP.WorldModel = "models/weapons/w_rocket_launcher.mdl"
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "SniperRound"
+SWEP.Primary.Delay = 1.25
+SWEP.Primary.DefaultClip = 5
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.UseHands = true
+
+if CLIENT then
+ SWEP.ViewModelFOV = 60
+end
+
+SWEP.WalkSpeed = SPEED_SLOWEST
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType("rpg")
+ self:SetDeploySpeed(1.1)
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:EmitSound("Weapon_Shotgun.Empty")
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ return false
+ end
+
+ return true
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+end
+
+util.PrecacheModel("models/props_debris/wood_board05a.mdl")
+util.PrecacheSound("npc/dog/dog_servo12.wav")
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_base/animations.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_base/animations.lua
new file mode 100644
index 0000000..11b7734
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_base/animations.lua
@@ -0,0 +1,520 @@
+--[[*******************************************************
+ SWEP Construction Kit base code
+ Created by Clavus
+ Available for public use, thread at:
+ facepunch.com/threads/1032378
+
+
+ DESCRIPTION:
+ This script is meant for experienced scripters
+ that KNOW WHAT THEY ARE DOING. Don't come to me
+ with basic Lua questions.
+
+ Just copy into your SWEP or SWEP base of choice
+ and merge with your own code.
+
+ The SWEP.VElements, SWEP.WElements and
+ SWEP.ViewModelBoneMods tables are all optional
+ and only have to be visible to the client.
+********************************************************]]
+
+function SWEP:Anim_Initialize()
+
+ // other initialize code goes here
+
+ if CLIENT then
+
+ // Create a new table for every weapon instance
+ self.VElements = table.FullCopy( self.VElements )
+ self.WElements = table.FullCopy( self.WElements )
+ self.ViewModelBoneMods = table.FullCopy( self.ViewModelBoneMods )
+
+ self:CreateModels(self.VElements) // create viewmodels
+ self:CreateModels(self.WElements) // create worldmodels
+
+ // init view model bone build function
+ if IsValid(self.Owner) then
+ local vm = self.Owner:GetViewModel()
+ if IsValid(vm) then
+ self:ResetBonePositions(vm)
+
+ // Init viewmodel visibility
+ --[[if (self.ShowViewModel == nil or self.ShowViewModel) then
+ vm:SetColor(Color(255,255,255,255))
+ else
+ // we set the alpha to 1 instead of 0 because else ViewModelDrawn stops being called
+ vm:SetColor(Color(255,255,255,1))
+ // ^ stopped working in GMod 13 because you have to do Entity:SetRenderMode(1) for translucency to kick in
+ // however for some reason the view model resets to render mode 0 every frame so we just apply a debug material to prevent it from drawing
+ vm:SetMaterial("Debug/hsv")
+ end]]
+ end
+ end
+
+ end
+
+end
+
+function SWEP:Anim_Holster()
+
+ if CLIENT and IsValid(self.Owner) then
+ local vm = self.Owner:GetViewModel()
+ if IsValid(vm) then
+ self:ResetBonePositions(vm)
+ end
+ end
+
+ return true
+end
+
+function SWEP:Anim_OnRemove()
+ self:Anim_Holster()
+end
+
+if CLIENT then
+
+ SWEP.vRenderOrder = nil
+ function SWEP:Anim_ViewModelDrawn()
+
+ local vm = self.Owner:GetViewModel()
+ if !IsValid(vm) then return end
+
+ if (!self.VElements) then return end
+
+ self:UpdateBonePositions(vm)
+
+ if (!self.vRenderOrder) then
+
+ // we build a render order because sprites need to be drawn after models
+ self.vRenderOrder = {}
+
+ for k, v in pairs( self.VElements ) do
+ if (v.type == "Model") then
+ table.insert(self.vRenderOrder, 1, k)
+ elseif (v.type == "Sprite" or v.type == "Quad") then
+ table.insert(self.vRenderOrder, k)
+ end
+ end
+
+ end
+
+ for k, name in ipairs( self.vRenderOrder ) do
+
+ local v = self.VElements[name]
+ if (!v) then self.vRenderOrder = nil break end
+ if (v.hide) then continue end
+
+ local model = v.modelEnt
+ local sprite = v.spriteMaterial
+
+ if (!v.bone) then continue end
+
+ local pos, ang = self:GetBoneOrientation( self.VElements, v, vm )
+
+ if (!pos) then continue end
+
+ if (v.type == "Model" and IsValid(model)) then
+
+ model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ model:SetAngles(ang)
+ //model:SetModelScale(v.size)
+ local matrix = Matrix()
+ matrix:Scale(v.size)
+ model:EnableMatrix( "RenderMultiply", matrix )
+
+ if (v.material == "") then
+ model:SetMaterial("")
+ elseif (model:GetMaterial() != v.material) then
+ model:SetMaterial( v.material )
+ end
+
+ if (v.skin and v.skin != model:GetSkin()) then
+ model:SetSkin(v.skin)
+ end
+
+ if (v.bodygroup) then
+ for k, v in pairs( v.bodygroup ) do
+ if (model:GetBodygroup(k) != v) then
+ model:SetBodygroup(k, v)
+ end
+ end
+ end
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(true)
+ end
+
+ render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
+ render.SetBlend(v.color.a/255)
+ model:DrawModel()
+ render.SetBlend(1)
+ render.SetColorModulation(1, 1, 1)
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(false)
+ end
+
+ elseif (v.type == "Sprite" and sprite) then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ render.SetMaterial(sprite)
+ render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
+
+ elseif (v.type == "Quad" and v.draw_func) then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ cam.Start3D2D(drawpos, ang, v.size)
+ v.draw_func( self )
+ cam.End3D2D()
+
+ end
+
+ end
+
+ end
+
+ SWEP.wRenderOrder = nil
+ function SWEP:Anim_DrawWorldModel()
+
+ if (self.ShowWorldModel == nil or self.ShowWorldModel) then
+ self:DrawModel()
+ end
+
+ if (!self.WElements) then return end
+
+ if (!self.wRenderOrder) then
+
+ self.wRenderOrder = {}
+
+ for k, v in pairs( self.WElements ) do
+ if (v.type == "Model") then
+ table.insert(self.wRenderOrder, 1, k)
+ elseif (v.type == "Sprite" or v.type == "Quad") then
+ table.insert(self.wRenderOrder, k)
+ end
+ end
+
+ end
+
+ if (IsValid(self.Owner)) then
+ bone_ent = self.Owner
+ else
+ // when the weapon is dropped
+ bone_ent = self
+ end
+
+ for k, name in pairs( self.wRenderOrder ) do
+
+ local v = self.WElements[name]
+ if (!v) then self.wRenderOrder = nil break end
+ if (v.hide) then continue end
+
+ local pos, ang
+
+ if (v.bone) then
+ pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent )
+ else
+ pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent, "ValveBiped.Bip01_R_Hand" )
+ end
+
+ if (!pos) then continue end
+
+ local model = v.modelEnt
+ local sprite = v.spriteMaterial
+
+ if (v.type == "Model" and IsValid(model)) then
+
+ model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ model:SetAngles(ang)
+ //model:SetModelScale(v.size)
+ local matrix = Matrix()
+ matrix:Scale(v.size)
+ model:EnableMatrix( "RenderMultiply", matrix )
+
+ if (v.material == "") then
+ model:SetMaterial("")
+ elseif (model:GetMaterial() != v.material) then
+ model:SetMaterial( v.material )
+ end
+
+ if (v.skin and v.skin != model:GetSkin()) then
+ model:SetSkin(v.skin)
+ end
+
+ if (v.bodygroup) then
+ for k, v in pairs( v.bodygroup ) do
+ if (model:GetBodygroup(k) != v) then
+ model:SetBodygroup(k, v)
+ end
+ end
+ end
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(true)
+ end
+
+ render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
+ render.SetBlend(v.color.a/255)
+ model:DrawModel()
+ render.SetBlend(1)
+ render.SetColorModulation(1, 1, 1)
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(false)
+ end
+
+ elseif (v.type == "Sprite" and sprite) then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ render.SetMaterial(sprite)
+ render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
+
+ elseif (v.type == "Quad" and v.draw_func) then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ cam.Start3D2D(drawpos, ang, v.size)
+ v.draw_func( self )
+ cam.End3D2D()
+
+ end
+
+ end
+
+ end
+
+ function SWEP:GetBoneOrientation( basetab, tab, ent, bone_override )
+
+ local bone, pos, ang
+ if (tab.rel and tab.rel != "") then
+
+ local v = basetab[tab.rel]
+
+ if (!v) then return end
+
+ // Technically, if there exists an element with the same name as a bone
+ // you can get in an infinite loop. Let's just hope nobody's that stupid.
+ pos, ang = self:GetBoneOrientation( basetab, v, ent )
+
+ if (!pos) then return end
+
+ pos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ else
+
+ bone = ent:LookupBone(bone_override or tab.bone)
+
+ if (!bone) then return end
+
+ pos, ang = Vector(0,0,0), Angle(0,0,0)
+ local m = ent:GetBoneMatrix(bone)
+ if (m) then
+ pos, ang = m:GetTranslation(), m:GetAngles()
+ end
+
+ if (IsValid(self.Owner) and self.Owner:IsPlayer() and
+ ent == self.Owner:GetViewModel() and self.ViewModelFlip) then
+ ang.r = -ang.r // Fixes mirrored models
+ end
+
+ end
+
+ return pos, ang
+ end
+
+ function SWEP:CreateModels( tab )
+
+ if (!tab) then return end
+
+ // Create the clientside models here because Garry says we can't do it in the render hook
+ for k, v in pairs( tab ) do
+ if (v.type == "Model" and v.model and v.model != "" and (!IsValid(v.modelEnt) or v.createdModel != v.model) and
+ string.find(v.model, ".mdl") and file.Exists (v.model, "GAME") ) then
+
+ v.modelEnt = ClientsideModel(v.model, RENDER_GROUP_VIEW_MODEL_OPAQUE)
+ if (IsValid(v.modelEnt)) then
+ v.modelEnt:SetPos(self:GetPos())
+ v.modelEnt:SetAngles(self:GetAngles())
+ v.modelEnt:SetParent(self)
+ v.modelEnt:SetNoDraw(true)
+ v.createdModel = v.model
+ else
+ v.modelEnt = nil
+ end
+
+ elseif (v.type == "Sprite" and v.sprite and v.sprite != "" and (!v.spriteMaterial or v.createdSprite != v.sprite)
+ and file.Exists ("materials/"..v.sprite..".vmt", "GAME")) then
+
+ local name = v.sprite.."-"
+ local params = { ["$basetexture"] = v.sprite }
+ // make sure we create a unique name based on the selected options
+ local tocheck = { "nocull", "additive", "vertexalpha", "vertexcolor", "ignorez" }
+ for i, j in pairs( tocheck ) do
+ if (v[j]) then
+ params["$"..j] = 1
+ name = name.."1"
+ else
+ name = name.."0"
+ end
+ end
+
+ v.createdSprite = v.sprite
+ v.spriteMaterial = CreateMaterial(name,"UnlitGeneric",params)
+
+ end
+ end
+
+ end
+
+ local allbones
+ local hasGarryFixedBoneScalingYet = false
+
+ function SWEP:UpdateBonePositions(vm)
+
+ if self.ViewModelBoneMods then
+
+ if (!vm:GetBoneCount()) then return end
+
+ // !! WORKAROUND !! //
+ // We need to check all model names :/
+ local loopthrough = self.ViewModelBoneMods
+ if (!hasGarryFixedBoneScalingYet) then
+ allbones = {}
+ for i=0, vm:GetBoneCount() do
+ local bonename = vm:GetBoneName(i)
+ if (self.ViewModelBoneMods[bonename]) then
+ allbones[bonename] = self.ViewModelBoneMods[bonename]
+ else
+ allbones[bonename] = {
+ scale = Vector(1,1,1),
+ pos = Vector(0,0,0),
+ angle = Angle(0,0,0)
+ }
+ end
+ end
+
+ loopthrough = allbones
+ end
+ // !! ----------- !! //
+
+ for k, v in pairs( loopthrough ) do
+ local bone = vm:LookupBone(k)
+ if (!bone) then continue end
+
+ // !! WORKAROUND !! //
+ local s = Vector(v.scale.x,v.scale.y,v.scale.z)
+ local p = Vector(v.pos.x,v.pos.y,v.pos.z)
+ local ms = Vector(1,1,1)
+ if (!hasGarryFixedBoneScalingYet) then
+ local cur = vm:GetBoneParent(bone)
+ while(cur >= 0) do
+ local pscale = loopthrough[vm:GetBoneName(cur)].scale
+ ms = ms * pscale
+ cur = vm:GetBoneParent(cur)
+ end
+ end
+
+ s = s * ms
+ // !! ----------- !! //
+
+ if vm:GetManipulateBoneScale(bone) != s then
+ vm:ManipulateBoneScale( bone, s )
+ end
+ if vm:GetManipulateBoneAngles(bone) != v.angle then
+ vm:ManipulateBoneAngles( bone, v.angle )
+ end
+ if vm:GetManipulateBonePosition(bone) != p then
+ vm:ManipulateBonePosition( bone, p )
+ end
+ end
+ else
+ self:ResetBonePositions(vm)
+ end
+
+ end
+
+ function SWEP:ResetBonePositions(vm)
+ -- New code
+ vm:SetColor(color_white)
+ vm:SetMaterial("")
+ --------
+
+ if (!vm:GetBoneCount()) then return end
+ for i=0, vm:GetBoneCount() do
+ vm:ManipulateBoneScale( i, Vector(1, 1, 1) )
+ vm:ManipulateBoneAngles( i, Angle(0, 0, 0) )
+ vm:ManipulateBonePosition( i, Vector(0, 0, 0) )
+ end
+
+ end
+
+ /**************************
+ Global utility code
+ **************************/
+
+ // Fully copies the table, meaning all tables inside this table are copied too and so on (normal table.Copy copies only their reference).
+ // Does not copy entities of course, only copies their reference.
+ // WARNING: do not use on tables that contain themselves somewhere down the line or you'll get an infinite loop
+ function table.FullCopy( tab )
+
+ if (!tab) then return nil end
+
+ local res = {}
+ for k, v in pairs( tab ) do
+ if (type(v) == "table") then
+ res[k] = table.FullCopy(v) // recursion ho!
+ elseif (type(v) == "Vector") then
+ res[k] = Vector(v.x, v.y, v.z)
+ elseif (type(v) == "Angle") then
+ res[k] = Angle(v.p, v.y, v.r)
+ else
+ res[k] = v
+ end
+ end
+
+ return res
+
+ end
+
+end
+
+----------------
+-- Extra code --
+----------------
+
+function SWEP:RemoveModels()
+ if (self.VElements) then
+ for k, v in pairs( self.VElements ) do
+ if (IsValid( v.modelEnt )) then
+ v.modelEnt:Remove()
+ v.modelEnt = nil
+ end
+ end
+ end
+ if (self.WElements) then
+ for k, v in pairs( self.WElements ) do
+ if (IsValid( v.modelEnt )) then
+ v.modelEnt:Remove()
+ v.modelEnt = nil
+ end
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_base/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_base/cl_init.lua
new file mode 100644
index 0000000..cfc4299
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_base/cl_init.lua
@@ -0,0 +1,271 @@
+include("shared.lua")
+include("animations.lua")
+
+SWEP.DrawAmmo = true
+SWEP.DrawCrosshair = false
+SWEP.ViewModelFOV = 60
+SWEP.ViewModelFlip = true
+SWEP.BobScale = 1
+SWEP.SwayScale = 1
+SWEP.Slot = 0
+
+SWEP.IronsightsMultiplier = 0.6
+
+SWEP.HUD3DScale = 0.01
+SWEP.HUD3DBone = "base"
+SWEP.HUD3DAng = Angle(180, 0, 0)
+
+function SWEP:Deploy()
+ return true
+end
+
+function SWEP:TranslateFOV(fov)
+ return GAMEMODE.FOVLerp * fov
+end
+
+function SWEP:AdjustMouseSensitivity()
+ if self:GetIronsights() then return GAMEMODE.FOVLerp end
+end
+
+function SWEP:PreDrawViewModel(vm)
+ if self.ShowViewModel == false then
+ render.SetBlend(0)
+ end
+end
+
+function SWEP:PostDrawViewModel(vm)
+ if self.ShowViewModel == false then
+ render.SetBlend(1)
+ end
+
+ if not self.HUD3DPos or GAMEMODE.WeaponHUDMode == 1 then return end
+
+ local pos, ang = self:GetHUD3DPos(vm)
+ if pos then
+ self:Draw3DHUD(vm, pos, ang)
+ end
+end
+
+function SWEP:GetHUD3DPos(vm)
+ local bone = vm:LookupBone(self.HUD3DBone)
+ if not bone then return end
+
+ local m = vm:GetBoneMatrix(bone)
+ if not m then return end
+
+ local pos, ang = m:GetTranslation(), m:GetAngles()
+
+ if self.ViewModelFlip then
+ ang.r = -ang.r
+ end
+
+ local offset = self.HUD3DPos
+ local aoffset = self.HUD3DAng
+
+ pos = pos + ang:Forward() * offset.x + ang:Right() * offset.y + ang:Up() * offset.z
+
+ if aoffset.yaw ~= 0 then ang:RotateAroundAxis(ang:Up(), aoffset.yaw) end
+ if aoffset.pitch ~= 0 then ang:RotateAroundAxis(ang:Right(), aoffset.pitch) end
+ if aoffset.roll ~= 0 then ang:RotateAroundAxis(ang:Forward(), aoffset.roll) end
+
+ return pos, ang
+end
+
+local colBG = Color(16, 16, 16, 90)
+local colRed = Color(220, 0, 0, 230)
+local colYellow = Color(220, 220, 0, 230)
+local colWhite = Color(220, 220, 220, 230)
+local colAmmo = Color(255, 255, 255, 230)
+local function GetAmmoColor(clip, maxclip)
+ if clip == 0 then
+ colAmmo.r = 255 colAmmo.g = 0 colAmmo.b = 0
+ else
+ local sat = clip / maxclip
+ colAmmo.r = 255
+ colAmmo.g = sat ^ 0.3 * 255
+ colAmmo.b = sat * 255
+ end
+end
+
+function SWEP:Draw3DHUD(vm, pos, ang)
+ local wid, hei = 180, 200
+ local x, y = wid * -0.6, hei * -0.5
+ local clip = self:Clip1()
+ local spare = self.Owner:GetAmmoCount(self:GetPrimaryAmmoType())
+ local maxclip = self.Primary.ClipSize
+
+ if self.RequiredClip ~= 1 then
+ clip = math.floor(clip / self.RequiredClip)
+ spare = math.floor(spare / self.RequiredClip)
+ maxclip = math.ceil(maxclip / self.RequiredClip)
+ end
+
+ cam.Start3D2D(pos, ang, self.HUD3DScale / 2)
+ draw.RoundedBoxEx(32, x, y, wid, hei, colBG, true, false, true, false)
+
+ local displayspare = maxclip > 0 and self.Primary.DefaultClip ~= 99999
+ if displayspare then
+ draw.SimpleTextBlurry(spare, spare >= 1000 and "ZS3D2DFontSmall" or "ZS3D2DFont", x + wid * 0.5, y + hei * 0.75, spare == 0 and colRed or spare <= maxclip and colYellow or colWhite, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+ end
+
+ GetAmmoColor(clip, maxclip)
+ draw.SimpleTextBlurry(clip, clip >= 100 and "ZS3D2DFont" or "ZS3D2DFontBig", x + wid * 0.5, y + hei * (displayspare and 0.3 or 0.5), colAmmo, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+ cam.End3D2D()
+end
+
+function SWEP:Draw2DHUD()
+ local screenscale = BetterScreenScale()
+
+ local wid, hei = 180 * screenscale, 64 * screenscale
+ local x, y = ScrW() - wid - screenscale * 128, ScrH() - hei - screenscale * 72
+ local clip = self:Clip1()
+ local spare = self.Owner:GetAmmoCount(self:GetPrimaryAmmoType())
+ local maxclip = self.Primary.ClipSize
+
+ if self.RequiredClip ~= 1 then
+ clip = math.floor(clip / self.RequiredClip)
+ spare = math.floor(spare / self.RequiredClip)
+ maxclip = math.ceil(maxclip / self.RequiredClip)
+ end
+
+ draw.RoundedBox(16, x, y, wid, hei, colBG)
+
+ local displayspare = maxclip > 0 and self.Primary.DefaultClip ~= 99999
+ if displayspare then
+ draw.SimpleTextBlurry(spare, spare >= 1000 and "ZSHUDFontSmall" or "ZSHUDFont", x + wid * 0.75, y + hei * 0.5, spare == 0 and colRed or spare <= maxclip and colYellow or colWhite, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+ end
+
+ GetAmmoColor(clip, maxclip)
+ draw.SimpleTextBlurry(clip, clip >= 100 and "ZSHUDFont" or "ZSHUDFontBig", x + wid * (displayspare and 0.25 or 0.5), y + hei * 0.5, colAmmo, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+end
+
+function SWEP:Think()
+ if self:GetIronsights() and not self.Owner:KeyDown(IN_ATTACK2) then
+ self:SetIronsights(false)
+ end
+end
+
+function SWEP:GetIronsightsDeltaMultiplier()
+ local bIron = self:GetIronsights()
+ local fIronTime = self.fIronTime or 0
+
+ if not bIron and fIronTime < CurTime() - 0.25 then
+ return 0
+ end
+
+ local Mul = 1
+
+ if fIronTime > CurTime() - 0.25 then
+ Mul = math.Clamp((CurTime() - fIronTime) * 4, 0, 1)
+ if not bIron then Mul = 1 - Mul end
+ end
+
+ return Mul
+end
+
+local ghostlerp = 0
+function SWEP:CalcViewModelView(vm, oldpos, oldang, pos, ang)
+ local bIron = self:GetIronsights()
+
+ if bIron ~= self.bLastIron then
+ self.bLastIron = bIron
+ self.fIronTime = CurTime()
+
+ if bIron then
+ self.SwayScale = 0.3
+ self.BobScale = 0.1
+ else
+ self.SwayScale = 2.0
+ self.BobScale = 1.5
+ end
+ end
+
+ local Mul = math.Clamp((CurTime() - (self.fIronTime or 0)) * 4, 0, 1)
+ if not bIron then Mul = 1 - Mul end
+
+ if Mul > 0 then
+ local Offset = self.IronSightsPos
+ if self.IronSightsAng then
+ ang = Angle(ang.p, ang.y, ang.r)
+ ang:RotateAroundAxis(ang:Right(), self.IronSightsAng.x * Mul)
+ ang:RotateAroundAxis(ang:Up(), self.IronSightsAng.y * Mul)
+ ang:RotateAroundAxis(ang:Forward(), self.IronSightsAng.z * Mul)
+ end
+
+ pos = pos + Offset.x * Mul * ang:Right() + Offset.y * Mul * ang:Forward() + Offset.z * Mul * ang:Up()
+ end
+
+ if self.Owner:GetBarricadeGhosting() then
+ ghostlerp = math.min(1, ghostlerp + FrameTime() * 4)
+ elseif ghostlerp > 0 then
+ ghostlerp = math.max(0, ghostlerp - FrameTime() * 5)
+ end
+
+ if ghostlerp > 0 then
+ pos = pos + 3.5 * ghostlerp * ang:Up()
+ ang:RotateAroundAxis(ang:Right(), -30 * ghostlerp)
+ end
+
+ return pos, ang
+end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
+
+function SWEP:DrawHUD()
+ self:DrawCrosshair()
+
+ if GAMEMODE.WeaponHUDMode >= 1 then
+ self:Draw2DHUD()
+ end
+end
+
+local OverrideIronSights = {}
+function SWEP:CheckCustomIronSights()
+ local class = self:GetClass()
+ if OverrideIronSights[class] then
+ if type(OverrideIronSights[class]) == "table" then
+ self.IronSightsPos = OverrideIronSights[class].Pos
+ self.IronSightsAng = OverrideIronSights[class].Ang
+ end
+
+ return
+ end
+
+ local filename = "ironsights/"..class..".txt"
+ if file.Exists(filename, "MOD") then
+ local pos = Vector(0, 0, 0)
+ local ang = Vector(0, 0, 0)
+
+ local tab = string.Explode(" ", file.Read(filename, "MOD"))
+ pos.x = tonumber(tab[1]) or 0
+ pos.y = tonumber(tab[2]) or 0
+ pos.z = tonumber(tab[3]) or 0
+ ang.x = tonumber(tab[4]) or 0
+ ang.y = tonumber(tab[5]) or 0
+ ang.z = tonumber(tab[6]) or 0
+
+ OverrideIronSights[class] = {Pos = pos, Ang = ang}
+
+ self.IronSightsPos = pos
+ self.IronSightsAng = ang
+ else
+ OverrideIronSights[class] = true
+ end
+end
+
+function SWEP:OnRemove()
+ self:Anim_OnRemove()
+end
+
+function SWEP:ViewModelDrawn()
+ self:Anim_ViewModelDrawn()
+end
+
+function SWEP:DrawWorldModel()
+ local owner = self:GetOwner()
+ if owner:IsValid() and owner.ShadowMan then return end
+
+ self:Anim_DrawWorldModel()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_base/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_base/init.lua
new file mode 100644
index 0000000..ea3565c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_base/init.lua
@@ -0,0 +1,15 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+AddCSLuaFile("animations.lua")
+
+include("shared.lua")
+
+function SWEP:Think()
+ if self.IdleAnimation and self.IdleAnimation <= CurTime() then
+ self.IdleAnimation = nil
+ self:SendWeaponAnim(ACT_VM_IDLE)
+ end
+ if self:GetIronsights() and not self.Owner:KeyDown(IN_ATTACK2) then
+ self:SetIronsights(false)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_base/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_base/shared.lua
new file mode 100644
index 0000000..e3d3e1b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_base/shared.lua
@@ -0,0 +1,308 @@
+SWEP.Primary.Sound = Sound("Weapon_Pistol.Single")
+SWEP.Primary.Damage = 30
+SWEP.Primary.KnockbackScale = 1
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.15
+
+SWEP.ConeMax = 0.03
+SWEP.ConeMin = 0.01
+SWEP.ConeRamp = 2
+
+SWEP.CSMuzzleFlashes = true
+
+SWEP.Primary.ClipSize = 8
+SWEP.Primary.DefaultClip = 0
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "pistol"
+SWEP.RequiredClip = 1
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_NORMAL
+
+SWEP.HoldType = "pistol"
+SWEP.IronSightsHoldType = "ar2"
+
+SWEP.IronSightsPos = Vector(0, 0, 0)
+
+SWEP.EmptyWhenPurchased = true
+
+function SWEP:Initialize()
+ if not self:IsValid() then return end --???
+
+ self:SetWeaponHoldType(self.HoldType)
+ self:SetDeploySpeed(1.1)
+
+ -- Maybe we didn't want to convert the weapon to the new system...
+ if self.Cone then
+ self.ConeMin = self.ConeIronCrouching
+ self.ConeMax = self.ConeMoving
+ self.ConeRamp = 2
+ end
+
+ if CLIENT then
+ self:CheckCustomIronSights()
+ self:Anim_Initialize()
+ end
+end
+
+function SWEP:GetCone()
+ if not self.Owner:OnGround() or self.ConeMax == self.ConeMin then return self.ConeMax end
+
+ local basecone = self.ConeMin
+ local conedelta = self.ConeMax - basecone
+
+ local multiplier = math.min(self.Owner:GetVelocity():Length() / self.WalkSpeed, 1) * 0.5
+ if not self.Owner:Crouching() then multiplier = multiplier + 0.25 end
+ if not self:GetIronsights() then multiplier = multiplier + 0.25 end
+
+ return basecone + conedelta * multiplier ^ self.ConeRamp
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+
+ self:EmitFireSound()
+ self:TakeAmmo()
+ self:ShootBullets(self.Primary.Damage, self.Primary.NumShots, self:GetCone())
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+end
+
+function SWEP:GetWalkSpeed()
+ if self:GetIronsights() then
+ return math.min(self.WalkSpeed, math.max(90, self.WalkSpeed * 0.5))
+ end
+
+ return self.WalkSpeed
+end
+
+function SWEP:EmitFireSound()
+ self:EmitSound(self.Primary.Sound)
+end
+
+function SWEP:SetIronsights(b)
+ self:SetDTBool(0, b)
+
+ if self.IronSightsHoldType then
+ if b then
+ self:SetWeaponHoldType(self.IronSightsHoldType)
+ else
+ self:SetWeaponHoldType(self.HoldType)
+ end
+ end
+
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+end
+
+function SWEP:Deploy()
+ self:SetNextReload(0)
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+ self:SetIronsights(false)
+
+ if self.PreHolsterClip1 then
+ local diff = self:Clip1() - self.PreHolsterClip1
+ self:SetClip1(self.PreHolsterClip1)
+ if SERVER then
+ self.Owner:GiveAmmo(diff, self.Primary.Ammo, true)
+ end
+ self.PreHolsterClip1 = nil
+ end
+ if self.PreHolsterClip2 then
+ local diff = self:Clip2() - self.PreHolsterClip2
+ self:SetClip2(self.PreHolsterClip2)
+ if SERVER then
+ self.Owner:GiveAmmo(diff, self.Secondary.Ammo, true)
+ end
+ self.PreHolsterClip2 = nil
+ end
+
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ if CLIENT then
+ self:CheckCustomIronSights()
+ end
+
+ return true
+end
+
+function SWEP:Holster()
+ if self:ValidPrimaryAmmo() then
+ self.PreHolsterClip1 = self:Clip1()
+ end
+ if self:ValidSecondaryAmmo() then
+ self.PreHolsterClip2 = self:Clip2()
+ end
+
+ if CLIENT then
+ self:Anim_Holster()
+ end
+
+ return true
+end
+
+function SWEP:TakeAmmo()
+ self:TakePrimaryAmmo(self.RequiredClip)
+end
+
+function SWEP:Reload()
+ if self.Owner:IsHolding() then return end
+
+ if self:GetIronsights() then
+ self:SetIronsights(false)
+ end
+
+ if self:GetNextReload() <= CurTime() and self:DefaultReload(ACT_VM_RELOAD) then
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+ self:SetNextReload(self.IdleAnimation)
+ self.Owner:DoReloadEvent()
+ if self.ReloadSound then
+ self:EmitSound(self.ReloadSound)
+ end
+ end
+end
+
+function SWEP:GetIronsights()
+ return self:GetDTBool(0)
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:Clip1() < self.RequiredClip then
+ self:EmitSound("Weapon_Pistol.Empty")
+ self:SetNextPrimaryFire(CurTime() + math.max(0.25, self.Primary.Delay))
+ return false
+ end
+
+ return self:GetNextPrimaryFire() <= CurTime()
+end
+
+function SWEP:SecondaryAttack()
+ if self:GetNextSecondaryFire() <= CurTime() and not self.Owner:IsHolding() then
+ self:SetIronsights(true)
+ end
+end
+
+function SWEP:OnRestore()
+ self:SetIronsights(false)
+end
+
+local tempknockback
+function SWEP:StartBulletKnockback()
+ tempknockback = {}
+end
+
+function SWEP:EndBulletKnockback()
+ tempknockback = nil
+end
+
+function SWEP:DoBulletKnockback(scale)
+ for ent, prevvel in pairs(tempknockback) do
+ local curvel = ent:GetVelocity()
+ ent:SetVelocity(curvel * -1 + (curvel - prevvel) * scale + prevvel)
+ end
+end
+
+function GenericBulletCallback(attacker, tr, dmginfo)
+ local ent = tr.Entity
+ if ent:IsValid() then
+ if ent:IsPlayer() then
+ if ent:Team() == TEAM_UNDEAD and tempknockback then
+ tempknockback[ent] = ent:GetVelocity()
+ end
+ else
+ local phys = ent:GetPhysicsObject()
+ if ent:GetMoveType() == MOVETYPE_VPHYSICS and phys:IsValid() and phys:IsMoveable() then
+ ent:SetPhysicsAttacker(attacker)
+ end
+ end
+ end
+end
+
+function SWEP:SendWeaponAnimation()
+ self:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
+end
+
+SWEP.BulletCallback = GenericBulletCallback
+function SWEP:ShootBullets(dmg, numbul, cone)
+ local owner = self.Owner
+ --owner:MuzzleFlash()
+ self:SendWeaponAnimation()
+ owner:DoAttackEvent()
+
+ self:StartBulletKnockback()
+ owner:FireBullets({Num = numbul, Src = owner:GetShootPos(), Dir = owner:GetAimVector(), Spread = Vector(cone, cone, 0), Tracer = 1, TracerName = self.TracerName, Force = dmg * 0.1, Damage = dmg, Callback = self.BulletCallback})
+ self:DoBulletKnockback(self.Primary.KnockbackScale * 0.05)
+ self:EndBulletKnockback()
+end
+
+local ActIndex = {
+ [ "pistol" ] = ACT_HL2MP_IDLE_PISTOL,
+ [ "smg" ] = ACT_HL2MP_IDLE_SMG1,
+ [ "grenade" ] = ACT_HL2MP_IDLE_GRENADE,
+ [ "ar2" ] = ACT_HL2MP_IDLE_AR2,
+ [ "shotgun" ] = ACT_HL2MP_IDLE_SHOTGUN,
+ [ "rpg" ] = ACT_HL2MP_IDLE_RPG,
+ [ "physgun" ] = ACT_HL2MP_IDLE_PHYSGUN,
+ [ "crossbow" ] = ACT_HL2MP_IDLE_CROSSBOW,
+ [ "melee" ] = ACT_HL2MP_IDLE_MELEE,
+ [ "slam" ] = ACT_HL2MP_IDLE_SLAM,
+ [ "normal" ] = ACT_HL2MP_IDLE,
+ [ "fist" ] = ACT_HL2MP_IDLE_FIST,
+ [ "melee2" ] = ACT_HL2MP_IDLE_MELEE2,
+ [ "passive" ] = ACT_HL2MP_IDLE_PASSIVE,
+ [ "knife" ] = ACT_HL2MP_IDLE_KNIFE,
+ [ "duel" ] = ACT_HL2MP_IDLE_DUEL,
+ [ "revolver" ] = ACT_HL2MP_IDLE_REVOLVER
+}
+
+function SWEP:SetWeaponHoldType( t )
+
+ t = string.lower( t )
+ local index = ActIndex[ t ]
+
+ if ( index == nil ) then
+ Msg( "SWEP:SetWeaponHoldType - ActIndex[ \""..t.."\" ] isn't set! (defaulting to normal)\n" )
+ t = "normal"
+ index = ActIndex[ t ]
+ end
+
+ self.ActivityTranslate = {}
+ self.ActivityTranslate [ ACT_MP_STAND_IDLE ] = index
+ self.ActivityTranslate [ ACT_MP_WALK ] = index+1
+ self.ActivityTranslate [ ACT_MP_RUN ] = index+2
+ self.ActivityTranslate [ ACT_MP_CROUCH_IDLE ] = index+3
+ self.ActivityTranslate [ ACT_MP_CROUCHWALK ] = index+4
+ self.ActivityTranslate [ ACT_MP_ATTACK_STAND_PRIMARYFIRE ] = index+5
+ self.ActivityTranslate [ ACT_MP_ATTACK_CROUCH_PRIMARYFIRE ] = index+5
+ self.ActivityTranslate [ ACT_MP_RELOAD_STAND ] = index+6
+ self.ActivityTranslate [ ACT_MP_RELOAD_CROUCH ] = index+6
+ self.ActivityTranslate [ ACT_MP_JUMP ] = index+7
+ self.ActivityTranslate [ ACT_RANGE_ATTACK1 ] = index+8
+ self.ActivityTranslate [ ACT_MP_SWIM_IDLE ] = index+8
+ self.ActivityTranslate [ ACT_MP_SWIM ] = index+9
+
+ -- "normal" jump animation doesn't exist
+ if t == "normal" then
+ self.ActivityTranslate [ ACT_MP_JUMP ] = ACT_HL2MP_JUMP_SLAM
+ end
+
+ -- these two aren't defined in ACTs for whatever reason
+ if t == "knife" || t == "melee2" then
+ self.ActivityTranslate [ ACT_MP_CROUCH_IDLE ] = nil
+ end
+end
+
+SWEP:SetWeaponHoldType("pistol")
+
+function SWEP:TranslateActivity(act)
+ if self:GetIronsights() and self.ActivityTranslateIronSights then
+ return self.ActivityTranslateIronSights[act] or -1
+ end
+
+ return self.ActivityTranslate and self.ActivityTranslate[act] or -1
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_basefood.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_basefood.lua
new file mode 100644
index 0000000..5a59e85
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_basefood.lua
@@ -0,0 +1,30 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_basemelee"
+
+if CLIENT then
+ SWEP.PrintName = "Food"
+
+ SWEP.ViewModelFOV = 55
+ SWEP.ViewModelFlip = false
+
+ SWEP.ShowViewModel = false
+ SWEP.ShowWorldModel = false
+end
+
+SWEP.ViewModel = "models/weapons/c_stunstick.mdl"
+SWEP.WorldModel = "models/weapons/w_crowbar.mdl"
+SWEP.UseHands = true
+
+SWEP.HoldType = "slam"
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "watermelon"
+SWEP.Primary.Delay = 1
+SWEP.Primary.DefaultClip = 1
+
+SWEP.HealthValue = 15
+SWEP.EatTime = 1
+
+SWEP.AmmoIfHas = true
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_basemelee/animations.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_basemelee/animations.lua
new file mode 100644
index 0000000..11b7734
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_basemelee/animations.lua
@@ -0,0 +1,520 @@
+--[[*******************************************************
+ SWEP Construction Kit base code
+ Created by Clavus
+ Available for public use, thread at:
+ facepunch.com/threads/1032378
+
+
+ DESCRIPTION:
+ This script is meant for experienced scripters
+ that KNOW WHAT THEY ARE DOING. Don't come to me
+ with basic Lua questions.
+
+ Just copy into your SWEP or SWEP base of choice
+ and merge with your own code.
+
+ The SWEP.VElements, SWEP.WElements and
+ SWEP.ViewModelBoneMods tables are all optional
+ and only have to be visible to the client.
+********************************************************]]
+
+function SWEP:Anim_Initialize()
+
+ // other initialize code goes here
+
+ if CLIENT then
+
+ // Create a new table for every weapon instance
+ self.VElements = table.FullCopy( self.VElements )
+ self.WElements = table.FullCopy( self.WElements )
+ self.ViewModelBoneMods = table.FullCopy( self.ViewModelBoneMods )
+
+ self:CreateModels(self.VElements) // create viewmodels
+ self:CreateModels(self.WElements) // create worldmodels
+
+ // init view model bone build function
+ if IsValid(self.Owner) then
+ local vm = self.Owner:GetViewModel()
+ if IsValid(vm) then
+ self:ResetBonePositions(vm)
+
+ // Init viewmodel visibility
+ --[[if (self.ShowViewModel == nil or self.ShowViewModel) then
+ vm:SetColor(Color(255,255,255,255))
+ else
+ // we set the alpha to 1 instead of 0 because else ViewModelDrawn stops being called
+ vm:SetColor(Color(255,255,255,1))
+ // ^ stopped working in GMod 13 because you have to do Entity:SetRenderMode(1) for translucency to kick in
+ // however for some reason the view model resets to render mode 0 every frame so we just apply a debug material to prevent it from drawing
+ vm:SetMaterial("Debug/hsv")
+ end]]
+ end
+ end
+
+ end
+
+end
+
+function SWEP:Anim_Holster()
+
+ if CLIENT and IsValid(self.Owner) then
+ local vm = self.Owner:GetViewModel()
+ if IsValid(vm) then
+ self:ResetBonePositions(vm)
+ end
+ end
+
+ return true
+end
+
+function SWEP:Anim_OnRemove()
+ self:Anim_Holster()
+end
+
+if CLIENT then
+
+ SWEP.vRenderOrder = nil
+ function SWEP:Anim_ViewModelDrawn()
+
+ local vm = self.Owner:GetViewModel()
+ if !IsValid(vm) then return end
+
+ if (!self.VElements) then return end
+
+ self:UpdateBonePositions(vm)
+
+ if (!self.vRenderOrder) then
+
+ // we build a render order because sprites need to be drawn after models
+ self.vRenderOrder = {}
+
+ for k, v in pairs( self.VElements ) do
+ if (v.type == "Model") then
+ table.insert(self.vRenderOrder, 1, k)
+ elseif (v.type == "Sprite" or v.type == "Quad") then
+ table.insert(self.vRenderOrder, k)
+ end
+ end
+
+ end
+
+ for k, name in ipairs( self.vRenderOrder ) do
+
+ local v = self.VElements[name]
+ if (!v) then self.vRenderOrder = nil break end
+ if (v.hide) then continue end
+
+ local model = v.modelEnt
+ local sprite = v.spriteMaterial
+
+ if (!v.bone) then continue end
+
+ local pos, ang = self:GetBoneOrientation( self.VElements, v, vm )
+
+ if (!pos) then continue end
+
+ if (v.type == "Model" and IsValid(model)) then
+
+ model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ model:SetAngles(ang)
+ //model:SetModelScale(v.size)
+ local matrix = Matrix()
+ matrix:Scale(v.size)
+ model:EnableMatrix( "RenderMultiply", matrix )
+
+ if (v.material == "") then
+ model:SetMaterial("")
+ elseif (model:GetMaterial() != v.material) then
+ model:SetMaterial( v.material )
+ end
+
+ if (v.skin and v.skin != model:GetSkin()) then
+ model:SetSkin(v.skin)
+ end
+
+ if (v.bodygroup) then
+ for k, v in pairs( v.bodygroup ) do
+ if (model:GetBodygroup(k) != v) then
+ model:SetBodygroup(k, v)
+ end
+ end
+ end
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(true)
+ end
+
+ render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
+ render.SetBlend(v.color.a/255)
+ model:DrawModel()
+ render.SetBlend(1)
+ render.SetColorModulation(1, 1, 1)
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(false)
+ end
+
+ elseif (v.type == "Sprite" and sprite) then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ render.SetMaterial(sprite)
+ render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
+
+ elseif (v.type == "Quad" and v.draw_func) then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ cam.Start3D2D(drawpos, ang, v.size)
+ v.draw_func( self )
+ cam.End3D2D()
+
+ end
+
+ end
+
+ end
+
+ SWEP.wRenderOrder = nil
+ function SWEP:Anim_DrawWorldModel()
+
+ if (self.ShowWorldModel == nil or self.ShowWorldModel) then
+ self:DrawModel()
+ end
+
+ if (!self.WElements) then return end
+
+ if (!self.wRenderOrder) then
+
+ self.wRenderOrder = {}
+
+ for k, v in pairs( self.WElements ) do
+ if (v.type == "Model") then
+ table.insert(self.wRenderOrder, 1, k)
+ elseif (v.type == "Sprite" or v.type == "Quad") then
+ table.insert(self.wRenderOrder, k)
+ end
+ end
+
+ end
+
+ if (IsValid(self.Owner)) then
+ bone_ent = self.Owner
+ else
+ // when the weapon is dropped
+ bone_ent = self
+ end
+
+ for k, name in pairs( self.wRenderOrder ) do
+
+ local v = self.WElements[name]
+ if (!v) then self.wRenderOrder = nil break end
+ if (v.hide) then continue end
+
+ local pos, ang
+
+ if (v.bone) then
+ pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent )
+ else
+ pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent, "ValveBiped.Bip01_R_Hand" )
+ end
+
+ if (!pos) then continue end
+
+ local model = v.modelEnt
+ local sprite = v.spriteMaterial
+
+ if (v.type == "Model" and IsValid(model)) then
+
+ model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ model:SetAngles(ang)
+ //model:SetModelScale(v.size)
+ local matrix = Matrix()
+ matrix:Scale(v.size)
+ model:EnableMatrix( "RenderMultiply", matrix )
+
+ if (v.material == "") then
+ model:SetMaterial("")
+ elseif (model:GetMaterial() != v.material) then
+ model:SetMaterial( v.material )
+ end
+
+ if (v.skin and v.skin != model:GetSkin()) then
+ model:SetSkin(v.skin)
+ end
+
+ if (v.bodygroup) then
+ for k, v in pairs( v.bodygroup ) do
+ if (model:GetBodygroup(k) != v) then
+ model:SetBodygroup(k, v)
+ end
+ end
+ end
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(true)
+ end
+
+ render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
+ render.SetBlend(v.color.a/255)
+ model:DrawModel()
+ render.SetBlend(1)
+ render.SetColorModulation(1, 1, 1)
+
+ if (v.surpresslightning) then
+ render.SuppressEngineLighting(false)
+ end
+
+ elseif (v.type == "Sprite" and sprite) then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ render.SetMaterial(sprite)
+ render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
+
+ elseif (v.type == "Quad" and v.draw_func) then
+
+ local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ cam.Start3D2D(drawpos, ang, v.size)
+ v.draw_func( self )
+ cam.End3D2D()
+
+ end
+
+ end
+
+ end
+
+ function SWEP:GetBoneOrientation( basetab, tab, ent, bone_override )
+
+ local bone, pos, ang
+ if (tab.rel and tab.rel != "") then
+
+ local v = basetab[tab.rel]
+
+ if (!v) then return end
+
+ // Technically, if there exists an element with the same name as a bone
+ // you can get in an infinite loop. Let's just hope nobody's that stupid.
+ pos, ang = self:GetBoneOrientation( basetab, v, ent )
+
+ if (!pos) then return end
+
+ pos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
+ ang:RotateAroundAxis(ang:Up(), v.angle.y)
+ ang:RotateAroundAxis(ang:Right(), v.angle.p)
+ ang:RotateAroundAxis(ang:Forward(), v.angle.r)
+
+ else
+
+ bone = ent:LookupBone(bone_override or tab.bone)
+
+ if (!bone) then return end
+
+ pos, ang = Vector(0,0,0), Angle(0,0,0)
+ local m = ent:GetBoneMatrix(bone)
+ if (m) then
+ pos, ang = m:GetTranslation(), m:GetAngles()
+ end
+
+ if (IsValid(self.Owner) and self.Owner:IsPlayer() and
+ ent == self.Owner:GetViewModel() and self.ViewModelFlip) then
+ ang.r = -ang.r // Fixes mirrored models
+ end
+
+ end
+
+ return pos, ang
+ end
+
+ function SWEP:CreateModels( tab )
+
+ if (!tab) then return end
+
+ // Create the clientside models here because Garry says we can't do it in the render hook
+ for k, v in pairs( tab ) do
+ if (v.type == "Model" and v.model and v.model != "" and (!IsValid(v.modelEnt) or v.createdModel != v.model) and
+ string.find(v.model, ".mdl") and file.Exists (v.model, "GAME") ) then
+
+ v.modelEnt = ClientsideModel(v.model, RENDER_GROUP_VIEW_MODEL_OPAQUE)
+ if (IsValid(v.modelEnt)) then
+ v.modelEnt:SetPos(self:GetPos())
+ v.modelEnt:SetAngles(self:GetAngles())
+ v.modelEnt:SetParent(self)
+ v.modelEnt:SetNoDraw(true)
+ v.createdModel = v.model
+ else
+ v.modelEnt = nil
+ end
+
+ elseif (v.type == "Sprite" and v.sprite and v.sprite != "" and (!v.spriteMaterial or v.createdSprite != v.sprite)
+ and file.Exists ("materials/"..v.sprite..".vmt", "GAME")) then
+
+ local name = v.sprite.."-"
+ local params = { ["$basetexture"] = v.sprite }
+ // make sure we create a unique name based on the selected options
+ local tocheck = { "nocull", "additive", "vertexalpha", "vertexcolor", "ignorez" }
+ for i, j in pairs( tocheck ) do
+ if (v[j]) then
+ params["$"..j] = 1
+ name = name.."1"
+ else
+ name = name.."0"
+ end
+ end
+
+ v.createdSprite = v.sprite
+ v.spriteMaterial = CreateMaterial(name,"UnlitGeneric",params)
+
+ end
+ end
+
+ end
+
+ local allbones
+ local hasGarryFixedBoneScalingYet = false
+
+ function SWEP:UpdateBonePositions(vm)
+
+ if self.ViewModelBoneMods then
+
+ if (!vm:GetBoneCount()) then return end
+
+ // !! WORKAROUND !! //
+ // We need to check all model names :/
+ local loopthrough = self.ViewModelBoneMods
+ if (!hasGarryFixedBoneScalingYet) then
+ allbones = {}
+ for i=0, vm:GetBoneCount() do
+ local bonename = vm:GetBoneName(i)
+ if (self.ViewModelBoneMods[bonename]) then
+ allbones[bonename] = self.ViewModelBoneMods[bonename]
+ else
+ allbones[bonename] = {
+ scale = Vector(1,1,1),
+ pos = Vector(0,0,0),
+ angle = Angle(0,0,0)
+ }
+ end
+ end
+
+ loopthrough = allbones
+ end
+ // !! ----------- !! //
+
+ for k, v in pairs( loopthrough ) do
+ local bone = vm:LookupBone(k)
+ if (!bone) then continue end
+
+ // !! WORKAROUND !! //
+ local s = Vector(v.scale.x,v.scale.y,v.scale.z)
+ local p = Vector(v.pos.x,v.pos.y,v.pos.z)
+ local ms = Vector(1,1,1)
+ if (!hasGarryFixedBoneScalingYet) then
+ local cur = vm:GetBoneParent(bone)
+ while(cur >= 0) do
+ local pscale = loopthrough[vm:GetBoneName(cur)].scale
+ ms = ms * pscale
+ cur = vm:GetBoneParent(cur)
+ end
+ end
+
+ s = s * ms
+ // !! ----------- !! //
+
+ if vm:GetManipulateBoneScale(bone) != s then
+ vm:ManipulateBoneScale( bone, s )
+ end
+ if vm:GetManipulateBoneAngles(bone) != v.angle then
+ vm:ManipulateBoneAngles( bone, v.angle )
+ end
+ if vm:GetManipulateBonePosition(bone) != p then
+ vm:ManipulateBonePosition( bone, p )
+ end
+ end
+ else
+ self:ResetBonePositions(vm)
+ end
+
+ end
+
+ function SWEP:ResetBonePositions(vm)
+ -- New code
+ vm:SetColor(color_white)
+ vm:SetMaterial("")
+ --------
+
+ if (!vm:GetBoneCount()) then return end
+ for i=0, vm:GetBoneCount() do
+ vm:ManipulateBoneScale( i, Vector(1, 1, 1) )
+ vm:ManipulateBoneAngles( i, Angle(0, 0, 0) )
+ vm:ManipulateBonePosition( i, Vector(0, 0, 0) )
+ end
+
+ end
+
+ /**************************
+ Global utility code
+ **************************/
+
+ // Fully copies the table, meaning all tables inside this table are copied too and so on (normal table.Copy copies only their reference).
+ // Does not copy entities of course, only copies their reference.
+ // WARNING: do not use on tables that contain themselves somewhere down the line or you'll get an infinite loop
+ function table.FullCopy( tab )
+
+ if (!tab) then return nil end
+
+ local res = {}
+ for k, v in pairs( tab ) do
+ if (type(v) == "table") then
+ res[k] = table.FullCopy(v) // recursion ho!
+ elseif (type(v) == "Vector") then
+ res[k] = Vector(v.x, v.y, v.z)
+ elseif (type(v) == "Angle") then
+ res[k] = Angle(v.p, v.y, v.r)
+ else
+ res[k] = v
+ end
+ end
+
+ return res
+
+ end
+
+end
+
+----------------
+-- Extra code --
+----------------
+
+function SWEP:RemoveModels()
+ if (self.VElements) then
+ for k, v in pairs( self.VElements ) do
+ if (IsValid( v.modelEnt )) then
+ v.modelEnt:Remove()
+ v.modelEnt = nil
+ end
+ end
+ end
+ if (self.WElements) then
+ for k, v in pairs( self.WElements ) do
+ if (IsValid( v.modelEnt )) then
+ v.modelEnt:Remove()
+ v.modelEnt = nil
+ end
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_basemelee/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_basemelee/cl_init.lua
new file mode 100644
index 0000000..c760b23
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_basemelee/cl_init.lua
@@ -0,0 +1,86 @@
+include("shared.lua")
+include("animations.lua")
+
+SWEP.DrawAmmo = false
+SWEP.DrawCrosshair = false
+SWEP.ViewModelFOV = 60
+
+SWEP.Slot = 0
+SWEP.SlotPos = 0
+
+function SWEP:TranslateFOV(fov)
+ return GAMEMODE.FOVLerp * fov
+end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
+
+function SWEP:DrawHUD()
+ if GetConVarNumber("crosshair") ~= 1 then return end
+ self:DrawCrosshairDot()
+end
+
+function SWEP:OnRemove()
+ self:Anim_OnRemove()
+end
+
+function SWEP:ViewModelDrawn()
+ self:Anim_ViewModelDrawn()
+end
+
+function SWEP:PreDrawViewModel(vm)
+ if self.ShowViewModel == false then
+ render.SetBlend(0)
+ end
+end
+
+function SWEP:PostDrawViewModel(vm)
+ if self.ShowViewModel == false then
+ render.SetBlend(1)
+ end
+end
+
+function SWEP:DrawWorldModel()
+ local owner = self:GetOwner()
+ if owner:IsValid() and owner.ShadowMan then return end
+
+ self:Anim_DrawWorldModel()
+end
+
+local ghostlerp = 0
+function SWEP:GetViewModelPosition(pos, ang)
+ if self:IsSwinging() then
+ local rot = self.SwingRotation
+ local offset = self.SwingOffset
+
+ ang = Angle(ang.pitch, ang.yaw, ang.roll) -- Copy
+
+ local swingend = self:GetSwingEnd()
+ local delta = self.SwingTime - math.Clamp(swingend - CurTime(), 0, self.SwingTime)
+ local power = CosineInterpolation(0, 1, delta / self.SwingTime)
+
+ if power >= 0.9 then
+ power = (1 - power) ^ 0.4 * 2
+ end
+
+ pos = pos + offset.x * power * ang:Right() + offset.y * power * ang:Forward() + offset.z * power * ang:Up()
+
+ ang:RotateAroundAxis(ang:Right(), rot.pitch * power)
+ ang:RotateAroundAxis(ang:Up(), rot.yaw * power)
+ ang:RotateAroundAxis(ang:Forward(), rot.roll * power)
+ end
+
+ if self.Owner:GetBarricadeGhosting() then
+ ghostlerp = math.min(1, ghostlerp + FrameTime() * 4)
+ elseif ghostlerp > 0 then
+ ghostlerp = math.max(0, ghostlerp - FrameTime() * 5)
+ end
+
+ if ghostlerp > 0 then
+ pos = pos + 3.5 * ghostlerp * ang:Up()
+ ang:RotateAroundAxis(ang:Right(), -30 * ghostlerp)
+ end
+
+ return pos, ang
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_basemelee/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_basemelee/shared.lua
new file mode 100644
index 0000000..8708230
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_basemelee/shared.lua
@@ -0,0 +1,331 @@
+if SERVER then
+ AddCSLuaFile("shared.lua")
+ AddCSLuaFile("cl_init.lua")
+ AddCSLuaFile("animations.lua")
+end
+
+SWEP.ViewModel = "models/weapons/v_axe/v_axe.mdl"
+SWEP.WorldModel = "models/weapons/w_axe.mdl"
+
+SWEP.Primary.ClipSize = -1
+SWEP.Primary.DefaultClip = -1
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "none"
+SWEP.Primary.Delay = 1
+
+SWEP.MeleeDamage = 30
+SWEP.MeleeRange = 65
+SWEP.MeleeSize = 1.5
+SWEP.MeleeKnockBack = 0
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = true
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_FAST
+
+SWEP.IsMelee = true
+
+SWEP.HoldType = "melee"
+SWEP.SwingHoldType = "grenade"
+
+SWEP.DamageType = DMG_SLASH
+
+SWEP.BloodDecal = "Blood"
+SWEP.HitDecal = "Impact.Concrete"
+
+SWEP.HitAnim = ACT_VM_HITCENTER
+SWEP.MissAnim = ACT_VM_MISSCENTER
+
+SWEP.SwingTime = 0
+SWEP.SwingRotation = Angle(0, 0, 0)
+SWEP.SwingOffset = Vector(0, 0, 0)
+
+function SWEP:Initialize()
+ self:SetDeploySpeed(1.1)
+ self:SetWeaponHoldType(self.HoldType)
+ self:SetWeaponSwingHoldType(self.SwingHoldType)
+
+ if CLIENT then
+ self:Anim_Initialize()
+ end
+end
+
+function SWEP:SetWeaponSwingHoldType(t)
+ local old = self.ActivityTranslate
+ self:SetWeaponHoldType(t)
+ local new = self.ActivityTranslate
+ self.ActivityTranslate = old
+ self.ActivityTranslateSwing = new
+end
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ return true
+end
+
+function SWEP:Think()
+ if self.IdleAnimation and self.IdleAnimation <= CurTime() then
+ self.IdleAnimation = nil
+ self:SendWeaponAnim(ACT_VM_IDLE)
+ end
+
+ if self:IsSwinging() and self:GetSwingEnd() <= CurTime() then
+ self:StopSwinging()
+ self:MeleeSwing()
+ end
+
+ --[[if CLIENT then
+ self:Anim_Think()
+ end]]
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+ return false
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ return self:GetNextPrimaryFire() <= CurTime() and not self:IsSwinging()
+end
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("weapons/iceaxe/iceaxe_swing1.wav")
+end
+
+function SWEP:PlayStartSwingSound()
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("weapons/melee/golf club/golf_hit-0"..math.random(4)..".ogg")
+end
+
+function SWEP:PlayHitFleshSound()
+ self:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav")
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+
+ if self.SwingTime == 0 then
+ self:MeleeSwing()
+ else
+ self:StartSwinging()
+ end
+end
+
+function SWEP:Holster()
+ if CurTime() >= self:GetSwingEnd() then
+ if CLIENT then
+ self:Anim_Holster()
+ end
+
+ return true
+ end
+
+ return false
+end
+
+function SWEP:StartSwinging()
+ if self.StartSwingAnimation then
+ self:SendWeaponAnim(self.StartSwingAnimation)
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+ end
+ self:PlayStartSwingSound()
+ self:SetSwingEnd(CurTime() + self.SwingTime)
+end
+
+function SWEP:MeleeSwing()
+ local owner = self.Owner
+
+ owner:DoAttackEvent()
+
+ local filter = owner:GetMeleeFilter()
+
+ owner:LagCompensation(true)
+
+ local tr = owner:MeleeTrace(self.MeleeRange, self.MeleeSize, filter)
+ if tr.Hit then
+ local damagemultiplier = owner.BuffMuscular and 1.2 or 1
+ local damage = self.MeleeDamage * damagemultiplier
+ local hitent = tr.Entity
+ local hitflesh = tr.MatType == MAT_FLESH or tr.MatType == MAT_BLOODYFLESH or tr.MatType == MAT_ANTLION or tr.MatType == MAT_ALIENFLESH
+
+ if self.HitAnim then
+ self:SendWeaponAnim(self.HitAnim)
+ end
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ if hitflesh then
+ util.Decal(self.BloodDecal, tr.HitPos + tr.HitNormal, tr.HitPos - tr.HitNormal)
+ self:PlayHitFleshSound()
+ if SERVER and not (hitent:IsValid() and hitent:IsPlayer() and hitent:Team() == owner:Team()) then
+ util.Blood(tr.HitPos, math.Rand(damage * 0.25, damage * 0.6), (tr.HitPos - owner:GetShootPos()):GetNormalized(), math.Rand(damage * 6, damage * 12), true)
+ end
+ if not self.NoHitSoundFlesh then
+ self:PlayHitSound()
+ end
+ else
+ util.Decal(self.HitDecal, tr.HitPos + tr.HitNormal, tr.HitPos - tr.HitNormal)
+ self:PlayHitSound()
+ end
+
+ if self.OnMeleeHit and self:OnMeleeHit(hitent, hitflesh, tr) then
+ owner:LagCompensation(false)
+ return
+ end
+
+ if SERVER and hitent:IsValid() then
+ damage = self.MeleeDamage * damagemultiplier
+
+ if hitent:GetClass() == "func_breakable_surf" then
+ hitent:Fire("break", "", 0.01) -- Delayed because no way to do prediction.
+ else
+ local dmginfo = DamageInfo()
+ dmginfo:SetDamagePosition(tr.HitPos)
+ dmginfo:SetDamage(damage)
+ dmginfo:SetAttacker(owner)
+ dmginfo:SetInflictor(self)
+ dmginfo:SetDamageType(self.DamageType)
+ dmginfo:SetDamageForce(self.MeleeDamage * 20 * owner:GetAimVector())
+ if hitent:IsPlayer() then
+ hitent:MeleeViewPunch(damage)
+ if hitent:IsHeadcrab() then
+ damage = damage * 2
+ dmginfo:SetDamage(damage)
+ end
+ gamemode.Call("ScalePlayerDamage", hitent, tr.HitGroup, dmginfo)
+
+ if self.MeleeKnockBack > 0 then
+ hitent:ThrowFromPositionSetZ(tr.HitPos, self.MeleeKnockBack, nil, true)
+ end
+ end
+
+ if hitent:IsPlayer() then
+ hitent:TakeDamageInfo(dmginfo)
+ else
+ -- Again, no way to do prediction.
+ timer.Simple(0, function()
+ if hitent:IsValid() then
+ -- Workaround for propbroken not calling.
+ local h = hitent:Health()
+
+ hitent:TakeDamageInfo(dmginfo)
+
+ if hitent:Health() <= 0 and h ~= hitent:Health() then
+ gamemode.Call("PropBroken", hitent, owner)
+ end
+
+ local phys = hitent:GetPhysicsObject()
+ if hitent:GetMoveType() == MOVETYPE_VPHYSICS and phys:IsValid() and phys:IsMoveable() then
+ hitent:SetPhysicsAttacker(owner)
+ end
+ end
+ end)
+ end
+ end
+ end
+
+ if self.PostOnMeleeHit then self:PostOnMeleeHit(hitent, hitflesh, tr) end
+ else
+ if self.MissAnim then
+ self:SendWeaponAnim(self.MissAnim)
+ end
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+ self:PlaySwingSound()
+
+ if self.PostOnMeleeMiss then self:PostOnMeleeMiss(tr) end
+ end
+
+ owner:LagCompensation(false)
+end
+
+function SWEP:StopSwinging()
+ self:SetSwingEnd(0)
+end
+
+function SWEP:IsSwinging()
+ return self:GetSwingEnd() > 0
+end
+
+function SWEP:SetSwingEnd(swingend)
+ self:SetDTFloat(0, swingend)
+end
+
+function SWEP:GetSwingEnd()
+ return self:GetDTFloat(0)
+end
+
+local ActIndex = {
+ [ "pistol" ] = ACT_HL2MP_IDLE_PISTOL,
+ [ "smg" ] = ACT_HL2MP_IDLE_SMG1,
+ [ "grenade" ] = ACT_HL2MP_IDLE_GRENADE,
+ [ "ar2" ] = ACT_HL2MP_IDLE_AR2,
+ [ "shotgun" ] = ACT_HL2MP_IDLE_SHOTGUN,
+ [ "rpg" ] = ACT_HL2MP_IDLE_RPG,
+ [ "physgun" ] = ACT_HL2MP_IDLE_PHYSGUN,
+ [ "crossbow" ] = ACT_HL2MP_IDLE_CROSSBOW,
+ [ "melee" ] = ACT_HL2MP_IDLE_MELEE,
+ [ "slam" ] = ACT_HL2MP_IDLE_SLAM,
+ [ "normal" ] = ACT_HL2MP_IDLE,
+ [ "fist" ] = ACT_HL2MP_IDLE_FIST,
+ [ "melee2" ] = ACT_HL2MP_IDLE_MELEE2,
+ [ "passive" ] = ACT_HL2MP_IDLE_PASSIVE,
+ [ "knife" ] = ACT_HL2MP_IDLE_KNIFE,
+ [ "duel" ] = ACT_HL2MP_IDLE_DUEL
+}
+
+function SWEP:SetWeaponHoldType( t )
+
+ t = string.lower( t )
+ local index = ActIndex[ t ]
+
+ if ( index == nil ) then
+ Msg( "SWEP:SetWeaponHoldType - ActIndex[ \""..t.."\" ] isn't set! (defaulting to normal)\n" )
+ t = "normal"
+ index = ActIndex[ t ]
+ end
+
+ self.ActivityTranslate = {}
+ self.ActivityTranslate [ ACT_MP_STAND_IDLE ] = index
+ self.ActivityTranslate [ ACT_MP_WALK ] = index+1
+ self.ActivityTranslate [ ACT_MP_RUN ] = index+2
+ self.ActivityTranslate [ ACT_MP_CROUCH_IDLE ] = index+3
+ self.ActivityTranslate [ ACT_MP_CROUCHWALK ] = index+4
+ self.ActivityTranslate [ ACT_MP_ATTACK_STAND_PRIMARYFIRE ] = index+5
+ self.ActivityTranslate [ ACT_MP_ATTACK_CROUCH_PRIMARYFIRE ] = index+5
+ self.ActivityTranslate [ ACT_MP_RELOAD_STAND ] = index+6
+ self.ActivityTranslate [ ACT_MP_RELOAD_CROUCH ] = index+6
+ self.ActivityTranslate [ ACT_MP_JUMP ] = index+7
+ self.ActivityTranslate [ ACT_RANGE_ATTACK1 ] = index+8
+ self.ActivityTranslate [ ACT_MP_SWIM_IDLE ] = index+8
+ self.ActivityTranslate [ ACT_MP_SWIM ] = index+9
+
+ -- "normal" jump animation doesn't exist
+ if t == "normal" then
+ self.ActivityTranslate [ ACT_MP_JUMP ] = ACT_HL2MP_JUMP_SLAM
+ end
+
+ -- these two aren't defined in ACTs for whatever reason
+ if t == "knife" || t == "melee2" then
+ self.ActivityTranslate [ ACT_MP_CROUCH_IDLE ] = nil
+ end
+end
+
+SWEP:SetWeaponHoldType("pistol")
+
+function SWEP:TranslateActivity( act )
+ if self:GetSwingEnd() ~= 0 and self.ActivityTranslateSwing[act] then
+ return self.ActivityTranslateSwing[act] or -1
+ end
+
+ return self.ActivityTranslate and self.ActivityTranslate[act] or -1
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_battleaxe.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_battleaxe.lua
new file mode 100644
index 0000000..e6182a3
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_battleaxe.lua
@@ -0,0 +1,37 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Battleaxe' Handgun"
+ SWEP.Slot = 1
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+
+ SWEP.HUD3DPos = Vector(-0.95, 0, 1)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+ SWEP.HUD3DBone = "v_weapon.USP_Slide"
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "pistol"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_pist_usp.mdl"
+SWEP.WorldModel = "models/weapons/w_pist_usp.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("Weapon_USP.Single")
+SWEP.Primary.Damage = 22
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.2
+
+SWEP.Primary.ClipSize = 12
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "pistol"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.IronSightsPos = Vector(-5.9, 12, 2.3)
+
+SWEP.ConeMax = 0.05
+SWEP.ConeMin = 0.015
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_blaster.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_blaster.lua
new file mode 100644
index 0000000..8a76710
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_blaster.lua
@@ -0,0 +1,109 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Blaster' Shotgun"
+ SWEP.Slot = 3
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+
+ SWEP.HUD3DPos = Vector(4, -3.5, -1.2)
+ SWEP.HUD3DAng = Angle(90, 0, -30)
+ SWEP.HUD3DScale = 0.02
+ SWEP.HUD3DBone = "SS.Grip.Dummy"
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "shotgun"
+
+SWEP.ViewModel = "models/weapons/v_supershorty/v_supershorty.mdl"
+SWEP.WorldModel = "models/weapons/w_supershorty.mdl"
+
+SWEP.ReloadDelay = 0.4
+
+SWEP.Primary.Sound = Sound("Weapon_Shotgun.Single")
+SWEP.Primary.Damage = 12
+SWEP.Primary.NumShots = 7
+SWEP.Primary.Delay = 0.8
+
+SWEP.Primary.ClipSize = 6
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "buckshot"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.ConeMax = 0.18
+SWEP.ConeMin = 0.155
+
+SWEP.WalkSpeed = SPEED_SLOWER
+
+SWEP.reloadtimer = 0
+SWEP.nextreloadfinish = 0
+
+function SWEP:Reload()
+ if self.reloading then return end
+
+ if self:Clip1() < self.Primary.ClipSize and 0 < self.Owner:GetAmmoCount(self.Primary.Ammo) then
+ self:SetNextPrimaryFire(CurTime() + self.ReloadDelay)
+ self.reloading = true
+ self.reloadtimer = CurTime() + self.ReloadDelay
+ self:SendWeaponAnim(ACT_SHOTGUN_RELOAD_START)
+ self.Owner:RestartGesture(ACT_HL2MP_GESTURE_RELOAD_SHOTGUN)
+ end
+
+ self:SetIronsights(false)
+end
+
+function SWEP:Think()
+ if self.reloading and self.reloadtimer < CurTime() then
+ self.reloadtimer = CurTime() + self.ReloadDelay
+ self:SendWeaponAnim(ACT_VM_RELOAD)
+
+ self.Owner:RemoveAmmo(1, self.Primary.Ammo, false)
+ self:SetClip1(self:Clip1() + 1)
+ self:EmitSound("Weapon_Shotgun.Reload")
+
+ if self.Primary.ClipSize <= self:Clip1() or self.Owner:GetAmmoCount(self.Primary.Ammo) <= 0 then
+ self.nextreloadfinish = CurTime() + self.ReloadDelay
+ self.reloading = false
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ end
+ end
+
+ local nextreloadfinish = self.nextreloadfinish
+ if nextreloadfinish ~= 0 and nextreloadfinish < CurTime() then
+ self:EmitSound("Weapon_M3.Pump")
+ self:SendWeaponAnim(ACT_SHOTGUN_PUMP)
+ self.nextreloadfinish = 0
+ end
+
+ if self:GetIronsights() and not self.Owner:KeyDown(IN_ATTACK2) then
+ self:SetIronsights(false)
+ end
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:Clip1() <= 0 then
+ self:EmitSound("Weapon_Shotgun.Empty")
+ self:SetNextPrimaryFire(CurTime() + 0.25)
+ return false
+ end
+
+ if self.reloading then
+ if 0 < self:Clip1() then
+ self:SendWeaponAnim(ACT_SHOTGUN_RELOAD_FINISH)
+ else
+ self:SendWeaponAnim(ACT_VM_IDLE)
+ end
+ self.reloading = false
+ self:SetNextPrimaryFire(CurTime() + 0.25)
+ return false
+ end
+
+ return true
+end
+
+function SWEP:SecondaryAttack()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bloatedzombie.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bloatedzombie.lua
new file mode 100644
index 0000000..f47932d
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bloatedzombie.lua
@@ -0,0 +1,39 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Bloated Zombie"
+end
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.MeleeDamage = 30
+SWEP.MeleeForceScale = 1.25
+
+SWEP.Primary.Delay = 1.5
+
+function SWEP:Reload()
+ self.BaseClass.SecondaryAttack(self)
+end
+
+function SWEP:PlayAlertSound()
+ self:PlayAttackSound()
+end
+
+function SWEP:PlayIdleSound()
+ self.Owner:EmitSound("npc/barnacle/barnacle_tongue_pull"..math.random(3)..".wav")
+end
+
+function SWEP:PlayAttackSound()
+ self.Owner:EmitSound("npc/ichthyosaur/attack_growl"..math.random(3)..".wav", 70, math.Rand(145, 155))
+end
+
+if not CLIENT then return end
+
+function SWEP:ViewModelDrawn()
+ render.ModelMaterialOverride(0)
+end
+
+local matSheet = Material("models/weapons/v_zombiearms/ghoulsheet")
+function SWEP:PreDrawViewModel(vm)
+ render.ModelMaterialOverride(matSheet)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_boardpack/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_boardpack/cl_init.lua
new file mode 100644
index 0000000..0887879
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_boardpack/cl_init.lua
@@ -0,0 +1,47 @@
+include("shared.lua")
+
+SWEP.PrintName = "Junk Pack"
+SWEP.Description = "It's simply a pack of wooden junk kept together with some duct tape.\nVery useful for making barricades when no materials are around.\nNeeds something like a hammer and nails to keep the things in place."
+SWEP.ViewModelFOV = 45
+SWEP.ViewModelFlip = false
+
+SWEP.Slot = 4
+SWEP.SlotPos = 0
+
+function SWEP:Deploy()
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ return true
+end
+
+function SWEP:DrawWorldModel()
+ local owner = self.Owner
+ if owner:IsValid() and self:GetReplicatedAmmo() > 0 then
+ local id = owner:LookupAttachment("anim_attachment_RH")
+ if id and id > 0 then
+ local attch = owner:GetAttachment(id)
+ if attch then
+ cam.Start3D(EyePos() + (owner:GetPos() - attch.Pos + Vector(0, 0, 24)), EyeAngles())
+ self:DrawModel()
+ cam.End3D()
+ end
+ end
+ end
+end
+SWEP.DrawWorldModelTranslucent = SWEP.DrawWorldModel
+
+function SWEP:Initialize()
+ self:SetDeploySpeed(1.1)
+end
+
+function SWEP:GetViewModelPosition(pos, ang)
+ if self:GetPrimaryAmmoCount() <= 0 then
+ return pos + ang:Forward() * -256, ang
+ end
+
+ return pos, ang
+end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_boardpack/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_boardpack/init.lua
new file mode 100644
index 0000000..f524b52
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_boardpack/init.lua
@@ -0,0 +1,26 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ return true
+end
+
+function SWEP:Initialize()
+ self.ActivityTranslate = {}
+ self.ActivityTranslate[ACT_HL2MP_IDLE] = ACT_HL2MP_IDLE_MELEE2
+ self.ActivityTranslate[ACT_HL2MP_WALK] = ACT_HL2MP_WALK_MELEE2
+ self.ActivityTranslate[ACT_HL2MP_RUN] = ACT_HL2MP_RUN_MELEE2
+ self.ActivityTranslate[ACT_HL2MP_IDLE_CROUCH] = ACT_HL2MP_IDLE_CROUCH_MELEE2
+ self.ActivityTranslate[ACT_HL2MP_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH_MELEE2
+ self.ActivityTranslate[ACT_HL2MP_GESTURE_RANGE_ATTACK] = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2
+ self.ActivityTranslate[ACT_HL2MP_GESTURE_RELOAD] = ACT_HL2MP_GESTURE_RELOAD_MELEE2
+ self.ActivityTranslate[ACT_HL2MP_JUMP] = ACT_HL2MP_JUMP_MELEE2
+ self.ActivityTranslate[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_MELEE2
+ self:SetDeploySpeed(1.1)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_boardpack/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_boardpack/shared.lua
new file mode 100644
index 0000000..2511c91
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_boardpack/shared.lua
@@ -0,0 +1,129 @@
+SWEP.ViewModel = "models/weapons/v_aegiskit.mdl"
+SWEP.WorldModel = "models/props_debris/wood_board06a.mdl"
+
+SWEP.AmmoIfHas = true
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "SniperRound"
+SWEP.Primary.Delay = 1
+SWEP.Primary.DefaultClip = 3
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = true
+SWEP.Secondary.Ammo = "none"
+SWEP.Secondary.Delay = 0.15
+
+SWEP.WalkSpeed = SPEED_NORMAL
+SWEP.FullWalkSpeed = SPEED_SLOWEST
+
+SWEP.JunkModels = {
+ Model("models/props_debris/wood_board04a.mdl"),
+ Model("models/props_debris/wood_board06a.mdl"),
+ Model("models/props_debris/wood_board02a.mdl"),
+ Model("models/props_debris/wood_board01a.mdl"),
+ Model("models/props_debris/wood_board07a.mdl"),
+ Model("models/props_c17/furnituredrawer002a.mdl"),
+ Model("models/props_c17/furnituredrawer003a.mdl"),
+ Model("models/props_c17/furnituredrawer001a_chunk01.mdl"),
+ Model("models/props_c17/furniturechair001a_chunk01.mdl"),
+ Model("models/props_c17/furnituredrawer001a_chunk02.mdl"),
+ Model("models/props_c17/furnituretable003a.mdl"),
+ Model("models/props_c17/furniturechair001a.mdl")
+}
+
+function SWEP:SetReplicatedAmmo(count)
+ self:SetDTInt(0, count)
+end
+
+function SWEP:GetReplicatedAmmo()
+ return self:GetDTInt(0)
+end
+
+function SWEP:GetWalkSpeed()
+ if self:GetPrimaryAmmoCount() > 0 then
+ return self.FullWalkSpeed
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+
+ local aimvec = self.Owner:GetAimVector()
+ local shootpos = self.Owner:GetShootPos()
+ local tr = util.TraceLine({start = shootpos, endpos = shootpos + aimvec * 32, filter = self.Owner})
+
+ self:SetNextPrimaryAttack(CurTime() + self.Primary.Delay)
+
+ self:EmitSound("weapons/iceaxe/iceaxe_swing1.wav", 75, math.random(75, 80))
+
+ self:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
+ self.Owner:RestartGesture(ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE)
+ self.IdleAnimation = CurTime() + math.min(self.Primary.Delay, self:SequenceDuration())
+
+ if SERVER then
+ local ent = ents.Create("prop_physics")
+ if ent:IsValid() then
+ local ang = aimvec:Angle()
+ ang:RotateAroundAxis(ang:Forward(), 90)
+ ent:SetPos(tr.HitPos)
+ ent:SetAngles(ang)
+ ent:SetModel(table.Random(self.JunkModels))
+ ent:Spawn()
+ ent:SetHealth(350)
+ ent.NoVolumeCarryCheck = true
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMass(math.min(phys:GetMass(), 50))
+ phys:SetVelocityInstantaneous(self.Owner:GetVelocity())
+ end
+ ent:SetPhysicsAttacker(self.Owner)
+ self:TakePrimaryAmmo(1)
+ end
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if math.abs(self.Owner:GetVelocity().z) >= 256 then return false end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ return false
+ end
+
+ return true
+end
+
+function SWEP:Think()
+ if self.IdleAnimation and self.IdleAnimation <= CurTime() then
+ self.IdleAnimation = nil
+ self:SendWeaponAnim(ACT_VM_IDLE)
+ end
+
+ if SERVER then
+ local count = self:GetPrimaryAmmoCount()
+ if count ~= self:GetReplicatedAmmo() then
+ self:SetReplicatedAmmo(count)
+ self.Owner:ResetSpeed()
+ end
+ end
+end
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ return true
+end
+
+util.PrecacheModel("models/props_debris/wood_board04a.mdl")
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bonemesh/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bonemesh/cl_init.lua
new file mode 100644
index 0000000..e6b3baa
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bonemesh/cl_init.lua
@@ -0,0 +1,11 @@
+include("shared.lua")
+
+SWEP.PrintName = "Bone Mesh"
+SWEP.ViewModelFOV = 47
+SWEP.DrawCrosshair = false
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bonemesh/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bonemesh/init.lua
new file mode 100644
index 0000000..1fbe360
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bonemesh/init.lua
@@ -0,0 +1,62 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function SWEP:Reload()
+ self.BaseClass.SecondaryAttack(self)
+end
+
+local function DoFleshThrow(pl, wep)
+ if pl:IsValid() and pl:Alive() and wep:IsValid() then
+ pl:ResetSpeed()
+
+ local startpos = pl:GetPos()
+ startpos.z = pl:GetShootPos().z
+ local heading = pl:GetAimVector()
+
+ local ent = ents.Create("projectile_bonemesh")
+ if ent:IsValid() then
+ ent:SetPos(startpos + heading * 8)
+ ent:SetAngles(AngleRand())
+ ent:SetOwner(pl)
+ ent:Spawn()
+ ent:SetTeamID(TEAM_UNDEAD)
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetVelocityInstantaneous(heading * 800)
+ phys:AddAngleVelocity(VectorRand() * 45)
+ end
+ end
+
+ pl:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav", 72, math.random(70, 80))
+
+ pl:RawCapLegDamage(CurTime() + 2)
+ end
+end
+
+local function DoSwing(pl, wep)
+ if pl:IsValid() and pl:Alive() and wep:IsValid() then
+ pl:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav", 72, math.random(70, 83))
+ if wep.SwapAnims then wep:SendWeaponAnim(ACT_VM_HITCENTER) else wep:SendWeaponAnim(ACT_VM_SECONDARYATTACK) end
+ wep.IdleAnimation = CurTime() + wep:SequenceDuration()
+ wep.SwapAnims = not wep.SwapAnims
+ end
+end
+
+function SWEP:SecondaryAttack()
+ if CurTime() < self:GetNextPrimaryFire() or CurTime() < self:GetNextSecondaryFire() then return end
+
+ local owner = self.Owner
+ if owner:Team() ~= TEAM_UNDEAD then owner:Kill() return end
+
+ self:SetSwingAnimTime(CurTime() + 1)
+ self.Owner:DoAnimationEvent(ACT_RANGE_ATTACK2)
+ self.Owner:EmitSound("NPC_PoisonZombie.Throw")
+ self.Owner:SetSpeed(1)
+ self:SetNextSecondaryFire(CurTime() + 4)
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+
+ timer.Simple(0.6, function() DoSwing(owner, self) end)
+ timer.Simple(0.75, function() DoFleshThrow(owner, self) end)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bonemesh/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bonemesh/shared.lua
new file mode 100644
index 0000000..4076059
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bonemesh/shared.lua
@@ -0,0 +1,57 @@
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.MeleeReach = 48
+SWEP.MeleeDelay = 0.55
+SWEP.MeleeSize = 1.5
+SWEP.MeleeDamage = 35
+SWEP.MeleeDamageType = DMG_SLASH
+SWEP.MeleeAnimationDelay = 0.05
+SWEP.FrozenWhileSwinging = true
+
+SWEP.Primary.Delay = 1.6
+
+SWEP.ViewModel = Model("models/weapons/v_pza.mdl")
+SWEP.WorldModel = "models/weapons/w_crowbar.mdl"
+
+function SWEP:CheckMoaning()
+end
+
+function SWEP:StopMoaningSound()
+end
+
+function SWEP:StartMoaningSound()
+end
+
+function SWEP:PlayHitSound()
+ self.Owner:EmitSound("npc/zombie/claw_strike"..math.random(3)..".wav", 75, 80)
+end
+
+function SWEP:PlayMissSound()
+ self.Owner:EmitSound("npc/zombie/claw_miss"..math.random(2)..".wav", 75, 80)
+end
+
+function SWEP:PlayAttackSound()
+ self.Owner:EmitSound("NPC_PoisonZombie.ThrowWarn")
+end
+
+function SWEP:PlayAlertSound()
+ self.Owner:EmitSound("npc/antlion_guard/angry"..math.random(3)..".wav", 75, 140)
+end
+SWEP.PlayIdleSound = SWEP.PlayAlertSound
+
+function SWEP:SetSwingAnimTime(time)
+ self:SetDTFloat(3, time)
+end
+
+function SWEP:GetSwingAnimTime()
+ return self:GetDTFloat(3)
+end
+
+function SWEP:StartSwinging()
+ self.BaseClass.StartSwinging(self)
+ self:SetSwingAnimTime(CurTime() + 1)
+end
+
+function SWEP:PrimaryAttack()
+ if self.Owner:IsOnGround() then self.BaseClass.PrimaryAttack(self) end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_boomstick.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_boomstick.lua
new file mode 100644
index 0000000..8af370c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_boomstick.lua
@@ -0,0 +1,137 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Boom Stick"
+ SWEP.Description = "This shotgun allows you to load up to four shells in the chamber at once. Hold down reload for faster loading of each shell."
+ SWEP.Slot = 3
+ SWEP.SlotPos = 0
+
+ SWEP.HUD3DBone = "ValveBiped.Gun"
+ SWEP.HUD3DPos = Vector(1.65, 0, -8)
+ SWEP.HUD3DScale = 0.025
+
+ SWEP.ViewModelFlip = false
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "shotgun"
+
+SWEP.ViewModel = "models/weapons/c_shotgun.mdl"
+SWEP.WorldModel = "models/weapons/w_shotgun.mdl"
+SWEP.UseHands = true
+
+SWEP.CSMuzzleFlashes = false
+
+SWEP.ReloadDelay = 0.4
+
+SWEP.Primary.Sound = Sound("weapons/shotgun/shotgun_dbl_fire.wav")
+SWEP.Primary.Recoil = 12.5
+SWEP.Primary.Damage = 36
+SWEP.Primary.NumShots = 6
+SWEP.Primary.Delay = 1.5
+
+SWEP.Primary.ClipSize = 4
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "buckshot"
+SWEP.Primary.DefaultClip = 28
+
+SWEP.ConeMax = 0.23
+SWEP.ConeMin = 0.2
+
+SWEP.WalkSpeed = SPEED_SLOWER
+
+function SWEP:SetIronsights()
+end
+
+SWEP.reloadtimer = 0
+SWEP.nextreloadfinish = 0
+
+function SWEP:Reload()
+ if self.reloading then return end
+
+ if self:GetNextReload() <= CurTime() and self:Clip1() < self.Primary.ClipSize and 0 < self.Owner:GetAmmoCount(self.Primary.Ammo) then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ self.reloading = true
+ self.reloadtimer = CurTime() + self.ReloadDelay
+ self:SendWeaponAnim(ACT_SHOTGUN_RELOAD_START)
+ self.Owner:DoReloadEvent()
+ self:SetNextReload(CurTime() + self:SequenceDuration())
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if self:CanPrimaryAttack() then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ self:EmitSound(self.Primary.Sound)
+
+ local clip = self:Clip1()
+
+ self:ShootBullets(self.Primary.Damage, self.Primary.NumShots * clip, self:GetCone())
+
+ self:TakePrimaryAmmo(clip)
+ self.Owner:ViewPunch(clip * 0.5 * self.Primary.Recoil * Angle(math.Rand(-0.1, -0.1), math.Rand(-0.1, 0.1), 0))
+
+ self.Owner:SetGroundEntity(NULL)
+ self.Owner:SetVelocity(-80 * clip * self.Owner:GetAimVector())
+
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+ end
+end
+
+function SWEP:Think()
+ if self.reloading and self.reloadtimer < CurTime() then
+ self.reloadtimer = CurTime() + self.ReloadDelay
+ self:SendWeaponAnim(ACT_VM_RELOAD)
+
+ self.Owner:RemoveAmmo(1, self.Primary.Ammo, false)
+ self:SetClip1(self:Clip1() + 1)
+ self:EmitSound("Weapon_Shotgun.Reload")
+
+ if self.Primary.ClipSize <= self:Clip1() or self.Owner:GetAmmoCount(self.Primary.Ammo) <= 0 or not self.Owner:KeyDown(IN_RELOAD) then
+ self.nextreloadfinish = CurTime() + self.ReloadDelay
+ self.reloading = false
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ end
+ end
+
+ local nextreloadfinish = self.nextreloadfinish
+ if nextreloadfinish ~= 0 and nextreloadfinish < CurTime() then
+ self:SendWeaponAnim(ACT_SHOTGUN_PUMP)
+ self:EmitSound("Weapon_Shotgun.Special1")
+ self.nextreloadfinish = 0
+ end
+
+ if self.IdleAnimation and self.IdleAnimation <= CurTime() then
+ self.IdleAnimation = nil
+ self:SendWeaponAnim(ACT_VM_IDLE)
+ end
+
+ if self:GetIronsights() and not self.Owner:KeyDown(IN_ATTACK2) then
+ self:SetIronsights(false)
+ end
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:Clip1() <= 0 then
+ self:EmitSound("Weapon_Shotgun.Empty")
+ self:SetNextPrimaryFire(CurTime() + 0.25)
+ return false
+ end
+
+ if self.reloading then
+ if self:Clip1() < self.Primary.ClipSize then
+ self:SendWeaponAnim(ACT_SHOTGUN_RELOAD_FINISH)
+ else
+ self:SendWeaponAnim(ACT_SHOTGUN_PUMP)
+ self:EmitSound("Weapon_Shotgun.Special1")
+ end
+ self.reloading = false
+ self:SetNextPrimaryFire(CurTime() + 0.25)
+ return false
+ end
+
+ return self:GetNextPrimaryFire() <= CurTime()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bulletstorm.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bulletstorm.lua
new file mode 100644
index 0000000..984eb56
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bulletstorm.lua
@@ -0,0 +1,86 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Bullet Storm' SMG"
+ SWEP.Description = "Hold right click to use the Storm firing mode: fire rate is reduced to 60% but two bullets are fired at once."
+ SWEP.Slot = 2
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 50
+
+ SWEP.HUD3DBone = "v_weapon.p90_Release"
+ SWEP.HUD3DPos = Vector(-1.35, -0.5, -6.5)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "smg"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_smg_p90.mdl"
+SWEP.WorldModel = "models/weapons/w_smg_p90.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("Weapon_p90.Single")
+SWEP.Primary.Damage = 15.5
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.07
+
+SWEP.Primary.ClipSize = 50
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "smg1"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.ConeMax = 0.11
+SWEP.ConeMin = 0.06
+
+SWEP.Primary.Gesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1
+SWEP.ReloadGesture = ACT_HL2MP_GESTURE_RELOAD_SMG1
+
+SWEP.WalkSpeed = SPEED_SLOW
+
+SWEP.IronSightsPos = Vector(-2, 6, 3)
+SWEP.IronSightsAng = Vector(0, 2, 0)
+
+SWEP.Primary.DefaultNumShots = SWEP.Primary.NumShots
+SWEP.Primary.DefaultDelay = SWEP.Primary.Delay
+SWEP.Primary.IronsightsNumShots = SWEP.Primary.NumShots * 2
+SWEP.Primary.IronsightsDelay = SWEP.Primary.Delay * 1.6666
+
+function SWEP:SetIronsights(b)
+ if self:GetIronsights() ~= b then
+ if b then
+ self.Primary.NumShots = self.Primary.IronsightsNumShots
+ self.Primary.Delay = self.Primary.IronsightsDelay
+
+ self:EmitSound("npc/scanner/scanner_scan4.wav", 40)
+ else
+ self.Primary.NumShots = self.Primary.DefaultNumShots
+ self.Primary.Delay = self.Primary.DefaultDelay
+
+ self:EmitSound("npc/scanner/scanner_scan2.wav", 40)
+ end
+ end
+
+ self.BaseClass.SetIronsights(self, b)
+end
+
+function SWEP:CanPrimaryAttack()
+ if self:GetIronsights() and self:Clip1() == 1 then
+ self:SetIronsights(false)
+ end
+
+ return self.BaseClass.CanPrimaryAttack(self)
+end
+
+function SWEP:TakeAmmo()
+ if self:GetIronsights() then
+ self:TakePrimaryAmmo(2)
+ else
+ self.BaseClass.TakeAmmo(self)
+ end
+end
+
+util.PrecacheSound("npc/scanner/scanner_scan4.wav")
+util.PrecacheSound("npc/scanner/scanner_scan2.wav")
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_burster.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_burster.lua
new file mode 100644
index 0000000..fe18459
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_burster.lua
@@ -0,0 +1,54 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.ChargeTime = 2
+
+function SWEP:PrimaryAttack()
+ if self:GetChargeStart() == 0 then
+ self:SetChargeStart(CurTime())
+ self.Owner:EmitSound("weapons/cguard/charging.wav", 80, 60)
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+ self.BaseClass.SecondaryAttack(self)
+end
+
+function SWEP:Think()
+ if self:GetCharge() >= 1 then
+ self.Owner:Kill()
+ end
+
+ self:NextThink(CurTime())
+ return true
+end
+
+function SWEP:IsMoaning()
+ return false
+end
+
+function SWEP:Move(mv)
+ local charge = self:GetCharge()
+ if charge > 0 then
+ mv:SetMaxSpeed(mv:GetMaxSpeed() * math.max(0, 1 - charge * 2))
+ mv:SetMaxClientSpeed(mv:GetMaxSpeed())
+ end
+end
+
+function SWEP:SetChargeStart(time)
+ self:SetDTFloat(0, time)
+end
+
+function SWEP:GetChargeStart()
+ return self:GetDTFloat(0)
+end
+
+function SWEP:GetCharge()
+ if self:GetChargeStart() == 0 then return 0 end
+
+ return math.Clamp((CurTime() - self:GetChargeStart()) / self.ChargeTime, 0, 1)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bust.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bust.lua
new file mode 100644
index 0000000..53769ec
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_bust.lua
@@ -0,0 +1,53 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Bust-on-a-stick"
+ SWEP.ViewModelFOV = 70
+ SWEP.ViewModelFlip = false
+
+ SWEP.ShowViewModel = true
+ SWEP.ShowWorldModel = false
+
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props_combine/breenbust.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(6, -2, -17), angle = Angle(180, 0, 0), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["stick"] = { type = "Model", model = "models/props_docks/dock01_pole01a_128.mdl", bone = "ValveBiped.Bip01", rel = "base", pos = Vector(3.25, 3.194, -20.932), angle = Angle(5, 0, 0), size = Vector(0.15, 0.15, 0.15), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props_combine/breenbust.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(0, 1, -20), angle = Angle(180, 270, 0), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["stick"] = { type = "Model", model = "models/props_docks/dock01_pole01a_128.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "base", pos = Vector(0, -3, -18), angle = Angle(0, 0, 0), size = Vector(0.1, 0.1, 0.1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.DamageType = DMG_CLUB
+
+SWEP.ViewModel = "models/weapons/c_crowbar.mdl"
+SWEP.WorldModel = Model("models/props_combine/breenbust.mdl")
+SWEP.UseHands = true
+
+SWEP.MeleeDamage = 100
+SWEP.MeleeRange = 60
+SWEP.MeleeSize = 1.4
+
+SWEP.UseMelee1 = false
+
+SWEP.HitGesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE
+SWEP.MissGesture = SWEP.HitGesture
+
+SWEP.SwingRotation = Angle(30, -30, -30)
+SWEP.SwingTime = 0.3
+SWEP.SwingHoldType = "grenade"
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("weapons/iceaxe/iceaxe_swing1.wav", 75, math.Rand(35, 45))
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("physics/concrete/rock_impact_hard"..math.random(6)..".wav", 75, math.Rand(86, 90))
+end
+
+function SWEP:PlayHitFleshSound()
+ self:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav", 75, math.Rand(86, 90))
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_butcherknife.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_butcherknife.lua
new file mode 100644
index 0000000..f157972
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_butcherknife.lua
@@ -0,0 +1,62 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Butcher Knife"
+
+ SWEP.ViewModelFOV = 55
+ SWEP.ViewModelFlip = false
+
+ SWEP.ShowViewModel = false
+ SWEP.ShowWorldModel = false
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props_lab/cleaver.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(3, 1, -1), angle = Angle(90, 0, 0), size = Vector(0.8, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props_lab/cleaver.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(3, 1, -3.182), angle = Angle(90, 0, 0), size = Vector(0.8, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.DamageType = DMG_SLASH
+
+SWEP.ViewModel = "models/weapons/c_crowbar.mdl"
+SWEP.WorldModel = "models/weapons/w_crowbar.mdl"
+SWEP.UseHands = true
+SWEP.NoDroppedWorldModel = true
+--[[SWEP.BoxPhysicsMax = Vector(8, 1, 4)
+SWEP.BoxPhysicsMin = Vector(-8, -1, -4)]]
+
+SWEP.MeleeDamage = 40
+SWEP.MeleeRange = 48
+SWEP.MeleeSize = 0.875
+SWEP.Primary.Delay = 0.7
+
+SWEP.WalkSpeed = SPEED_FAST
+
+SWEP.UseMelee1 = true
+
+SWEP.HitGesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE
+SWEP.MissGesture = SWEP.HitGesture
+
+SWEP.HitDecal = "Manhackcut"
+SWEP.HitAnim = ACT_VM_MISSCENTER
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("weapons/knife/knife_slash"..math.random(2)..".wav", 72, math.Rand(85, 95))
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("weapons/knife/knife_hitwall1.wav", 72, math.Rand(75, 85))
+end
+
+function SWEP:PlayHitFleshSound()
+ self:EmitSound("physics/flesh/flesh_squishy_impact_hard"..math.random(4)..".wav")
+ self:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav")
+end
+
+function SWEP:PostOnMeleeHit(hitent, hitflesh, tr)
+ if hitent:IsValid() and hitent:IsPlayer() and hitent:Health() <= 0 then
+ -- Dismember closest limb to tr.HitPos
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_butcherknifez.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_butcherknifez.lua
new file mode 100644
index 0000000..c228f5e
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_butcherknifez.lua
@@ -0,0 +1,17 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_butcherknife"
+
+SWEP.ZombieOnly = true
+SWEP.MeleeDamage = 30
+SWEP.Primary.Delay = 0.4
+
+function SWEP:OnMeleeHit(hitent, hitflesh, tr)
+ if not hitent:IsPlayer() then
+ self.MeleeDamage = 11
+ end
+end
+
+function SWEP:PostOnMeleeHit(hitent, hitflesh, tr)
+ self.MeleeDamage = 24
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_chemzombie/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_chemzombie/cl_init.lua
new file mode 100644
index 0000000..b8ca775
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_chemzombie/cl_init.lua
@@ -0,0 +1,12 @@
+include("shared.lua")
+
+SWEP.PrintName = "Chem Zombie"
+SWEP.DrawCrosshair = false
+
+function SWEP:Think()
+end
+
+function SWEP:DrawHUD()
+ if GetConVarNumber("crosshair") ~= 1 then return end
+ self:DrawCrosshairDot()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_chemzombie/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_chemzombie/init.lua
new file mode 100644
index 0000000..61d9473
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_chemzombie/init.lua
@@ -0,0 +1,23 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+SWEP.NextAura = 0
+function SWEP:Think()
+ if self.IdleAnimation and self.IdleAnimation <= CurTime() then
+ self.IdleAnimation = nil
+ self:SendWeaponAnim(ACT_VM_IDLE)
+ end
+
+ if self.NextAura <= CurTime() then
+ self.NextAura = CurTime() + 2
+
+ local origin = self.Owner:LocalToWorld(self.Owner:OBBCenter())
+ for _, ent in pairs(ents.FindInSphere(origin, 40)) do
+ if ent:IsPlayer() and ent:Team() ~= TEAM_UNDEAD and ent:Alive() and TrueVisible(origin, ent:NearestPoint(origin)) then
+ ent:PoisonDamage(1, self.Owner, self)
+ end
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_chemzombie/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_chemzombie/shared.lua
new file mode 100644
index 0000000..1ba5c97
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_chemzombie/shared.lua
@@ -0,0 +1,33 @@
+SWEP.ZombieOnly = true
+
+SWEP.ViewModel = "models/weapons/v_crowbar.mdl"
+SWEP.WorldModel = "models/weapons/w_crowbar.mdl"
+
+SWEP.Primary.ClipSize = -1
+SWEP.Primary.DefaultClip = -1
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "none"
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = true
+SWEP.Secondary.Ammo = "none"
+
+function SWEP:Deploy()
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ return true
+end
+
+function SWEP:Initialize()
+ self:HideViewAndWorldModel()
+end
+
+function SWEP:PrimaryAttack()
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_classiczombie.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_classiczombie.lua
new file mode 100644
index 0000000..c18df0f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_classiczombie.lua
@@ -0,0 +1,159 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.MeleeDamage = 20
+
+function SWEP:Reload()
+ self.BaseClass.SecondaryAttack(self)
+end
+
+function SWEP:StartMoaning()
+end
+
+function SWEP:StopMoaning()
+end
+
+function SWEP:IsMoaning()
+ return false
+end
+
+SWEP.NextClimbSound = 0
+function SWEP:Think()
+ local curtime = CurTime()
+ local owner = self.Owner
+
+ if self:GetClimbing() then
+ if self:GetClimbSurface() and owner:KeyDown(IN_ATTACK2) then
+ if SERVER and CurTime() >= self.NextClimbSound then
+ local speed = owner:GetVelocity():Length()
+ if speed >= 16 then
+ if speed >= 50 then
+ self.NextClimbSound = CurTime() + 0.75
+ else
+ self.NextClimbSound = CurTime() + 1
+ end
+ owner:EmitSound("player/footsteps/metalgrate"..math.random(4)..".wav")
+ end
+ end
+ else
+ self:StopClimbing()
+ end
+ end
+
+ return self.BaseClass.Think(self)
+end
+
+local climblerp = 0
+function SWEP:GetViewModelPosition(pos, ang)
+ climblerp = math.Approach(climblerp, self:IsClimbing() and 1 or 0, FrameTime() * ((climblerp + 1) ^ 3))
+ ang:RotateAroundAxis(ang:Right(), 64 * climblerp)
+ if climblerp > 0 then
+ pos = pos + -8 * climblerp * ang:Up() + -12 * climblerp * ang:Forward()
+ end
+
+ return self.BaseClass.GetViewModelPosition(self, pos, ang)
+end
+
+function SWEP:PrimaryAttack()
+ if self:IsClimbing() then return end
+
+ self.BaseClass.PrimaryAttack(self)
+end
+
+local climbtrace = {mask = MASK_SOLID_BRUSHONLY, mins = Vector(-5, -5, -5), maxs = Vector(5, 5, 5)}
+function SWEP:GetClimbSurface()
+ local owner = self.Owner
+
+ local fwd = owner:SyncAngles():Forward()
+ local up = owner:GetUp()
+ local pos = owner:GetPos()
+ local tr
+ for i=-15, owner:OBBMaxs().z, 5 do
+ if not tr or not tr.Hit then
+ climbtrace.start = pos + up * i
+ climbtrace.endpos = climbtrace.start + fwd * 28
+ tr = util.TraceHull(climbtrace)
+ if tr.Hit and not tr.HitSky then break end
+ end
+ end
+
+ if tr.Hit and not tr.HitSky then
+ climbtrace.start = tr.HitPos + tr.HitNormal
+ climbtrace.endpos = climbtrace.start + owner:SyncAngles():Up() * 72
+ local tr2 = util.TraceHull(climbtrace)
+ if tr2.Hit and not tr2.HitSky then
+ return tr2
+ end
+
+ return tr
+ end
+end
+
+function SWEP:SecondaryAttack()
+ if self:IsClimbing() then return end
+
+ if not self.Owner:IsOnGround() and self.Owner:GetVelocity():Length() < 200 and self:GetClimbSurface() then
+ self:StartClimbing()
+ else
+ self.BaseClass.SecondaryAttack(self)
+ end
+end
+
+function SWEP:StartClimbing()
+ if self:GetClimbing() then return end
+
+ self:SetClimbing(true)
+
+ self:SetNextPrimaryFire(math.huge)
+end
+
+function SWEP:StopClimbing()
+ if not self:GetClimbing() then return end
+
+ self:SetClimbing(false)
+
+ self:SetNextPrimaryFire(CurTime() + 0.5)
+end
+
+function SWEP:Move(mv)
+ if self:GetClimbing() then
+ mv:SetMaxSpeed(0)
+ mv:SetMaxClientSpeed(0)
+
+ local owner = self.Owner
+ local tr = self:GetClimbSurface()
+ local angs = self.Owner:SyncAngles()
+ local dir = tr and tr.Hit and (tr.HitNormal.z <= -0.5 and (angs:Forward() * -1) or math.abs(tr.HitNormal.z) < 0.75 and tr.HitNormal:Angle():Up()) or Vector(0, 0, 1)
+ local vel = Vector(0, 0, 4)
+
+ if owner:KeyDown(IN_FORWARD) then
+ vel = vel + dir * 60
+ end
+ if owner:KeyDown(IN_BACK) then
+ vel = vel + dir * -60
+ end
+
+ if vel.z == 4 then
+ if owner:KeyDown(IN_MOVERIGHT) then
+ vel = vel + angs:Right() * 35
+ end
+ if owner:KeyDown(IN_MOVELEFT) then
+ vel = vel + angs:Right() * -35
+ end
+ end
+
+ mv:SetVelocity(vel)
+
+ return true
+ end
+end
+
+function SWEP:SetClimbing(climbing)
+ self:SetDTBool(1, climbing)
+end
+
+function SWEP:GetClimbing()
+ return self:GetDTBool(1)
+end
+SWEP.IsClimbing = SWEP.GetClimbing
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crackler.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crackler.lua
new file mode 100644
index 0000000..5e5ab5c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crackler.lua
@@ -0,0 +1,40 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Crackler' Assault Rifle"
+ SWEP.Slot = 2
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+
+ SWEP.HUD3DBone = "v_weapon.famas"
+ SWEP.HUD3DPos = Vector(1.1, -3.5, 10)
+ SWEP.HUD3DScale = 0.02
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "ar2"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_rif_famas.mdl"
+SWEP.WorldModel = "models/weapons/w_rif_famas.mdl"
+SWEP.UseHands = true
+
+SWEP.ReloadSound = Sound("Weapon_FAMAS.Clipout")
+SWEP.Primary.Sound = Sound("Weapon_FAMAS.Single")
+SWEP.Primary.Damage = 16
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.175
+
+SWEP.Primary.ClipSize = 22
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "ar2"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.ConeMax = 0.045
+SWEP.ConeMin = 0.019
+
+SWEP.WalkSpeed = SPEED_SLOW
+
+SWEP.IronSightsPos = Vector(-3, 3, 2)
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crossbow.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crossbow.lua
new file mode 100644
index 0000000..fb98d58
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crossbow.lua
@@ -0,0 +1,187 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Impaler' Crossbow"
+ SWEP.Description = "This ancient weapon can easily skewer groups of zombies."
+
+ SWEP.HUD3DBone = "ValveBiped.Crossbow_base"
+ SWEP.HUD3DPos = Vector(1.5, 0.5, 11)
+ SWEP.HUD3DScale = 0.025
+
+ SWEP.ViewModelFOV = 60
+ SWEP.ViewModelFlip = false
+
+ SWEP.Slot = 3
+ SWEP.SlotPos = 0
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "crossbow"
+
+SWEP.ViewModel = "models/weapons/c_crossbow.mdl"
+SWEP.WorldModel = "models/weapons/w_crossbow.mdl"
+SWEP.UseHands = true
+
+SWEP.CSMuzzleFlashes = false
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "XBowBolt"
+SWEP.Primary.Delay = 2.0
+SWEP.Primary.DefaultClip = 15
+
+SWEP.SecondaryDelay = 0.25
+
+SWEP.WalkSpeed = SPEED_SLOW
+
+SWEP.NextZoom = 0
+
+if SERVER then
+ function SWEP:PrimaryAttack()
+ if self:CanPrimaryAttack() then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+
+ local owner = self.Owner
+
+ self:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
+ owner:RestartGesture(ACT_HL2MP_GESTURE_RANGE_ATTACK_CROSSBOW)
+
+ self:TakePrimaryAmmo(1)
+
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ self:EmitSound("Weapon_Crossbow.Single")
+
+ local ent = ents.Create("projectile_arrow")
+ if ent:IsValid() then
+ ent:SetOwner(owner)
+ ent:SetPos(owner:GetShootPos())
+ ent:SetAngles(owner:GetAimVector():Angle())
+ ent.Team = owner:Team()
+ ent:Spawn()
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:SetVelocityInstantaneous(owner:GetAimVector() * 1400)
+ end
+ end
+ end
+ end
+
+ function SWEP:Reload()
+ if self:GetNextReload() <= CurTime() and self:Clip1() == 0 and 0 < self.Owner:GetAmmoCount("XBowBolt") then
+ self:EmitSound("weapons/crossbow/bolt_load"..math.random(2)..".wav", 50, 100)
+ self:EmitSound("weapons/crossbow/reload1.wav")
+ self:DefaultReload(ACT_VM_RELOAD)
+ self.Owner:RestartGesture(ACT_HL2MP_GESTURE_RELOAD_CROSSBOW)
+ self:SetNextReload(CurTime() + self:SequenceDuration())
+ end
+ end
+
+ function SWEP:SecondaryAttack()
+ if CurTime() < self.NextZoom then return end
+
+ self.NextZoom = CurTime() + self.SecondaryDelay
+
+ local zoomed = self:GetDTBool(1)
+ self:SetDTBool(1, not zoomed)
+
+ if zoomed then
+ self.Owner:SetFOV(self.Owner:GetInfo("fov_desired"), 0.15)
+ self:EmitSound("weapons/sniper/sniper_zoomout.wav", 50, 100)
+ else
+ self.Owner:SetFOV(self.Owner:GetInfo("fov_desired") * 0.25, 0.15)
+ self:EmitSound("weapons/sniper/sniper_zoomin.wav", 50, 100)
+ end
+ end
+end
+
+if CLIENT then
+ function SWEP:PrimaryAttack()
+ if self:CanPrimaryAttack() then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ self:TakePrimaryAmmo(1)
+ self:EmitSound("Weapon_Crossbow.Single")
+ self.Owner:RestartGesture(ACT_HL2MP_GESTURE_RANGE_ATTACK_CROSSBOW)
+ self:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+ end
+ end
+
+ function SWEP:SecondaryAttack()
+ if CurTime() < self.NextZoom then return end
+ self.NextZoom = CurTime() + self.SecondaryDelay
+
+ local zoomed = self:GetDTBool(1)
+ self:SetDTBool(1, not zoomed)
+ if zoomed then
+ surface.PlaySound("weapons/sniper/sniper_zoomout.wav")
+ else
+ surface.PlaySound("weapons/sniper/sniper_zoomin.wav")
+ end
+ end
+
+ function SWEP:Reload()
+ if self:GetNextReload() <= CurTime() and self:Clip1() == 0 and 0 < self.Owner:GetAmmoCount("XBowBolt") then
+ surface.PlaySound("weapons/crossbow/bolt_load"..math.random(1,2)..".wav")
+ self:DefaultReload(ACT_VM_RELOAD)
+ self.Owner:RestartGesture(ACT_HL2MP_GESTURE_RELOAD_CROSSBOW)
+ self:SetNextReload(CurTime() + self:SequenceDuration())
+ end
+ end
+
+ local texScope = surface.GetTextureID("zombiesurvival/scope")
+ function SWEP:DrawHUDBackground()
+ if self:GetDTBool(1) then
+ local scrw, scrh = ScrW(), ScrH()
+ local size = math.min(scrw, scrh)
+
+ local hw = scrw * 0.5
+ local hh = scrh * 0.5
+
+ surface.SetDrawColor(255, 0, 0, 180)
+ surface.DrawLine(0, hh, scrw, hh)
+ surface.DrawLine(hw, 0, hw, scrh)
+ for i=1, 10 do
+ surface.DrawLine(hw, hh + i * 7, hw + (50 - i * 5), hh + i * 7)
+ end
+
+ surface.SetTexture(texScope)
+ surface.SetDrawColor(255, 255, 255, 255)
+ surface.DrawTexturedRect((scrw - size) * 0.5, (scrh - size) * 0.5, size, size)
+ surface.SetDrawColor(0, 0, 0, 255)
+ if scrw > size then
+ local extra = (scrw - size) * 0.5
+ surface.DrawRect(0, 0, extra, scrh)
+ surface.DrawRect(scrw - extra, 0, extra, scrh)
+ end
+ if scrh > size then
+ local extra = (scrh - size) * 0.5
+ surface.DrawRect(0, 0, scrw, extra)
+ surface.DrawRect(0, scrh - extra, scrw, extra)
+ end
+ end
+ end
+end
+
+function SWEP:Holster()
+ if self:GetDTBool(1) then
+ self.Owner:SetFOV(self.Owner:GetInfo("fov_desired"), 0.5)
+ self:EmitSound("weapons/sniper/sniper_zoomout.wav", 50, 100)
+ self:SetDTBool(1, false)
+ end
+
+ return true
+end
+
+function SWEP:OnRemove()
+ if self.Owner:IsValid() and self:GetDTBool(1) then
+ self.Owner:SetFOV(self.Owner:GetInfo("fov_desired"), 0.5)
+ end
+end
+
+util.PrecacheSound("weapons/crossbow/bolt_load1.wav")
+util.PrecacheSound("weapons/crossbow/bolt_load2.wav")
+util.PrecacheSound("weapons/sniper/sniper_zoomin.wav")
+util.PrecacheSound("weapons/sniper/sniper_zoomout.wav")
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crow/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crow/cl_init.lua
new file mode 100644
index 0000000..022a2ae
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crow/cl_init.lua
@@ -0,0 +1,16 @@
+include("shared.lua")
+
+SWEP.PrintName = "Crow"
+SWEP.DrawCrosshair = false
+
+function SWEP:PrimaryAttack()
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+end
+
+function SWEP:Think()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crow/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crow/init.lua
new file mode 100644
index 0000000..97ba69d
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crow/init.lua
@@ -0,0 +1,93 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function SWEP:Deploy()
+ self.Owner.SkipCrow = true
+ return true
+end
+
+function SWEP:Holster()
+ local owner = self.Owner
+ if owner:IsValid() then
+ owner:StopSound("NPC_Crow.Flap")
+ owner:SetAllowFullRotation(false)
+ end
+end
+SWEP.OnRemove = SWEP.Holster
+
+function SWEP:Think()
+ local owner = self.Owner
+
+ if owner:KeyDown(IN_WALK) then
+ owner:TrySpawnAsGoreChild()
+ return
+ end
+
+ local fullrot = not owner:OnGround()
+ if owner:GetAllowFullRotation() ~= fullrot then
+ owner:SetAllowFullRotation(fullrot)
+ end
+
+ if owner:IsOnGround() or not owner:KeyDown(IN_JUMP) or not owner:KeyDown(IN_FORWARD) then
+ if self.PlayFlap then
+ owner:StopSound("NPC_Crow.Flap")
+ self.PlayFlap = nil
+ end
+ else
+ if not self.PlayFlap then
+ owner:EmitSound("NPC_Crow.Flap")
+ self.PlayFlap = true
+ end
+ end
+
+ local peckend = self:GetPeckEndTime()
+ if peckend == 0 or CurTime() < peckend then return end
+ self:SetPeckEndTime(0)
+
+ local trace = owner:TraceLine(14, MASK_SOLID)
+ local ent = NULL
+ if trace.Entity then
+ ent = trace.Entity
+ end
+
+ owner:ResetSpeed()
+
+ if ent:IsValid() then
+ local phys = ent:GetPhysicsObject()
+ if ent:IsPlayer() and (ent:Team() ~= TEAM_UNDEAD or ent:GetZombieClassTable().Name ~= "Crow") then
+ return
+ end
+
+ ent:TakeSpecialDamage(2, DMG_SLASH, owner, self)
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if CurTime() < self:GetNextPrimaryFire() or not self.Owner:IsOnGround() then return end
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+
+ if self.Owner:Team() ~= TEAM_UNDEAD then self.Owner:Kill() return end
+
+ self.Owner:EmitSound("NPC_Crow.Squawk")
+ self.Owner.EatAnim = CurTime() + 2
+
+ self:SetPeckEndTime(CurTime() + 1)
+
+ self.Owner:SetSpeed(1)
+end
+
+function SWEP:SecondaryAttack()
+ if CurTime() < self:GetNextSecondaryFire() then return end
+ self:SetNextSecondaryFire(CurTime() + 1.6)
+
+ if self.Owner:Team() ~= TEAM_UNDEAD then self.Owner:Kill() return end
+
+ self.Owner:EmitSound("NPC_Crow.Alert")
+end
+
+function SWEP:Reload()
+ self:SecondaryAttack()
+ return false
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crow/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crow/shared.lua
new file mode 100644
index 0000000..156d52c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crow/shared.lua
@@ -0,0 +1,44 @@
+SWEP.ZombieOnly = true
+SWEP.IsMelee = true
+SWEP.IsCrow = true
+
+SWEP.ViewModel = "models/weapons/v_knife_t.mdl"
+SWEP.WorldModel = "models/weapons/w_knife_t.mdl"
+
+SWEP.Primary.ClipSize = -1
+SWEP.Primary.DefaultClip = -1
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "none"
+SWEP.Primary.Delay = 2
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = true
+SWEP.Secondary.Ammo = "none"
+
+function SWEP:Initialize()
+ self:HideViewAndWorldModel()
+end
+
+function SWEP:OnRemove()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ if owner.Flapping then
+ owner:StopSound("NPC_Crow.Flap")
+ end
+ owner.Flapping = nil
+ end
+end
+SWEP.Holster = SWEP.OnRemove
+
+function SWEP:SetPeckEndTime(time)
+ self:SetDTFloat(0, time)
+end
+
+function SWEP:GetPeckEndTime()
+ return self:GetDTFloat(0)
+end
+
+function SWEP:IsPecking()
+ return CurTime() < self:GetPeckEndTime()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crowbar.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crowbar.lua
new file mode 100644
index 0000000..8e0e2ce
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_crowbar.lua
@@ -0,0 +1,45 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Crowbar"
+ SWEP.Description = "Instantly kills headcrabs."
+
+ SWEP.ViewModelFOV = 65
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.ViewModel = "models/weapons/c_crowbar.mdl"
+SWEP.WorldModel = "models/weapons/w_crowbar.mdl"
+SWEP.UseHands = true
+
+SWEP.HoldType = "melee"
+
+SWEP.MeleeDamage = 35
+SWEP.MeleeRange = 55
+SWEP.MeleeSize = 1.5
+SWEP.MeleeKnockBack = SWEP.MeleeDamage * 1.5
+
+SWEP.Primary.Delay = 0.7
+
+SWEP.SwingTime = 0.4
+SWEP.SwingRotation = Angle(30, -30, -30)
+SWEP.SwingHoldType = "grenade"
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("Weapon_Crowbar.Single")
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("Weapon_Crowbar.Melee_HitWorld")
+end
+
+function SWEP:PlayHitFleshSound()
+ self:EmitSound("Weapon_Crowbar.Melee_Hit")
+end
+
+function SWEP:OnMeleeHit(hitent, hitflesh, tr)
+ if hitent:IsValid() and hitent:IsPlayer() and hitent:Team() == TEAM_UNDEAD and hitent:IsHeadcrab() and gamemode.Call("PlayerShouldTakeDamage", hitent, self.Owner) then
+ hitent:SetHealth(1)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_deagle.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_deagle.lua
new file mode 100644
index 0000000..4d7bc73
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_deagle.lua
@@ -0,0 +1,40 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Zombie Drill' Desert Eagle"
+ SWEP.Description = "This handgun uses high-powered rounds that have more knockback than others." --SWEP.Description = "This high-powered handgun has the ability to pierce through multiple zombies. The bullet's power decreases by half which each zombie it hits."
+ SWEP.Slot = 1
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 55
+
+ SWEP.HUD3DBone = "v_weapon.Deagle_Slide"
+ SWEP.HUD3DPos = Vector(-1, 0, 1)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+ SWEP.HUD3DScale = 0.015
+
+ SWEP.IronSightsPos = Vector(-6.35, 5, 1.7)
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "revolver"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_pist_deagle.mdl"
+SWEP.WorldModel = "models/weapons/w_pist_deagle.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("Weapon_Deagle.Single")
+SWEP.Primary.Damage = 47
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.32
+SWEP.Primary.KnockbackScale = 2
+
+SWEP.Primary.ClipSize = 7
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "pistol"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.ConeMax = 0.1
+SWEP.ConeMin = 0.04
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_detpack/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_detpack/cl_init.lua
new file mode 100644
index 0000000..cb0f1be
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_detpack/cl_init.lua
@@ -0,0 +1,26 @@
+include("shared.lua")
+
+SWEP.PrintName = "Remote Detonation Pack"
+SWEP.Description = "A pack of explosives that can be placed on surfaces and detonated remotely.\nPress PRIMARY ATTACK to deploy.\nPress PRIMARY ATTACK again to detonate.\nPress SPRINT on a deployed detonation pack to disarm and retrieve it."
+SWEP.DrawCrosshair = false
+
+SWEP.Slot = 4
+SWEP.SlotPos = 0
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ return true
+end
+
+function SWEP:DrawHUD()
+ if GetConVarNumber("crosshair") ~= 1 then return end
+ self:DrawCrosshairDot()
+end
+
+function SWEP:PrimaryAttack()
+end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_detpack/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_detpack/init.lua
new file mode 100644
index 0000000..532efbe
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_detpack/init.lua
@@ -0,0 +1,87 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self:SpawnGhost()
+
+ return true
+end
+
+function SWEP:OnRemove()
+ self:RemoveGhost()
+end
+
+function SWEP:Holster()
+ self:RemoveGhost()
+ return true
+end
+
+function SWEP:SpawnGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:GiveStatus("ghost_detpack")
+ end
+end
+
+function SWEP:RemoveGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:RemoveStatus("ghost_detpack", false, true)
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+
+ local owner = self.Owner
+
+ local status = owner.status_ghost_detpack
+ if not (status and status:IsValid()) then return end
+ status:RecalculateValidity()
+ if not status:GetValidPlacement() then return end
+
+ local pos, ang, entity = status:RecalculateValidity()
+ if not pos or not ang then return end
+
+ self:SetNextPrimaryAttack(CurTime() + self.Primary.Delay)
+
+ local ent = ents.Create("prop_detpack")
+ if ent:IsValid() then
+ ent:SetPos(pos)
+ ent:SetAngles(ang)
+ ent:Spawn()
+ if entity and entity:IsValid() then
+ ent:SetParent(entity)
+ end
+
+ ent:EmitSound("weapons/c4/c4_plant.wav")
+
+ self:TakePrimaryAmmo(1)
+
+ ent:SetOwner(self.Owner)
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ owner:StripWeapon(self:GetClass())
+ end
+
+ if not owner:HasWeapon("weapon_zs_detpackremote") then
+ owner:Give("weapon_zs_detpackremote")
+ end
+ owner:SelectWeapon("weapon_zs_detpackremote")
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Think()
+ local count = self:GetPrimaryAmmoCount()
+ if count ~= self:GetReplicatedAmmo() then
+ self:SetReplicatedAmmo(count)
+ self.Owner:ResetSpeed()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_detpack/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_detpack/shared.lua
new file mode 100644
index 0000000..eefaa35
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_detpack/shared.lua
@@ -0,0 +1,66 @@
+SWEP.ViewModel = "models/weapons/v_pistol.mdl"
+SWEP.WorldModel = Model("models/weapons/w_c4_planted.mdl")
+
+SWEP.AmmoIfHas = true
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.DefaultClip = 1
+SWEP.Primary.Ammo = "sniperpenetratedround"
+SWEP.Primary.Delay = 1
+SWEP.Primary.Automatic = true
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_NORMAL
+SWEP.FullWalkSpeed = SPEED_SLOW
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType("slam")
+ self:SetDeploySpeed(1.1)
+ self:HideViewAndWorldModel()
+end
+
+function SWEP:SetReplicatedAmmo(count)
+ self:SetDTInt(0, count)
+end
+
+function SWEP:GetReplicatedAmmo()
+ return self:GetDTInt(0)
+end
+
+function SWEP:GetWalkSpeed()
+ if self:GetPrimaryAmmoCount() > 0 then
+ return self.FullWalkSpeed
+ end
+end
+
+function SWEP:Reload()
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ return false
+ end
+
+ return true
+end
+
+function SWEP:CanSecondaryAttack()
+ return false
+end
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ return true
+end
+
+function SWEP:Holster()
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_detpackremote.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_detpackremote.lua
new file mode 100644
index 0000000..06e4b09
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_detpackremote.lua
@@ -0,0 +1,90 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.ViewModelFOV = 50
+ SWEP.BobScale = 0.5
+ SWEP.SwayScale = 0.5
+ SWEP.PrintName = "Detonation Pack Remote"
+ SWEP.Description = "Allows the user to remotely detonate their detonation packs."
+
+ SWEP.Slot = 4
+ SWEP.SlotPos = 0
+end
+
+SWEP.ViewModel = "models/weapons/c_slam.mdl"
+SWEP.WorldModel = "models/weapons/w_slam.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.ClipSize = -1
+SWEP.Primary.DefaultClip = -1
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "none"
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_NORMAL
+
+SWEP.NoMagazine = true
+SWEP.Undroppable = true
+SWEP.NoPickupNotification = true
+
+SWEP.HoldType = "slam"
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType(self.HoldType)
+end
+
+if SERVER then
+function SWEP:Think()
+ for _, ent in pairs(ents.FindByClass("prop_detpack")) do
+ if ent:GetOwner() == self.Owner then
+ return
+ end
+ end
+
+ self.Owner:StripWeapon(self:GetClass())
+end
+end
+
+function SWEP:PrimaryAttack()
+ self:SendWeaponAnim(ACT_SLAM_DETONATOR_DETONATE)
+
+ if CLIENT then return end
+
+ for _, ent in pairs(ents.FindByClass("prop_detpack")) do
+ if ent:GetOwner() == self.Owner and ent:GetExplodeTime() == 0 then
+ ent:SetExplodeTime(CurTime() + ent.ExplosionDelay)
+ end
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+ return false
+end
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self:SendWeaponAnim(ACT_SLAM_DETONATOR_IDLE)
+
+ return true
+end
+
+function SWEP:Holster()
+ return true
+end
+
+if not CLIENT then return end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
+
+function SWEP:Think()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_drone.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_drone.lua
new file mode 100644
index 0000000..b0c7866
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_drone.lua
@@ -0,0 +1,200 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Drone"
+ SWEP.Description = "A deployable, remotely controlled device.\nIdeal for scouting, retrieval, and targeted attacks."
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 50
+ SWEP.ShowViewModel = true
+ SWEP.ShowWorldModel = false
+
+ SWEP.ViewModelBoneMods = {
+ ["ValveBiped.cube1"] = { scale = Vector(0.009, 0.009, 0.009), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) },
+ ["ValveBiped.cube2"] = { scale = Vector(0.009, 0.009, 0.009), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) },
+ ["ValveBiped.cube3"] = { scale = Vector(0.009, 0.009, 0.009), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) },
+ ["ValveBiped.cube"] = { scale = Vector(0.009, 0.009, 0.009), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) }
+ }
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/combine_scanner.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(5, 4, 0), angle = Angle(-54.206, 58.294, -50.114), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/combine_scanner.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(5, 5, 0), angle = Angle(-43.978, 27.614, 0), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.ViewModel = "models/weapons/c_bugbait.mdl"
+SWEP.WorldModel = "models/combine_scanner.mdl"
+SWEP.UseHands = true
+
+SWEP.HoldType = "grenade"
+
+SWEP.WalkSpeed = SPEED_FAST
+
+SWEP.AmmoIfHas = true
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "drone"
+SWEP.Primary.Delay = 1
+SWEP.Primary.DefaultClip = 1
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_FAST
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType("grenade")
+ self:SetDeploySpeed(1.1)
+
+ if CLIENT then
+ self:Anim_Initialize()
+ end
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ for _, ent in pairs(ents.FindByClass("prop_drone")) do
+ if ent:GetOwner() == self.Owner then return false end
+ end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ return false
+ end
+
+ return true
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+
+ local owner = self.Owner
+ self:SendWeaponAnim(ACT_VM_THROW)
+ owner:DoAttackEvent()
+
+ self:TakePrimaryAmmo(1)
+ self.NextDeploy = CurTime() + 0.75
+
+ if SERVER then
+ local ent = ents.Create("prop_drone")
+ if ent:IsValid() then
+ ent:SetPos(owner:GetShootPos())
+ ent:SetOwner(owner)
+ ent:Spawn()
+
+ local stored = owner:PopPackedItem(ent:GetClass())
+ if stored then
+ ent:SetObjectHealth(stored[1])
+ end
+
+ ent:EmitSound("WeaponFrag.Throw")
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:SetVelocityInstantaneous(self.Owner:GetAimVector() * 200)
+ end
+
+ if not owner:HasWeapon("weapon_zs_dronecontrol") then
+ owner:Give("weapon_zs_dronecontrol")
+ end
+ owner:SelectWeapon("weapon_zs_dronecontrol")
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ owner:StripWeapon(self:GetClass())
+ end
+ end
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:CanSecondaryAttack()
+ return false
+end
+
+function SWEP:Reload()
+ return false
+end
+
+function SWEP:Deploy()
+ GAMEMODE:WeaponDeployed(self.Owner, self)
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SendWeaponAnim(ACT_VM_THROW)
+ end
+
+ return true
+end
+
+function SWEP:Holster()
+ self.NextDeploy = nil
+
+ if CLIENT then
+ self:Anim_Holster()
+ end
+
+ return true
+end
+
+function SWEP:Think()
+ if self.NextDeploy and self.NextDeploy <= CurTime() then
+ self.NextDeploy = nil
+
+ if 0 < self:GetPrimaryAmmoCount() then
+ self:SendWeaponAnim(ACT_VM_DRAW)
+ else
+ self:SendWeaponAnim(ACT_VM_THROW)
+ if SERVER then
+ self:Remove()
+ end
+ end
+ end
+end
+
+local colBG = Color(16, 16, 16, 90)
+local colWhite = Color(220, 220, 220, 230)
+
+SWEP.HUD3DPos = Vector(5, 2, 0)
+
+function SWEP:PostDrawViewModel(vm)
+ if not self.HUD3DPos or GAMEMODE.WeaponHUDMode == 1 then return end
+
+ local bone = vm:LookupBone("ValveBiped.Bip01_R_Hand")
+ if not bone then return end
+
+ local m = vm:GetBoneMatrix(bone)
+ if not m then return end
+
+ local pos, ang = m:GetTranslation(), m:GetAngles()
+
+ local offset = self.HUD3DPos
+
+ pos = pos + ang:Forward() * offset.x + ang:Right() * offset.y + ang:Up() * offset.z
+
+ ang:RotateAroundAxis(ang:Up(), math.sin(CurTime() * math.pi) * 20)
+ ang:RotateAroundAxis(ang:Right(), CurTime() * 180)
+
+ pos = pos + ang:Forward() * 7
+
+ ang:RotateAroundAxis(ang:Right(), 270)
+ ang:RotateAroundAxis(ang:Up(), 180)
+
+ local wid, hei = 144, 144
+ local x, y = wid * -0.5, hei * -0.5
+ local clip = self:GetPrimaryAmmoCount()
+
+ cam.Start3D2D(pos, ang, 0.0125)
+ draw.RoundedBox(32, x, y, wid, hei, colBG)
+ draw.SimpleText(clip, "ZS3D2DFontBig", x + wid * 0.5, y + hei * 0.5, colWhite, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+ cam.End3D2D()
+end
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_dronecontrol.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_dronecontrol.lua
new file mode 100644
index 0000000..70d9899
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_dronecontrol.lua
@@ -0,0 +1,102 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Drone Control"
+ SWEP.Description = "Controller for your Drone."
+
+ SWEP.ViewModelFOV = 50
+
+ SWEP.BobScale = 0.5
+ SWEP.SwayScale = 0.5
+
+ SWEP.Slot = 4
+ SWEP.SlotPos = 0
+end
+
+SWEP.ViewModel = "models/weapons/c_slam.mdl"
+SWEP.WorldModel = "models/weapons/w_slam.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Delay = 0
+SWEP.Primary.ClipSize = -1
+SWEP.Primary.DefaultClip = -1
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "none"
+
+SWEP.Secondary.Delay = 20
+SWEP.Secondary.Heal = 10
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_FAST
+
+SWEP.NoMagazine = true
+SWEP.Undroppable = true
+SWEP.NoPickupNotification = true
+
+SWEP.HoldType = "slam"
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType(self.HoldType)
+ self:SetDeploySpeed(10)
+end
+
+function SWEP:Think()
+ if self.IdleAnimation and self.IdleAnimation <= CurTime() then
+ self.IdleAnimation = nil
+ self:SendWeaponAnim(ACT_VM_IDLE)
+ end
+
+ if SERVER then
+ for _, ent in pairs(ents.FindByClass("prop_drone")) do
+ if ent:GetOwner() == self.Owner then
+ return
+ end
+ end
+
+ self.Owner:StripWeapon(self:GetClass())
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if IsFirstTimePredicted() then
+ self:SetDTBool(0, not self:GetDTBool(0))
+
+ if CLIENT then
+ LocalPlayer():EmitSound(self:GetDTBool(0) and "buttons/button17.wav" or "buttons/button19.wav", 0)
+ end
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+ return false
+end
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ return true
+end
+
+function SWEP:Holster()
+ self:SetDTBool(0, false)
+
+ return true
+end
+
+function SWEP:Reload()
+end
+
+if not CLIENT then return end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_electrohammer.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_electrohammer.lua
new file mode 100644
index 0000000..858247d
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_electrohammer.lua
@@ -0,0 +1,27 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Electrohammer"
+
+ SWEP.VElements = {
+ ["base2"] = { type = "Model", model = "models/props_lab/teleportring.mdl", bone = "ValveBiped.Bip01", rel = "base", pos = Vector(0, 0, 0), angle = Angle(0, 180, 0), size = Vector(0.08, 0.08, 0.08), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base"] = { type = "Model", model = "models/props_lab/powerbox02d.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(6.4, 3.975, -9.412), angle = Angle(5.961, 270, 16.764), size = Vector(0.25, 0.25, 0.25), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["ss"] = { type = "Sprite", sprite = "sprites/grav_flare", bone = "ValveBiped.Bip01", rel = "base", pos = Vector(-1.338, 2.894, 0.125), size = { x = 5, y = 5 }, color = Color(255, 255, 255, 255), nocull = true, additive = true, vertexalpha = true, vertexcolor = true, ignorez = false},
+ ["base2+"] = { type = "Model", model = "models/props_lab/teleportring.mdl", bone = "ValveBiped.Bip01", rel = "base", pos = Vector(-0.975, -0.263, 0.232), angle = Angle(0, 270, 90), size = Vector(0.15, 0.15, 0.15), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+
+ SWEP.WElements = {
+ ["base2"] = { type = "Model", model = "models/props_lab/teleportring.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "base", pos = Vector(0, 0, 0), angle = Angle(0, 180, 0), size = Vector(0.08, 0.08, 0.08), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["ss"] = { type = "Sprite", sprite = "sprites/grav_flare", bone = "ValveBiped.Bip01_R_Hand", rel = "base", pos = Vector(-1.338, 2.894, 0.125), size = { x = 5, y = 5 }, color = Color(255, 255, 255, 255), nocull = true, additive = true, vertexalpha = true, vertexcolor = true, ignorez = false},
+ ["base"] = { type = "Model", model = "models/props_lab/powerbox02d.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(3, 1, -8), angle = Angle(270, 90, 90), size = Vector(0.25, 0.25, 0.25), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base2+"] = { type = "Model", model = "models/props_lab/teleportring.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "base", pos = Vector(-0.975, -0.263, 0.232), angle = Angle(0, 270, 90), size = Vector(0.15, 0.15, 0.15), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_hammer"
+
+SWEP.MeleeDamage = 40
+SWEP.HealStrength = 1.4
+
+SWEP.ViewModel = "models/weapons/v_hammer/v_hammer.mdl"
+SWEP.WorldModel = "models/weapons/w_hammer.mdl"
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ender.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ender.lua
new file mode 100644
index 0000000..76904b9
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ender.lua
@@ -0,0 +1,40 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Ender' Automatic Shotgun"
+ SWEP.Slot = 3
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+
+ SWEP.HUD3DBone = "v_weapon.galil"
+ SWEP.HUD3DPos = Vector(1, 0, 6)
+ SWEP.HUD3DScale = 0.015
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "shotgun"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_rif_galil.mdl"
+SWEP.WorldModel = "models/weapons/w_rif_galil.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("Weapon_Galil.Single")
+SWEP.Primary.Damage = 23
+SWEP.Primary.NumShots = 4
+SWEP.Primary.Delay = 0.4
+
+SWEP.Primary.ClipSize = 8
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "buckshot"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.ConeMax = 0.16
+SWEP.ConeMin = 0.14
+
+SWEP.WalkSpeed = SPEED_SLOWER
+
+function SWEP:SecondaryAttack()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_eraser.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_eraser.lua
new file mode 100644
index 0000000..58a3834
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_eraser.lua
@@ -0,0 +1,53 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Eraser' Tactical Pistol"
+ SWEP.Description = "Damage increases as remaining bullets decrease. The last shot is worth triple damage."
+
+ SWEP.ViewModelFOV = 60
+ SWEP.ViewModelFlip = false
+
+ SWEP.Slot = 1
+ SWEP.SlotPos = 0
+
+ SWEP.HUD3DBone = "v_weapon.FIVESEVEN_PARENT"
+ SWEP.HUD3DPos = Vector(-1, -2.5, -1)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "pistol"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_pist_fiveseven.mdl"
+SWEP.WorldModel = "models/weapons/w_pist_fiveseven.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("weapons/ar2/npc_ar2_altfire.wav")
+SWEP.Primary.Damage = 21
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.1
+
+SWEP.Primary.ClipSize = 12
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "pistol"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.ConeMax = 0.06
+SWEP.ConeMin = 0.03
+
+SWEP.IronSightsPos = Vector(-5.95, 0, 2.5)
+
+function SWEP:EmitFireSound()
+ self:EmitSound(self.Primary.Sound, 80, 70 + (1 - (self:Clip1() / self.Primary.ClipSize)) * 90)
+end
+
+function SWEP:ShootBullets(dmg, numbul, cone)
+ if self:Clip1() == 1 then
+ dmg = dmg * 3
+ else
+ dmg = dmg + dmg * (1 - self:Clip1() / self.Primary.ClipSize)
+ end
+
+ self.BaseClass.ShootBullets(self, dmg, numbul, cone)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_fastheadcrab.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_fastheadcrab.lua
new file mode 100644
index 0000000..1573813
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_fastheadcrab.lua
@@ -0,0 +1,27 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_headcrab"
+
+if CLIENT then
+ SWEP.PrintName = "Fast Headcrab"
+end
+
+SWEP.PounceDamage = 6
+
+SWEP.NoHitRecovery = 0.6
+SWEP.HitRecovery = 0.75
+
+function SWEP:EmitBiteSound()
+ self.Owner:EmitSound("NPC_FastHeadcrab.Bite")
+end
+
+function SWEP:EmitIdleSound()
+ self.Owner:EmitSound("NPC_FastHeadcrab.Idle")
+end
+
+function SWEP:EmitAttackSound()
+ self.Owner:EmitSound("NPC_FastHeadcrab.Attack")
+end
+
+function SWEP:Reload()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_fastzombie.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_fastzombie.lua
new file mode 100644
index 0000000..bd2529d
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_fastzombie.lua
@@ -0,0 +1,418 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.ViewModel = Model("models/weapons/v_fza.mdl")
+SWEP.WorldModel = Model("models/weapons/w_crowbar.mdl")
+
+if CLIENT then
+ SWEP.ViewModelFOV = 70
+end
+
+SWEP.MeleeDelay = 0
+SWEP.MeleeReach = 42
+SWEP.MeleeDamage = 8
+SWEP.MeleeForceScale = 0.1
+SWEP.MeleeSize = 1.5
+SWEP.MeleeDamageType = DMG_SLASH
+SWEP.Primary.Delay = 0.32
+
+SWEP.PounceDamage = 10
+SWEP.PounceDamageType = DMG_IMPACT
+SWEP.PounceReach = 32
+SWEP.PounceSize = 16
+SWEP.PounceStartDelay = 0.5
+SWEP.PounceDelay = 1.25
+SWEP.PounceVelocity = 700
+
+SWEP.RoarTime = 1.6
+
+SWEP.Secondary.Automatic = false
+
+SWEP.NextClimbSound = 0
+SWEP.NextAllowPounce = 0
+function SWEP:Think()
+ self.BaseClass.Think(self)
+
+ local curtime = CurTime()
+ local owner = self.Owner
+
+ if self.NextAllowJump and self.NextAllowJump <= curtime then
+ self.NextAllowJump = nil
+
+ owner:ResetJumpPower()
+ end
+
+ if self:GetClimbing() then
+ if self:GetClimbSurface() and owner:KeyDown(IN_ATTACK2) then
+ if SERVER and curtime >= self.NextClimbSound then
+ local speed = owner:GetVelocity():Length()
+ if speed >= 50 then
+ if speed >= 100 then
+ self.NextClimbSound = curtime + 0.25
+ else
+ self.NextClimbSound = curtime + 0.8
+ end
+ owner:EmitSound("player/footsteps/metalgrate"..math.random(4)..".wav")
+ end
+ end
+ else
+ self:StopClimbing()
+ end
+ end
+
+ if self:GetSwinging() then
+ if not owner:KeyDown(IN_ATTACK) and self.SwingStop and self.SwingStop <= curtime then
+ self:SetSwinging(false)
+ self.SwingStop = nil
+
+ self.RoarCheck = curtime + 0.1
+
+ self:StopSwingingSound()
+ end
+ elseif self.RoarCheck then
+ if self.RoarCheck <= curtime then
+ self.RoarCheck = nil
+
+ if owner:GetVelocity():Length2D() <= 0.5 and owner:IsOnGround() then
+ self:SetRoarEndTime(curtime + self.RoarTime)
+ if SERVER then
+ owner:EmitSound("NPC_FastZombie.Frenzy")
+ end
+ end
+ end
+ elseif self:GetPouncing() then
+ if owner:IsOnGround() or owner:WaterLevel() >= 2 then
+ self:StopPounce()
+ else
+ owner:LagCompensation(true)
+
+ local hit = false
+ local traces = owner:PenetratingMeleeTrace(self.PounceReach, self.PounceSize, nil, owner:LocalToWorld(owner:OBBCenter()))
+ local damage = self:GetDamage(self:GetTracesNumPlayers(traces), self.PounceDamage)
+
+ for _, trace in ipairs(traces) do
+ if not trace.Hit then continue end
+
+ hit = true
+
+ if trace.HitWorld then
+ self:MeleeHitWorld(trace)
+ else
+ local ent = trace.Entity
+ if ent and ent:IsValid() then
+ self:MeleeHit(ent, trace, damage, 10)
+ end
+ end
+ end
+
+ if SERVER and hit then
+ owner:EmitSound("physics/flesh/flesh_strider_impact_bullet1.wav")
+ owner:EmitSound("npc/fast_zombie/wake1.wav")
+ end
+
+ owner:LagCompensation(false)
+
+ if hit then
+ self:StopPounce()
+ end
+ end
+ elseif self:GetPounceTime() > 0 and curtime >= self:GetPounceTime() then
+ self:StartPounce()
+ end
+
+ self:NextThink(curtime)
+ return true
+end
+
+function SWEP:MeleeHitEntity(ent, trace, damage, forcescale)
+ self.BaseClass.MeleeHitEntity(self, ent, trace, damage, forcescale ~= nil and forcescale * 0.25)
+end
+
+local climblerp = 0
+function SWEP:GetViewModelPosition(pos, ang)
+ climblerp = math.Approach(climblerp, self:IsClimbing() and not self:IsSwinging() and 1 or 0, FrameTime() * ((climblerp + 1) ^ 3))
+ ang:RotateAroundAxis(ang:Right(), 64 * climblerp)
+ if climblerp > 0 then
+ pos = pos + -8 * climblerp * ang:Up() + -12 * climblerp * ang:Forward()
+ end
+
+ return pos, ang
+end
+
+function SWEP:Swung()
+ self.SwingStop = CurTime() + 0.5
+
+ if not self:GetSwinging() then
+ self:SetSwinging(true)
+
+ self:StartSwingingSound()
+ end
+
+ self.BaseClass.Swung(self)
+end
+
+function SWEP:PrimaryAttack()
+ if self:IsPouncing() or self:GetPounceTime() > 0 or not self.Owner:OnGround() and not self:IsClimbing() and self.Owner:WaterLevel() < 2 then return end
+
+ self.BaseClass.PrimaryAttack(self)
+end
+
+local climbtrace = {mask = MASK_SOLID_BRUSHONLY, mins = Vector(-4, -4, -4), maxs = Vector(4, 4, 4)}
+function SWEP:GetClimbSurface()
+ local owner = self.Owner
+ climbtrace.start = owner:GetPos() + owner:GetUp() * 8
+ climbtrace.endpos = climbtrace.start + owner:SyncAngles():Forward() * 24
+ local tr = util.TraceHull(climbtrace)
+ if tr.Hit and not tr.HitSky then
+ return tr
+ end
+end
+
+function SWEP:SecondaryAttack()
+ if self:IsPouncing() or self:IsClimbing() or self:GetPounceTime() > 0 then return end
+
+ if self.Owner:IsOnGround() then
+ if CurTime() < self:GetNextPrimaryFire() or CurTime() < self:GetNextSecondaryFire() or CurTime() < self.NextAllowPounce then return end
+
+ self:SetNextPrimaryFire(math.huge)
+ self:SetPounceTime(CurTime() + self.PounceStartDelay)
+
+ self.Owner:ResetJumpPower()
+ if SERVER then
+ self.Owner:EmitSound("npc/fast_zombie/leap1.wav")
+ end
+ elseif self:GetClimbSurface() then
+ self:StartClimbing()
+ end
+end
+
+function SWEP:StartClimbing()
+ if self:GetClimbing() then return end
+
+ self:SetClimbing(true)
+
+ self:SetNextSecondaryFire(CurTime() + 0.5)
+end
+
+function SWEP:StopClimbing()
+ if not self:GetClimbing() then return end
+
+ self:SetClimbing(false)
+
+ self:SetNextSecondaryFire(CurTime())
+end
+
+function SWEP:StartPounce()
+ if self:IsPouncing() then return end
+
+ self:SetPounceTime(0)
+
+ local owner = self.Owner
+ if owner:IsOnGround() then
+ self:SetPouncing(true)
+
+ self.m_ViewAngles = owner:EyeAngles()
+
+ if SERVER then
+ owner:EmitSound("NPC_FastZombie.Scream")
+ end
+
+ local dir = owner:GetAimVector()
+ dir.z = math.max(0.25, dir.z)
+ dir:Normalize()
+
+ owner:SetGroundEntity(NULL)
+ owner:SetVelocity((1 - 0.5 * (owner:GetLegDamage() / GAMEMODE.MaxLegDamage)) * self.PounceVelocity * dir)
+ owner:SetAnimation(PLAYER_JUMP)
+ end
+end
+
+function SWEP:StopPounce()
+ if not self:IsPouncing() then return end
+
+ self:SetPouncing(false)
+ self:SetNextSecondaryFire(CurTime())
+ self.m_ViewAngles = nil
+ self.NextAllowJump = CurTime() + 0.25
+ self.NextAllowPounce = CurTime() + self.PounceDelay
+ self:SetNextPrimaryFire(CurTime() + 0.1)
+ self.Owner:ResetJumpPower()
+end
+
+function SWEP:Reload()
+ self.BaseClass.SecondaryAttack(self)
+end
+
+function SWEP:OnRemove()
+ self.Removing = true
+
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ self:StopSwingingSound()
+ owner:ResetJumpPower()
+ end
+
+ self.BaseClass.OnRemove(self)
+end
+
+function SWEP:Holster()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ self:StopSwingingSound()
+ owner:ResetJumpPower()
+ end
+
+ self.BaseClass.Holster(self)
+end
+
+function SWEP:ResetJumpPower(power)
+ if self.Removing then return end
+
+ if self.NextAllowJump and CurTime() < self.NextAllowJump or self:IsPouncing() or self:GetPounceTime() > 0 then
+ return 1
+ end
+end
+
+function SWEP:StartMoaning()
+end
+
+function SWEP:StopMoaning()
+end
+
+function SWEP:StartMoaningSound()
+end
+
+function SWEP:PlayHitSound()
+ self.Owner:EmitSound("NPC_FastZombie.AttackHit")
+end
+
+function SWEP:PlayMissSound()
+ self.Owner:EmitSound("NPC_FastZombie.AttackMiss")
+end
+
+function SWEP:PlayAttackSound()
+end
+
+function SWEP:PlayIdleSound()
+ self.Owner:EmitSound("NPC_FastZombie.AlertFar")
+ self:SetRoarEndTime(CurTime() + self.RoarTime)
+end
+
+function SWEP:PlayAlertSound()
+ self.Owner:EmitSound("NPC_FastZombie.Frenzy")
+ self:SetRoarEndTime(CurTime() + self.RoarTime)
+end
+
+function SWEP:StartSwingingSound()
+ self.Owner:EmitSound("NPC_FastZombie.Gurgle")
+end
+
+function SWEP:StopSwingingSound()
+ self.Owner:StopSound("NPC_FastZombie.Gurgle")
+end
+
+function SWEP:IsMoaning()
+ return false
+end
+
+function SWEP:Move(mv)
+ if self:IsPouncing() or self:GetPounceTime() > 0 then
+ mv:SetMaxSpeed(0)
+ mv:SetMaxClientSpeed(0)
+ elseif self:GetClimbing() then
+ mv:SetMaxSpeed(0)
+ mv:SetMaxClientSpeed(0)
+
+ local owner = self.Owner
+ local tr = self:GetClimbSurface()
+ local angs = self.Owner:SyncAngles()
+ local dir = tr and tr.Hit and (tr.HitNormal.z <= -0.5 and (angs:Forward() * -1) or math.abs(tr.HitNormal.z) < 0.75 and tr.HitNormal:Angle():Up()) or Vector(0, 0, 1)
+ local vel = Vector(0, 0, 4)
+
+ if owner:KeyDown(IN_FORWARD) then
+ vel = vel + dir * 160
+ end
+ if owner:KeyDown(IN_BACK) then
+ vel = vel + dir * -160
+ end
+
+ if vel.z == 4 then
+ if owner:KeyDown(IN_MOVERIGHT) then
+ vel = vel + angs:Right() * 60
+ end
+ if owner:KeyDown(IN_MOVELEFT) then
+ vel = vel + angs:Right() * -60
+ end
+ end
+
+ mv:SetVelocity(vel)
+
+ return true
+ elseif self:GetSwinging() then
+ mv:SetMaxSpeed(math.min(mv:GetMaxSpeed(), 60))
+ mv:SetMaxClientSpeed(math.min(mv:GetMaxClientSpeed(), 60))
+ end
+end
+
+function SWEP:SetRoarEndTime(time)
+ self:SetDTFloat(1, time)
+end
+
+function SWEP:GetRoarEndTime()
+ return self:GetDTFloat(1)
+end
+
+function SWEP:IsRoaring()
+ return CurTime() < self:GetRoarEndTime()
+end
+
+function SWEP:SetPounceTime(time)
+ self:SetDTFloat(2, time)
+end
+
+function SWEP:GetPounceTime()
+ return self:GetDTFloat(2)
+end
+
+function SWEP:SetPounceTime(time)
+ self:SetDTFloat(2, time)
+end
+
+function SWEP:GetPounceTime()
+ return self:GetDTFloat(2)
+end
+
+function SWEP:SetClimbing(climbing)
+ self:SetDTBool(1, climbing)
+end
+
+function SWEP:GetClimbing()
+ return self:GetDTBool(1)
+end
+SWEP.IsClimbing = SWEP.GetClimbing
+
+function SWEP:SetSwinging(swinging)
+ self:SetDTBool(2, swinging)
+end
+
+function SWEP:GetSwinging()
+ return self:GetDTBool(2)
+end
+
+function SWEP:SetPouncing(leaping)
+ self:SetDTBool(3, leaping)
+end
+
+function SWEP:GetPouncing()
+ return self:GetDTBool(3)
+end
+SWEP.IsPouncing = SWEP.GetPouncing
+
+if CLIENT then return end
+
+function SWEP:Deploy()
+ self.Owner:CreateAmbience("fastzombieambience")
+
+ return self.BaseClass.Deploy(self)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_fastzombielegs.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_fastzombielegs.lua
new file mode 100644
index 0000000..2863399
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_fastzombielegs.lua
@@ -0,0 +1,63 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Fast Zombie Kung Fu"
+end
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.Primary.Delay = 1
+
+SWEP.MeleeDelay = 0.25
+SWEP.MeleeReach = 38
+SWEP.MeleeDamage = 13
+
+SWEP.DelayWhenDeployed = true
+
+function SWEP:Move(mv)
+ if self:IsSwinging() then
+ mv:SetMaxSpeed(0)
+ mv:SetMaxClientSpeed(0)
+ end
+end
+
+function SWEP:PrimaryAttack(fromsecondary)
+ local n = self:GetNextPrimaryAttack()
+
+ if self.Owner:IsOnGround() or self.Owner:WaterLevel() >= 2 or self.Owner:GetMoveType() ~= MOVETYPE_WALK then
+ self.BaseClass.PrimaryAttack(self)
+ end
+
+ if not fromsecondary and n ~= self:GetNextPrimaryAttack() then
+ self:SetDTBool(3, false)
+ end
+end
+
+function SWEP:SecondaryAttack()
+ local n = self:GetNextPrimaryAttack()
+ self:PrimaryAttack(true)
+ if n ~= self:GetNextPrimaryAttack() then
+ self:SetDTBool(3, true)
+ end
+end
+
+function SWEP:PlayHitSound()
+ self.Owner:EmitSound("npc/zombie/zombie_pound_door.wav")
+end
+
+function SWEP:PlayAttackSound()
+ self.Owner:EmitSound("npc/zombie/foot_slide"..math.random(3)..".wav")
+end
+
+function SWEP:Reload()
+end
+
+function SWEP:StartMoaning()
+end
+
+function SWEP:StopMoaning()
+end
+
+function SWEP:IsMoaning()
+ return false
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ffemitter/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ffemitter/cl_init.lua
new file mode 100644
index 0000000..1dc3073
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ffemitter/cl_init.lua
@@ -0,0 +1,44 @@
+include("shared.lua")
+
+SWEP.PrintName = "Force Field Emitter"
+SWEP.Description = "Blocks bullets and other projectiles but will not stop humans, zombies, or other creatures from passing.\nPress PRIMARY ATTACK to deploy.\nPress SECONDARY ATTACK and RELOAD to rotate."
+SWEP.DrawCrosshair = false
+
+SWEP.Slot = 4
+SWEP.SlotPos = 0
+
+function SWEP:DrawHUD()
+ if GetConVarNumber("crosshair") ~= 1 then return end
+ self:DrawCrosshairDot()
+end
+
+function SWEP:PrimaryAttack()
+end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ return true
+end
+
+function SWEP:Think()
+ if self.Owner:KeyDown(IN_ATTACK2) then
+ self:RotateGhost(FrameTime() * 60)
+ end
+ if self.Owner:KeyDown(IN_RELOAD) then
+ self:RotateGhost(FrameTime() * -60)
+ end
+end
+
+local nextclick = 0
+function SWEP:RotateGhost(amount)
+ if nextclick <= RealTime() then
+ surface.PlaySound("npc/headcrab_poison/ph_step4.wav")
+ nextclick = RealTime() + 0.3
+ end
+ RunConsoleCommand("_zs_ghostrotation", math.NormalizeAngle(GetConVarNumber("_zs_ghostrotation") + amount))
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ffemitter/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ffemitter/init.lua
new file mode 100644
index 0000000..994587d
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ffemitter/init.lua
@@ -0,0 +1,83 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self:SpawnGhost()
+
+ return true
+end
+
+function SWEP:OnRemove()
+ self:RemoveGhost()
+end
+
+function SWEP:Holster()
+ self:RemoveGhost()
+ return true
+end
+
+function SWEP:SpawnGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:GiveStatus("ghost_ffemitter")
+ end
+end
+
+function SWEP:RemoveGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:RemoveStatus("ghost_ffemitter", false, true)
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+
+ local owner = self.Owner
+
+ local status = owner.status_ghost_ffemitter
+ if not (status and status:IsValid()) then return end
+ status:RecalculateValidity()
+ if not status:GetValidPlacement() then return end
+
+ local pos, ang = status:RecalculateValidity()
+ if not pos or not ang then return end
+
+ self:SetNextPrimaryAttack(CurTime() + self.Primary.Delay)
+
+ local ent = ents.Create("prop_ffemitter")
+ if ent:IsValid() then
+ ent:SetPos(pos)
+ ent:SetAngles(ang)
+ ent:Spawn()
+
+ ent:SetObjectOwner(owner)
+
+ ent:EmitSound("npc/dog/dog_servo12.wav")
+
+ ent:GhostAllPlayersInMe(5)
+
+ self:TakePrimaryAmmo(1)
+
+ local stored = owner:PopPackedItem(ent:GetClass())
+ if stored then
+ ent.m_Health = stored[1]
+ end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ owner:StripWeapon(self:GetClass())
+ end
+ end
+end
+
+function SWEP:Think()
+ local count = self:GetPrimaryAmmoCount()
+ if count ~= self:GetReplicatedAmmo() then
+ self:SetReplicatedAmmo(count)
+ self.Owner:ResetSpeed()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ffemitter/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ffemitter/shared.lua
new file mode 100644
index 0000000..6b8c986
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ffemitter/shared.lua
@@ -0,0 +1,59 @@
+SWEP.ViewModel = "models/weapons/v_pistol.mdl"
+SWEP.WorldModel = Model("models/props_lab/lab_flourescentlight002b.mdl")
+
+SWEP.AmmoIfHas = true
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.DefaultClip = 1
+SWEP.Primary.Ammo = "slam"
+SWEP.Primary.Delay = 1
+SWEP.Primary.Automatic = true
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_NORMAL
+SWEP.FullWalkSpeed = SPEED_SLOWEST
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType("slam")
+ self:SetDeploySpeed(1.1)
+ self:HideViewAndWorldModel()
+end
+
+function SWEP:SetReplicatedAmmo(count)
+ self:SetDTInt(0, count)
+end
+
+function SWEP:GetReplicatedAmmo()
+ return self:GetDTInt(0)
+end
+
+function SWEP:GetWalkSpeed()
+ if self:GetPrimaryAmmoCount() > 0 then
+ return self.FullWalkSpeed
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ return false
+ end
+
+ return true
+end
+
+function SWEP:Holster()
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_fleshcreeper.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_fleshcreeper.lua
new file mode 100644
index 0000000..fe85fd6
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_fleshcreeper.lua
@@ -0,0 +1,249 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.PrintName = "Flesh Creeper"
+
+SWEP.MeleeDelay = 0.5
+SWEP.MeleeReach = 52
+SWEP.MeleeDamage = 15
+SWEP.MeleeForceScale = 1.25
+SWEP.MeleeSize = 3
+SWEP.MeleeDamageType = DMG_SLASH
+SWEP.Primary.Delay = 0.75
+
+SWEP.Secondary.Automatic = false
+
+AccessorFuncDT(SWEP, "RightClickStart", "Float", 2)
+AccessorFuncDT(SWEP, "AttackAnimTime", "Float", 3)
+
+SWEP.NextDigSound = 0
+SWEP.NextMessage = 0
+
+function SWEP:Think()
+ self.BaseClass.Think(self)
+
+ if self:GetHoldingRightClick() and not self.Owner:KeyDown(IN_ATTACK2) then
+ self:SetRightClickStart(0)
+
+ if self.BuildSoundPlaying then
+ self.BuildSoundPlaying = false
+ self.BuildSound:ChangeVolume(0, 0.5)
+ end
+ elseif self:IsBuilding() then
+ if not self.BuildSoundPlaying then
+ self.BuildSoundPlaying = true
+ self.BuildSound:ChangeVolume(0.45, 0.5)
+ end
+
+ if SERVER then
+ self:BuildingThink()
+ end
+ end
+
+ self:NextThink(CurTime())
+ return true
+end
+
+function SWEP:SendMessage(msg, friendly)
+ if CurTime() >= self.NextMessage then
+ self.NextMessage = CurTime() + 2
+ self.Owner:CenterNotify(friendly and COLOR_GREEN or COLOR_RED, translate.ClientGet(self.Owner, msg))
+ end
+end
+
+function SWEP:Initialize()
+ self.BaseClass.Initialize(self)
+
+ self.BuildSound = CreateSound(self, "npc/antlion/charge_loop1.wav")
+ self.BuildSound:PlayEx(0, 100)
+end
+
+function SWEP:OnRemove()
+ self.BaseClass.OnRemove(self)
+
+ self.BuildSound:Stop()
+end
+
+function SWEP:BuildingThink()
+ local owner = self.Owner
+ local pos = owner:WorldSpaceCenter()
+ local ang = owner:EyeAngles()
+ ang.pitch = 0
+ ang.roll = 0
+ local forward = ang:Forward()
+ local right = ang:Right()
+ local endpos = pos + forward * 32
+
+ local tr = util.TraceLine({start = pos, endpos = endpos, filter = player.GetAll(), mask = MASK_PLAYERSOLID})
+ local trent = tr.Entity
+
+ if trent and trent:IsValid() and trent:GetClass() == "prop_creepernest" then
+ --[[if not trent:GetNestBuilt() and trent.LastBuilder and trent.LastBuild and trent.LastBuilder:IsValid() and trent.LastBuilder ~= owner and CurTime() < trent.LastBuild + 0.1 then
+ owner:ConCommand("-attack2")
+ self:SendMessage("nest_already_being_built")
+ return
+ end]]
+
+ self:BuildNest(trent)
+
+ return
+ end
+
+ if owner.NextNestSpawn and CurTime() < owner.NextNestSpawn then
+ if CurTime() >= self.NextMessage then
+ self.NextMessage = CurTime() + 2
+ owner:CenterNotify(COLOR_RED, translate.ClientFormat(owner, "wait_x_seconds_before_making_a_new_nest", math.ceil(owner.NextNestSpawn - CurTime())))
+ end
+
+ return
+ end
+
+ tr = util.TraceLine({start = endpos, endpos = endpos + Vector(0, 0, -48), mask = MASK_PLAYERSOLID})
+ local hitnormal = tr.HitNormal
+ local z = hitnormal.z
+ if not tr.HitWorld or tr.HitSky or z < 0.75 then
+ self:SendMessage("not_enough_room_for_a_nest")
+ return
+ end
+
+ local hitpos = tr.HitPos
+
+ for x = -20, 20, 20 do
+ for y = -20, 20, 20 do
+ local start = endpos + x * right + y * forward
+ tr = util.TraceLine({start = start, endpos = start + Vector(0, 0, -48), mask = MASK_PLAYERSOLID})
+ if not tr.HitWorld or tr.HitSky or math.abs(tr.HitNormal.z - z) >= 0.2 then
+ self:SendMessage("not_enough_room_for_a_nest")
+ return
+ end
+ end
+ end
+
+ for _, ent in pairs(team.GetValidSpawnPoint(TEAM_UNDEAD)) do
+ if ent.Disabled then continue end
+
+ if util.SkewedDistance(ent:GetPos(), hitpos, 2.5) < GAMEMODE.DynamicSpawnDistBuild then
+ self:SendMessage("too_close_to_a_spawn")
+ return
+ end
+ end
+
+ -- See if there's a nest nearby.
+ for _, ent in pairs(ents.FindByClass("prop_creepernest")) do
+ if util.SkewedDistance(ent:GetPos(), hitpos, 2.5) <= GAMEMODE.DynamicSpawnDistBuild then
+ self:SendMessage("too_close_to_another_nest")
+ return
+ end
+ end
+
+ for _, human in pairs(team.GetPlayers(TEAM_HUMAN)) do
+ if util.SkewedDistance(human:GetPos(), hitpos, 2.75) <= GAMEMODE.DynamicSpawnDistBuild then
+ self:SendMessage("too_close_to_a_human")
+ return
+ end
+ end
+
+ -- I didn't make this check where trigger_hurt entities are. Rather I made it check the time since the last time you were hit with a trigger_hurt.
+ -- I'm not sure if it's possible to check if a trigger_hurt is enabled or disabled through the Lua bindings.
+ if owner.LastHitWithTriggerHurt and CurTime() < owner.LastHitWithTriggerHurt + 2 then
+ return
+ end
+
+ local ent = ents.Create("prop_creepernest")
+ if ent:IsValid() then
+ nestang = hitnormal:Angle()
+ nestang:RotateAroundAxis(nestang:Right(), 270)
+
+ ent:SetPos(hitpos)
+ ent:SetAngles(nestang)
+ ent:Spawn()
+
+ ent:SetNestHealth(1)
+ ent:SetNestBuilt(false)
+
+ self:SendMessage("nest_created")
+
+ ent.Owner = owner
+
+ owner.NextNestSpawn = CurTime() + 10
+ end
+end
+
+function SWEP:BuildNest(ent)
+ ent:BuildUp()
+
+ ent.LastBuild = CurTime()
+ ent.LastBuilder = self.Owner
+
+ if not ent:GetNestBuilt() and ent:GetNestHealth() == ent:GetNestMaxHealth() then
+ ent:SetNestBuilt(true)
+ ent:EmitSound("physics/flesh/flesh_bloody_break.wav")
+
+ local name = self.Owner:Name()
+ for _, pl in pairs(team.GetPlayers(TEAM_UNDEAD)) do
+ pl:CenterNotify(COLOR_GREEN, translate.ClientFormat(pl, "nest_built_by_x", name))
+ end
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if self:GetHoldingRightClick() or not self.Owner:OnGround() then return end
+
+ self.BaseClass.PrimaryAttack(self)
+
+ if self:IsSwinging() then
+ self:SetAttackAnimTime(CurTime() + self.Primary.Delay)
+ end
+end
+
+function SWEP:SecondaryAttack()
+ if self:IsSwinging() or self:IsInAttackAnim() or not self.Owner:OnGround() then return end
+
+ self:SetRightClickStart(CurTime())
+end
+
+function SWEP:GetHoldingRightClick()
+ return self:GetRightClickStart() > 0
+end
+
+function SWEP:IsBuilding()
+ return self:GetHoldingRightClick() and (CurTime() - self:GetRightClickStart()) >= 1
+end
+
+function SWEP:Reload()
+ self.BaseClass.SecondaryAttack(self)
+end
+
+function SWEP:IsMoaning()
+ return false
+end
+
+function SWEP:PlayAlertSound()
+ self.Owner:EmitSound("npc/barnacle/barnacle_pull"..math.random(4)..".wav", 70)
+end
+
+function SWEP:PlayIdleSound()
+ self.Owner:EmitSound("npc/barnacle/barnacle_pull"..math.random(4)..".wav", 70, 85)
+end
+
+function SWEP:PlayAttackSound()
+end
+
+function SWEP:PlayHitSound()
+ self.Owner:EmitSound("physics/body/body_medium_impact_hard"..math.random(6)..".wav", 70, math.random(110, 120))
+end
+
+function SWEP:PlayMissSound()
+ self.Owner:EmitSound("npc/zombie/claw_miss"..math.random(2)..".wav", 70, math.random(90, 100))
+end
+
+function SWEP:IsInAttackAnim()
+ return self:GetAttackAnimTime() > 0 and CurTime() < self:GetAttackAnimTime()
+end
+
+if not CLIENT then return end
+
+function SWEP:PreDrawViewModel(vm)
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_freshdead.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_freshdead.lua
new file mode 100644
index 0000000..e6f42a1
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_freshdead.lua
@@ -0,0 +1,19 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.MeleeDamage = 20
+
+function SWEP:Reload()
+ self:SecondaryAttack()
+end
+
+function SWEP:StartMoaning()
+end
+
+function SWEP:StopMoaning()
+end
+
+function SWEP:IsMoaning()
+ return false
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_fryingpan.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_fryingpan.lua
new file mode 100644
index 0000000..2132af7
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_fryingpan.lua
@@ -0,0 +1,43 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Frying Pan"
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 55
+
+ SWEP.ShowViewModel = false
+ SWEP.ShowWorldModel = false
+
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props_c17/metalpot002a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(5, 1.368, -9), angle = Angle(-90, 90, -90), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props_c17/metalpot002a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(5, 1.368, -9), angle = Angle(-90, 90, -90), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.DamageType = DMG_CLUB
+
+SWEP.ViewModel = "models/weapons/c_stunstick.mdl"
+SWEP.WorldModel = "models/props_c17/metalpot002a.mdl"
+SWEP.UseHands = true
+
+SWEP.MeleeDamage = 40
+SWEP.MeleeRange = 50
+SWEP.MeleeSize = 1.15
+
+SWEP.UseMelee1 = true
+
+SWEP.HitGesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE
+SWEP.MissGesture = SWEP.HitGesture
+
+SWEP.SwingRotation = Angle(30, -30, -30)
+SWEP.SwingTime = 0.3
+SWEP.SwingHoldType = "grenade"
+
+function SWEP:PlayHitSound()
+ self:EmitSound("weapons/melee/frying_pan/pan_hit-0"..math.random(4)..".ogg")
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ghoul.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ghoul.lua
new file mode 100644
index 0000000..b91cf08
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ghoul.lua
@@ -0,0 +1,93 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Ghoul"
+end
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.MeleeDamage = 26
+SWEP.MeleeForceScale = 0.1
+SWEP.SlowDownScale = 2.25
+SWEP.SlowDownImmunityTime = 2
+
+function SWEP:ApplyMeleeDamage(ent, trace, damage)
+ ent:PoisonDamage(damage, self.Owner, self, trace.HitPos)
+end
+
+function SWEP:Reload()
+ self.BaseClass.SecondaryAttack(self)
+end
+
+function SWEP:PlayAlertSound()
+ self.Owner:EmitSound("npc/fast_zombie/fz_alert_close1.wav", 75, math.Rand(70, 80))
+end
+SWEP.PlayIdleSound = SWEP.PlayAlertSound
+
+function SWEP:PlayAttackSound()
+ self.Owner:EmitSound("npc/fast_zombie/leap1.wav", 74, math.Rand(110, 130))
+end
+
+local function DoFleshThrow(pl, wep)
+ if pl:IsValid() and pl:Alive() and wep:IsValid() then
+ pl:ResetSpeed()
+
+ if SERVER then
+ local startpos = pl:GetShootPos()
+ local aimang = pl:EyeAngles()
+
+ for i=1, 4 do
+ local ang = Angle(aimang.p, aimang.y, aimang.r)
+ ang:RotateAroundAxis(ang:Up(), math.Rand(-8, 8))
+ ang:RotateAroundAxis(ang:Right(), math.Rand(-8, 8))
+
+ local ent = ents.Create("projectile_poisonflesh")
+ if ent:IsValid() then
+ ent:SetPos(startpos)
+ ent:SetOwner(pl)
+ ent:Spawn()
+ ent:SetTeamID(TEAM_UNDEAD)
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetVelocityInstantaneous(ang:Forward() * math.Rand(320, 380))
+ end
+ end
+ end
+
+ pl:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav", 72, math.Rand(85, 95))
+ end
+
+ if CurTime() >= (pl.GhoulImmunity or 0) then
+ pl.GhoulImmunity = CurTime() + 2
+ pl:RawCapLegDamage(CurTime() + 2)
+ end
+ end
+end
+
+function SWEP:SecondaryAttack()
+ local owner = self.Owner
+ if CurTime() < self:GetNextPrimaryFire() or CurTime() < self:GetNextSecondaryFire() or IsValid(owner.FeignDeath) then return end
+
+ self:SetNextSecondaryFire(CurTime() + 3)
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+
+ self.Owner:DoAttackEvent()
+ self:EmitSound("npc/fast_zombie/leap1.wav", 74, math.Rand(110, 130))
+ self:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav", 72, math.Rand(85, 95))
+ self.Owner:RawCapLegDamage(CurTime() + 3)
+ self:SendWeaponAnim(ACT_VM_HITCENTER)
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ timer.Simple(0.7, function() DoFleshThrow(owner, self) end)
+end
+
+if not CLIENT then return end
+
+function SWEP:ViewModelDrawn()
+ render.ModelMaterialOverride(0)
+end
+
+local matSheet = Material("models/weapons/v_zombiearms/ghoulsheet")
+function SWEP:PreDrawViewModel(vm)
+ render.ModelMaterialOverride(matSheet)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gigagorechild.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gigagorechild.lua
new file mode 100644
index 0000000..23ab85b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gigagorechild.lua
@@ -0,0 +1,107 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.MeleeReach = 100
+SWEP.MeleeDamage = 30
+SWEP.MeleeForceScale = 2
+SWEP.MeleeSize = 3
+SWEP.MeleeDamageType = DMG_SLASH
+SWEP.Primary.Delay = 3
+SWEP.Secondary.Delay = 5
+
+SWEP.ThrowDelay = 1
+
+AccessorFuncDT(SWEP, "ThrowTime", "Float", 3)
+
+function SWEP:Think()
+ self:CheckMeleeAttack()
+ self:CheckThrow()
+end
+
+function SWEP:ApplyMeleeDamage(ent, trace, damage)
+ if ent:IsValid() and ent:IsPlayer() then
+ local vel = ent:GetPos() - self.Owner:GetPos()
+ vel.z = 0
+ vel:Normalize()
+ vel = vel * 400
+ vel.z = 200
+
+ ent:KnockDown()
+ ent:SetGroundEntity(NULL)
+ ent:SetVelocity(vel)
+ end
+
+ self.BaseClass.ApplyMeleeDamage(self, ent, trace, damage)
+end
+
+function SWEP:PrimaryAttack()
+ if self:IsThrowing() then return end
+
+ self.BaseClass.PrimaryAttack(self)
+end
+
+function SWEP:SecondaryAttack()
+ if self:IsSwinging() or CurTime() <= self:GetNextSecondaryAttack() then return end
+
+ self:SetThrowTime(CurTime() + self.ThrowDelay)
+ self.Owner:DoReloadEvent() -- Handled in the class file. Fires the throwing anim.
+
+ self:SetNextSecondaryAttack(CurTime() + self.Secondary.Delay)
+end
+
+function SWEP:CheckThrow()
+ if self:GetThrowing() and CurTime() >= self:GetThrowTime() then
+ self:SetThrowTime(0)
+
+ self.Owner:EmitSound("weapons/slam/throw.wav", 70, math.random(78, 82))
+
+ if SERVER then
+ local ent = ents.Create("prop_thrownbaby")
+ if ent:IsValid() then
+ ent:SetPos(self.Owner:GetShootPos())
+ ent:SetAngles(AngleRand())
+ ent:SetOwner(self.Owner)
+ ent:Spawn()
+
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:SetVelocityInstantaneous(self.Owner:GetAimVector() * 500)
+ phys:AddAngleVelocity(VectorRand() * math.Rand(200, 300))
+
+ ent:SetPhysicsAttacker(self.Owner)
+ end
+ end
+ end
+ end
+end
+
+function SWEP:IsThrowing()
+ return self:GetThrowTime() > 0
+end
+SWEP.GetThrowing = SWEP.IsThrowing
+
+function SWEP:Reload()
+ self.BaseClass.SecondaryAttack(self)
+end
+
+function SWEP:PlayAlertSound()
+ self.Owner:EmitSound("ambient/creatures/teddy.wav", 77, 45)
+end
+
+function SWEP:PlayIdleSound()
+ self.Owner:EmitSound("ambient/creatures/teddy.wav", 77, 60)
+end
+
+function SWEP:PlayAttackSound()
+ self.Owner:EmitSound("ambient/creatures/teddy.wav", 77, 60)
+end
+
+function SWEP:PlayHitSound()
+ self.Owner:EmitSound("physics/body/body_medium_impact_hard"..math.random(6)..".wav", 77, math.random(60, 70))
+end
+
+function SWEP:PlayMissSound()
+ self.Owner:EmitSound("npc/zombie/claw_miss"..math.random(2)..".wav", 77, math.random(60, 70))
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_glock3.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_glock3.lua
new file mode 100644
index 0000000..3f0808e
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_glock3.lua
@@ -0,0 +1,37 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Crossfire' Glock 3"
+ SWEP.Slot = 1
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFOV = 50
+ SWEP.ViewModelFlip = false
+
+ SWEP.HUD3DBone = "v_weapon.Glock_Slide"
+ SWEP.HUD3DPos = Vector(5, 0.25, -0.8)
+ SWEP.HUD3DAng = Angle(90, 0, 0)
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "pistol"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_pist_glock18.mdl"
+SWEP.WorldModel = "models/weapons/w_pist_glock18.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("Weapon_Glock.Single")
+SWEP.Primary.Damage = 17
+SWEP.Primary.NumShots = 3
+SWEP.Primary.Delay = 0.3
+
+SWEP.Primary.ClipSize = 7
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "pistol"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.ConeMax = 0.14
+SWEP.ConeMin = 0.07
+
+SWEP.IronSightsPos = Vector(-5.75, 10, 2.7)
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gorechild.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gorechild.lua
new file mode 100644
index 0000000..896085f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gorechild.lua
@@ -0,0 +1,73 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.MeleeDelay = 0
+SWEP.MeleeReach = 16
+SWEP.MeleeDamage = 3
+SWEP.MeleeForceScale = 0.025
+SWEP.MeleeSize = 0.5
+SWEP.MeleeDamageType = DMG_SLASH
+SWEP.Primary.Delay = 0.32
+
+function SWEP:Think()
+ self.BaseClass.Think(self)
+
+ local curtime = CurTime()
+ local owner = self.Owner
+
+ if self:GetSwinging() then
+ if not owner:KeyDown(IN_ATTACK) and self.SwingStop and self.SwingStop <= curtime then
+ self:SetSwinging(false)
+ self.SwingStop = nil
+ end
+ end
+
+ self:NextThink(CurTime())
+ return true
+end
+
+function SWEP:Swung()
+ self.SwingStop = CurTime() + 0.5
+
+ if not self:GetSwinging() then
+ self:SetSwinging(true)
+ end
+
+ self.BaseClass.Swung(self)
+end
+
+function SWEP:Reload()
+ self:SecondaryAttack()
+end
+
+function SWEP:IsMoaning()
+ return false
+end
+
+function SWEP:PlayAlertSound()
+ self.Owner:EmitSound("ambient/creatures/teddy.wav", 65, 85)
+end
+
+function SWEP:PlayIdleSound()
+ self.Owner:EmitSound("ambient/creatures/teddy.wav", 65)
+end
+
+function SWEP:PlayAttackSound()
+end
+
+function SWEP:PlayHitSound()
+ self.Owner:EmitSound("physics/body/body_medium_impact_hard"..math.random(6)..".wav", 65, math.random(130, 140))
+end
+
+function SWEP:PlayMissSound()
+ self.Owner:EmitSound("npc/zombie/claw_miss"..math.random(2)..".wav", 65, math.random(140, 150))
+end
+
+function SWEP:SetSwinging(swinging)
+ self:SetDTBool(2, swinging)
+end
+
+function SWEP:GetSwinging()
+ return self:GetDTBool(2)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_grenade/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_grenade/cl_init.lua
new file mode 100644
index 0000000..546517c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_grenade/cl_init.lua
@@ -0,0 +1,21 @@
+include("shared.lua")
+
+SWEP.PrintName = "Grenade"
+SWEP.Description = "A simple fragmentation grenade.\nWhen used in the right conditions, it can obliterate groups of zombies."
+
+SWEP.ViewModelFOV = 60
+
+SWEP.Slot = 4
+SWEP.SlotPos = 0
+
+--[[function SWEP:GetViewModelPosition(pos, ang)
+ if self:GetPrimaryAmmoCount() <= 0 then
+ return pos + ang:Forward() * -256, ang
+ end
+
+ return pos, ang
+end]]
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_grenade/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_grenade/init.lua
new file mode 100644
index 0000000..25b35c2
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_grenade/init.lua
@@ -0,0 +1,4 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_grenade/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_grenade/shared.lua
new file mode 100644
index 0000000..a0800b1
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_grenade/shared.lua
@@ -0,0 +1,112 @@
+SWEP.ViewModel = "models/weapons/c_grenade.mdl"
+SWEP.WorldModel = "models/weapons/w_grenade.mdl"
+SWEP.UseHands = true
+
+SWEP.AmmoIfHas = true
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "grenade"
+SWEP.Primary.Delay = 1.25
+SWEP.Primary.DefaultClip = 1
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_FAST
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType("grenade")
+ self:SetDeploySpeed(1.1)
+end
+
+function SWEP:Precache()
+ util.PrecacheSound("WeaponFrag.Throw")
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ return false
+ end
+
+ return true
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+
+ local owner = self.Owner
+ self:SendWeaponAnim(ACT_VM_THROW)
+ owner:DoAttackEvent()
+
+ self:TakePrimaryAmmo(1)
+ self.NextDeploy = CurTime() + 1
+
+ if SERVER then
+ local ent = ents.Create("projectile_zsgrenade")
+ if ent:IsValid() then
+ ent:SetPos(owner:GetShootPos())
+ ent:SetOwner(owner)
+ ent:Spawn()
+ ent.GrenadeDamage = self.GrenadeDamage
+ ent.GrenadeRadius = self.GrenadeRadius
+ ent:EmitSound("WeaponFrag.Throw")
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:AddAngleVelocity(VectorRand() * 5)
+ phys:SetVelocityInstantaneous(self.Owner:GetAimVector() * 800)
+ end
+ end
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:CanSecondaryAttack()
+ return false
+end
+
+function SWEP:Reload()
+ return false
+end
+
+function SWEP:Deploy()
+ GAMEMODE:WeaponDeployed(self.Owner, self)
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SendWeaponAnim(ACT_VM_SECONDARYATTACK)
+ end
+
+ return true
+end
+
+function SWEP:Holster()
+ self.NextDeploy = nil
+ return true
+end
+
+function SWEP:Think()
+ if self.NextDeploy and self.NextDeploy <= CurTime() then
+ self.NextDeploy = nil
+
+ if 0 < self:GetPrimaryAmmoCount() then
+ self:SendWeaponAnim(ACT_VM_DRAW)
+ else
+ self:SendWeaponAnim(ACT_VM_SECONDARYATTACK)
+
+ if SERVER then
+ self:Remove()
+ end
+ end
+ elseif SERVER and self:GetPrimaryAmmoCount() <= 0 then
+ self:Remove()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gunturret/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gunturret/cl_init.lua
new file mode 100644
index 0000000..a697473
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gunturret/cl_init.lua
@@ -0,0 +1,48 @@
+include("shared.lua")
+
+SWEP.PrintName = "Gun Turret"
+SWEP.Description = "This automated turret requires constant upkeep to be useful.\nPress PRIMARY ATTACK to deploy the turret.\nPress SECONDARY ATTACK and RELOAD to rotate the turret.\nPress USE on a deployed turret to give it some of your SMG ammunition.\nPress USE on a deployed turret with no owner (blue light) to reclaim it."
+SWEP.DrawCrosshair = false
+
+SWEP.Slot = 4
+SWEP.SlotPos = 0
+
+function SWEP:DrawHUD()
+ if GetConVarNumber("crosshair") ~= 1 then return end
+ self:DrawCrosshairDot()
+end
+
+function SWEP:Deploy()
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ return true
+end
+
+function SWEP:DrawWorldModel()
+end
+SWEP.DrawWorldModelTranslucent = SWEP.DrawWorldModel
+
+function SWEP:PrimaryAttack()
+end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
+
+function SWEP:Think()
+ if self.Owner:KeyDown(IN_ATTACK2) then
+ self:RotateGhost(FrameTime() * 60)
+ end
+ if self.Owner:KeyDown(IN_RELOAD) then
+ self:RotateGhost(FrameTime() * -60)
+ end
+end
+
+local nextclick = 0
+function SWEP:RotateGhost(amount)
+ if nextclick <= RealTime() then
+ surface.PlaySound("npc/headcrab_poison/ph_step4.wav")
+ nextclick = RealTime() + 0.3
+ end
+ RunConsoleCommand("_zs_ghostrotation", math.NormalizeAngle(GetConVarNumber("_zs_ghostrotation") + amount))
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gunturret/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gunturret/init.lua
new file mode 100644
index 0000000..4a20eb4
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gunturret/init.lua
@@ -0,0 +1,82 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ self:SpawnGhost()
+
+ return true
+end
+
+function SWEP:OnRemove()
+ self:RemoveGhost()
+end
+
+function SWEP:Holster()
+ self:RemoveGhost()
+ return true
+end
+
+function SWEP:SpawnGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:GiveStatus("ghost_gunturret")
+ end
+end
+
+function SWEP:RemoveGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:RemoveStatus("ghost_gunturret", false, true)
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+
+ local owner = self.Owner
+
+ local status = owner.status_ghost_gunturret
+ if not (status and status:IsValid()) then return end
+ status:RecalculateValidity()
+ if not status:GetValidPlacement() then return end
+
+ local pos, ang = status:RecalculateValidity()
+ if not pos or not ang then return end
+
+ self:SetNextPrimaryAttack(CurTime() + self.Primary.Delay)
+
+ local ent = ents.Create("prop_gunturret")
+ if ent:IsValid() then
+ ent:SetPos(pos)
+ ent:SetAngles(ang)
+ ent:Spawn()
+
+ ent:SetObjectOwner(owner)
+
+ ent:EmitSound("npc/dog/dog_servo12.wav")
+
+ ent:GhostAllPlayersInMe(5)
+
+ self:TakePrimaryAmmo(1)
+
+ local stored = owner:PopPackedItem(ent:GetClass())
+ if stored then
+ ent:SetObjectHealth(stored[1])
+ ent:SetAmmo(stored[2])
+ end
+
+ if not owner:HasWeapon("weapon_zs_gunturretcontrol") then
+ owner:Give("weapon_zs_gunturretcontrol")
+ end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ owner:StripWeapon(self:GetClass())
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gunturret/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gunturret/shared.lua
new file mode 100644
index 0000000..ecf038e
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gunturret/shared.lua
@@ -0,0 +1,84 @@
+SWEP.ViewModel = "models/weapons/v_pistol.mdl"
+SWEP.WorldModel = "models/Combine_turrets/Floor_turret.mdl"
+
+SWEP.AmmoIfHas = true
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.DefaultClip = 1
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "thumper"
+SWEP.Primary.Delay = 2
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_NORMAL
+SWEP.FullWalkSpeed = SPEED_SLOWEST
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType("slam")
+ self:SetDeploySpeed(1.1)
+ self:HideViewAndWorldModel()
+end
+
+function SWEP:SetReplicatedAmmo(count)
+ self:SetDTInt(0, count)
+end
+
+function SWEP:GetReplicatedAmmo()
+ return self:GetDTInt(0)
+end
+
+function SWEP:GetWalkSpeed()
+ if self:GetPrimaryAmmoCount() > 0 then
+ return self.FullWalkSpeed
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ return false
+ end
+
+ return true
+end
+
+function SWEP:Think()
+ if self.IdleAnimation and self.IdleAnimation <= CurTime() then
+ self.IdleAnimation = nil
+ self:SendWeaponAnim(ACT_VM_IDLE)
+ end
+
+ if SERVER then
+ local count = self:GetPrimaryAmmoCount()
+ if count ~= self:GetReplicatedAmmo() then
+ self:SetReplicatedAmmo(count)
+ self.Owner:ResetSpeed()
+ end
+ end
+end
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ return true
+end
+
+function SWEP:Holster()
+ return true
+end
+
+util.PrecacheModel("models/Combine_turrets/Floor_turret.mdl")
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gunturretcontrol.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gunturretcontrol.lua
new file mode 100644
index 0000000..5afbe74
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_gunturretcontrol.lua
@@ -0,0 +1,127 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Gun Turret Controller"
+ SWEP.Description = "Allows the user to manually take control of any turrets they own."
+
+ SWEP.ViewModelFOV = 50
+
+ SWEP.BobScale = 0.5
+ SWEP.SwayScale = 0.5
+
+ SWEP.Slot = 4
+ SWEP.SlotPos = 0
+end
+
+SWEP.ViewModel = "models/weapons/c_slam.mdl"
+SWEP.WorldModel = "models/weapons/w_slam.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Delay = 0
+SWEP.Primary.ClipSize = -1
+SWEP.Primary.DefaultClip = -1
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "none"
+
+SWEP.Secondary.Delay = 20
+SWEP.Secondary.Heal = 10
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_FAST
+
+SWEP.NoMagazine = true
+SWEP.Undroppable = true
+SWEP.NoPickupNotification = true
+
+SWEP.HoldType = "slam"
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType(self.HoldType)
+ self:SetDeploySpeed(10)
+end
+
+function SWEP:Think()
+ if self.IdleAnimation and self.IdleAnimation <= CurTime() then
+ self.IdleAnimation = nil
+ self:SendWeaponAnim(ACT_VM_IDLE)
+ end
+
+ if SERVER then
+ self:ControlClosestTurret()
+
+ for _, ent in pairs(ents.FindByClass("prop_gunturret")) do
+ if ent:GetObjectOwner() == self.Owner then
+ return
+ end
+ end
+
+ self.Owner:StripWeapon(self:GetClass())
+ end
+end
+
+function SWEP:ControlClosestTurret()
+ local closest, closestdist
+ local ownerpos = self.Owner:GetPos()
+ for _, ent in pairs(ents.FindByClass("prop_gunturret")) do
+ if ent:GetObjectOwner() == self.Owner then
+ local dist = ent:NearestPoint(ownerpos):Distance(ownerpos)
+ if not closestdist or dist < closestdist then
+ closest = ent
+ closestdist = dist
+ end
+ end
+ end
+ if closest then
+ self:SetTurret(closest)
+ end
+end
+
+function SWEP:PrimaryAttack()
+end
+
+function SWEP:SecondaryAttack()
+ if IsFirstTimePredicted() then
+ self:SetDTBool(0, not self:GetDTBool(0))
+
+ if CLIENT then
+ LocalPlayer():EmitSound(self:GetDTBool(0) and "buttons/button17.wav" or "buttons/button19.wav", 0)
+ end
+ end
+end
+
+function SWEP:GetTurret()
+ return self:GetDTEntity(0)
+end
+
+function SWEP:SetTurret(ent)
+ self:SetDTEntity(0, ent)
+end
+
+function SWEP:Reload()
+ return false
+end
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ return true
+end
+
+function SWEP:Holster()
+ return true
+end
+
+function SWEP:Reload()
+end
+
+if not CLIENT then return end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_hammer/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_hammer/cl_init.lua
new file mode 100644
index 0000000..395cb15
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_hammer/cl_init.lua
@@ -0,0 +1,22 @@
+include("shared.lua")
+
+SWEP.PrintName = "Carpenter's Hammer"
+SWEP.Description = "A simple but extremely useful tool. Allows you to hammer in nails to make barricades.\nPress SECONDARY FIRE to hammer in nail. It will be attached to whatever is behind it.\nPress RELOAD to take a nail out.\nUse PRIMARY FIRE to bash zombie brains or to repair damaged nails.\nYou get a point bonus for repairing damaged nails but a point penalty for removing another player's nails."
+
+SWEP.ViewModelFOV = 75
+
+function SWEP:DrawHUD()
+ if GetGlobalBool("classicmode") then return end
+
+ surface.SetFont("ZSHUDFontSmall")
+ local text = translate.Get("right_click_to_hammer_nail")
+ local nails = self:GetPrimaryAmmoCount()
+ local nTEXW, nTEXH = surface.GetTextSize(text)
+
+ draw.SimpleTextBlurry(translate.Format("nails_x", nails), "ZSHUDFontSmall", ScrW() - nTEXW * 0.5 - 24, ScrH() - nTEXH * 3, nails > 0 and COLOR_LIMEGREEN or COLOR_RED, TEXT_ALIGN_CENTER)
+
+ draw.SimpleTextBlurry(text, "ZSHUDFontSmall", ScrW() - nTEXW * 0.5 - 24, ScrH() - nTEXH * 2, COLOR_LIMEGREEN, TEXT_ALIGN_CENTER)
+
+ if GetConVarNumber("crosshair") ~= 1 then return end
+ self:DrawCrosshairDot()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_hammer/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_hammer/init.lua
new file mode 100644
index 0000000..2d4a42d
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_hammer/init.lua
@@ -0,0 +1,211 @@
+AddCSLuaFile("shared.lua")
+AddCSLuaFile("cl_init.lua")
+
+include("shared.lua")
+
+function SWEP:Reload()
+ if CurTime() < self:GetNextPrimaryFire() then return end
+
+ local owner = self.Owner
+ if owner:GetBarricadeGhosting() then return end
+
+ local tr = owner:MeleeTrace(self.MeleeRange, self.MeleeSize, owner:GetMeleeFilter())
+ local trent = tr.Entity
+ if not trent:IsValid() or not trent:IsNailed() then return end
+
+ local ent
+ local dist
+
+ for _, e in pairs(ents.FindByClass("prop_nail")) do
+ if not e.m_PryingOut and e:GetParent() == trent then
+ local edist = e:GetActualPos():Distance(tr.HitPos)
+ if not dist or edist < dist then
+ ent = e
+ dist = edist
+ end
+ end
+ end
+
+ if not ent or not gamemode.Call("CanRemoveNail", owner, ent) then return end
+
+ local nailowner = ent:GetOwner()
+ if nailowner:IsValid() and nailowner ~= owner and nailowner:Team() == TEAM_HUMAN and not gamemode.Call("PlayerIsAdmin", owner) and not gamemode.Call("CanRemoveOthersNail", owner, nailowner, ent) then return end
+
+ self:SetNextPrimaryFire(CurTime() + 1)
+
+ ent.m_PryingOut = true -- Prevents infinite loops
+
+ self:SendWeaponAnim(self.Alternate and ACT_VM_HITCENTER or ACT_VM_MISSCENTER)
+ self.Alternate = not self.Alternate
+
+ owner:DoAnimationEvent(ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE)
+
+ owner:EmitSound("weapons/melee/crowbar/crowbar_hit-"..math.random(4)..".ogg")
+
+ ent:GetParent():RemoveNail(ent, nil, self.Owner)
+
+ if nailowner and nailowner ~= owner and nailowner:Team() == TEAM_HUMAN then
+ if not gamemode.Call("PlayerIsAdmin", owner) and (nailowner:Frags() >= 75 or owner:Frags() < 75) then
+ owner:GivePenalty(30)
+ owner:ReflectDamage(20)
+ end
+
+ if nailowner:NearestPoint(tr.HitPos):Distance(tr.HitPos) <= 768 and (nailowner:HasWeapon("weapon_zs_hammer") or nailowner:HasWeapon("weapon_zs_electrohammer")) then
+ nailowner:GiveAmmo(1, self.Primary.Ammo)
+ else
+ owner:GiveAmmo(1, self.Primary.Ammo)
+ end
+ else
+ owner:GiveAmmo(1, self.Primary.Ammo)
+ end
+end
+
+function SWEP:OnMeleeHit(hitent, hitflesh, tr)
+ if hitent:IsValid() then
+ if hitent.HitByHammer and hitent:HitByHammer(self, self.Owner, tr) then
+ return
+ end
+
+ if hitent:IsNailed() then
+ local healstrength = GAMEMODE.NailHealthPerRepair * (self.Owner.HumanRepairMultiplier or 1) * self.HealStrength
+ local oldhealth = hitent:GetBarricadeHealth()
+ if oldhealth <= 0 or oldhealth >= hitent:GetMaxBarricadeHealth() or hitent:GetBarricadeRepairs() <= 0 then return end
+
+ hitent:SetBarricadeHealth(math.min(hitent:GetMaxBarricadeHealth(), hitent:GetBarricadeHealth() + math.min(hitent:GetBarricadeRepairs(), healstrength)))
+ local healed = hitent:GetBarricadeHealth() - oldhealth
+ hitent:SetBarricadeRepairs(math.max(hitent:GetBarricadeRepairs() - healed, 0))
+ self:PlayRepairSound(hitent)
+ gamemode.Call("PlayerRepairedObject", self.Owner, hitent, healed, self)
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(tr.HitPos)
+ effectdata:SetNormal(tr.HitNormal)
+ effectdata:SetMagnitude(1)
+ util.Effect("nailrepaired", effectdata, true, true)
+
+ return true
+ end
+ end
+end
+
+function SWEP:SecondaryAttack()
+ if self:GetPrimaryAmmoCount() <= 0 or CurTime() < self:GetNextPrimaryFire() or self.Owner:GetBarricadeGhosting() then return end
+
+ local owner = self.Owner
+
+ if GAMEMODE:IsClassicMode() then
+ owner:PrintTranslatedMessage(HUD_PRINTCENTER, "cant_do_that_in_classic_mode")
+ return
+ end
+
+ local tr = owner:TraceLine(64, MASK_SOLID, owner:GetMeleeFilter())
+ local trent = tr.Entity
+
+ if not trent:IsValid()
+ or not util.IsValidPhysicsObject(trent, tr.PhysicsBone)
+ or tr.Fraction == 0
+ or trent:GetMoveType() ~= MOVETYPE_VPHYSICS and not trent:GetNailFrozen()
+ or trent.NoNails
+ or trent:IsNailed() and (#trent.Nails >= 8 or trent:GetPropsInContraption() >= GAMEMODE.MaxPropsInBarricade)
+ or trent:GetMaxHealth() == 1 and trent:Health() == 0 and not trent.TotalHealth
+ or not trent:IsNailed() and not trent:GetPhysicsObject():IsMoveable() then return end
+
+ if not gamemode.Call("CanPlaceNail", owner, tr) then return end
+
+ local count = 0
+ for _, nail in pairs(trent:GetNails()) do
+ if nail:GetDeployer() == owner then
+ count = count + 1
+ if count >= 3 then
+ return
+ end
+ end
+ end
+
+ if tr.MatType == MAT_GRATE or tr.MatType == MAT_CLIP then
+ owner:PrintTranslatedMessage(HUD_PRINTCENTER, "impossible")
+ return
+ end
+ if tr.MatType == MAT_GLASS then
+ owner:PrintTranslatedMessage(HUD_PRINTCENTER, "trying_to_put_nails_in_glass")
+ return
+ end
+
+ if trent:IsValid() then
+ for _, nail in pairs(ents.FindByClass("prop_nail")) do
+ if nail:GetParent() == trent and nail:GetActualPos():Distance(tr.HitPos) <= 16 then
+ owner:PrintTranslatedMessage(HUD_PRINTCENTER, "too_close_to_another_nail")
+ return
+ end
+ end
+
+ if trent:GetBarricadeHealth() <= 0 and trent:GetMaxBarricadeHealth() > 0 then
+ owner:PrintTranslatedMessage(HUD_PRINTCENTER, "object_too_damaged_to_be_used")
+ return
+ end
+ end
+
+ local aimvec = owner:GetAimVector()
+
+ local trtwo = util.TraceLine({start = tr.HitPos, endpos = tr.HitPos + aimvec * 24, filter = {owner, trent}, mask = MASK_SOLID})
+
+ if trtwo.HitSky then return end
+
+ local ent = trtwo.Entity
+ if trtwo.HitWorld
+ or ent:IsValid() and util.IsValidPhysicsObject(ent, trtwo.PhysicsBone) and (ent:GetMoveType() == MOVETYPE_VPHYSICS or ent:GetNailFrozen()) and not ent.NoNails and not (not ent:IsNailed() and not ent:GetPhysicsObject():IsMoveable()) and not (ent:GetMaxHealth() == 1 and ent:Health() == 0 and not ent.TotalHealth) then
+ if trtwo.MatType == MAT_GRATE or trtwo.MatType == MAT_CLIP then
+ owner:PrintTranslatedMessage(HUD_PRINTCENTER, "impossible")
+ return
+ end
+ if trtwo.MatType == MAT_GLASS then
+ owner:PrintTranslatedMessage(HUD_PRINTCENTER, "trying_to_put_nails_in_glass")
+ return
+ end
+
+ if ent and ent:IsValid() and (ent.NoNails or ent:IsNailed() and (#ent.Nails >= 8 or ent:GetPropsInContraption() >= GAMEMODE.MaxPropsInBarricade)) then return end
+
+ if ent:GetBarricadeHealth() <= 0 and ent:GetMaxBarricadeHealth() > 0 then
+ owner:PrintTranslatedMessage(HUD_PRINTCENTER, "object_too_damaged_to_be_used")
+ return
+ end
+
+ if GAMEMODE:EntityWouldBlockSpawn(ent) then return end
+
+ local cons = constraint.Weld(trent, ent, tr.PhysicsBone, trtwo.PhysicsBone, 0, true)
+ if cons ~= nil then
+ for _, oldcons in pairs(constraint.FindConstraints(trent, "Weld")) do
+ if oldcons.Ent1 == ent or oldcons.Ent2 == ent then
+ cons = oldcons.Constraint
+ break
+ end
+ end
+ end
+
+ if not cons then return end
+
+ self:SendWeaponAnim(self.Alternate and ACT_VM_HITCENTER or ACT_VM_MISSCENTER)
+ self.Alternate = not self.Alternate
+
+ owner:DoAnimationEvent(ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE)
+
+ self:SetNextPrimaryFire(CurTime() + 1)
+ self:TakePrimaryAmmo(1)
+
+ trent:EmitSound("weapons/melee/crowbar/crowbar_hit-"..math.random(4)..".ogg")
+
+ local nail = ents.Create("prop_nail")
+ if nail:IsValid() then
+ nail:SetActualOffset(tr.HitPos, trent)
+ nail:SetPos(tr.HitPos - aimvec * 8)
+ nail:SetAngles(aimvec:Angle())
+ nail:AttachTo(trent, ent, tr.PhysicsBone, trtwo.PhysicsBone)
+ nail:Spawn()
+ nail:SetDeployer(owner)
+
+ cons:DeleteOnRemove(nail)
+
+ gamemode.Call("OnNailCreated", trent, ent, nail)
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_hammer/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_hammer/shared.lua
new file mode 100644
index 0000000..38092b8
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_hammer/shared.lua
@@ -0,0 +1,47 @@
+AddCSLuaFile("shared.lua")
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.DamageType = DMG_CLUB
+
+SWEP.ViewModel = "models/weapons/v_hammer/v_hammer.mdl"
+SWEP.WorldModel = "models/weapons/w_hammer.mdl"
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "GaussEnergy"
+SWEP.Primary.Delay = 1
+SWEP.Primary.DefaultClip = 16
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.MeleeDamage = 35
+SWEP.MeleeRange = 50
+SWEP.MeleeSize = 0.875
+
+SWEP.UseMelee1 = true
+
+SWEP.NoPropThrowing = true
+
+SWEP.HitGesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE
+SWEP.MissGesture = SWEP.HitGesture
+
+SWEP.SwingTime = 0.25
+SWEP.SwingRotation = Angle(30, -30, -30)
+SWEP.SwingOffset = Vector(0, -30, 0)
+SWEP.SwingHoldType = "grenade"
+
+SWEP.HealStrength = 1
+
+SWEP.NoHolsterOnCarry = true
+
+function SWEP:PlayHitSound()
+ self:EmitSound("weapons/melee/crowbar/crowbar_hit-"..math.random(4)..".ogg", 75, math.random(110, 115))
+end
+
+function SWEP:PlayRepairSound(hitent)
+ hitent:EmitSound("npc/dog/dog_servo"..math.random(7, 8)..".wav", 70, math.random(100, 105))
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_headcrab/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_headcrab/cl_init.lua
new file mode 100644
index 0000000..776041f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_headcrab/cl_init.lua
@@ -0,0 +1,13 @@
+include("shared.lua")
+
+SWEP.PrintName = "Headcrab"
+SWEP.DrawCrosshair = false
+
+function SWEP:DrawHUD()
+ if GetConVarNumber("crosshair") ~= 1 then return end
+ self:DrawCrosshairDot()
+end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_headcrab/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_headcrab/init.lua
new file mode 100644
index 0000000..25b35c2
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_headcrab/init.lua
@@ -0,0 +1,4 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_headcrab/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_headcrab/shared.lua
new file mode 100644
index 0000000..6befc68
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_headcrab/shared.lua
@@ -0,0 +1,233 @@
+SWEP.ZombieOnly = true
+SWEP.IsMelee = true
+
+SWEP.ViewModel = "models/weapons/v_crowbar.mdl"
+SWEP.WorldModel = "models/weapons/w_crowbar.mdl"
+
+SWEP.Primary.ClipSize = -1
+SWEP.Primary.DefaultClip = -1
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "none"
+SWEP.Primary.Delay = 0.4
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.Delay = 0.22
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = true
+SWEP.Secondary.Ammo = "none"
+
+SWEP.PounceDamage = 7
+SWEP.PounceDamageType = DMG_SLASH
+
+SWEP.NoHitRecovery = 0.75
+SWEP.HitRecovery = 1
+
+SWEP.BurrowTime = 1.5
+
+function SWEP:Initialize()
+ self:HideViewAndWorldModel()
+end
+
+if SERVER then SWEP.NextHeal = 0 end
+function SWEP:Think()
+ local curtime = CurTime()
+ local owner = self.Owner
+
+ if self:GetBurrowTime() > 0 and curtime >= self:GetBurrowTime() then
+ if not self:CanBurrow() then
+ self:SetBurrowTime(-(curtime + self.BurrowTime))
+ else
+ owner:DrawShadow(false)
+ if SERVER and curtime >= self.NextHeal then
+ self.NextHeal = curtime + 0.333
+
+ if owner:Health() < owner:GetMaxHealth() then
+ owner:SetHealth(owner:Health() + 1)
+ end
+ end
+ end
+ elseif self:GetBurrowTime() < 0 and curtime >= -self:GetBurrowTime() then
+ self:SetBurrowTime(0)
+ elseif self:GetPouncing() then
+ if owner:IsOnGround() or 1 < owner:WaterLevel() then
+ self:SetPouncing(false)
+ self:SetNextPrimaryFire(curtime + self.NoHitRecovery)
+ else
+ owner:LagCompensation(true)
+
+ local shootpos = owner:GetShootPos()
+ local trace = util.TraceHull({start = shootpos, endpos = shootpos + owner:GetForward() * 8, mins = owner:OBBMins() * 0.8, maxs = owner:OBBMaxs() * 0.8, filter = owner:GetMeleeFilter()})
+ local ent = trace.Entity
+
+ if trace.Hit then
+ self:SetPouncing(false)
+ self:SetNextPrimaryFire(curtime + self.HitRecovery)
+ end
+
+ if ent:IsValid() then
+ self:SetPouncing(false)
+
+ if SERVER then
+ self:EmitBiteSound()
+ end
+
+ local damage = self.PounceDamage
+
+ local phys = ent:GetPhysicsObject()
+ if ent:IsPlayer() then
+ ent:MeleeViewPunch(damage)
+ if SERVER then
+ local nearest = ent:NearestPoint(shootpos)
+ util.Blood(nearest, math.Rand(damage * 0.5, damage * 0.75), (nearest - shootpos):GetNormalized(), math.Rand(damage * 5, damage * 10), true)
+ end
+
+ owner:AirBrake()
+ elseif phys:IsValid() and phys:IsMoveable() then
+ phys:ApplyForceOffset(damage * 600 * owner:EyeAngles():Forward(), (ent:NearestPoint(shootpos) + ent:GetPos() * 2) / 3)
+ ent:SetPhysicsAttacker(owner)
+ end
+
+ ent:TakeSpecialDamage(damage, self.PounceDamageType, owner, self, trace.HitPos)
+
+ owner:ViewPunch(Angle(math.Rand(-20, 20), math.Rand(-20, 20), math.Rand(-20, 20)))
+ elseif trace.HitWorld then
+ if SERVER then
+ self:EmitHitSound()
+ end
+ end
+
+ owner:LagCompensation(false)
+ end
+ end
+
+ self:NextThink(curtime)
+ return true
+end
+
+function SWEP:PrimaryAttack()
+ local owner = self.Owner
+ if self:GetPouncing() or CurTime() < self:GetNextPrimaryFire() or not owner:IsOnGround() or self:IsBurrowing() then return end
+
+ local vel = owner:GetAimVector()
+ vel.z = math.max(0.45, vel.z)
+ vel:Normalize()
+
+ owner:SetGroundEntity(NULL)
+ owner:SetLocalVelocity(vel * 450)
+ owner:DoAnimationEvent(ACT_RANGE_ATTACK1)
+
+ if SERVER then
+ self:EmitAttackSound()
+ end
+
+ self.m_ViewAngles = owner:EyeAngles()
+
+ self:SetPouncing(true)
+end
+
+function SWEP:SecondaryAttack()
+ if CurTime() < self:GetNextSecondaryFire() then return end
+ self:SetNextSecondaryFire(CurTime() + 2)
+
+ if SERVER then
+ self:EmitIdleSound()
+ end
+end
+
+function SWEP:Reload()
+ local owner = self.Owner
+ if self:GetPouncing() or CurTime() < self:GetNextPrimaryFire() or not owner:IsOnGround() then return end
+
+ if self:GetBurrowTime() == 0 then
+ if self:CanBurrow() then
+ self:SetBurrowTime(CurTime() + self.BurrowTime)
+ if SERVER then owner:EmitSound("npc/antlion/digdown1.wav", 60, 100) end
+ end
+ elseif self:GetBurrowTime() > 0 and CurTime() >= self:GetBurrowTime() then
+ self:SetBurrowTime(-(CurTime() + self.BurrowTime))
+ if SERVER then owner:EmitSound("npc/antlion/digup1.wav", 60, 100) end
+ owner:DrawShadow(true)
+ end
+end
+
+function SWEP:CanBurrow()
+ local owner = self.Owner
+ local tr = util.TraceLine({start = owner:GetPos(), endpos = owner:GetPos() - owner:GetUp() * 8, mask = MASK_SOLID_BRUSHONLY})
+ return tr.HitWorld and (tr.MatType == MAT_DIRT or tr.MatType == MAT_SAND or tr.MatType == MAT_SLOSH or tr.MatType == MAT_FOILAGE or tr.MatType == 88)
+end
+
+function SWEP:Move(mv)
+ if self:IsPouncing() then
+ mv:SetSideSpeed(0)
+ mv:SetForwardSpeed(0)
+ elseif self:IsBurrowed() then
+ mv:SetMaxSpeed(80)
+ mv:SetMaxClientSpeed(80)
+ elseif self:IsBurrowing() then
+ mv:SetSideSpeed(0)
+ mv:SetForwardSpeed(0)
+ mv:SetVelocity(vector_origin)
+ return true
+ end
+end
+
+function SWEP:EmitHitSound()
+ self.Owner:EmitSound("npc/headcrab_poison/ph_wallhit"..math.random(1, 2)..".wav")
+end
+
+function SWEP:EmitBiteSound()
+ self.Owner:EmitSound("NPC_HeadCrab.Bite")
+end
+
+function SWEP:EmitIdleSound()
+ local ent = self.Owner:MeleeTrace(4096, 24, self.Owner:GetMeleeFilter()).Entity
+ if ent:IsValid() and ent:IsPlayer() then
+ self.Owner:EmitSound("NPC_HeadCrab.Alert")
+ else
+ self.Owner:EmitSound("NPC_HeadCrab.Idle")
+ end
+end
+
+function SWEP:EmitAttackSound()
+ self.Owner:EmitSound("NPC_HeadCrab.Attack")
+end
+
+function SWEP:SetPouncing(pouncing)
+ if not pouncing then
+ self.m_ViewAngles = nil
+ end
+
+ self:SetDTBool(1, pouncing)
+end
+
+function SWEP:GetPouncing()
+ return self:GetDTBool(1)
+end
+SWEP.IsPouncing = SWEP.GetPouncing
+
+function SWEP:SetBurrowTime(time)
+ self:SetDTFloat(1, time)
+
+ if SERVER then
+ if time == 0 then
+ self.Owner:TemporaryNoCollide(true)
+ else
+ self.Owner:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
+ end
+ end
+end
+
+function SWEP:GetBurrowTime()
+ return self:GetDTFloat(1)
+end
+
+function SWEP:IsBurrowing()
+ return self:GetBurrowTime() ~= 0
+end
+
+function SWEP:IsBurrowed()
+ return self:GetBurrowTime() > 0 and CurTime() >= self:GetBurrowTime()
+end
+
+util.PrecacheSound("npc/antlion/digdown1.wav")
+util.PrecacheSound("npc/antlion/digup1.wav")
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_hook.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_hook.lua
new file mode 100644
index 0000000..cef6921
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_hook.lua
@@ -0,0 +1,84 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Meat Hook"
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+
+ SWEP.ShowViewModel = false
+ SWEP.ShowWorldModel = false
+
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props_junk/meathook001a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(5, 1.363, -5), angle = Angle(0, 90, 0), size = Vector(0.5, 0.5, 0.5), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props_junk/meathook001a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(3.181, 4, -9), angle = Angle(0, 0, 0), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.DamageType = DMG_SLASH
+
+SWEP.ViewModel = "models/weapons/c_crowbar.mdl"
+SWEP.WorldModel = "models/props_junk/meathook001a.mdl"
+SWEP.UseHands = true
+
+SWEP.MeleeDamage = 40
+SWEP.MeleeRange = 50
+SWEP.MeleeSize = 1.15
+
+SWEP.HitGesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE
+SWEP.MissGesture = SWEP.HitGesture
+
+SWEP.SwingRotation = Angle(30, -30, -30)
+SWEP.SwingTime = 0.75
+SWEP.SwingHoldType = "grenade"
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("weapons/iceaxe/iceaxe_swing1.wav", 75, math.random(95, 105))
+end
+
+function SWEP:PlayHitFleshSound()
+ self:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav", 75, math.random(120, 130))
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("physics/metal/metal_sheet_impact_bullet"..math.random(2)..".wav")
+end
+
+function SWEP:OnMeleeHit(hitent, hitflesh, tr)
+ if hitent:IsValid() and hitent:IsPlayer() and hitent:Health() > self.MeleeDamage then
+ hitent:AddLegDamage(30)
+
+ if SERVER then
+ local ang = self.Owner:EyeAngles()
+ ang:RotateAroundAxis(ang:Forward(), 180)
+
+ local ent = ents.Create("prop_meathook")
+ if ent:IsValid() then
+ ent:SetPos(tr.HitPos)
+ ent:Spawn()
+ ent:SetOwner(self.Owner)
+
+ local followed = false
+ if hitent:GetBoneCount() > 1 then
+ local boneindex = hitent:NearestBone(tr.HitPos)
+ if boneindex and boneindex > 0 then
+ ent:FollowBone(hitent, boneindex)
+ ent:SetPos((hitent:GetBonePositionMatrixed(boneindex) * 2 + tr.HitPos) / 3)
+ followed = true
+ end
+ end
+ if not followed then
+ ent:SetParent(hitent)
+ end
+
+ ent:SetAngles(ang)
+ end
+
+ self:Remove()
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_hunter.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_hunter.lua
new file mode 100644
index 0000000..29ed811
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_hunter.lua
@@ -0,0 +1,115 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Hunter' Rifle"
+ SWEP.Description = "Fires special large caliber rounds. The reloading time is slow but it packs a powerful punch."
+ SWEP.Slot = 3
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+
+ SWEP.HUD3DBone = "v_weapon.awm_parent"
+ SWEP.HUD3DPos = Vector(-1.25, -3.5, -16)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+ SWEP.HUD3DScale = 0.02
+end
+
+sound.Add(
+{
+ name = "Weapon_Hunter.Single",
+ channel = CHAN_WEAPON,
+ volume = 1.0,
+ soundlevel = 100,
+ pitchstart = 134,
+ pitchend = 10,
+ sound = "weapons/awp/awp1.wav"
+})
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "ar2"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_snip_awp.mdl"
+SWEP.WorldModel = "models/weapons/w_snip_awp.mdl"
+SWEP.UseHands = true
+
+SWEP.ReloadSound = Sound("Weapon_AWP.ClipOut")
+SWEP.Primary.Sound = Sound("Weapon_Hunter.Single")
+SWEP.Primary.Damage = 115
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 1.5
+SWEP.ReloadDelay = SWEP.Primary.Delay
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "357"
+SWEP.Primary.DefaultClip = 15
+
+SWEP.Primary.Gesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_CROSSBOW
+SWEP.ReloadGesture = ACT_HL2MP_GESTURE_RELOAD_SHOTGUN
+
+SWEP.ConeMax = 0.115
+SWEP.ConeMin = 0
+
+SWEP.IronSightsPos = Vector(5.015, -8, 2.52)
+SWEP.IronSightsAng = Vector(0, 0, 0)
+
+SWEP.WalkSpeed = SPEED_SLOWER
+
+SWEP.TracerName = "AR2Tracer"
+
+function SWEP:IsScoped()
+ return self:GetIronsights() and self.fIronTime and self.fIronTime + 0.25 <= CurTime()
+end
+
+--[[function SWEP:EmitFireSound()
+ self:EmitSound(self.Primary.Sound, 85, 80)
+end]]
+
+function SWEP:SendWeaponAnimation()
+ self:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
+end
+
+function SWEP.BulletCallback(attacker, tr, dmginfo)
+ local effectdata = EffectData()
+ effectdata:SetOrigin(tr.HitPos)
+ effectdata:SetNormal(tr.HitNormal)
+ util.Effect("hit_hunter", effectdata)
+
+ GenericBulletCallback(attacker, tr, dmginfo)
+end
+
+if CLIENT then
+ SWEP.IronsightsMultiplier = 0.25
+
+ function SWEP:GetViewModelPosition(pos, ang)
+ if self:IsScoped() then
+ return pos + ang:Up() * 256, ang
+ end
+
+ return self.BaseClass.GetViewModelPosition(self, pos, ang)
+ end
+
+ local matScope = Material("zombiesurvival/scope")
+ function SWEP:DrawHUDBackground()
+ if self:IsScoped() then
+ local scrw, scrh = ScrW(), ScrH()
+ local size = math.min(scrw, scrh)
+ surface.SetMaterial(matScope)
+ surface.SetDrawColor(255, 255, 255, 255)
+ surface.DrawTexturedRect((scrw - size) * 0.5, (scrh - size) * 0.5, size, size)
+ surface.SetDrawColor(0, 0, 0, 255)
+ if scrw > size then
+ local extra = (scrw - size) * 0.5
+ surface.DrawRect(0, 0, extra, scrh)
+ surface.DrawRect(scrw - extra, 0, extra, scrh)
+ end
+ if scrh > size then
+ local extra = (scrh - size) * 0.5
+ surface.DrawRect(0, 0, scrw, extra)
+ surface.DrawRect(0, scrh - extra, scrw, extra)
+ end
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_inferno.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_inferno.lua
new file mode 100644
index 0000000..785cc36
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_inferno.lua
@@ -0,0 +1,44 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Inferno' AUG"
+ SWEP.Slot = 2
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+
+ SWEP.HUD3DBone = "v_weapon.aug_Parent"
+ SWEP.HUD3DPos = Vector(-1, -2.5, -3)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+ SWEP.HUD3DScale = 0.015
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "ar2"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_rif_aug.mdl"
+SWEP.WorldModel = "models/weapons/w_rif_aug.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("Weapon_AUG.Single")
+SWEP.Primary.Damage = 23
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.095
+
+SWEP.Primary.ClipSize = 30
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "ar2"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.Primary.Gesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2
+SWEP.ReloadGesture = ACT_HL2MP_GESTURE_RELOAD_AR2
+
+SWEP.ConeMax = 0.08
+SWEP.ConeMin = 0.02
+
+SWEP.WalkSpeed = SPEED_SLOW
+
+SWEP.IronSightsAng = Vector(-1, -1, 0)
+SWEP.IronSightsPos = Vector(-3, 4, 3)
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_keyboard.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_keyboard.lua
new file mode 100644
index 0000000..1b755d9
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_keyboard.lua
@@ -0,0 +1,47 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Keyboard"
+
+ SWEP.ViewModelFOV = 55
+ SWEP.ViewModelFlip = false
+
+ SWEP.ShowViewModel = false
+ SWEP.ShowWorldModel = false
+
+ SWEP.ViewModelBoneMods = {
+ ["ValveBiped.Bip01_R_Finger02"] = { scale = Vector(1, 1, 1), pos = Vector(0, 0, 0), angle = Angle(0, -45.715, 0) },
+ ["ValveBiped.Bip01_R_Finger01"] = { scale = Vector(1, 1, 1), pos = Vector(0, 0, 0), angle = Angle(0, -49.524, 0) }
+ }
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props_c17/computer01_keyboard.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(4.091, 4.4, -7.728), angle = Angle(180, -82.842, 80.794), size = Vector(0.75, 0.75, 0.75), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props_c17/computer01_keyboard.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(5, 4.091, -8.636), angle = Angle(180, -60.341, 90), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.HoldType = "melee"
+
+SWEP.DamageType = DMG_CLUB
+
+SWEP.ViewModel = "models/weapons/c_stunstick.mdl"
+SWEP.WorldModel = "models/props_c17/computer01_keyboard.mdl"
+SWEP.UseHands = true
+
+SWEP.MeleeDamage = 35
+SWEP.MeleeRange = 52
+SWEP.MeleeSize = 1.25
+
+SWEP.Primary.Delay = 0.75
+
+SWEP.SwingTime = 0.3
+SWEP.SwingRotation = Angle(30, -30, -30)
+SWEP.SwingOffset = Vector(0, -30, 0)
+SWEP.SwingHoldType = "grenade"
+
+function SWEP:PlayHitSound()
+ self:EmitSound("weapons/melee/keyboard/keyboard_hit-0"..math.random(4)..".ogg")
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_lamp.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_lamp.lua
new file mode 100644
index 0000000..3d84f71
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_lamp.lua
@@ -0,0 +1,52 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Lamp"
+
+ SWEP.ViewModelFOV = 65
+ SWEP.ViewModelFlip = false
+
+ SWEP.ShowViewModel = false
+ SWEP.ShowWorldModel = false
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props_interiors/Furniture_Lamp01a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(3, 1.85, -8), angle = Angle(183, 0, 2), size = Vector(1.5, 1.5, 1.5), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props_interiors/Furniture_Lamp01a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(2.837, 1.638, -10), angle = Angle(180, 0, 0), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.ViewModel = "models/weapons/c_stunstick.mdl"
+SWEP.WorldModel = "models/props_interiors/Furniture_Lamp01a.mdl"
+SWEP.UseHands = true
+
+SWEP.HoldType = "melee2"
+
+SWEP.DamageType = DMG_CLUB
+
+SWEP.MeleeDamage = 44
+SWEP.MeleeRange = 68
+SWEP.MeleeSize = 2
+
+SWEP.Primary.Delay = 1
+
+SWEP.WalkSpeed = SPEED_SLOW
+
+SWEP.SwingRotation = Angle(0, -90, -60)
+SWEP.SwingOffset = Vector(0, 30, -40)
+SWEP.SwingTime = 0.4
+SWEP.SwingHoldType = "melee"
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("weapons/iceaxe/iceaxe_swing1.wav", 80, math.Rand(65, 70))
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("physics/metal/metal_solid_impact_hard"..math.random(4, 5)..".wav")
+end
+
+function SWEP:PlayHitFleshSound()
+ self:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav")
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_m4.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_m4.lua
new file mode 100644
index 0000000..c8d8ee0
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_m4.lua
@@ -0,0 +1,48 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Stalker' M4"
+ SWEP.Description = "Using this gun will severely reduce the distance in which zombies can see your aura."
+ SWEP.Slot = 2
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+
+ SWEP.HUD3DBone = "v_weapon.m4_Parent"
+ SWEP.HUD3DPos = Vector(-0.5, -5, -1.2)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+ SWEP.HUD3DScale = 0.015
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "smg"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_rif_m4a1.mdl"
+SWEP.WorldModel = "models/weapons/w_rif_m4a1.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("Weapon_m4a1.Single")
+SWEP.Primary.Damage = 24
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.11
+
+SWEP.Primary.ClipSize = 30
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "ar2"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.Primary.Gesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1
+SWEP.ReloadGesture = ACT_HL2MP_GESTURE_RELOAD_SMG1
+
+SWEP.ConeMax = 0.125
+SWEP.ConeMin = 0.045
+
+SWEP.WalkSpeed = SPEED_SLOW
+
+SWEP.IronSightsPos = Vector(-3, 0, 2)
+
+function SWEP:GetAuraRange()
+ return 512
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_magnum.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_magnum.lua
new file mode 100644
index 0000000..6a2c8ee
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_magnum.lua
@@ -0,0 +1,56 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Ricochete' Magnum"
+ SWEP.Description = "This gun's bullets will bounce off of walls which will then deal extra damage."
+ SWEP.Slot = 1
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+
+ SWEP.HUD3DBone = "Python"
+ SWEP.HUD3DPos = Vector(0.85, 0, -2.5)
+ SWEP.HUD3DScale = 0.015
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "revolver"
+
+SWEP.ViewModel = "models/weapons/c_357.mdl"
+SWEP.WorldModel = "models/weapons/w_357.mdl"
+SWEP.UseHands = true
+
+SWEP.CSMuzzleFlashes = false
+
+SWEP.Primary.Sound = Sound("Weapon_357.Single")
+SWEP.Primary.Delay = 0.7
+SWEP.Primary.Damage = 59
+SWEP.Primary.NumShots = 1
+
+SWEP.Primary.ClipSize = 6
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "pistol"
+SWEP.Primary.Gesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.ConeMax = 0.075
+SWEP.ConeMin = 0.04
+
+SWEP.IronSightsPos = Vector(-4.65, 4, 0.25)
+SWEP.IronSightsAng = Vector(0, 0, 1)
+
+local function DoRicochet(attacker, hitpos, hitnormal, normal, damage)
+ attacker.RicochetBullet = true
+ attacker:FireBullets({Num = 1, Src = hitpos, Dir = 2 * hitnormal * hitnormal:Dot(normal * -1) + normal, Spread = Vector(0, 0, 0), Tracer = 1, TracerName = "rico_trace", Force = damage * 0.15, Damage = damage, Callback = GenericBulletCallback})
+ attacker.RicochetBullet = nil
+end
+function SWEP.BulletCallback(attacker, tr, dmginfo)
+ if SERVER and tr.HitWorld and not tr.HitSky then
+ local hitpos, hitnormal, normal, dmg = tr.HitPos, tr.HitNormal, tr.Normal, dmginfo:GetDamage() * 1.5
+ timer.Simple(0, function() DoRicochet(attacker, hitpos, hitnormal, normal, dmg) end)
+ end
+
+ GenericBulletCallback(attacker, tr, dmginfo)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_manhack.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_manhack.lua
new file mode 100644
index 0000000..b2a775c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_manhack.lua
@@ -0,0 +1,203 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Manhack"
+ SWEP.Description = "A deployable, remotely controlled device.\nIdeal for scouting but also can be used for attacking from safety."
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 50
+ SWEP.ShowViewModel = true
+ SWEP.ShowWorldModel = false
+
+ SWEP.ViewModelBoneMods = {
+ ["ValveBiped.cube1"] = { scale = Vector(0.009, 0.009, 0.009), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) },
+ ["ValveBiped.cube2"] = { scale = Vector(0.009, 0.009, 0.009), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) },
+ ["ValveBiped.cube3"] = { scale = Vector(0.009, 0.009, 0.009), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) },
+ ["ValveBiped.cube"] = { scale = Vector(0.009, 0.009, 0.009), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) }
+ }
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/manhack.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(5, 4, 0), angle = Angle(-54.206, 58.294, -50.114), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/manhack.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(5, 5, 0), angle = Angle(-43.978, 27.614, 0), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.ViewModel = "models/weapons/c_bugbait.mdl"
+SWEP.WorldModel = "models/manhack.mdl"
+SWEP.UseHands = true
+
+SWEP.DeployClass = "prop_manhack"
+SWEP.ControlWeapon = "weapon_zs_manhackcontrol"
+
+SWEP.HoldType = "grenade"
+
+SWEP.WalkSpeed = SPEED_FAST
+
+SWEP.AmmoIfHas = true
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "manhack"
+SWEP.Primary.Delay = 1
+SWEP.Primary.DefaultClip = 1
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_FAST
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType("grenade")
+ self:SetDeploySpeed(1.1)
+
+ if CLIENT then
+ self:Anim_Initialize()
+ end
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ for _, ent in pairs(ents.FindByClass("prop_manhac*")) do
+ if ent:GetOwner() == self.Owner then return false end
+ end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ return false
+ end
+
+ return true
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+
+ local owner = self.Owner
+ self:SendWeaponAnim(ACT_VM_THROW)
+ owner:DoAttackEvent()
+
+ self:TakePrimaryAmmo(1)
+ self.NextDeploy = CurTime() + 0.75
+
+ if SERVER then
+ local ent = ents.Create(self.DeployClass)
+ if ent:IsValid() then
+ ent:SetPos(owner:GetShootPos())
+ ent:SetOwner(owner)
+ ent:Spawn()
+
+ local stored = owner:PopPackedItem(ent:GetClass())
+ if stored then
+ ent:SetObjectHealth(stored[1])
+ end
+
+ ent:EmitSound("WeaponFrag.Throw")
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:SetVelocityInstantaneous(self.Owner:GetAimVector() * 200)
+ end
+
+ if not owner:HasWeapon(self.ControlWeapon) then
+ owner:Give(self.ControlWeapon)
+ end
+ owner:SelectWeapon(self.ControlWeapon)
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ owner:StripWeapon(self:GetClass())
+ end
+ end
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:CanSecondaryAttack()
+ return false
+end
+
+function SWEP:Reload()
+ return false
+end
+
+function SWEP:Deploy()
+ GAMEMODE:WeaponDeployed(self.Owner, self)
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SendWeaponAnim(ACT_VM_THROW)
+ end
+
+ return true
+end
+
+function SWEP:Holster()
+ self.NextDeploy = nil
+
+ if CLIENT then
+ self:Anim_Holster()
+ end
+
+ return true
+end
+
+function SWEP:Think()
+ if self.NextDeploy and self.NextDeploy <= CurTime() then
+ self.NextDeploy = nil
+
+ if 0 < self:GetPrimaryAmmoCount() then
+ self:SendWeaponAnim(ACT_VM_DRAW)
+ else
+ self:SendWeaponAnim(ACT_VM_THROW)
+ if SERVER then
+ self:Remove()
+ end
+ end
+ end
+end
+
+local colBG = Color(16, 16, 16, 90)
+local colWhite = Color(220, 220, 220, 230)
+
+SWEP.HUD3DPos = Vector(5, 2, 0)
+
+function SWEP:PostDrawViewModel(vm)
+ if not self.HUD3DPos or GAMEMODE.WeaponHUDMode == 1 then return end
+
+ local bone = vm:LookupBone("ValveBiped.Bip01_R_Hand")
+ if not bone then return end
+
+ local m = vm:GetBoneMatrix(bone)
+ if not m then return end
+
+ local pos, ang = m:GetTranslation(), m:GetAngles()
+
+ local offset = self.HUD3DPos
+
+ pos = pos + ang:Forward() * offset.x + ang:Right() * offset.y + ang:Up() * offset.z
+
+ ang:RotateAroundAxis(ang:Up(), math.sin(CurTime() * math.pi) * 20)
+ ang:RotateAroundAxis(ang:Right(), CurTime() * 180)
+
+ pos = pos + ang:Forward() * 7
+
+ ang:RotateAroundAxis(ang:Right(), 270)
+ ang:RotateAroundAxis(ang:Up(), 180)
+
+ local wid, hei = 144, 144
+ local x, y = wid * -0.5, hei * -0.5
+ local clip = self:GetPrimaryAmmoCount()
+
+ cam.Start3D2D(pos, ang, 0.0125)
+ draw.RoundedBox(32, x, y, wid, hei, colBG)
+ draw.SimpleText(clip, "ZS3D2DFontBig", x + wid * 0.5, y + hei * 0.5, colWhite, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+ cam.End3D2D()
+end
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_manhack_saw.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_manhack_saw.lua
new file mode 100644
index 0000000..3dcb3ac
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_manhack_saw.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Manhack - Saw Attachment"
+ SWEP.Description = "A modified manhack with a saw blade attachment.\nDoes significantly more damage and is more durable. Slightly less easy to control."
+end
+
+SWEP.Base = "weapon_zs_manhack"
+
+SWEP.DeployClass = "prop_manhack_saw"
+SWEP.ControlWeapon = "weapon_zs_manhackcontrol_saw"
+
+SWEP.Primary.Ammo = "manhack_saw"
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_manhackcontrol.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_manhackcontrol.lua
new file mode 100644
index 0000000..0d99f81
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_manhackcontrol.lua
@@ -0,0 +1,104 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Manhack Control"
+ SWEP.Description = "Controller for your Manhack."
+
+ SWEP.ViewModelFOV = 50
+
+ SWEP.BobScale = 0.5
+ SWEP.SwayScale = 0.5
+
+ SWEP.Slot = 4
+ SWEP.SlotPos = 0
+end
+
+SWEP.ViewModel = "models/weapons/c_slam.mdl"
+SWEP.WorldModel = "models/weapons/w_slam.mdl"
+SWEP.UseHands = true
+
+SWEP.EntityClass = "prop_manhack"
+
+SWEP.Primary.Delay = 0
+SWEP.Primary.ClipSize = -1
+SWEP.Primary.DefaultClip = -1
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "none"
+
+SWEP.Secondary.Delay = 20
+SWEP.Secondary.Heal = 10
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_FAST
+
+SWEP.NoMagazine = true
+SWEP.Undroppable = true
+SWEP.NoPickupNotification = true
+
+SWEP.HoldType = "slam"
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType(self.HoldType)
+ self:SetDeploySpeed(10)
+end
+
+function SWEP:Think()
+ if self.IdleAnimation and self.IdleAnimation <= CurTime() then
+ self.IdleAnimation = nil
+ self:SendWeaponAnim(ACT_VM_IDLE)
+ end
+
+ if SERVER then
+ for _, ent in pairs(ents.FindByClass(self.EntityClass)) do
+ if ent:GetOwner() == self.Owner then
+ return
+ end
+ end
+
+ self.Owner:StripWeapon(self:GetClass())
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if IsFirstTimePredicted() then
+ self:SetDTBool(0, not self:GetDTBool(0))
+
+ if CLIENT then
+ LocalPlayer():EmitSound(self:GetDTBool(0) and "buttons/button17.wav" or "buttons/button19.wav", 0)
+ end
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+ return false
+end
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ return true
+end
+
+function SWEP:Holster()
+ self:SetDTBool(0, false)
+
+ return true
+end
+
+function SWEP:Reload()
+end
+
+if not CLIENT then return end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_manhackcontrol_saw.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_manhackcontrol_saw.lua
new file mode 100644
index 0000000..f78fd89
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_manhackcontrol_saw.lua
@@ -0,0 +1,10 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_manhackcontrol"
+
+if CLIENT then
+ SWEP.PrintName = "Manhack Control - Saw"
+ SWEP.Description = "Controller for your modified Manhack."
+end
+
+SWEP.EntityClass = "prop_manhack_saw"
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_medicalkit.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_medicalkit.lua
new file mode 100644
index 0000000..fe9492a
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_medicalkit.lua
@@ -0,0 +1,201 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Medical Kit"
+ SWEP.Description = "An advanced kit of medicine, bandages, and morphine.\nVery useful for keeping a group of survivors healthy.\nUse PRIMARY FIRE to heal other players.\nUse SECONDARY FIRE to heal yourself.\nHealing other players is not only faster but you get a nice point bonus!"
+ SWEP.Slot = 4
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFOV = 50
+ SWEP.ViewModelFlip = false
+
+ SWEP.BobScale = 2
+ SWEP.SwayScale = 1.5
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.WorldModel = "models/weapons/w_medkit.mdl"
+SWEP.ViewModel = "models/weapons/c_medkit.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Delay = 10
+SWEP.Primary.Heal = 15
+
+SWEP.Primary.ClipSize = 30
+SWEP.Primary.DefaultClip = 150
+SWEP.Primary.Ammo = "Battery"
+
+SWEP.Secondary.Delay = 20
+SWEP.Secondary.Heal = 10
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_NORMAL
+
+SWEP.NoMagazine = true
+
+SWEP.HoldType = "slam"
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType(self.HoldType)
+ self:SetDeploySpeed(1.1)
+end
+
+function SWEP:Think()
+ if self.IdleAnimation and self.IdleAnimation <= CurTime() then
+ self.IdleAnimation = nil
+ self:SendWeaponAnim(ACT_VM_IDLE)
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+
+ local owner = self.Owner
+
+ owner:LagCompensation(true)
+ local ent = owner:MeleeTrace(32, 2).Entity
+ owner:LagCompensation(false)
+
+ if ent and ent:IsValid() and ent:IsPlayer() and ent:Team() == owner:Team() and ent:Alive() and gamemode.Call("PlayerCanBeHealed", ent) then
+ local health, maxhealth = ent:Health(), ent:GetMaxHealth()
+ local multiplier = owner.HumanHealMultiplier or 1
+ local toheal = math.min(self:GetPrimaryAmmoCount(), math.ceil(math.min(self.Primary.Heal * multiplier, maxhealth - health)))
+ local totake = math.ceil(toheal / multiplier)
+ if toheal > 0 then
+ self:SetNextCharge(CurTime() + self.Primary.Delay * math.min(1, toheal / self.Primary.Heal))
+ owner.NextMedKitUse = self:GetNextCharge()
+
+ self:TakeCombinedPrimaryAmmo(totake)
+
+ ent:SetHealth(health + toheal)
+ self:EmitSound("items/medshot4.wav")
+
+ self:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
+
+ owner:DoAttackEvent()
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ gamemode.Call("PlayerHealedTeamMember", owner, ent, toheal, self)
+ end
+ end
+end
+
+function SWEP:SecondaryAttack()
+ local owner = self.Owner
+ if not self:CanPrimaryAttack() or not gamemode.Call("PlayerCanBeHealed", owner) then return end
+
+ local health, maxhealth = owner:Health(), owner:GetMaxHealth()
+ local multiplier = owner.HumanHealMultiplier or 1
+ local toheal = math.min(self:GetPrimaryAmmoCount(), math.ceil(math.min(self.Secondary.Heal * multiplier, maxhealth - health)))
+ local totake = math.ceil(toheal / multiplier)
+ if toheal > 0 then
+ self:SetNextCharge(CurTime() + self.Secondary.Delay * math.min(1, toheal / self.Secondary.Heal))
+ owner.NextMedKitUse = self:GetNextCharge()
+
+ self:TakeCombinedPrimaryAmmo(totake)
+
+ owner:SetHealth(health + toheal)
+ self:EmitSound("items/smallmedkit1.wav")
+
+ self:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
+
+ owner:DoAttackEvent()
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+ end
+end
+
+--[[function SWEP:Initialize()
+ if CLIENT and self:GetOwner() == LocalPlayer() and LocalPlayer():GetActiveWeapon() == self then
+ hook.Add("PostPlayerDraw", "PostPlayerDrawMedical", GAMEMODE.PostPlayerDrawMedical)
+ end
+end]]
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ if CLIENT then
+ hook.Add("PostPlayerDraw", "PostPlayerDrawMedical", GAMEMODE.PostPlayerDrawMedical)
+ end
+
+ return true
+end
+
+function SWEP:Holster()
+ if CLIENT then
+ hook.Remove("PostPlayerDraw", "PostPlayerDrawMedical")
+ end
+
+ return true
+end
+
+function SWEP:Reload()
+end
+
+function SWEP:SetNextCharge(tim)
+ self:SetDTFloat(0, tim)
+end
+
+function SWEP:GetNextCharge()
+ return self:GetDTFloat(0)
+end
+
+function SWEP:CanPrimaryAttack()
+ local owner = self.Owner
+ if owner:IsHolding() or owner:GetBarricadeGhosting() then return false end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:EmitSound("items/medshotno1.wav")
+
+ self:SetNextCharge(CurTime() + 0.75)
+ owner.NextMedKitUse = self:GetNextCharge()
+ return false
+ end
+
+ return self:GetNextCharge() <= CurTime() and (owner.NextMedKitUse or 0) <= CurTime()
+end
+
+if not CLIENT then return end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
+
+local texGradDown = surface.GetTextureID("VGUI/gradient_down")
+function SWEP:DrawHUD()
+ local screenscale = BetterScreenScale()
+ local wid, hei = 256, 16
+ local x, y = ScrW() - wid - 32, ScrH() - hei - 72
+ local texty = y - 4 - draw.GetFontHeight("ZSHUDFontSmall")
+
+ local timeleft = self:GetNextCharge() - CurTime()
+ if 0 < timeleft then
+ surface.SetDrawColor(5, 5, 5, 180)
+ surface.DrawRect(x, y, wid, hei)
+
+ surface.SetDrawColor(255, 0, 0, 180)
+ surface.SetTexture(texGradDown)
+ surface.DrawTexturedRect(x, y, math.min(1, timeleft / math.max(self.Primary.Delay, self.Secondary.Delay)) * wid, hei)
+
+ surface.SetDrawColor(255, 0, 0, 180)
+ surface.DrawOutlinedRect(x, y, wid, hei)
+ end
+
+ draw.SimpleText("Medical Kit", "ZSHUDFontSmall", x, texty, COLOR_GREEN, TEXT_ALIGN_LEFT)
+
+ local charges = self:GetPrimaryAmmoCount()
+ if charges > 0 then
+ draw.SimpleText(charges, "ZSHUDFontSmall", x + wid, texty, COLOR_GREEN, TEXT_ALIGN_RIGHT)
+ else
+ draw.SimpleText(charges, "ZSHUDFontSmall", x + wid, texty, COLOR_DARKRED, TEXT_ALIGN_RIGHT)
+ end
+
+ if GetConVarNumber("crosshair") == 1 then
+ self:DrawCrosshairDot()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_medicgun.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_medicgun.lua
new file mode 100644
index 0000000..a60ec96
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_medicgun.lua
@@ -0,0 +1,107 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Savior' Medic Gun"
+ SWEP.Description = "Fires medical darts which can heal at a range. Although less potent than a full medical kit, it can be fired rapidly and used at a range."
+ SWEP.Slot = 4
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+
+ SWEP.HUD3DBone = "ValveBiped.square"
+ SWEP.HUD3DPos = Vector(1.1, 0.25, -2)
+ SWEP.HUD3DScale = 0.015
+
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/healthvial.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(8.5, 2, -3.701), angle = Angle(0, -90, -8), size = Vector(0.5, 0.5, 0.5), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["2"] = { type = "Model", model = "models/airboatgun.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "base", pos = Vector(0, -3, 0), angle = Angle(0, 90, 180), size = Vector(0.25, 0.25, 0.25), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["2+"] = { type = "Model", model = "models/airboatgun.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "base", pos = Vector(0, -3, 0), angle = Angle(0, 90, 180), size = Vector(0.25, 0.25, 0.25), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/healthvial.mdl", bone = "ValveBiped.square", rel = "", pos = Vector(0, 0.5, 3), angle = Angle(0, 0, 90), size = Vector(0.5, 0.5, 0.5), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["2"] = { type = "Model", model = "models/airboatgun.mdl", bone = "ValveBiped.Bip01_Spine4", rel = "base", pos = Vector(0, -3, 0), angle = Angle(0, 90, 180), size = Vector(0.25, 0.25, 0.25), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["2+"] = { type = "Model", model = "models/airboatgun.mdl", bone = "ValveBiped.Bip01_Spine4", rel = "base", pos = Vector(0, -3, 0), angle = Angle(0, 90, 180), size = Vector(0.25, 0.25, 0.25), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "pistol"
+
+SWEP.ViewModel = "models/weapons/c_pistol.mdl"
+SWEP.WorldModel = "models/weapons/w_pistol.mdl"
+SWEP.UseHands = true
+
+SWEP.CSMuzzleFlashes = false
+
+SWEP.ReloadSound = Sound("Weapon_Pistol.Reload")
+
+SWEP.Primary.Delay = 0.25
+
+SWEP.Primary.ClipSize = 25
+SWEP.Primary.DefaultClip = 150
+SWEP.Primary.Ammo = "Battery"
+SWEP.RequiredClip = 5
+
+SWEP.WalkSpeed = SPEED_NORMAL
+
+SWEP.NoMagazine = true
+
+SWEP.ConeMax = 0.005
+SWEP.ConeMin = 0.005
+
+SWEP.IronSightsPos = Vector(-5.95, 3, 2.75)
+SWEP.IronSightsAng = Vector(-0.15, -1, 2)
+
+function SWEP:ShootBullets(dmg, numbul, cone)
+ local owner = self.Owner
+ self:SendWeaponAnimation()
+ owner:DoAttackEvent()
+
+ if CLIENT then return end
+
+ local aimvec = owner:GetAimVector()
+
+ local ent = ents.Create("projectile_healdart")
+ if ent:IsValid() then
+ ent:SetPos(owner:GetShootPos())
+ ent:SetAngles(aimvec:Angle())
+ ent:SetOwner(owner)
+ ent:Spawn()
+
+ ent.Heal = math.ceil(ent.Heal * (owner.HumanHealMultiplier or 1))
+
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:SetVelocityInstantaneous(aimvec * 2000)
+ end
+ end
+end
+
+--[[function SWEP:Initialize()
+ if CLIENT and self:GetOwner() == LocalPlayer() and LocalPlayer():GetActiveWeapon() == self then
+ hook.Add("PostPlayerDraw", "PostPlayerDrawMedical", GAMEMODE.PostPlayerDrawMedical)
+ end
+end]]
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ if CLIENT then
+ hook.Add("PostPlayerDraw", "PostPlayerDrawMedical", GAMEMODE.PostPlayerDrawMedical)
+ end
+
+ return true
+end
+
+function SWEP:Holster()
+ if CLIENT then
+ hook.Remove("PostPlayerDraw", "PostPlayerDrawMedical")
+ end
+
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_megamasher.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_megamasher.lua
new file mode 100644
index 0000000..432f7cd
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_megamasher.lua
@@ -0,0 +1,60 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Mega Masher"
+ SWEP.ViewModelFOV = 75
+
+ SWEP.VElements = {
+ ["base2"] = { type = "Model", model = "models/props_wasteland/buoy01.mdl", bone = "ValveBiped.Bip01", rel = "base", pos = Vector(12, 0, 0), angle = Angle(0, 90, 270), size = Vector(0.2, 0.2, 0.2), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base"] = { type = "Model", model = "models/props_junk/iBeam01a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(12.706, 2.761, -22), angle = Angle(13, -12.5, 0), size = Vector(0.15, 0.5, 0.5), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base3"] = { type = "Model", model = "models/props_borealis/bluebarrel001.mdl", bone = "ValveBiped.Bip01", rel = "base", pos = Vector(-5, 0, 0), angle = Angle(0, 270, 90), size = Vector(0.4, 0.4, 0.4), color = Color(255, 0, 0, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+
+ SWEP.WElements = {
+ ["base2"] = { type = "Model", model = "models/props_wasteland/buoy01.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "base", pos = Vector(12, 0, 0), angle = Angle(90, 0, 90), size = Vector(0.2, 0.2, 0.2), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base"] = { type = "Model", model = "models/props_junk/iBeam01a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(10, 1, -35), angle = Angle(0, 0, 0), size = Vector(0.15, 0.5, 0.5), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base3"] = { type = "Model", model = "models/props_borealis/bluebarrel001.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "base", pos = Vector(-5, 0, 0), angle = Angle(90, 0, 90), size = Vector(0.4, 0.4, 0.4), color = Color(255, 0, 0, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.HoldType = "melee2"
+
+SWEP.DamageType = DMG_CLUB
+
+SWEP.ViewModel = "models/weapons/v_sledgehammer/v_sledgehammer.mdl"
+SWEP.WorldModel = "models/weapons/w_sledgehammer.mdl"
+
+SWEP.MeleeDamage = 190
+SWEP.MeleeRange = 75
+SWEP.MeleeSize = 4
+SWEP.MeleeKnockBack = SWEP.MeleeDamage * 2
+
+SWEP.Primary.Delay = 2.25
+
+SWEP.WalkSpeed = SPEED_SLOWEST * 0.7
+
+SWEP.SwingRotation = Angle(60, 0, -80)
+SWEP.SwingOffset = Vector(0, -30, 0)
+SWEP.SwingTime = 1.33
+SWEP.SwingHoldType = "melee"
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("weapons/iceaxe/iceaxe_swing1.wav", 75, math.random(20, 25))
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("vehicles/v8/vehicle_impact_heavy"..math.random(4)..".wav", 80, math.Rand(95, 105))
+end
+
+function SWEP:PlayHitFleshSound()
+ self:EmitSound("physics/flesh/flesh_bloody_break.wav", 80, math.Rand(90, 100))
+end
+
+function SWEP:OnMeleeHit(hitent, hitflesh, tr)
+ local effectdata = EffectData()
+ effectdata:SetOrigin(tr.HitPos)
+ effectdata:SetNormal(tr.HitNormal)
+ util.Effect("explosion", effectdata)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_messagebeacon/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_messagebeacon/cl_init.lua
new file mode 100644
index 0000000..fdd4d9f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_messagebeacon/cl_init.lua
@@ -0,0 +1,70 @@
+include("shared.lua")
+
+SWEP.PrintName = "Message Beacon"
+SWEP.Description = "This beacon allows you to display messages to all other humans in range.\nPress SECONDARY ATTACK to select different messages.\nPress PRIMARY ATTACK to deploy.\nPress SPRINT on a deployed message beacon that you own to pick it up."
+SWEP.DrawCrosshair = false
+
+SWEP.Slot = 4
+SWEP.SlotPos = 0
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ return true
+end
+
+function SWEP:DrawHUD()
+ if GetConVarNumber("crosshair") ~= 1 then return end
+ self:DrawCrosshairDot()
+end
+
+function SWEP:PrimaryAttack()
+end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
+
+function SWEP:Think()
+end
+
+local function okclick(self)
+ RunConsoleCommand("setmessagebeaconmessage", self:GetParent().Choice)
+ self:GetParent():Close()
+end
+
+local function onselect(self, index, value, data)
+ self:GetParent().Choice = data
+end
+
+local Menu
+function SWEP:SecondaryAttack()
+ if Menu and Menu:Valid() then
+ Menu:SetVisible(true)
+ return
+ end
+
+ Menu = vgui.Create("DFrame")
+ Menu:SetDeleteOnClose(false)
+ Menu:SetSize(200, 100)
+ Menu:SetTitle("Select a message")
+ Menu:Center()
+ Menu.Choice = 1
+
+ local choice = vgui.Create("DComboBox", Menu)
+ for k, v in ipairs(GAMEMODE.ValidBeaconMessages) do
+ choice:AddChoice(translate.Get(v), k)
+ end
+ choice:ChooseOption(GAMEMODE.ValidBeaconMessages[1], 1)
+ choice:SizeToContents()
+ choice:SetWide(Menu:GetWide() - 16)
+ choice:Center()
+ choice.OnSelect = onselect
+
+ local ok = EasyButton(Menu, "OK", 8, 4)
+ ok:AlignBottom(8)
+ ok:CenterHorizontal()
+ ok.DoClick = okclick
+
+ Menu:MakePopup()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_messagebeacon/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_messagebeacon/init.lua
new file mode 100644
index 0000000..6b08a0c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_messagebeacon/init.lua
@@ -0,0 +1,97 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self:SpawnGhost()
+
+ return true
+end
+
+function SWEP:OnRemove()
+ self:RemoveGhost()
+end
+
+function SWEP:Holster()
+ self:RemoveGhost()
+ return true
+end
+
+function SWEP:SpawnGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:GiveStatus("ghost_messagebeacon")
+ end
+end
+
+function SWEP:RemoveGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:RemoveStatus("ghost_messagebeacon", false, true)
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+
+ local owner = self.Owner
+
+ local status = owner.status_ghost_messagebeacon
+ if not (status and status:IsValid()) then return end
+ status:RecalculateValidity()
+ if not status:GetValidPlacement() then return end
+
+ local pos, ang = status:RecalculateValidity()
+ if not pos or not ang then return end
+
+ self:SetNextPrimaryAttack(CurTime() + self.Primary.Delay)
+
+ local ent = ents.Create("prop_messagebeacon")
+ if ent:IsValid() then
+ ent:SetPos(pos)
+ ent:SetAngles(ang)
+ ent:Spawn()
+
+ ent:SetObjectOwner(owner)
+ ent:SetMessageID(self.MessageID)
+
+ ent:EmitSound("npc/dog/dog_servo12.wav")
+
+ --ent:GhostAllPlayersInMe(5)
+
+ self:TakePrimaryAmmo(1)
+
+ local stored = owner:PopPackedItem(ent:GetClass())
+ if stored then
+ ent.m_Health = stored[1]
+ end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ owner:StripWeapon(self:GetClass())
+ end
+ end
+end
+
+function SWEP:Think()
+ local count = self:GetPrimaryAmmoCount()
+ if count ~= self:GetReplicatedAmmo() then
+ self:SetReplicatedAmmo(count)
+ self.Owner:ResetSpeed()
+ end
+end
+
+SWEP.MessageID = 1
+concommand.Add("setmessagebeaconmessage", function(sender, command, arguments)
+ if not sender:IsValid() then return end
+
+ local wep = sender:GetActiveWeapon()
+ if wep:IsValid() and wep:GetClass() == "weapon_zs_messagebeacon" then
+ wep.MessageID = math.Clamp(math.floor(tonumbersafe(arguments[1]) or 1), 1, #GAMEMODE.ValidBeaconMessages)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_messagebeacon/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_messagebeacon/shared.lua
new file mode 100644
index 0000000..3d62ae9
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_messagebeacon/shared.lua
@@ -0,0 +1,62 @@
+SWEP.ViewModel = "models/weapons/v_pistol.mdl"
+SWEP.WorldModel = Model("models/props_combine/combine_mine01.mdl")
+
+SWEP.AmmoIfHas = true
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.DefaultClip = 1
+SWEP.Primary.Ammo = "striderminigun"
+SWEP.Primary.Delay = 1
+SWEP.Primary.Automatic = true
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_NORMAL
+SWEP.FullWalkSpeed = SPEED_SLOW
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType("slam")
+ self:SetDeploySpeed(1.1)
+ self:HideViewAndWorldModel()
+end
+
+function SWEP:SetReplicatedAmmo(count)
+ self:SetDTInt(0, count)
+end
+
+function SWEP:GetReplicatedAmmo()
+ return self:GetDTInt(0)
+end
+
+function SWEP:GetWalkSpeed()
+ if self:GetPrimaryAmmoCount() > 0 then
+ return self.FullWalkSpeed
+ end
+end
+
+function SWEP:Reload()
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ return false
+ end
+
+ return true
+end
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ return true
+end
+
+function SWEP:Holster()
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_nightmare.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_nightmare.lua
new file mode 100644
index 0000000..cd9442c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_nightmare.lua
@@ -0,0 +1,34 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Nightmare"
+end
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.MeleeDamage = 49
+SWEP.SlowDownScale = 2
+
+function SWEP:Reload()
+ self:SecondaryAttack()
+end
+
+function SWEP:PlayAlertSound()
+ self.Owner:EmitSound("npc/barnacle/barnacle_tongue_pull"..math.random(3)..".wav")
+end
+SWEP.PlayIdleSound = SWEP.PlayAlertSound
+
+function SWEP:PlayAttackSound()
+ self.Owner:EmitSound("npc/barnacle/barnacle_bark"..math.random(2)..".wav")
+end
+
+if not CLIENT then return end
+
+function SWEP:ViewModelDrawn()
+ render.ModelMaterialOverride(0)
+end
+
+local matSheet = Material("Models/Charple/Charple1_sheet")
+function SWEP:PreDrawViewModel(vm)
+ render.ModelMaterialOverride(matSheet)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_owens.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_owens.lua
new file mode 100644
index 0000000..ce52e64
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_owens.lua
@@ -0,0 +1,41 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Owens' Handgun"
+ SWEP.Slot = 1
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+
+ SWEP.HUD3DBone = "ValveBiped.square"
+ SWEP.HUD3DPos = Vector(1.1, 0.25, -2)
+ SWEP.HUD3DScale = 0.015
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "pistol"
+
+SWEP.ViewModel = "models/weapons/c_pistol.mdl"
+SWEP.WorldModel = "models/weapons/w_pistol.mdl"
+SWEP.UseHands = true
+
+SWEP.CSMuzzleFlashes = false
+
+SWEP.ReloadSound = Sound("Weapon_Pistol.Reload")
+SWEP.Primary.Sound = Sound("Weapon_Pistol.NPC_Single")
+SWEP.Primary.Damage = 12
+SWEP.Primary.NumShots = 2
+SWEP.Primary.Delay = 0.2
+
+SWEP.Primary.ClipSize = 12
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "pistol"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.ConeMax = 0.08
+SWEP.ConeMin = 0.04
+
+SWEP.IronSightsPos = Vector(-5.95, 3, 2.75)
+SWEP.IronSightsAng = Vector(-0.15, -1, 2)
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_oxygentank.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_oxygentank.lua
new file mode 100644
index 0000000..fae8426
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_oxygentank.lua
@@ -0,0 +1,83 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Oxygen Tank"
+ SWEP.Description = "Grants the user much higher air capacity."
+
+ SWEP.ViewModelFOV = 60
+
+ SWEP.Slot = 4
+
+ SWEP.ShowViewModel = false
+ SWEP.ShowWorldModel = false
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props_c17/canister01a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(4, 3, -1), angle = Angle(180, 0, 0), size = Vector(0.5, 0.5, 0.5), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props_c17/canister01a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(4, 3, -1), angle = Angle(180, 0, 0), size = Vector(0.5, 0.5, 0.5), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.ViewModel = "models/weapons/c_grenade.mdl"
+SWEP.WorldModel = "models/props_c17/canister01a.mdl"
+SWEP.ModelScale = 0.5
+SWEP.UseHands = true
+
+SWEP.Primary.ClipSize = -1
+SWEP.Primary.DefaultClip = -1
+SWEP.Primary.Ammo = "none"
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_NORMAL
+
+SWEP.HoldType = "slam"
+
+function SWEP:PrimaryAttack()
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+end
+
+if CLIENT then return end
+
+function SWEP:Initialize()
+ self.BaseClass.Initialize(self)
+
+ timer.Simple(0, function()
+ if IsValid(self) then
+ self:SpawnTank()
+ end
+ end)
+end
+
+function SWEP:Deploy()
+ self.BaseClass.Deploy(self)
+
+ self:SpawnTank()
+end
+
+function SWEP:SpawnTank()
+ local owner = self.Owner
+ if not owner:IsValid() then return end
+
+ for _, ent in pairs(ents.FindByClass("status_oxygentank")) do
+ if ent:GetOwner() == owner then return end
+ end
+
+ local ent = ents.Create("status_oxygentank")
+ if ent:IsValid() then
+ ent:SetPos(owner:EyePos())
+ ent:SetParent(owner)
+ ent:SetOwner(owner)
+ ent:Spawn()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_peashooter.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_peashooter.lua
new file mode 100644
index 0000000..9d05cdd
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_peashooter.lua
@@ -0,0 +1,38 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Peashooter' Handgun"
+ SWEP.Slot = 1
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFOV = 60
+ SWEP.ViewModelFlip = false
+
+ SWEP.HUD3DBone = "v_weapon.p228_Slide"
+ SWEP.HUD3DPos = Vector(-0.88, 0.35, 1)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+ SWEP.HUD3DScale = 0.015
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "pistol"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_pist_p228.mdl"
+SWEP.WorldModel = "models/weapons/w_pist_p228.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("Weapon_P228.Single")
+SWEP.Primary.Damage = 16
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.1
+
+SWEP.Primary.ClipSize = 18
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "pistol"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.ConeMax = 0.08
+SWEP.ConeMin = 0.015
+
+SWEP.IronSightsPos = Vector(-6, -1, 2.25)
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_pipe.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_pipe.lua
new file mode 100644
index 0000000..5e351c6
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_pipe.lua
@@ -0,0 +1,57 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Lead Pipe"
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+
+ SWEP.ShowViewModel = false
+ SWEP.ShowWorldModel = false
+
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props_canal/mattpipe.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(2.2, 1, -2.274), angle = Angle(0, 0, 0), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props_canal/mattpipe.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(2.599, 1, -6), angle = Angle(0, 0, 0), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.DamageType = DMG_CLUB
+
+SWEP.ViewModel = "models/weapons/c_stunstick.mdl"
+SWEP.WorldModel = "models/props_canal/mattpipe.mdl"
+SWEP.UseHands = true
+
+SWEP.MeleeDamage = 40
+SWEP.MeleeRange = 50
+SWEP.MeleeSize = 1.15
+
+SWEP.Primary.Delay = 1.75
+
+SWEP.UseMelee1 = true
+
+SWEP.HitGesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE
+SWEP.MissGesture = SWEP.HitGesture
+
+SWEP.SwingRotation = Angle(30, -30, -30)
+SWEP.SwingTime = 0.4
+SWEP.SwingHoldType = "grenade"
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("weapons/iceaxe/iceaxe_swing1.wav", 75, math.random(55, 65))
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("physics/metal/metal_canister_impact_hard"..math.random(3)..".wav", 75, math.random(115, 125))
+end
+
+if SERVER then
+function SWEP:OnMeleeHit(hitent, hitflesh, tr)
+ if hitent:IsValid() and hitent:IsPlayer() and hitent:GetZombieClassTable().Name ~= "Shade" then
+ hitent:GiveStatus("disorientation")
+ end
+end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_plank.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_plank.lua
new file mode 100644
index 0000000..c669be7
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_plank.lua
@@ -0,0 +1,65 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Plank"
+
+ SWEP.ViewModelFOV = 55
+ SWEP.ViewModelFlip = false
+
+ SWEP.ShowViewModel = false
+ SWEP.ShowWorldModel = false
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props_debris/wood_chunk03a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(1.363, 1.363, -11.365), angle = Angle(180, 90, 0), size = Vector(0.5, 0.5, 0.5), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props_debris/wood_chunk03a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(2.273, 1.363, -12.273), angle = Angle(180, 90, 0), size = Vector(0.5, 0.5, 0.5), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.DamageType = DMG_CLUB
+
+SWEP.ViewModel = "models/weapons/c_crowbar.mdl"
+SWEP.WorldModel = "models/props_debris/wood_chunk03a.mdl"
+SWEP.ModelScale = 0.5
+SWEP.UseHands = true
+SWEP.BoxPhysicsMin = Vector(-0.5764, -2.397225, -20.080572) * SWEP.ModelScale
+SWEP.BoxPhysicsMax = Vector(0.70365, 2.501825, 19.973375) * SWEP.ModelScale
+
+SWEP.MeleeDamage = 20
+SWEP.MeleeRange = 48
+SWEP.MeleeSize = 0.875
+SWEP.Primary.Delay = 0.37
+
+SWEP.WalkSpeed = SPEED_FASTEST
+
+SWEP.UseMelee1 = true
+
+SWEP.HitGesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE
+SWEP.MissGesture = SWEP.HitGesture
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("weapons/knife/knife_slash"..math.random(2)..".wav")
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("physics/wood/wood_plank_impact_hard"..math.random(5)..".wav")
+end
+
+function SWEP:PlayHitFleshSound()
+ self:EmitSound("physics/flesh/flesh_impact_bullet"..math.random(5)..".wav")
+end
+
+function SWEP:PostOnMeleeHit(hitent, hitflesh, tr)
+ if hitent:IsValid() and hitent:IsPlayer() then
+ local combo = self:GetDTInt(2)
+ self:SetNextPrimaryFire(CurTime() + math.max(0.2, self.Primary.Delay * (1 - combo / 10)))
+
+ self:SetDTInt(2, combo + 1)
+ end
+end
+
+function SWEP:PostOnMeleeMiss(tr)
+ self:SetDTInt(2, 0)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonheadcrab/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonheadcrab/cl_init.lua
new file mode 100644
index 0000000..d07b879
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonheadcrab/cl_init.lua
@@ -0,0 +1,10 @@
+include("shared.lua")
+
+SWEP.PrintName = "Poison Headcrab"
+SWEP.ViewModelFOV = 70
+SWEP.DrawCrosshair = false
+
+function SWEP:DrawHUD()
+ if GetConVarNumber("crosshair") ~= 1 then return end
+ self:DrawCrosshairDot()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonheadcrab/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonheadcrab/init.lua
new file mode 100644
index 0000000..25b35c2
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonheadcrab/init.lua
@@ -0,0 +1,4 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonheadcrab/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonheadcrab/shared.lua
new file mode 100644
index 0000000..bfe7c55
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonheadcrab/shared.lua
@@ -0,0 +1,238 @@
+SWEP.ZombieOnly = true
+SWEP.IsMelee = true
+
+SWEP.ViewModel = "models/weapons/v_knife_t.mdl"
+SWEP.WorldModel = "models/weapons/w_knife_t.mdl"
+
+SWEP.Primary.ClipSize = -1
+SWEP.Primary.DefaultClip = -1
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "none"
+SWEP.Primary.Delay = 0.4
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.Delay = 0.22
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = true
+SWEP.Secondary.Ammo = "none"
+
+SWEP.PounceDamage = 10
+SWEP.PounceDamagePerTick = 5
+SWEP.PounceDamageTicks = 10
+SWEP.PounceDamageTime = 1
+SWEP.PounceDamageVsPropsMultiplier = 2
+
+function SWEP:Initialize()
+ self:HideViewAndWorldModel()
+end
+
+local function DoPoisoned(hitent, owner, damage, timername)
+ if not (hitent:IsValid() and hitent:Alive()) then
+ timer.Destroy(timername)
+ return
+ end
+
+ hitent:PoisonDamage(damage, owner)
+end
+function SWEP:Think()
+ local curtime = CurTime()
+ local owner = self.Owner
+
+ if self:IsGoingToSpit() and self:GetNextSpit() <= curtime then
+ self:SetNextSpit(0)
+ self:SetNextPrimaryFire(curtime + 2)
+ self:SetNextSecondaryFire(self:GetNextPrimaryFire())
+
+ if SERVER then
+ owner:EmitSound("weapons/crossbow/bolt_fly4.wav", 74, 150)
+
+ local ent = ents.Create("projectile_poisonspit")
+ if ent:IsValid() then
+ ent:SetOwner(owner)
+ local aimvec = owner:GetAimVector()
+ aimvec.z = math.max(aimvec.z, -0.25)
+ aimvec:Normalize()
+ local vStart = owner:GetShootPos()
+ local tr = util.TraceLine({start=vStart, endpos=vStart + owner:GetAimVector() * 30, filter=owner})
+ if tr.Hit then
+ ent:SetPos(tr.HitPos + tr.HitNormal * 4)
+ else
+ ent:SetPos(tr.HitPos)
+ end
+ ent:Spawn()
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetVelocityInstantaneous(aimvec * 510)
+ end
+ end
+ end
+ elseif self:IsGoingToLeap() and self:GetNextLeap() <= curtime then
+ self:SetNextLeap(0)
+ if owner:IsOnGround() then
+ local vel = owner:GetAimVector()
+ vel.z = math.max(0.45, vel.z)
+ vel:Normalize()
+
+ owner:SetGroundEntity(NULL)
+ owner:SetLocalVelocity(vel * 470)
+
+ self:SetLeaping(true)
+
+ if SERVER then
+ owner:EmitSound("NPC_BlackHeadcrab.Attack")
+ end
+ end
+ elseif self:IsLeaping() then
+ if owner:IsOnGround() or 1 < owner:WaterLevel() then
+ self:SetLeaping(false)
+ self:SetNextPrimaryFire(curtime + 0.8)
+ else
+ owner:LagCompensation(true)
+
+ local vStart = owner:LocalToWorld(owner:OBBCenter())
+ local trace = util.TraceHull({start = vStart, endpos = vStart + owner:GetForward() * (owner:BoundingRadius() + 8), mins = owner:OBBMins() * 0.8, maxs = owner:OBBMaxs() * 0.8, filter = owner:GetMeleeFilter()})
+ local ent = trace.Entity
+
+ if ent:IsValid() then
+ local phys = ent:GetPhysicsObject()
+
+ if phys:IsValid() and not ent:IsPlayer() and phys:IsMoveable() then
+ local vel = 12000 * owner:EyeAngles():Forward()
+
+ phys:ApplyForceOffset(vel, (ent:NearestPoint(vStart) + ent:GetPos() * 2) / 3)
+ ent:SetPhysicsAttacker(owner)
+ end
+
+ self:SetLeaping(false)
+ self:SetNextPrimaryFire(curtime + 1)
+
+ if SERVER then
+ owner:EmitSound("NPC_BlackHeadcrab.Bite")
+ end
+ owner:ViewPunch(Angle(math.Rand(-20, 20), math.Rand(-20, 20), math.Rand(-20, 20)))
+
+ if ent:IsPlayer() then
+ ent:MeleeViewPunch(self.PounceDamage)
+ ent:PoisonDamage(self.PounceDamage, owner, self)
+ local timername = tostring(ent).."poisonedby"..tostring(owner)..CurTime()
+ timer.CreateEx(timername, self.PounceDamageTime, self.PounceDamageTicks, DoPoisoned, ent, owner, self.PounceDamagePerTick, timername)
+ else
+ ent:PoisonDamage(self.PounceDamage * self.PounceDamageVsPropsMultiplier, owner, self)
+ end
+ elseif trace.HitWorld then
+ if SERVER then
+ owner:EmitSound("NPC_BlackHeadcrab.Impact")
+ end
+ self:SetLeaping(false)
+ self:SetNextPrimaryFire(curtime + 1)
+ end
+
+ owner:LagCompensation(false)
+ end
+ end
+
+ self:NextThink(curtime)
+ return true
+end
+
+function SWEP:PrimaryAttack()
+ local owner = self.Owner
+ if self:IsLeaping() or self:IsGoingToSpit() or self:IsGoingToLeap() or CurTime() < self:GetNextPrimaryFire() or not owner:IsOnGround() then return end
+
+ self:SetNextLeap(CurTime() + 1.25)
+
+ self.m_ViewAngles = owner:EyeAngles()
+
+ if SERVER then
+ owner:EmitSound("NPC_BlackHeadcrab.Telegraph")
+ end
+end
+
+function SWEP:SecondaryAttack()
+ if self:IsLeaping() or self:IsGoingToSpit() or self:IsGoingToLeap() or CurTime() < self:GetNextSecondaryFire() or not self.Owner:IsOnGround() then return end
+
+ self:SetNextSpit(CurTime() + 1)
+
+ if SERVER then
+ self.Owner:EmitSound("npc/headcrab_poison/ph_scream"..math.random(1, 3)..".wav")
+ end
+end
+
+function SWEP:Reload()
+ if self:GetNextReload() > CurTime() then return end
+ self:SetNextReload(CurTime() + 3)
+
+ if SERVER then
+ self.Owner:LagCompensation(true)
+
+ local ent = self.Owner:MeleeTrace(4096, 24, self.Owner:GetMeleeFilter()).Entity
+ if ent:IsValid() and ent:IsPlayer() then
+ self.Owner:EmitSound("npc/headcrab_poison/ph_warning"..math.random(1, 3)..".wav")
+ else
+ self.Owner:EmitSound("npc/headcrab_poison/ph_idle"..math.random(1, 3)..".wav")
+ end
+
+ self.Owner:LagCompensation(false)
+ end
+
+ return false
+end
+
+function SWEP:Move(mv)
+ if self:IsLeaping() or self:IsGoingToLeap() or self:IsGoingToSpit() then
+ mv:SetSideSpeed(0)
+ mv:SetForwardSpeed(0)
+ end
+end
+
+function SWEP:Precache()
+ util.PrecacheSound("npc/headcrab_poison/ph_scream1.wav")
+ util.PrecacheSound("npc/headcrab_poison/ph_scream2.wav")
+ util.PrecacheSound("npc/headcrab_poison/ph_scream3.wav")
+ util.PrecacheSound("npc/headcrab_poison/ph_jump1.wav")
+ util.PrecacheSound("npc/headcrab_poison/ph_jump2.wav")
+ util.PrecacheSound("npc/headcrab_poison/ph_jump3.wav")
+ util.PrecacheSound("npc/headcrab_poison/ph_poisonbite1.wav")
+ util.PrecacheSound("npc/headcrab_poison/ph_poisonbite2.wav")
+ util.PrecacheSound("npc/headcrab_poison/ph_poisonbite3.wav")
+end
+
+function SWEP:SetLeaping(leap)
+ if not leap then
+ self.m_ViewAngles = nil
+ end
+ self:SetDTBool(0, leap)
+end
+
+function SWEP:GetLeaping()
+ return self:GetDTBool(0)
+end
+SWEP.IsLeaping = SWEP.GetLeaping
+
+function SWEP:SetNextLeap(time)
+ self:SetDTFloat(0, time)
+end
+
+function SWEP:GetNextLeap()
+ return self:GetDTFloat(0)
+end
+
+function SWEP:IsGoingToLeap()
+ return self:GetNextLeap() > 0
+end
+
+function SWEP:ShouldPlayLeapAnimation()
+ return self:IsLeaping() or self:IsGoingToLeap()
+end
+
+function SWEP:SetNextSpit(time)
+ self:SetDTFloat(1, time)
+end
+
+function SWEP:GetNextSpit()
+ return self:GetDTFloat(1)
+end
+
+function SWEP:IsGoingToSpit()
+ return self:GetNextSpit() > 0
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonzombie/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonzombie/cl_init.lua
new file mode 100644
index 0000000..1c6b7fe
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonzombie/cl_init.lua
@@ -0,0 +1,11 @@
+include("shared.lua")
+
+SWEP.PrintName = "Poison Zombie"
+SWEP.ViewModelFOV = 47
+SWEP.DrawCrosshair = false
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonzombie/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonzombie/init.lua
new file mode 100644
index 0000000..735abdc
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonzombie/init.lua
@@ -0,0 +1,65 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function SWEP:Reload()
+ self.BaseClass.SecondaryAttack(self)
+end
+
+local function DoFleshThrow(pl, wep)
+ if pl:IsValid() and pl:Alive() and wep:IsValid() then
+ pl:ResetSpeed()
+
+ local startpos = pl:GetPos()
+ startpos.z = pl:GetShootPos().z
+ local aimang = pl:EyeAngles()
+
+ for i=1, 10 do
+ local ang = Angle(aimang.p, aimang.y, aimang.r)
+ ang:RotateAroundAxis(ang:Up(), math.Rand(-25, 25))
+ ang:RotateAroundAxis(ang:Right(), math.Rand(-5, 5))
+ local heading = ang:Forward()
+
+ local ent = ents.Create("projectile_poisonflesh")
+ if ent:IsValid() then
+ ent:SetPos(startpos + heading * 8)
+ ent:SetOwner(pl)
+ ent:Spawn()
+ ent:SetTeamID(TEAM_UNDEAD)
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetVelocityInstantaneous(heading * math.Rand(340, 550))
+ end
+ end
+ end
+
+ pl:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav", 72, math.random(70, 80))
+
+ pl:RawCapLegDamage(CurTime() + 2)
+ end
+end
+
+local function DoSwing(pl, wep)
+ if pl:IsValid() and pl:Alive() and wep:IsValid() then
+ pl:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav", 72, math.random(70, 83))
+ if wep.SwapAnims then wep:SendWeaponAnim(ACT_VM_HITCENTER) else wep:SendWeaponAnim(ACT_VM_SECONDARYATTACK) end
+ wep.IdleAnimation = CurTime() + wep:SequenceDuration()
+ wep.SwapAnims = not wep.SwapAnims
+ end
+end
+
+function SWEP:SecondaryAttack()
+ if CurTime() < self:GetNextPrimaryFire() or CurTime() < self:GetNextSecondaryFire() then return end
+ local owner = self.Owner
+ if owner:Team() ~= TEAM_UNDEAD then owner:Kill() return end
+
+ self.Owner:DoAnimationEvent(ACT_RANGE_ATTACK2)
+ self.Owner:EmitSound("NPC_PoisonZombie.Throw")
+ self.Owner:SetSpeed(1)
+ self:SetNextSecondaryFire(CurTime() + 4)
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+
+ timer.Simple(0.6, function() DoSwing(owner, self) end)
+ timer.Simple(1, function() DoFleshThrow(owner, self) end)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonzombie/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonzombie/shared.lua
new file mode 100644
index 0000000..fadc95e
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_poisonzombie/shared.lua
@@ -0,0 +1,41 @@
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.MeleeReach = 48
+SWEP.MeleeDelay = 0.9
+SWEP.MeleeSize = 1.5
+SWEP.MeleeDamage = 40
+SWEP.MeleeDamageType = DMG_SLASH
+SWEP.MeleeAnimationDelay = 0.35
+
+SWEP.Primary.Delay = 1.6
+
+SWEP.FleshThrowRecoil = 40
+
+SWEP.ViewModel = Model("models/weapons/v_pza.mdl")
+SWEP.WorldModel = "models/weapons/w_crowbar.mdl"
+
+function SWEP:CheckMoaning()
+end
+
+function SWEP:StopMoaningSound()
+end
+
+function SWEP:StartMoaningSound()
+end
+
+function SWEP:PlayHitSound()
+ self.Owner:EmitSound("npc/zombie/claw_strike"..math.random(1, 3)..".wav", 75, 80)
+end
+
+function SWEP:PlayMissSound()
+ self.Owner:EmitSound("npc/zombie/claw_miss"..math.random(1, 2)..".wav", 75, 80)
+end
+
+function SWEP:PlayAttackSound()
+ self.Owner:EmitSound("NPC_PoisonZombie.ThrowWarn")
+end
+
+function SWEP:PlayAlertSound()
+ self.Owner:EmitSound("NPC_PoisonZombie.Alert")
+end
+SWEP.PlayIdleSound = SWEP.PlayAlertSound
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_pot.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_pot.lua
new file mode 100644
index 0000000..4d69eb0
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_pot.lua
@@ -0,0 +1,43 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Pot"
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 55
+
+ SWEP.ShowViewModel = false
+ SWEP.ShowWorldModel = false
+
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props_interiors/pot02a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(5, 1.363, -6.818), angle = Angle(0, 90, -90), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props_interiors/pot02a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(5, 1.363, -6.818), angle = Angle(0, 90, -90), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.DamageType = DMG_CLUB
+
+SWEP.ViewModel = "models/weapons/c_stunstick.mdl"
+SWEP.WorldModel = "models/props_interiors/pot02a.mdl"
+SWEP.UseHands = true
+
+SWEP.MeleeDamage = 40
+SWEP.MeleeRange = 50
+SWEP.MeleeSize = 1.15
+
+SWEP.UseMelee1 = true
+
+SWEP.HitGesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE
+SWEP.MissGesture = SWEP.HitGesture
+
+SWEP.SwingRotation = Angle(30, -30, -30)
+SWEP.SwingTime = 0.3
+SWEP.SwingHoldType = "grenade"
+
+function SWEP:PlayHitSound()
+ self:EmitSound("weapons/melee/frying_pan/pan_hit-0"..math.random(4)..".ogg")
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_pukepus.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_pukepus.lua
new file mode 100644
index 0000000..989be5f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_pukepus.lua
@@ -0,0 +1,69 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_zombie"
+
+if CLIENT then
+ SWEP.PrintName = "Puke Pus"
+end
+
+SWEP.Primary.Delay = 3.5
+
+SWEP.ViewModel = "models/weapons/v_crowbar.mdl"
+SWEP.WorldModel = "models/weapons/w_crowbar.mdl"
+
+SWEP.NextPuke = 0
+SWEP.PukeLeft = 0
+
+function SWEP:Initialize()
+ self:HideViewAndWorldModel()
+
+ self.BaseClass.Initialize(self)
+end
+
+function SWEP:PrimaryAttack()
+ if CurTime() < self:GetNextPrimaryFire() then return end
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+
+ self.PukeLeft = 40
+
+ self.Owner:EmitSound("npc/barnacle/barnacle_die2.wav")
+ self.Owner:EmitSound("npc/barnacle/barnacle_digesting1.wav")
+ self.Owner:EmitSound("npc/barnacle/barnacle_digesting2.wav")
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+end
+
+if not SERVER then return end
+
+function SWEP:Think()
+ local pl = self.Owner
+
+ if self.PukeLeft > 0 and CurTime() >= self.NextPuke then
+ self.PukeLeft = self.PukeLeft - 1
+ self.NextEmit = CurTime() + 0.1
+
+ local ent = ents.Create("projectile_poisonpuke")
+ if ent:IsValid() then
+ ent:SetPos(pl:EyePos())
+ ent:SetOwner(pl)
+ ent:Spawn()
+
+ ent:SetTeamID(TEAM_UNDEAD)
+
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ local ang = pl:EyeAngles()
+ ang:RotateAroundAxis(ang:Forward(), math.Rand(-30, 30))
+ ang:RotateAroundAxis(ang:Up(), math.Rand(-30, 30))
+ phys:SetVelocityInstantaneous(ang:Forward() * math.Rand(475, 750))
+ end
+ end
+ end
+
+ self:NextThink(CurTime())
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_pulserifle.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_pulserifle.lua
new file mode 100644
index 0000000..e76dc1c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_pulserifle.lua
@@ -0,0 +1,62 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Adonis' Pulse Rifle"
+ SWEP.Description = "Deals massive damage and slows targets."
+ SWEP.Slot = 2
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+
+ SWEP.HUD3DBone = "Vent"
+ SWEP.HUD3DPos = Vector(1, 0, 0)
+ SWEP.HUD3DScale = 0.018
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "ar2"
+
+SWEP.ViewModel = "models/weapons/c_irifle.mdl"
+SWEP.WorldModel = "models/weapons/w_IRifle.mdl"
+SWEP.UseHands = true
+
+SWEP.CSMuzzleFlashes = false
+
+SWEP.ReloadSound = Sound("Weapon_SMG1.Reload")
+SWEP.Primary.Sound = Sound("Airboat.FireGunHeavy")
+SWEP.Primary.Damage = 34
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.2
+
+SWEP.Primary.ClipSize = 20
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "pulse"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.ConeMax = 0.06
+SWEP.ConeMin = 0.02
+
+SWEP.WalkSpeed = SPEED_SLOW
+
+SWEP.IronSightsPos = Vector(-3, 1, 1)
+
+SWEP.TracerName = "AR2Tracer"
+
+function SWEP.BulletCallback(attacker, tr, dmginfo)
+ local ent = tr.Entity
+ if ent:IsValid() and ent:IsPlayer() and ent:Team() == TEAM_UNDEAD then
+ ent:AddLegDamage(4)
+ end
+
+ local e = EffectData()
+ e:SetOrigin(tr.HitPos)
+ e:SetNormal(tr.HitNormal)
+ e:SetRadius(8)
+ e:SetMagnitude(1)
+ e:SetScale(1)
+ util.Effect("cball_bounce", e)
+
+ GenericBulletCallback(attacker, tr, dmginfo)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_reaper.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_reaper.lua
new file mode 100644
index 0000000..bc43802
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_reaper.lua
@@ -0,0 +1,44 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Reaper' UMP"
+ SWEP.Slot = 2
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+
+ SWEP.HUD3DBone = "v_weapon.ump45_Release"
+ SWEP.HUD3DPos = Vector(-1.1, -3, 2)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+ SWEP.HUD3DScale = 0.02
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "ar2"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_smg_ump45.mdl"
+SWEP.WorldModel = "models/weapons/w_smg_ump45.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("Weapon_UMP45.Single")
+SWEP.Primary.Damage = 24
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.13
+
+SWEP.Primary.ClipSize = 28
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "smg1"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.Primary.Gesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2
+SWEP.ReloadGesture = ACT_HL2MP_GESTURE_RELOAD_AR2
+
+SWEP.ConeMax = 0.08
+SWEP.ConeMin = 0.045
+
+SWEP.WalkSpeed = SPEED_SLOW
+
+SWEP.IronSightsPos = Vector(-5.3, -3, 4.4)
+SWEP.IronSightsAng = Vector(-1, 0.2, 2.55)
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_redeemers.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_redeemers.lua
new file mode 100644
index 0000000..5802695
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_redeemers.lua
@@ -0,0 +1,42 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Redeemers' Dual Handguns"
+ SWEP.Slot = 1
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 50
+
+ SWEP.HUD3DBone = "v_weapon.slide_right"
+ SWEP.HUD3DPos = Vector(1, 0.1, -1)
+ SWEP.HUD3DScale = 0.015
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "duel"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_pist_elite.mdl"
+SWEP.WorldModel = "models/weapons/w_pist_elite.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("Weapon_ELITE.Single")
+SWEP.Primary.Damage = 22
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.15
+
+SWEP.Primary.ClipSize = 30
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "pistol"
+SWEP.Primary.DefaultClip = 150
+
+SWEP.ConeMax = 0.055
+SWEP.ConeMin = 0.05
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:SendWeaponAnimation()
+ self:SendWeaponAnim(self:Clip1() % 2 == 0 and ACT_VM_PRIMARYATTACK or ACT_VM_SECONDARYATTACK)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_resupplybox/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_resupplybox/cl_init.lua
new file mode 100644
index 0000000..1bdf74e
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_resupplybox/cl_init.lua
@@ -0,0 +1,44 @@
+include("shared.lua")
+
+SWEP.PrintName = "Resupply Box"
+SWEP.Description = "Allows survivors to get ammunition for their current weapon. Each person can only use the box once every so often.\nPress PRIMARY ATTACK to deploy the box.\nPress SECONDARY ATTACK and RELOAD to rotate the box."
+SWEP.DrawCrosshair = false
+
+SWEP.Slot = 4
+SWEP.SlotPos = 0
+
+function SWEP:DrawHUD()
+ if GetConVarNumber("crosshair") ~= 1 then return end
+ self:DrawCrosshairDot()
+end
+
+function SWEP:PrimaryAttack()
+end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
+
+function SWEP:Think()
+ if self.Owner:KeyDown(IN_ATTACK2) then
+ self:RotateGhost(FrameTime() * 60)
+ end
+ if self.Owner:KeyDown(IN_RELOAD) then
+ self:RotateGhost(FrameTime() * -60)
+ end
+end
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ return true
+end
+
+local nextclick = 0
+function SWEP:RotateGhost(amount)
+ if nextclick <= RealTime() then
+ surface.PlaySound("npc/headcrab_poison/ph_step4.wav")
+ nextclick = RealTime() + 0.3
+ end
+ RunConsoleCommand("_zs_ghostrotation", math.NormalizeAngle(GetConVarNumber("_zs_ghostrotation") + amount))
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_resupplybox/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_resupplybox/init.lua
new file mode 100644
index 0000000..df2bdb1
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_resupplybox/init.lua
@@ -0,0 +1,83 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self:SpawnGhost()
+
+ return true
+end
+
+function SWEP:OnRemove()
+ self:RemoveGhost()
+end
+
+function SWEP:Holster()
+ self:RemoveGhost()
+ return true
+end
+
+function SWEP:SpawnGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:GiveStatus("ghost_resupplybox")
+ end
+end
+
+function SWEP:RemoveGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:RemoveStatus("ghost_resupplybox", false, true)
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+
+ local owner = self.Owner
+
+ local status = owner.status_ghost_resupplybox
+ if not (status and status:IsValid()) then return end
+ status:RecalculateValidity()
+ if not status:GetValidPlacement() then return end
+
+ local pos, ang = status:RecalculateValidity()
+ if not pos or not ang then return end
+
+ self:SetNextPrimaryAttack(CurTime() + self.Primary.Delay)
+
+ local ent = ents.Create("prop_resupplybox")
+ if ent:IsValid() then
+ ent:SetPos(pos)
+ ent:SetAngles(ang)
+ ent:Spawn()
+
+ ent:SetObjectOwner(owner)
+
+ ent:EmitSound("npc/dog/dog_servo12.wav")
+
+ ent:GhostAllPlayersInMe(5)
+
+ self:TakePrimaryAmmo(1)
+
+ local stored = owner:PopPackedItem(ent:GetClass())
+ if stored then
+ ent:SetObjectHealth(stored[1])
+ end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ owner:StripWeapon(self:GetClass())
+ end
+ end
+end
+
+function SWEP:Think()
+ local count = self:GetPrimaryAmmoCount()
+ if count ~= self:GetReplicatedAmmo() then
+ self:SetReplicatedAmmo(count)
+ self.Owner:ResetSpeed()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_resupplybox/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_resupplybox/shared.lua
new file mode 100644
index 0000000..3c29674
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_resupplybox/shared.lua
@@ -0,0 +1,59 @@
+SWEP.ViewModel = "models/weapons/v_pistol.mdl"
+SWEP.WorldModel = Model("models/Items/ammocrate_ar2.mdl")
+
+SWEP.AmmoIfHas = true
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.DefaultClip = 1
+SWEP.Primary.Ammo = "helicoptergun"
+SWEP.Primary.Delay = 1
+SWEP.Primary.Automatic = true
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_NORMAL
+SWEP.FullWalkSpeed = SPEED_SLOWEST
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType("slam")
+ self:SetDeploySpeed(1.1)
+ self:HideViewAndWorldModel()
+end
+
+function SWEP:SetReplicatedAmmo(count)
+ self:SetDTInt(0, count)
+end
+
+function SWEP:GetReplicatedAmmo()
+ return self:GetDTInt(0)
+end
+
+function SWEP:GetWalkSpeed()
+ if self:GetPrimaryAmmoCount() > 0 then
+ return self.FullWalkSpeed
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ return false
+ end
+
+ return true
+end
+
+function SWEP:Holster()
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_sawhack.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_sawhack.lua
new file mode 100644
index 0000000..8200702
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_sawhack.lua
@@ -0,0 +1,70 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Sawhack"
+
+ SWEP.ViewModelFOV = 60
+
+ SWEP.VElements = {
+ ["base1+"] = { type = "Model", model = "models/props_lab/tpplug.mdl", bone = "ValveBiped.Bip01", rel = "base", pos = Vector(-1.45, 0, -0.25), angle = Angle(270, 0, 0), size = Vector(0.4, 0.4, 0.1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base1"] = { type = "Model", model = "models/props_lab/tpplug.mdl", bone = "ValveBiped.Bip01", rel = "base", pos = Vector(-1.45, 0, 0.394), angle = Angle(90, 0, 0), size = Vector(0.4, 0.4, 0.1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base"] = { type = "Model", model = "models/props_junk/sawblade001a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(7.956, 2.181, -18.506), angle = Angle(0, -6.212, 90), size = Vector(0.4, 0.4, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+
+ SWEP.WElements = {
+ ["base1+"] = { type = "Model", model = "models/props_lab/tpplug.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "base", pos = Vector(-1.45, 0, -0.25), angle = Angle(270, 0, 0), size = Vector(0.4, 0.4, 0.1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base1"] = { type = "Model", model = "models/props_lab/tpplug.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "base", pos = Vector(-1.45, 0, 0.394), angle = Angle(90, 0, 0), size = Vector(0.4, 0.4, 0.1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base"] = { type = "Model", model = "models/props_junk/sawblade001a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(7, 2, -22.5), angle = Angle(0, 0, 90), size = Vector(0.4, 0.4, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.ViewModel = "models/weapons/c_crowbar.mdl"
+SWEP.WorldModel = "models/weapons/w_crowbar.mdl"
+SWEP.UseHands = true
+
+SWEP.HoldType = "melee2"
+
+SWEP.Primary.Delay = 0.45
+
+SWEP.MeleeDamage = 32
+SWEP.MeleeRange = 55
+SWEP.MeleeSize = 1.9
+SWEP.MeleeKnockBack = SWEP.MeleeDamage * 0.5
+
+SWEP.WalkSpeed = SPEED_FAST
+
+SWEP.SwingTime = 0.15
+SWEP.SwingRotation = Angle(0, -35, -50)
+SWEP.SwingOffset = Vector(10, 0, 0)
+SWEP.HoldType = "melee2"
+SWEP.SwingHoldType = "melee2"
+
+SWEP.HitDecal = "Manhackcut"
+SWEP.HitAnim = ACT_VM_MISSCENTER
+
+SWEP.NoHitSoundFlesh = true
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("weapons/iceaxe/iceaxe_swing1.wav", 75, math.random(75, 80))
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("npc/manhack/grind"..math.random(5)..".wav")
+end
+
+function SWEP:PlayHitFleshSound()
+ self:EmitSound("ambient/machines/slicer"..math.random(4)..".wav")
+end
+
+function SWEP:OnMeleeHit(hitent, hitflesh, tr)
+ if not hitflesh then
+ local effectdata = EffectData()
+ effectdata:SetOrigin(tr.HitPos)
+ effectdata:SetNormal(tr.HitNormal)
+ effectdata:SetMagnitude(2)
+ effectdata:SetScale(1)
+ util.Effect("sparks", effectdata)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_shade.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_shade.lua
new file mode 100644
index 0000000..195449a
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_shade.lua
@@ -0,0 +1,114 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.ViewModel = Model("models/weapons/v_fza.mdl")
+SWEP.WorldModel = Model("models/weapons/w_crowbar.mdl")
+
+if CLIENT then
+ SWEP.ViewModelFOV = 70
+end
+
+SWEP.Primary.Automatic = false
+SWEP.Secondary.Automatic = false
+
+function SWEP:Initialize()
+ self:HideWorldModel()
+end
+
+function SWEP:Think()
+end
+
+function SWEP:PrimaryAttack()
+ if CurTime() <= self:GetNextPrimaryFire() then return end
+ self:SetNextSecondaryFire(CurTime() + 0.65)
+
+ for _, ent in pairs(ents.FindByClass("env_shadecontrol")) do
+ if ent:IsValid() and ent:GetOwner() == self.Owner then
+ local obj = ent:GetParent()
+ if obj:IsValid() then
+ self.Owner:DoAttackEvent()
+
+ if CLIENT then return end
+
+ local filt = team.GetPlayers(TEAM_UNDEAD)
+ table.insert(filt, obj)
+ local vel = (self.Owner:TraceLine(10240, MASK_SOLID, filt).HitPos - obj:LocalToWorld(obj:OBBCenter())):GetNormalized() * 1000
+
+ local phys = obj:GetPhysicsObject()
+ if phys:IsValid() and phys:IsMoveable() and phys:GetMass() <= 300 then
+ phys:Wake()
+ phys:SetVelocity(vel)
+ obj:SetPhysicsAttacker(self.Owner)
+ phys:AddGameFlag(FVPHYSICS_WAS_THROWN)
+
+ obj:EmitSound(")weapons/physcannon/superphys_launch"..math.random(4)..".wav")
+ end
+ end
+
+ ent:Remove()
+ end
+ end
+end
+
+function SWEP:SecondaryAttack()
+ if CurTime() <= self:GetNextSecondaryFire() then return end
+ self:SetNextPrimaryFire(CurTime() + 0.25)
+ self:SetNextSecondaryFire(CurTime() + 0.4)
+
+ if CLIENT then return end
+
+ for _, ent in pairs(ents.FindByClass("env_shadecontrol")) do
+ if ent:IsValid() and ent:GetOwner() == self.Owner then
+ ent:Remove()
+ return
+ end
+ end
+
+ local ent = self:GetOwner():TraceHull(400, MASK_SOLID, 4, player.GetAll()).Entity
+ if ent:IsValid() and ent:IsPhysicsModel() then
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() and phys:IsMoveable() and phys:GetMass() <= 300 then
+ for _, ent2 in pairs(ents.FindByClass("env_shadecontrol")) do
+ if ent2:IsValid() and ent2:GetParent() == ent then
+ ent2:Remove()
+ return
+ end
+ end
+
+ local con = ents.Create("env_shadecontrol")
+ if con:IsValid() then
+ con:Spawn()
+ con:SetOwner(self.Owner)
+ con:AttachTo(ent)
+
+ ent:EmitSound(")weapons/physcannon/physcannon_claws_close.wav")
+ end
+ end
+ end
+end
+
+function SWEP:Reload()
+end
+
+function SWEP:OnRemove()
+end
+
+function SWEP:Holster()
+end
+
+if not CLIENT then return end
+
+function SWEP:PreDrawViewModel(vm)
+ local owner = self.Owner
+ if owner:IsValid() then
+ owner:CallZombieFunction("PreRenderEffects", vm)
+ end
+end
+
+function SWEP:PostDrawViewModel(vm)
+ local owner = self.Owner
+ if owner:IsValid() then
+ owner:CallZombieFunction("PostRenderEffects", vm)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_shovel.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_shovel.lua
new file mode 100644
index 0000000..76828aa
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_shovel.lua
@@ -0,0 +1,60 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Shovel"
+ SWEP.Description = "Instantly kills zombies that are knocked down."
+
+ SWEP.ViewModelFOV = 60
+
+ SWEP.ShowViewModel = false
+ SWEP.ShowWorldModel = false
+
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props_junk/shovel01a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(1.363, 1.363, -7.728), angle = Angle(0, 0, 0), size = Vector(0.899, 0.899, 0.899), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props_junk/shovel01a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(5, 1.363, -15), angle = Angle(-3, 180, 0), size = Vector(1, 1, 1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.HoldType = "melee2"
+
+SWEP.DamageType = DMG_CLUB
+
+SWEP.ViewModel = "models/weapons/c_crowbar.mdl"
+SWEP.WorldModel = "models/props_junk/shovel01a.mdl"
+SWEP.UseHands = true
+
+SWEP.MeleeDamage = 50
+SWEP.MeleeRange = 68
+SWEP.MeleeSize = 1.5
+SWEP.MeleeKnockBack = SWEP.MeleeDamage * 2
+
+SWEP.Primary.Delay = 1.2
+
+SWEP.WalkSpeed = SPEED_SLOWER
+
+SWEP.SwingRotation = Angle(0, -90, -60)
+SWEP.SwingOffset = Vector(0, 30, -40)
+SWEP.SwingTime = 0.65
+SWEP.SwingHoldType = "melee"
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("weapons/iceaxe/iceaxe_swing1.wav", 75, math.random(65, 70))
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("weapons/melee/shovel/shovel_hit-0"..math.random(4)..".ogg")
+end
+
+function SWEP:PlayHitFleshSound()
+ self:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav")
+end
+
+function SWEP:OnMeleeHit(hitent, hitflesh, tr)
+ if hitent:IsValid() and hitent:IsPlayer() and hitent.Revive and hitent.Revive:IsValid() and gamemode.Call("PlayerShouldTakeDamage", hitent, self.Owner) then
+ hitent:SetHealth(1)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_sigilplacer/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_sigilplacer/shared.lua
new file mode 100644
index 0000000..02e62b8
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_sigilplacer/shared.lua
@@ -0,0 +1,196 @@
+SWEP.PrintName = "Sigil Placer"
+
+SWEP.ViewModel = "models/weapons/c_pistol.mdl"
+SWEP.WorldModel = "models/weapons/w_pistol.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.ClipSize = -1
+SWEP.Primary.DefaultClip = -1
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "none"
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+function SWEP:Initialize()
+ if SERVER then
+ self:RefreshSigils()
+ end
+end
+
+function SWEP:Deploy()
+ if SERVER then
+ self:RefreshSigils()
+ end
+
+ return true
+end
+
+function SWEP:Holster()
+ if SERVER then
+ for _, ent in pairs(ents.FindByClass("point_fakesigil")) do
+ ent:Remove()
+ end
+ end
+
+ return true
+end
+
+function SWEP:PrimaryAttack()
+ local owner = self.Owner
+ if not owner:IsSuperAdmin() then return end
+
+ owner:DoAttackEvent()
+
+ if CLIENT then return end
+
+ local tr = owner:TraceLine(10240)
+ if tr.HitWorld and tr.HitNormal.z >= 0.8 then
+ table.insert(GAMEMODE.ProfilerNodes, tr.HitPos)
+
+ self:RefreshSigils()
+ GAMEMODE.ProfilerIsPreMade = true
+
+ GAMEMODE:SaveProfilerPreMade(GAMEMODE.ProfilerNodes)
+ end
+end
+
+function SWEP:SecondaryAttack()
+ local owner = self.Owner
+ if not owner:IsSuperAdmin() then return end
+
+ owner:DoAttackEvent()
+
+ if CLIENT then return end
+
+ local tr = owner:TraceLine(10240)
+
+ local newpoints = {}
+ for _, point in pairs(GAMEMODE.ProfilerNodes) do
+ if point:Distance(tr.HitPos) > 64 then
+ table.insert(newpoints, point)
+ end
+ end
+ GAMEMODE.ProfilerNodes = newpoints
+
+ self:RefreshSigils()
+ GAMEMODE.ProfilerIsPreMade = true
+
+ GAMEMODE:SaveProfilerPreMade(GAMEMODE.ProfilerNodes)
+end
+
+function SWEP:Reload()
+ local owner = self.Owner
+ if not owner:IsSuperAdmin() then return end
+
+ owner:DoAttackEvent()
+
+ if CLIENT then return end
+
+ if not self.StartReload and not self.StartReload2 then
+ self.StartReload = CurTime()
+ owner:ChatPrint("Keep holding reload to clear all pre-made sigil points.")
+ end
+end
+
+if SERVER then
+function SWEP:Think()
+ if self.StartReload2 then
+ if not self.Owner:KeyDown(IN_RELOAD) then
+ self.StartReload2 = nil
+ return
+ end
+
+ if CurTime() >= self.StartReload2 + 3 then
+ self.StartReload2 = nil
+
+ self.Owner:ChatPrint("Deleted everything including generated nodes. Turned off generated mode.")
+
+ GAMEMODE.ProfilerIsPreMade = true
+ GAMEMODE:DeleteProfilerPreMade()
+ GAMEMODE.ProfilerNodes = {}
+ GAMEMODE:SaveProfiler()
+
+ self:RefreshSigils()
+ end
+ elseif self.StartReload then
+ if not self.Owner:KeyDown(IN_RELOAD) then
+ self.StartReload = nil
+ return
+ end
+
+ if CurTime() >= self.StartReload + 3 then
+ self.StartReload = nil
+
+ self.Owner:ChatPrint("Deleted all pre-made sigil points and reverted to generated mode. Keep holding reload to delete ALL nodes.")
+
+ GAMEMODE.ProfilerIsPreMade = false
+ GAMEMODE:DeleteProfilerPreMade()
+ GAMEMODE:LoadProfiler()
+
+ self:RefreshSigils()
+
+ self.StartReload2 = CurTime()
+ end
+ end
+end
+end
+
+function SWEP:RefreshSigils()
+ for _, ent in pairs(ents.FindByClass("point_fakesigil")) do
+ ent:Remove()
+ end
+
+ for _, point in pairs(GAMEMODE.ProfilerNodes) do
+ local ent = ents.Create("point_fakesigil")
+ if ent:IsValid() then
+ ent:SetPos(point)
+ ent:Spawn()
+ end
+ end
+end
+
+concommand.Add("zs_sigilplacer", function(sender)
+ if sender:IsValid() and sender:IsSuperAdmin() then
+ sender:Give("weapon_zs_sigilplacer")
+ end
+end)
+
+local ENT = {}
+
+ENT.Type = "anim"
+
+function ENT:Initialize()
+ self:DrawShadow(false)
+ self:SetModelScale(1.1, 0)
+ self:SetModel("models/props_wasteland/medbridge_post01.mdl")
+ self:SetMoveType(MOVETYPE_NONE)
+ self:SetSolid(SOLID_NONE)
+end
+
+if CLIENT then
+ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
+function ENT:DrawTranslucent()
+ local lp = LocalPlayer()
+ if lp:IsValid() then
+ local wep = lp:GetActiveWeapon()
+ if wep:IsValid() and wep:GetClass() == "weapon_zs_sigilplacer" then
+ cam.IgnoreZ(true)
+ render.SetBlend(0.5)
+ render.SetColorModulation(1, 0, 0)
+ render.SuppressEngineLighting(true)
+
+ self:DrawModel()
+
+ render.SuppressEngineLighting(false)
+ render.SetColorModulation(1, 1, 1)
+ render.SetBlend(1)
+ cam.IgnoreZ(false)
+ end
+ end
+end
+end
+
+scripted_ents.Register(ENT, "point_fakesigil")
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_silencer.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_silencer.lua
new file mode 100644
index 0000000..efba691
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_silencer.lua
@@ -0,0 +1,43 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Silencer' SMG"
+ SWEP.Slot = 2
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+
+ SWEP.HUD3DBone = "v_weapon.TMP_Parent"
+ SWEP.HUD3DPos = Vector(-1, -3.5, -1)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+ SWEP.HUD3DScale = 0.015
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "pistol"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_smg_tmp.mdl"
+SWEP.WorldModel = "models/weapons/w_smg_tmp.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("Weapon_TMP.Single")
+SWEP.Primary.Damage = 22
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.06
+
+SWEP.Primary.ClipSize = 25
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "smg1"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.Primary.Gesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1
+SWEP.ReloadGesture = ACT_HL2MP_GESTURE_RELOAD_SMG1
+
+SWEP.ConeMax = 0.13
+SWEP.ConeMin = 0.1
+
+SWEP.WalkSpeed = SPEED_NORMAL
+
+SWEP.IronSightsPos = Vector(-7, 3, 2.5)
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_sledgehammer.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_sledgehammer.lua
new file mode 100644
index 0000000..da468c3
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_sledgehammer.lua
@@ -0,0 +1,41 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Sledgehammer"
+ SWEP.ViewModelFOV = 75
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.HoldType = "melee2"
+
+SWEP.DamageType = DMG_CLUB
+
+SWEP.ViewModel = "models/weapons/v_sledgehammer/v_sledgehammer.mdl"
+SWEP.WorldModel = "models/weapons/w_sledgehammer.mdl"
+
+SWEP.MeleeDamage = 75
+SWEP.MeleeRange = 64
+SWEP.MeleeSize = 1.75
+SWEP.MeleeKnockBack = SWEP.MeleeDamage * 1.75
+
+SWEP.Primary.Delay = 1.3
+
+SWEP.WalkSpeed = SPEED_SLOWEST
+
+SWEP.SwingRotation = Angle(60, 0, -80)
+SWEP.SwingOffset = Vector(0, -30, 0)
+SWEP.SwingTime = 0.75
+SWEP.SwingHoldType = "melee"
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("weapons/iceaxe/iceaxe_swing1.wav", 75, math.random(35, 45))
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("physics/metal/metal_canister_impact_hard"..math.random(3)..".wav", 75, math.Rand(86, 90))
+end
+
+function SWEP:PlayHitFleshSound()
+ self:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav", 75, math.Rand(86, 90))
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_slugrifle.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_slugrifle.lua
new file mode 100644
index 0000000..7d08416
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_slugrifle.lua
@@ -0,0 +1,132 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Tiny' Slug Rifle"
+ SWEP.Description = "This powerful rifle instantly kills any zombie with a head shot."
+ SWEP.Slot = 3
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 50
+
+ SWEP.HUD3DBone = "v_weapon.xm1014_Bolt"
+ SWEP.HUD3DPos = Vector(-1, 0, 0)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+ SWEP.HUD3DScale = 0.02
+
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props_phx/construct/metal_plate_curve360x2.mdl", bone = "v_weapon.xm1014_Parent", rel = "", pos = Vector(0, -6, -9), angle = Angle(0, 0, 0), size = Vector(0.014, 0.014, 0.094), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base+"] = { type = "Model", model = "models/props_phx/construct/metal_angle360.mdl", bone = "v_weapon.xm1014_Parent", rel = "base", pos = Vector(0, 0, 8.5), angle = Angle(0, 0, 0), size = Vector(0.014, 0.014, 0.014), color = Color(255, 255, 255, 45), surpresslightning = false, material = "models/screenspace", skin = 0, bodygroup = {} },
+ ["base++"] = { type = "Model", model = "models/props_phx/construct/metal_angle360.mdl", bone = "v_weapon.xm1014_Parent", rel = "base", pos = Vector(0, 0, 2), angle = Angle(0, 0, 0), size = Vector(0.014, 0.014, 0.014), color = Color(255, 255, 255, 45), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props_phx/construct/metal_plate_curve360x2.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(13, 1, -7), angle = Angle(80, 0, 0), size = Vector(0.014, 0.014, 0.094), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base+"] = { type = "Model", model = "models/props_phx/construct/metal_angle360.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "base", pos = Vector(0, 0, 8.5), angle = Angle(0, 0, 0), size = Vector(0.014, 0.014, 0.014), color = Color(255, 255, 255, 45), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base++"] = { type = "Model", model = "models/props_phx/construct/metal_angle360.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "base", pos = Vector(0, 0, 2), angle = Angle(0, 0, 0), size = Vector(0.014, 0.014, 0.014), color = Color(255, 255, 255, 45), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "ar2"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_shot_xm1014.mdl"
+SWEP.WorldModel = "models/weapons/w_shot_xm1014.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("Weapon_AWP.Single")
+SWEP.Primary.Damage = 135
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 1.5
+SWEP.ReloadDelay = SWEP.Primary.Delay
+
+SWEP.Primary.ClipSize = 2
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "357"
+SWEP.Primary.DefaultClip = 10
+
+SWEP.Primary.Gesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_CROSSBOW
+SWEP.ReloadGesture = ACT_HL2MP_GESTURE_RELOAD_SHOTGUN
+
+SWEP.ConeMax = 0.12
+SWEP.ConeMin = 0.005
+
+SWEP.IronSightsPos = Vector() --Vector(-7.3, 9, 2.3)
+SWEP.IronSightsAng = Vector(0, -1, 0)
+
+SWEP.WalkSpeed = SPEED_SLOWER
+
+function SWEP:IsScoped()
+ return self:GetIronsights() and self.fIronTime and self.fIronTime + 0.25 <= CurTime()
+end
+
+if CLIENT then
+ SWEP.IronsightsMultiplier = 0.25
+
+ function SWEP:GetViewModelPosition(pos, ang)
+ if self:IsScoped() then
+ return pos + ang:Up() * 256, ang
+ end
+
+ return self.BaseClass.GetViewModelPosition(self, pos, ang)
+ end
+
+ local matScope = Material("zombiesurvival/scope")
+ function SWEP:DrawHUDBackground()
+ if self:IsScoped() then
+ local scrw, scrh = ScrW(), ScrH()
+ local size = math.min(scrw, scrh)
+ surface.SetMaterial(matScope)
+ surface.SetDrawColor(255, 255, 255, 255)
+ surface.DrawTexturedRect((scrw - size) * 0.5, (scrh - size) * 0.5, size, size)
+ surface.SetDrawColor(0, 0, 0, 255)
+ if scrw > size then
+ local extra = (scrw - size) * 0.5
+ surface.DrawRect(0, 0, extra, scrh)
+ surface.DrawRect(scrw - extra, 0, extra, scrh)
+ end
+ if scrh > size then
+ local extra = (scrh - size) * 0.5
+ surface.DrawRect(0, 0, scrw, extra)
+ surface.DrawRect(0, scrh - extra, scrw, extra)
+ end
+ end
+ end
+end
+
+SWEP.NextReload = 0
+function SWEP:Reload()
+ if CurTime() < self.NextReload then return end
+
+ self.NextReload = CurTime() + self.ReloadDelay
+
+ local owner = self.Owner
+
+ if self:Clip1() < self.Primary.ClipSize and 0 < owner:GetAmmoCount(self.Primary.Ammo) then
+ self:DefaultReload(ACT_VM_RELOAD)
+ owner:DoReloadEvent()
+ self:SetNextPrimaryFire(CurTime() + self.ReloadDelay)
+
+ timer.Simple(0.25, function()
+ if self:IsValid() and IsValid(owner) then
+ self:SendWeaponAnim(ACT_SHOTGUN_RELOAD_FINISH)
+ end
+ end)
+ end
+end
+
+function SWEP.BulletCallback(attacker, tr, dmginfo)
+ if tr.HitGroup == HITGROUP_HEAD then
+ local ent = tr.Entity
+ if ent:IsValid() and ent:IsPlayer() then
+ ent.Gibbed = CurTime()
+ end
+
+ if gamemode.Call("PlayerShouldTakeDamage", ent, attacker) then
+ ent:SetHealth(math.max(ent:Health() - 400, 1))
+ end
+ end
+
+ GenericBulletCallback(attacker, tr, dmginfo)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_smg.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_smg.lua
new file mode 100644
index 0000000..811e321
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_smg.lua
@@ -0,0 +1,44 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Shredder' SMG"
+ SWEP.Slot = 2
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 50
+
+ SWEP.HUD3DBone = "v_weapon.MP5_Parent"
+ SWEP.HUD3DPos = Vector(-1, -3, -6)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+ SWEP.HUD3DScale = 0.015
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "shotgun"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_smg_mp5.mdl"
+SWEP.WorldModel = "models/weapons/w_smg_mp5.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("Weapon_MP5Navy.Single")
+SWEP.Primary.Damage = 18
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.09
+
+SWEP.Primary.ClipSize = 30
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "smg1"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.Primary.Gesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN
+SWEP.ReloadGesture = ACT_HL2MP_GESTURE_RELOAD_SMG1
+
+SWEP.ConeMax = 0.11
+SWEP.ConeMin = 0.05
+
+SWEP.WalkSpeed = SPEED_SLOW
+
+SWEP.IronSightsAng = Vector(0.8, 0, 0)
+SWEP.IronSightsPos = Vector(-5.33, 7, 1.8)
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_special_wow/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_special_wow/cl_init.lua
new file mode 100644
index 0000000..3d390d0
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_special_wow/cl_init.lua
@@ -0,0 +1,4 @@
+include("shared.lua")
+
+SWEP.PrintName = "Will O' Wisp"
+SWEP.DrawCrosshair = false
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_special_wow/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_special_wow/init.lua
new file mode 100644
index 0000000..c3b2be0
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_special_wow/init.lua
@@ -0,0 +1,10 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function SWEP:Deploy()
+ self.Owner:CreateAmbience("ambience_wow")
+
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_special_wow/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_special_wow/shared.lua
new file mode 100644
index 0000000..c721eb8
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_special_wow/shared.lua
@@ -0,0 +1,49 @@
+SWEP.ZombieOnly = true
+SWEP.IsMelee = true
+
+SWEP.ViewModel = "models/weapons/v_knife_t.mdl"
+SWEP.WorldModel = "models/weapons/w_knife_t.mdl"
+
+function SWEP:Initialize()
+ self:HideViewAndWorldModel()
+end
+
+function SWEP:Think()
+ if self:GetAttackDown() and not self.Owner:KeyDown(IN_ATTACK) then
+ self:SetAttackDown(false)
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if not self:GetAttackDown() then
+ self:SetAttackDown(true)
+ self:EmitSound("npc/scanner/scanner_nearmiss"..math.random(2)..".wav")
+ end
+end
+
+function SWEP:SecondaryAttack()
+ if CurTime() >= self:GetNextPrimaryAttack() then
+ self:SetNextPrimaryAttack(CurTime() + 8)
+ self:EmitSound("npc/scanner/scanner_talk1.wav")
+ end
+end
+
+function SWEP:Reload()
+ if CurTime() >= self:GetNextPrimaryAttack() then
+ self:SetNextPrimaryAttack(CurTime() + 5)
+ self:EmitSound("npc/scanner/scanner_talk2.wav")
+ end
+end
+
+function SWEP:SetAttackDown(attackdown)
+ self:SetDTBool(0, attackdown)
+end
+
+function SWEP:GetAttackDown()
+ return self:GetDTBool(0)
+end
+
+util.PrecacheSound("npc/scanner/scanner_nearmiss1.wav")
+util.PrecacheSound("npc/scanner/scanner_nearmiss2.wav")
+util.PrecacheSound("npc/scanner/scanner_talk1.wav")
+util.PrecacheSound("npc/scanner/scanner_talk2.wav")
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_spotlamp/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_spotlamp/cl_init.lua
new file mode 100644
index 0000000..f13ae8a
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_spotlamp/cl_init.lua
@@ -0,0 +1,44 @@
+include("shared.lua")
+
+SWEP.PrintName = "Spot Lamp"
+SWEP.Description = "This lamp is a watchful eye which illuminates an area.\nPress PRIMARY ATTACK to deploy.\nPress SECONDARY ATTACK and RELOAD to rotate."
+SWEP.DrawCrosshair = false
+
+SWEP.Slot = 4
+SWEP.SlotPos = 0
+
+function SWEP:DrawHUD()
+ if GetConVarNumber("crosshair") ~= 1 then return end
+ self:DrawCrosshairDot()
+end
+
+function SWEP:PrimaryAttack()
+end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
+
+function SWEP:Think()
+ if self.Owner:KeyDown(IN_ATTACK2) then
+ self:RotateGhost(FrameTime() * 60)
+ end
+ if self.Owner:KeyDown(IN_RELOAD) then
+ self:RotateGhost(FrameTime() * -60)
+ end
+end
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ return true
+end
+
+local nextclick = 0
+function SWEP:RotateGhost(amount)
+ if nextclick <= RealTime() then
+ surface.PlaySound("npc/headcrab_poison/ph_step4.wav")
+ nextclick = RealTime() + 0.3
+ end
+ RunConsoleCommand("_zs_ghostrotation", math.NormalizeAngle(GetConVarNumber("_zs_ghostrotation") + amount))
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_spotlamp/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_spotlamp/init.lua
new file mode 100644
index 0000000..5d0e7eb
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_spotlamp/init.lua
@@ -0,0 +1,83 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+function SWEP:Deploy()
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+
+ self:SpawnGhost()
+
+ return true
+end
+
+function SWEP:OnRemove()
+ self:RemoveGhost()
+end
+
+function SWEP:Holster()
+ self:RemoveGhost()
+ return true
+end
+
+function SWEP:SpawnGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:GiveStatus("ghost_spotlamp")
+ end
+end
+
+function SWEP:RemoveGhost()
+ local owner = self.Owner
+ if owner and owner:IsValid() then
+ owner:RemoveStatus("ghost_spotlamp", false, true)
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+
+ local owner = self.Owner
+
+ local status = owner.status_ghost_spotlamp
+ if not (status and status:IsValid()) then return end
+ status:RecalculateValidity()
+ if not status:GetValidPlacement() then return end
+
+ local pos, ang = status:RecalculateValidity()
+ if not pos or not ang then return end
+
+ self:SetNextPrimaryAttack(CurTime() + self.Primary.Delay)
+
+ local ent = ents.Create("prop_spotlamp")
+ if ent:IsValid() then
+ ent:SetPos(pos)
+ ent:SetAngles(ang)
+ ent:Spawn()
+
+ ent:SetObjectOwner(owner)
+
+ ent:EmitSound("npc/dog/dog_servo12.wav")
+
+ ent:GhostAllPlayersInMe(5)
+
+ self:TakePrimaryAmmo(1)
+
+ local stored = owner:PopPackedItem(ent:GetClass())
+ if stored then
+ ent:SetObjectHealth(stored[1])
+ end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ owner:StripWeapon(self:GetClass())
+ end
+ end
+end
+
+function SWEP:Think()
+ local count = self:GetPrimaryAmmoCount()
+ if count ~= self:GetReplicatedAmmo() then
+ self:SetReplicatedAmmo(count)
+ self.Owner:ResetSpeed()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_spotlamp/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_spotlamp/shared.lua
new file mode 100644
index 0000000..d36c81c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_spotlamp/shared.lua
@@ -0,0 +1,59 @@
+SWEP.ViewModel = "models/weapons/v_pistol.mdl"
+SWEP.WorldModel = Model("models/props_combine/combine_light001a.mdl")
+
+SWEP.AmmoIfHas = true
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.DefaultClip = 1
+SWEP.Primary.Ammo = "spotlamp"
+SWEP.Primary.Delay = 1
+SWEP.Primary.Automatic = true
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_NORMAL
+SWEP.FullWalkSpeed = SPEED_SLOWEST
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType("slam")
+ self:SetDeploySpeed(1.1)
+ self:HideViewAndWorldModel()
+end
+
+function SWEP:SetReplicatedAmmo(count)
+ self:SetDTInt(0, count)
+end
+
+function SWEP:GetReplicatedAmmo()
+ return self:GetDTInt(0)
+end
+
+function SWEP:GetWalkSpeed()
+ if self:GetPrimaryAmmoCount() > 0 then
+ return self.FullWalkSpeed
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:Reload()
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ return false
+ end
+
+ return true
+end
+
+function SWEP:Holster()
+ return true
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_stone.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_stone.lua
new file mode 100644
index 0000000..0650cf8
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_stone.lua
@@ -0,0 +1,187 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Stone"
+ SWEP.Description = "A simple stone found laying pretty much anywhere."
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 50
+ SWEP.ShowViewModel = true
+ SWEP.ShowWorldModel = false
+
+ SWEP.ViewModelBoneMods = {
+ ["ValveBiped.cube1"] = { scale = Vector(0.009, 0.009, 0.009), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) },
+ ["ValveBiped.cube2"] = { scale = Vector(0.009, 0.009, 0.009), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) },
+ ["ValveBiped.cube3"] = { scale = Vector(0.009, 0.009, 0.009), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) },
+ ["ValveBiped.cube"] = { scale = Vector(0.009, 0.009, 0.009), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) }
+ }
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props_junk/rock001a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(4.091, 3.181, -0.456), angle = Angle(-54.206, 58.294, -50.114), size = Vector(0.492, 0.492, 0.492), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props_junk/rock001a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(3.181, 2.273, -0.456), angle = Angle(-43.978, 27.614, 70.568), size = Vector(0.379, 0.379, 0.379), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.ViewModel = "models/weapons/c_bugbait.mdl"
+SWEP.WorldModel = "models/props_junk/rock001a.mdl"
+SWEP.UseHands = true
+
+SWEP.HoldType = "grenade"
+
+SWEP.WalkSpeed = SPEED_FAST
+
+SWEP.AmmoIfHas = true
+
+SWEP.Primary.ClipSize = 1
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "stone"
+SWEP.Primary.Delay = 1
+SWEP.Primary.DefaultClip = 1
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = false
+SWEP.Secondary.Ammo = "none"
+
+SWEP.WalkSpeed = SPEED_FAST
+
+function SWEP:Initialize()
+ self:SetWeaponHoldType("grenade")
+ self:SetDeploySpeed(1.1)
+
+ if CLIENT then
+ self:Anim_Initialize()
+ end
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ return false
+ end
+
+ return true
+end
+
+function SWEP:PrimaryAttack()
+ if not self:CanPrimaryAttack() then return end
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+
+ local owner = self.Owner
+ self:SendWeaponAnim(ACT_VM_THROW)
+ owner:DoAttackEvent()
+
+ self:TakePrimaryAmmo(1)
+ self.NextDeploy = CurTime() + 0.75
+
+ if SERVER then
+ local ent = ents.Create("projectile_stone")
+ if ent:IsValid() then
+ ent:SetPos(owner:GetShootPos())
+ ent:SetOwner(owner)
+ ent:Spawn()
+ ent.Team = owner:Team()
+ ent:EmitSound("WeaponFrag.Throw")
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:AddAngleVelocity(VectorRand() * 360)
+ phys:SetVelocityInstantaneous(self.Owner:GetAimVector() * 900)
+ end
+ end
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ owner:StripWeapon(self:GetClass())
+ end
+ end
+end
+
+function SWEP:SecondaryAttack()
+end
+
+function SWEP:CanSecondaryAttack()
+ return false
+end
+
+function SWEP:Reload()
+ return false
+end
+
+function SWEP:Deploy()
+ GAMEMODE:WeaponDeployed(self.Owner, self)
+
+ if self:GetPrimaryAmmoCount() <= 0 then
+ self:SendWeaponAnim(ACT_VM_THROW)
+ end
+
+ return true
+end
+
+function SWEP:Holster()
+ self.NextDeploy = nil
+
+ if CLIENT then
+ self:Anim_Holster()
+ end
+
+ return true
+end
+
+function SWEP:Think()
+ if self.NextDeploy and self.NextDeploy <= CurTime() then
+ self.NextDeploy = nil
+
+ if 0 < self:GetPrimaryAmmoCount() then
+ self:SendWeaponAnim(ACT_VM_DRAW)
+ else
+ self:SendWeaponAnim(ACT_VM_THROW)
+ if SERVER then
+ self:Remove()
+ end
+ end
+ end
+end
+
+local colBG = Color(16, 16, 16, 90)
+local colWhite = Color(220, 220, 220, 230)
+
+SWEP.HUD3DPos = Vector(5, 2, 0)
+
+function SWEP:PostDrawViewModel(vm)
+ if not self.HUD3DPos or GAMEMODE.WeaponHUDMode == 1 then return end
+
+ local bone = vm:LookupBone("ValveBiped.Bip01_R_Hand")
+ if not bone then return end
+
+ local m = vm:GetBoneMatrix(bone)
+ if not m then return end
+
+ local pos, ang = m:GetTranslation(), m:GetAngles()
+
+ local offset = self.HUD3DPos
+
+ pos = pos + ang:Forward() * offset.x + ang:Right() * offset.y + ang:Up() * offset.z
+
+ ang:RotateAroundAxis(ang:Up(), math.sin(CurTime() * math.pi) * 20)
+ ang:RotateAroundAxis(ang:Right(), CurTime() * 180)
+
+ pos = pos + ang:Forward() * 5
+
+ ang:RotateAroundAxis(ang:Right(), 270)
+ ang:RotateAroundAxis(ang:Up(), 180)
+
+ local wid, hei = 144, 144
+ local x, y = wid * -0.5, hei * -0.5
+ local clip = self:GetPrimaryAmmoCount()
+
+ cam.Start3D2D(pos, ang, 0.0075)
+ draw.RoundedBox(32, x, y, wid, hei, colBG)
+ draw.SimpleText(clip, "ZS3D2DFontBig", x + wid * 0.5, y + hei * 0.5, colWhite, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+ cam.End3D2D()
+end
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_stubber.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_stubber.lua
new file mode 100644
index 0000000..9617988
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_stubber.lua
@@ -0,0 +1,87 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Stubber' Rifle"
+ SWEP.Slot = 3
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+
+ SWEP.HUD3DBone = "v_weapon.scout_Parent"
+ SWEP.HUD3DPos = Vector(-1, -2.75, -6)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+ SWEP.HUD3DScale = 0.015
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "ar2"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_snip_scout.mdl"
+SWEP.WorldModel = "models/weapons/w_snip_scout.mdl"
+SWEP.UseHands = true
+
+SWEP.ReloadSound = Sound("Weapon_Scout.ClipOut")
+SWEP.Primary.Sound = Sound("Weapon_Scout.Single")
+SWEP.Primary.Damage = 50
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 1.5
+SWEP.ReloadDelay = SWEP.Primary.Delay
+
+SWEP.Primary.ClipSize = 5
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "357"
+SWEP.Primary.DefaultClip = 25
+
+SWEP.Primary.Gesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_CROSSBOW
+SWEP.ReloadGesture = ACT_HL2MP_GESTURE_RELOAD_SHOTGUN
+
+SWEP.ConeMax = 0.075
+SWEP.ConeMin = 0
+
+SWEP.IronSightsPos = Vector(5.015, -8, 2.52)
+SWEP.IronSightsAng = Vector(0, 0, 0)
+
+SWEP.WalkSpeed = SPEED_SLOW
+
+function SWEP:IsScoped()
+ return self:GetIronsights() and self.fIronTime and self.fIronTime + 0.25 <= CurTime()
+end
+
+function SWEP:EmitFireSound()
+ self:EmitSound(self.Primary.Sound, 85, 100)
+end
+
+if CLIENT then
+ SWEP.IronsightsMultiplier = 0.25
+
+ function SWEP:GetViewModelPosition(pos, ang)
+ if self:IsScoped() then
+ return pos + ang:Up() * 256, ang
+ end
+
+ return self.BaseClass.GetViewModelPosition(self, pos, ang)
+ end
+
+ local matScope = Material("zombiesurvival/scope")
+ function SWEP:DrawHUDBackground()
+ if self:IsScoped() then
+ local scrw, scrh = ScrW(), ScrH()
+ local size = math.min(scrw, scrh)
+ surface.SetMaterial(matScope)
+ surface.SetDrawColor(255, 255, 255, 255)
+ surface.DrawTexturedRect((scrw - size) * 0.5, (scrh - size) * 0.5, size, size)
+ surface.SetDrawColor(0, 0, 0, 255)
+ if scrw > size then
+ local extra = (scrw - size) * 0.5
+ surface.DrawRect(0, 0, extra, scrh)
+ surface.DrawRect(scrw - extra, 0, extra, scrh)
+ end
+ if scrh > size then
+ local extra = (scrh - size) * 0.5
+ surface.DrawRect(0, 0, scrw, extra)
+ surface.DrawRect(0, scrh - extra, scrw, extra)
+ end
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_stunbaton.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_stunbaton.lua
new file mode 100644
index 0000000..ea01110
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_stunbaton.lua
@@ -0,0 +1,46 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Stun Baton"
+
+ SWEP.ViewModelFOV = 50
+
+ SWEP.Description = "Although weak compared to the other weapons, this baton\nhas the ability to slow zombies with an electric shock."
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.ViewModel = "models/weapons/c_stunstick.mdl"
+SWEP.WorldModel = "models/weapons/w_stunbaton.mdl"
+SWEP.UseHands = true
+
+SWEP.HoldType = "melee"
+
+SWEP.MeleeDamage = 27
+SWEP.StunDamage = 20
+SWEP.MeleeRange = 49
+SWEP.MeleeSize = 1.5
+SWEP.Primary.Delay = 0.9
+
+SWEP.SwingTime = 0.25
+SWEP.SwingRotation = Angle(60, 0, 0)
+SWEP.SwingOffset = Vector(0, -50, 0)
+SWEP.SwingHoldType = "grenade"
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("Weapon_StunStick.Swing")
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("Weapon_StunStick.Melee_HitWorld")
+end
+
+function SWEP:PlayHitFleshSound()
+ self:EmitSound("Weapon_StunStick.Melee_Hit")
+end
+
+function SWEP:OnMeleeHit(hitent, hitflesh, tr)
+ if hitent:IsValid() and hitent:IsPlayer() then
+ hitent:AddLegDamage(self.StunDamage)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_superzombie.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_superzombie.lua
new file mode 100644
index 0000000..d07c6e0
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_superzombie.lua
@@ -0,0 +1,158 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.MeleeDamage = 45
+
+function SWEP:Reload()
+ self.BaseClass.SecondaryAttack(self)
+end
+
+function SWEP:StartMoaning()
+end
+
+function SWEP:StopMoaning()
+end
+
+function SWEP:IsMoaning()
+ return false
+end
+
+function SWEP:Move(mv)
+ if self:GetClimbing() then
+ mv:SetMaxSpeed(0)
+ mv:SetMaxClientSpeed(0)
+
+ local owner = self.Owner
+ local tr = self:GetClimbSurface()
+ local angs = self.Owner:SyncAngles()
+ local dir = tr and tr.Hit and (tr.HitNormal.z <= -0.5 and (angs:Forward() * -1) or math.abs(tr.HitNormal.z) < 0.75 and tr.HitNormal:Angle():Up()) or Vector(0, 0, 1)
+ local vel = Vector(0, 0, 4)
+
+ if owner:KeyDown(IN_FORWARD) then
+ vel = vel + dir * 60
+ end
+ if owner:KeyDown(IN_BACK) then
+ vel = vel + dir * -60
+ end
+
+ if vel.z == 4 then
+ if owner:KeyDown(IN_MOVERIGHT) then
+ vel = vel + angs:Right() * 35
+ end
+ if owner:KeyDown(IN_MOVELEFT) then
+ vel = vel + angs:Right() * -35
+ end
+ end
+
+ mv:SetVelocity(vel)
+
+ return true
+ end
+end
+
+SWEP.NextClimbSound = 0
+function SWEP:Think()
+ local curtime = CurTime()
+ local owner = self.Owner
+
+ if self:GetClimbing() then
+ if self:GetClimbSurface() and owner:KeyDown(IN_ATTACK2) then
+ if SERVER and CurTime() >= self.NextClimbSound then
+ local speed = owner:GetVelocity():Length()
+ if speed >= 16 then
+ if speed >= 50 then
+ self.NextClimbSound = CurTime() + 0.75
+ else
+ self.NextClimbSound = CurTime() + 1
+ end
+ owner:EmitSound("player/footsteps/metalgrate"..math.random(4)..".wav")
+ end
+ end
+ else
+ self:StopClimbing()
+ end
+ end
+
+ return self.BaseClass.Think(self)
+end
+
+local climblerp = 0
+function SWEP:GetViewModelPosition(pos, ang)
+ climblerp = math.Approach(climblerp, self:IsClimbing() and 1 or 0, FrameTime() * ((climblerp + 1) ^ 3))
+ ang:RotateAroundAxis(ang:Right(), 64 * climblerp)
+ if climblerp > 0 then
+ pos = pos + -8 * climblerp * ang:Up() + -12 * climblerp * ang:Forward()
+ end
+ return self.BaseClass.GetViewModelPosition(self, pos, ang)
+end
+
+function SWEP:PrimaryAttack()
+ if self:IsClimbing() then return end
+
+ self.BaseClass.PrimaryAttack(self)
+end
+
+local climbtrace = {mask = MASK_SOLID_BRUSHONLY, mins = Vector(-5, -5, -5), maxs = Vector(5, 5, 5)}
+function SWEP:GetClimbSurface()
+ local owner = self.Owner
+
+ local fwd = owner:SyncAngles():Forward()
+ local up = owner:GetUp()
+ local pos = owner:GetPos()
+ local tr
+ for i=-15, owner:OBBMaxs().z, 5 do
+ if not tr or not tr.Hit then
+ climbtrace.start = pos + up * i
+ climbtrace.endpos = climbtrace.start + fwd * 28
+ tr = util.TraceHull(climbtrace)
+ if tr.Hit and not tr.HitSky then break end
+ end
+ end
+
+ if tr.Hit and not tr.HitSky then
+ climbtrace.start = tr.HitPos + tr.HitNormal
+ climbtrace.endpos = climbtrace.start + owner:SyncAngles():Up() * 72
+ local tr2 = util.TraceHull(climbtrace)
+ if tr2.Hit and not tr2.HitSky then
+ return tr2
+ end
+
+ return tr
+ end
+end
+
+function SWEP:SecondaryAttack()
+ if self:IsClimbing() then return end
+
+ if not self.Owner:IsOnGround() and self.Owner:GetVelocity():Length() < 200 and self:GetClimbSurface() then
+ self:StartClimbing()
+ else
+ self.BaseClass.SecondaryAttack(self)
+ end
+end
+
+function SWEP:StartClimbing()
+ if self:GetClimbing() then return end
+
+ self:SetClimbing(true)
+
+ self:SetNextPrimaryFire(math.huge)
+end
+
+function SWEP:StopClimbing()
+ if not self:GetClimbing() then return end
+
+ self:SetClimbing(false)
+
+ self:SetNextPrimaryFire(CurTime() + 0.5)
+end
+
+function SWEP:SetClimbing(climbing)
+ self:SetDTBool(1, climbing)
+end
+
+function SWEP:GetClimbing()
+ return self:GetDTBool(1)
+end
+SWEP.IsClimbing = SWEP.GetClimbing
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_sweepershotgun.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_sweepershotgun.lua
new file mode 100644
index 0000000..6951c27
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_sweepershotgun.lua
@@ -0,0 +1,108 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Sweeper' Shotgun"
+ SWEP.Slot = 3
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+
+ SWEP.HUD3DBone = "v_weapon.M3_PARENT"
+ SWEP.HUD3DPos = Vector(-1, -4, -3)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+ SWEP.HUD3DScale = 0.015
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "shotgun"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_shot_m3super90.mdl"
+SWEP.WorldModel = "models/weapons/w_shot_m3super90.mdl"
+SWEP.UseHands = true
+
+SWEP.ReloadDelay = 0.4
+
+SWEP.Primary.Sound = Sound("Weapon_M3.Single")
+SWEP.Primary.Damage = 28
+SWEP.Primary.NumShots = 6
+SWEP.Primary.Delay = 1
+
+SWEP.Primary.ClipSize = 6
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "buckshot"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.ConeMax = 0.14
+SWEP.ConeMin = 0.105
+
+SWEP.WalkSpeed = SPEED_SLOWER
+
+SWEP.reloadtimer = 0
+SWEP.nextreloadfinish = 0
+
+function SWEP:Reload()
+ if self.reloading then return end
+
+ if self:Clip1() < self.Primary.ClipSize and 0 < self.Owner:GetAmmoCount(self.Primary.Ammo) then
+ self:SetNextPrimaryFire(CurTime() + self.ReloadDelay)
+ self.reloading = true
+ self.reloadtimer = CurTime() + self.ReloadDelay
+ self:SendWeaponAnim(ACT_SHOTGUN_RELOAD_START)
+ self.Owner:RestartGesture(ACT_HL2MP_GESTURE_RELOAD_SHOTGUN)
+ end
+
+ self:SetIronsights(false)
+end
+
+function SWEP:Think()
+ if self.reloading and self.reloadtimer < CurTime() then
+ self.reloadtimer = CurTime() + self.ReloadDelay
+ self:SendWeaponAnim(ACT_VM_RELOAD)
+
+ self.Owner:RemoveAmmo(1, self.Primary.Ammo, false)
+ self:SetClip1(self:Clip1() + 1)
+
+ if self.Primary.ClipSize <= self:Clip1() or self.Owner:GetAmmoCount(self.Primary.Ammo) <= 0 then
+ self.nextreloadfinish = CurTime() + self.ReloadDelay
+ self.reloading = false
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ end
+ end
+
+ local nextreloadfinish = self.nextreloadfinish
+ if nextreloadfinish ~= 0 and nextreloadfinish < CurTime() then
+ self:SendWeaponAnim(ACT_SHOTGUN_RELOAD_FINISH)
+ self.nextreloadfinish = 0
+ end
+
+ if self:GetIronsights() and not self.Owner:KeyDown(IN_ATTACK2) then
+ self:SetIronsights(false)
+ end
+end
+
+function SWEP:CanPrimaryAttack()
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:Clip1() <= 0 then
+ self:EmitSound("Weapon_Shotgun.Empty")
+ self:SetNextPrimaryFire(CurTime() + 0.25)
+ return false
+ end
+
+ if self.reloading then
+ if 0 < self:Clip1() then
+ self:SendWeaponAnim(ACT_SHOTGUN_RELOAD_FINISH)
+ else
+ self:SendWeaponAnim(ACT_VM_IDLE)
+ end
+ self.reloading = false
+ self:SetNextPrimaryFire(CurTime() + 0.25)
+ return false
+ end
+
+ return true
+end
+
+function SWEP:SecondaryAttack()
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_swissarmyknife.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_swissarmyknife.lua
new file mode 100644
index 0000000..2941d19
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_swissarmyknife.lua
@@ -0,0 +1,77 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Knife"
+ SWEP.Description = "Deals double damage to the back."
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 55
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.HoldType = "knife"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_knife_t.mdl"
+SWEP.WorldModel = "models/weapons/w_knife_t.mdl"
+SWEP.UseHands = true
+
+SWEP.MeleeDamage = 19
+SWEP.MeleeRange = 62
+SWEP.MeleeSize = 0.875
+
+SWEP.WalkSpeed = SPEED_FASTEST
+
+SWEP.Primary.Delay = 0.85
+
+SWEP.HitDecal = "Manhackcut"
+
+SWEP.HitGesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE
+SWEP.MissGesture = SWEP.HitGesture
+
+SWEP.HitAnim = ACT_VM_MISSCENTER
+SWEP.MissAnim = ACT_VM_PRIMARYATTACK
+
+SWEP.NoHitSoundFlesh = true
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("weapons/knife/knife_slash"..math.random(2)..".wav")
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("weapons/knife/knife_hitwall1.wav")
+end
+
+function SWEP:PlayHitFleshSound()
+ self:EmitSound("weapons/knife/knife_hit"..math.random(4)..".wav")
+end
+
+function SWEP:OnMeleeHit(hitent, hitflesh, tr)
+ if hitent:IsValid() and hitent:IsPlayer() and not self.m_BackStabbing and math.abs(hitent:GetForward():Angle().yaw - self.Owner:GetForward():Angle().yaw) <= 90 then
+ self.m_BackStabbing = true
+ self.MeleeDamage = self.MeleeDamage * 2
+ end
+end
+
+function SWEP:PostOnMeleeHit(hitent, hitflesh, tr)
+ if self.m_BackStabbing then
+ self.m_BackStabbing = false
+
+ self.MeleeDamage = self.MeleeDamage / 2
+ end
+end
+
+if SERVER then
+ function SWEP:InitializeHoldType()
+ self.ActivityTranslate = {}
+ self.ActivityTranslate[ACT_HL2MP_IDLE] = ACT_HL2MP_IDLE_KNIFE
+ self.ActivityTranslate[ACT_HL2MP_WALK] = ACT_HL2MP_WALK_KNIFE
+ self.ActivityTranslate[ACT_HL2MP_RUN] = ACT_HL2MP_RUN_KNIFE
+ self.ActivityTranslate[ACT_HL2MP_IDLE_CROUCH] = ACT_HL2MP_IDLE_CROUCH_PHYSGUN
+ self.ActivityTranslate[ACT_HL2MP_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH_KNIFE
+ self.ActivityTranslate[ACT_HL2MP_GESTURE_RANGE_ATTACK] = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE
+ self.ActivityTranslate[ACT_HL2MP_GESTURE_RELOAD] = ACT_HL2MP_GESTURE_RELOAD_KNIFE
+ self.ActivityTranslate[ACT_HL2MP_JUMP] = ACT_HL2MP_JUMP_KNIFE
+ self.ActivityTranslate[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_KNIFE
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ticklemonster.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ticklemonster.lua
new file mode 100644
index 0000000..a4d5ad0
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_ticklemonster.lua
@@ -0,0 +1,35 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "The Tickle Monster"
+end
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.MeleeDamage = 22
+SWEP.MeleeReach = 160
+SWEP.MeleeSize = 5
+
+function SWEP:Reload()
+ self:SecondaryAttack()
+end
+
+function SWEP:PlayAlertSound()
+ self.Owner:EmitSound("npc/barnacle/barnacle_tongue_pull"..math.random(3)..".wav")
+end
+SWEP.PlayIdleSound = SWEP.PlayAlertSound
+
+function SWEP:PlayAttackSound()
+ self.Owner:EmitSound("npc/barnacle/barnacle_bark"..math.random(2)..".wav")
+end
+
+if not CLIENT then return end
+
+function SWEP:ViewModelDrawn()
+ render.ModelMaterialOverride(0)
+end
+
+local matSheet = Material("Models/Charple/Charple1_sheet")
+function SWEP:PreDrawViewModel(vm)
+ render.ModelMaterialOverride(matSheet)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_tosser.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_tosser.lua
new file mode 100644
index 0000000..710856f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_tosser.lua
@@ -0,0 +1,46 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Tosser' SMG"
+ SWEP.Slot = 2
+ SWEP.SlotPos = 0
+
+ SWEP.HUD3DBone = "ValveBiped.base"
+ SWEP.HUD3DPos = Vector(1.5, 0.25, -2)
+ SWEP.HUD3DScale = 0.02
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "smg"
+
+SWEP.ViewModel = "models/weapons/c_smg1.mdl"
+SWEP.WorldModel = "models/weapons/w_smg1.mdl"
+SWEP.UseHands = true
+
+SWEP.CSMuzzleFlashes = false
+
+SWEP.ReloadSound = Sound("Weapon_SMG1.Reload")
+SWEP.Primary.Sound = Sound("Weapon_AR2.NPC_Single")
+SWEP.Primary.Damage = 15
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.15
+
+SWEP.Primary.ClipSize = 25
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "smg1"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.Primary.Gesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1
+SWEP.ReloadGesture = ACT_HL2MP_GESTURE_RELOAD_SMG1
+
+SWEP.ConeMax = 0.055
+SWEP.ConeMin = 0.029
+
+SWEP.WalkSpeed = SPEED_NORMAL
+
+--SWEP.IronSightsPos = Vector(-6.42, 4, 2.53)
+SWEP.IronSightsPos = Vector(-6.425, 5, 1.02)
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_uzi.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_uzi.lua
new file mode 100644
index 0000000..2c5f95f
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_uzi.lua
@@ -0,0 +1,44 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Sprayer' Uzi 9mm"
+ SWEP.Slot = 2
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 50
+
+ SWEP.HUD3DBone = "v_weapon.mac10_bolt"
+ SWEP.HUD3DPos = Vector(-1.45, 1.25, 0)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+ SWEP.HUD3DScale = 0.015
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "pistol"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_smg_mac10.mdl"
+SWEP.WorldModel = "models/weapons/w_smg_mac10.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("Weapon_MAC10.Single")
+SWEP.Primary.Damage = 17
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.075
+
+SWEP.Primary.ClipSize = 40
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "smg1"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+SWEP.Primary.Gesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1
+SWEP.ReloadGesture = ACT_HL2MP_GESTURE_RELOAD_SMG1
+
+SWEP.ConeMax = 0.13
+SWEP.ConeMin = 0.06
+
+SWEP.WalkSpeed = SPEED_NORMAL
+
+SWEP.IronSightsPos = Vector(-7, 15, 0)
+SWEP.IronSightsAng = Vector(3, -3, -10)
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_waraxe.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_waraxe.lua
new file mode 100644
index 0000000..2811414
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_waraxe.lua
@@ -0,0 +1,34 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_battleaxe"
+
+if CLIENT then
+ SWEP.PrintName = "'Waraxe' Handgun"
+
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props_c17/concrete_barrier001a.mdl", bone = "v_weapon.USP_Parent", rel = "", pos = Vector(-0.69, -3.5, -1.5), angle = Angle(0, 0, 90), size = Vector(0.019, 0.019, 0.019), color = Color(203, 233, 236, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base+++"] = { type = "Model", model = "models/props_c17/canister02a.mdl", bone = "v_weapon.USP_Parent", rel = "base+", pos = Vector(-1.201, 0, -0.7), angle = Angle(90, 0, 0), size = Vector(0.129, 0.129, 0.059), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base+"] = { type = "Model", model = "models/props_junk/cinderblock01a.mdl", bone = "v_weapon.USP_Parent", rel = "base", pos = Vector(0.5, 3, 0), angle = Angle(0, 90, 90), size = Vector(0.119, 0.119, 0.119), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base++"] = { type = "Model", model = "models/props_c17/canister02a.mdl", bone = "v_weapon.USP_Parent", rel = "base+", pos = Vector(-1.201, 0, 0.699), angle = Angle(90, 0, 0), size = Vector(0.129, 0.129, 0.059), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props_c17/concrete_barrier001a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(6.659, 2.4, -3.651), angle = Angle(0, 85, 0), size = Vector(0.019, 0.019, 0.019), color = Color(203, 233, 236, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base+++"] = { type = "Model", model = "models/props_c17/canister02a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "base+", pos = Vector(-1.201, 0, -0.7), angle = Angle(90, 0, 0), size = Vector(0.129, 0.129, 0.059), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base+"] = { type = "Model", model = "models/props_junk/cinderblock01a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "base", pos = Vector(0.5, 3, 0), angle = Angle(0, 90, 90), size = Vector(0.119, 0.119, 0.119), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} },
+ ["base++"] = { type = "Model", model = "models/props_c17/canister02a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "base+", pos = Vector(-1.201, 0, 0.699), angle = Angle(90, 0, 0), size = Vector(0.129, 0.129, 0.059), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Primary.Damage = 18
+SWEP.Primary.NumShots = 2
+SWEP.Primary.Delay = 0.2
+
+SWEP.Primary.ClipSize = 15
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "pistol"
+GAMEMODE:SetupDefaultClip(SWEP.Primary)
+
+function SWEP:EmitFireSound()
+ self:EmitSound(self.Primary.Sound, 80, 75)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_wraith/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_wraith/cl_init.lua
new file mode 100644
index 0000000..e8ea16e
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_wraith/cl_init.lua
@@ -0,0 +1,28 @@
+include("shared.lua")
+
+SWEP.PrintName = "Wraith"
+SWEP.ViewModelFOV = 47
+
+--[[function SWEP:Holster()
+ if self.Owner:IsValid() and self.Owner == MySelf then
+ self.Owner:SetBarricadeGhosting(false)
+ end
+
+ return self.BaseClass.Holster(self)
+end]]
+
+function SWEP:PreDrawViewModel(vm)
+ self.Owner:CallZombieFunction("PrePlayerDraw")
+end
+
+function SWEP:PostDrawViewModel(vm)
+ self.Owner:CallZombieFunction("PostPlayerDraw")
+end
+
+--[[function SWEP:Think()
+ self.BaseClass.Think(self)
+
+ if self.Owner:IsValid() and MySelf == self.Owner then
+ self:BarricadeGhostingThink()
+ end
+end]]
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_wraith/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_wraith/init.lua
new file mode 100644
index 0000000..623c98e
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_wraith/init.lua
@@ -0,0 +1,20 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+SWEP.MoanDelay = 3
+
+--[[function SWEP:Think()
+ self.BaseClass.Think(self)
+
+ self:BarricadeGhostingThink()
+end
+
+function SWEP:Holster()
+ if self.Owner:IsValid() then
+ self.Owner:SetBarricadeGhosting(false)
+ end
+
+ return self.BaseClass.Holster(self)
+end]]
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_wraith/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_wraith/shared.lua
new file mode 100644
index 0000000..9966547
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_wraith/shared.lua
@@ -0,0 +1,116 @@
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.MeleeDelay = 0.5
+SWEP.MeleeReach = 48
+SWEP.MeleeSize = 1.5
+SWEP.MeleeDamage = 40
+SWEP.MeleeDamageType = DMG_SLASH
+
+SWEP.AlertDelay = 6
+
+SWEP.Primary.Delay = 2
+
+SWEP.ViewModel = Model("models/weapons/v_pza.mdl")
+SWEP.WorldModel = "models/weapons/w_crowbar.mdl"
+
+--[[function SWEP:BarricadeGhostingThink()
+ local pl = self.Owner
+ if not pl:IsValid() then return end
+
+ if pl:KeyDown(IN_SPEED) and pl:OnGround() then
+ if not pl:GetBarricadeGhosting() then
+ pl:SetBarricadeGhosting(true)
+ pl:ResetJumpPower()
+ end
+ elseif not pl:ActiveBarricadeGhosting(true) then
+ pl:SetBarricadeGhosting(false)
+ pl:ResetJumpPower()
+ end
+
+ self:NextThink(CurTime())
+ return true
+end]]
+
+function SWEP:Initialize()
+ self:HideWorldModel()
+end
+
+function SWEP:Precache()
+ util.PrecacheSound("npc/antlion/distract1.wav")
+ util.PrecacheSound("ambient/machines/slicer1.wav")
+ util.PrecacheSound("ambient/machines/slicer2.wav")
+ util.PrecacheSound("ambient/machines/slicer3.wav")
+ util.PrecacheSound("ambient/machines/slicer4.wav")
+ util.PrecacheSound("npc/zombie/claw_miss1.wav")
+ util.PrecacheSound("npc/zombie/claw_miss2.wav")
+end
+
+function SWEP:StopMoaningSound()
+end
+
+function SWEP:StartMoaningSound()
+ self.Owner:EmitSound("zombiesurvival/wraithdeath"..math.random(4)..".ogg")
+end
+
+function SWEP:PlayHitSound()
+ self.Owner:EmitSound("ambient/machines/slicer"..math.random(4)..".wav", 90, 80)
+end
+
+function SWEP:PlayMissSound()
+ self.Owner:EmitSound("npc/zombie/claw_miss"..math.random(1, 2)..".wav", 90, 80)
+end
+
+function SWEP:PlayAttackSound()
+ self.Owner:EmitSound("npc/antlion/distract1.wav")
+end
+
+function SWEP:Swung()
+ self.Owner:SetMoveType(MOVETYPE_WALK)
+
+ self.BaseClass.Swung(self)
+end
+
+function SWEP:StartSwinging()
+ self.Owner:SetMoveType(MOVETYPE_NONE)
+
+ self.BaseClass.StartSwinging(self)
+end
+
+local function viewpunch(ent, power)
+ if ent:IsValid() and ent:Alive() then
+ ent:ViewPunch(Angle(math.Rand(0.75, 1) * (math.random(0, 1) == 0 and 1 or -1), math.Rand(0.75, 1) * (math.random(0, 1) == 0 and 1 or -1), math.Rand(0.75, 1) * (math.random(0, 1) == 0 and 1 or -1)) * power)
+ end
+end
+
+function SWEP:DoAlert()
+ local owner = self.Owner
+
+ owner:EmitSound("npc/stalker/go_alert2a.wav")
+ owner:ViewPunch(Angle(-20, 0, math.Rand(-10, 10)))
+
+ owner:LagCompensation(true)
+
+ local mouthpos = owner:EyePos() + owner:GetUp() * -3
+ local screampos = mouthpos + owner:GetAimVector() * 16
+ for _, ent in pairs(ents.FindInSphere(screampos, 92)) do
+ if ent:IsPlayer() and ent:Team() ~= owner:Team() then
+ local entearpos = ent:EyePos()
+ local dist = screampos:Distance(entearpos)
+ if dist <= 92 and TrueVisible(entearpos, screampos) then
+ local power = (92 / dist - 1) * 2
+ viewpunch(ent, power)
+ for i=1, 5 do
+ timer.Simple(0.15 * i, function() viewpunch(ent, power - i * 0.125) end)
+ end
+ end
+ end
+ end
+
+ owner:LagCompensation(false)
+end
+
+--[[function SWEP:PrimaryAttack()
+ if self.Owner:IsBarricadeGhosting() then return end
+
+ self.BaseClass.PrimaryAttack(self)
+end]]
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_wrench.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_wrench.lua
new file mode 100644
index 0000000..2b9f466
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_wrench.lua
@@ -0,0 +1,81 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Mechanic's Wrench"
+
+ SWEP.ViewModelFOV = 55
+ SWEP.ViewModelFlip = false
+
+ SWEP.ShowViewModel = false
+ SWEP.ShowWorldModel = false
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/props_c17/tools_wrench01a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(2, 2, 0), angle = Angle(190, 0, 90), size = Vector(1.5, 1.5, 1.5), color = Color(255, 255, 255, 255), surpresslightning = false, material = "models/props_c17/metalladder001", skin = 0, bodygroup = {} }
+ }
+ SWEP.WElements = {
+ ["base"] = { type = "Model", model = "models/props_c17/tools_wrench01a.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(2, 1, 0), angle = Angle(190, 90, 90), size = Vector(1.5, 1.5, 1.5), color = Color(255, 255, 255, 255), surpresslightning = false, material = "models/props_c17/metalladder001", skin = 0, bodygroup = {} }
+ }
+
+ SWEP.Description = "This tool can be used to repair deployables as long as they were not damaged recently."
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.ViewModel = "models/weapons/c_crowbar.mdl"
+SWEP.WorldModel = "models/props_c17/tools_wrench01a.mdl"
+SWEP.ModelScale = 1.5
+SWEP.UseHands = true
+
+SWEP.HoldType = "melee"
+
+SWEP.Primary.Delay = 0.8
+SWEP.MeleeDamage = 28
+SWEP.MeleeRange = 50
+SWEP.MeleeSize = 0.875
+
+SWEP.HitGesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE
+SWEP.MissGesture = SWEP.HitGesture
+
+SWEP.SwingTime = 0.19
+SWEP.SwingRotation = Angle(30, -30, -30)
+SWEP.SwingOffset = Vector(0, -30, 0)
+SWEP.SwingHoldType = "grenade"
+
+SWEP.HealStrength = 13
+
+function SWEP:PlayHitSound()
+ self:EmitSound("weapons/melee/crowbar/crowbar_hit-"..math.random(4)..".ogg", 75, math.random(120, 125))
+end
+
+function SWEP:PlayRepairSound(hitent)
+ hitent:EmitSound("npc/dog/dog_servo"..math.random(7, 8)..".wav", 70, math.random(100, 105))
+end
+
+if CLIENT then return end
+
+function SWEP:OnMeleeHit(hitent, hitflesh, tr)
+ if not hitent:IsValid() then return end
+
+ if hitent.HitByWrench and hitent:HitByWrench(self, self.Owner, tr) then
+ return
+ end
+
+ if hitent.GetObjectHealth then
+ local oldhealth = hitent:GetObjectHealth()
+ if oldhealth <= 0 or oldhealth >= hitent:GetMaxObjectHealth() or hitent.m_LastDamaged and CurTime() < hitent.m_LastDamaged + 4 then return end
+
+ local healstrength = (self.Owner.HumanRepairMultiplier or 1) * self.HealStrength * (hitent.WrenchRepairMultiplier or 1)
+
+ hitent:SetObjectHealth(math.min(hitent:GetMaxObjectHealth(), hitent:GetObjectHealth() + healstrength))
+ local healed = hitent:GetObjectHealth() - oldhealth
+ self:PlayRepairSound(hitent)
+ gamemode.Call("PlayerRepairedObject", self.Owner, hitent, healed / 2, self)
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(tr.HitPos)
+ effectdata:SetNormal(tr.HitNormal)
+ effectdata:SetMagnitude(1)
+ util.Effect("nailrepaired", effectdata, true, true)
+
+ return true
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_z9000.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_z9000.lua
new file mode 100644
index 0000000..7241d26
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_z9000.lua
@@ -0,0 +1,67 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Z9000' Pulse Pistol"
+ SWEP.Description = "Although the Z9000 does not deal that much damage, the pulse shots it fires will slow targets."
+ SWEP.Slot = 1
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 60
+
+ SWEP.HUD3DBone = "ValveBiped.square"
+ SWEP.HUD3DPos = Vector(1.1, 0.25, -2)
+ SWEP.HUD3DScale = 0.015
+
+ SWEP.ShowViewModel = false
+
+ SWEP.VElements = {
+ ["base"] = { type = "Model", model = "models/weapons/w_alyx_gun.mdl", bone = "ValveBiped.Bip01_R_Hand", rel = "", pos = Vector(7, 2, -4.092), angle = Angle(170, 10, 10), size = Vector(1.1, 1.1, 1.1), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
+ }
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "pistol"
+
+SWEP.ViewModel = "models/weapons/c_pistol.mdl"
+SWEP.WorldModel = "models/weapons/w_alyx_gun.mdl"
+SWEP.UseHands = true
+
+SWEP.CSMuzzleFlashes = false
+
+SWEP.ReloadSound = Sound("Weapon_Alyx_Gun.Reload")
+SWEP.Primary.Sound = Sound("Weapon_Alyx_Gun.Single")
+SWEP.Primary.Damage = 14
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.2
+
+SWEP.Primary.ClipSize = 10
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "pulse"
+SWEP.Primary.DefaultClip = 50
+
+SWEP.ConeMax = 0.04
+SWEP.ConeMin = 0.03
+
+SWEP.IronSightsPos = Vector(-5.95, 3, 2.75)
+SWEP.IronSightsAng = Vector(-0.15, -1, 2)
+
+SWEP.TracerName = "AR2Tracer"
+
+function SWEP.BulletCallback(attacker, tr, dmginfo)
+ local ent = tr.Entity
+ if ent:IsValid() and ent:IsPlayer() and ent:Team() == TEAM_UNDEAD then
+ ent:AddLegDamage(8)
+ end
+
+ local e = EffectData()
+ e:SetOrigin(tr.HitPos)
+ e:SetNormal(tr.HitNormal)
+ e:SetRadius(8)
+ e:SetMagnitude(1)
+ e:SetScale(1)
+ util.Effect("cball_bounce", e)
+
+ GenericBulletCallback(attacker, tr, dmginfo)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zeakbar.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zeakbar.lua
new file mode 100644
index 0000000..ea4a2bb
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zeakbar.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_akbar"
+
+SWEP.Primary.Damage = 85
+
+SWEP.ConeMax = 0.05
+SWEP.ConeMin = 0.02
+
+SWEP.WalkSpeed = SPEED_ZOMBIEESCAPE_SLOW
+
+SWEP.Primary.KnockbackScale = ZE_KNOCKBACKSCALE
+SWEP.Primary.DefaultClip = 99999
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zebulletstorm.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zebulletstorm.lua
new file mode 100644
index 0000000..edc1c53
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zebulletstorm.lua
@@ -0,0 +1,62 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_bulletstorm"
+
+SWEP.Primary.Damage = 60
+
+SWEP.WalkSpeed = SPEED_ZOMBIEESCAPE_SLOW
+
+SWEP.Primary.KnockbackScale = ZE_KNOCKBACKSCALE
+SWEP.Primary.DefaultClip = 99999
+
+function SWEP:SetIronsights(b)
+ if self:GetIronsights() ~= b then
+ if b then
+ self.Primary.NumShots = self.Primary.IronsightsNumShots
+ self.Primary.Delay = self.Primary.IronsightsDelay
+
+ self:EmitSound("npc/scanner/scanner_scan4.wav", 40)
+ else
+ self.Primary.NumShots = self.Primary.DefaultNumShots
+ self.Primary.Delay = self.Primary.DefaultDelay
+
+ self:EmitSound("npc/scanner/scanner_scan2.wav", 40)
+ end
+ end
+
+ self:SetDTBool(0, b)
+
+ if self.IronSightsHoldType then
+ if b then
+ self:SetWeaponHoldType(self.IronSightsHoldType)
+ else
+ self:SetWeaponHoldType(self.HoldType)
+ end
+ end
+
+ gamemode.Call("WeaponDeployed", self.Owner, self)
+end
+
+function SWEP:CanPrimaryAttack()
+ if self:GetIronsights() and self:Clip1() == 1 then
+ self:SetIronsights(false)
+ end
+
+ if self.Owner:IsHolding() or self.Owner:GetBarricadeGhosting() then return false end
+
+ if self:Clip1() <= 0 then
+ self:EmitSound("Weapon_Pistol.Empty")
+ self:SetNextPrimaryFire(CurTime() + math.max(0.25, self.Primary.Delay))
+ return false
+ end
+
+ return self:GetNextPrimaryFire() <= CurTime()
+end
+
+function SWEP:TakeAmmo()
+ if self:GetIronsights() then
+ self:TakePrimaryAmmo(2)
+ else
+ self:TakePrimaryAmmo(1)
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zedeagle.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zedeagle.lua
new file mode 100644
index 0000000..481fc22
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zedeagle.lua
@@ -0,0 +1,42 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "'Zombie Drill' Desert Eagle"
+ SWEP.Slot = 1
+ SWEP.SlotPos = 0
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 55
+
+ SWEP.HUD3DBone = "v_weapon.Deagle_Slide"
+ SWEP.HUD3DPos = Vector(-1, 0, 1)
+ SWEP.HUD3DAng = Angle(0, 0, 0)
+ SWEP.HUD3DScale = 0.015
+
+ SWEP.IronSightsPos = Vector(-6.35, 5, 1.7)
+end
+
+SWEP.Base = "weapon_zs_base"
+
+SWEP.HoldType = "revolver"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_pist_deagle.mdl"
+SWEP.WorldModel = "models/weapons/w_pist_deagle.mdl"
+SWEP.UseHands = true
+
+SWEP.Primary.Sound = Sound("Weapon_Deagle.Single")
+SWEP.Primary.Damage = 250
+SWEP.Primary.NumShots = 1
+SWEP.Primary.Delay = 0.28
+
+SWEP.Primary.ClipSize = 7
+SWEP.Primary.Automatic = false
+SWEP.Primary.Ammo = "pistol"
+
+SWEP.ConeMax = 0.06
+SWEP.ConeMin = 0.03
+
+
+SWEP.WalkSpeed = SPEED_ZOMBIEESCAPE_NORMAL
+SWEP.Primary.KnockbackScale = ZE_KNOCKBACKSCALE
+SWEP.Primary.DefaultClip = 99999
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zegrenade.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zegrenade.lua
new file mode 100644
index 0000000..cb4af1b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zegrenade.lua
@@ -0,0 +1,8 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_grenade"
+
+SWEP.WalkSpeed = SPEED_ZOMBIEESCAPE_NORMAL
+
+SWEP.GrenadeDamage = 1280
+SWEP.GrenadeRadius = 256
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zeknife.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zeknife.lua
new file mode 100644
index 0000000..4c4a42c
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zeknife.lua
@@ -0,0 +1,61 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Knife"
+
+ SWEP.ViewModelFlip = false
+ SWEP.ViewModelFOV = 55
+end
+
+SWEP.Base = "weapon_zs_basemelee"
+
+SWEP.HoldType = "knife"
+
+SWEP.ViewModel = "models/weapons/cstrike/c_knife_t.mdl"
+SWEP.WorldModel = "models/weapons/w_knife_t.mdl"
+SWEP.UseHands = true
+
+SWEP.MeleeDamage = 50
+SWEP.MeleeRange = 62
+SWEP.MeleeSize = 0.875
+
+SWEP.WalkSpeed = SPEED_ZOMBIEESCAPE_NORMAL
+
+SWEP.Primary.Delay = 0.45
+
+SWEP.HitDecal = "Manhackcut"
+
+SWEP.HitGesture = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE
+SWEP.MissGesture = SWEP.HitGesture
+
+SWEP.HitAnim = ACT_VM_MISSCENTER
+SWEP.MissAnim = ACT_VM_PRIMARYATTACK
+
+SWEP.NoHitSoundFlesh = true
+
+function SWEP:PlaySwingSound()
+ self:EmitSound("weapons/knife/knife_slash"..math.random(2)..".wav")
+end
+
+function SWEP:PlayHitSound()
+ self:EmitSound("weapons/knife/knife_hitwall1.wav")
+end
+
+function SWEP:PlayHitFleshSound()
+ self:EmitSound("weapons/knife/knife_hit"..math.random(4)..".wav")
+end
+
+if SERVER then
+ function SWEP:InitializeHoldType()
+ self.ActivityTranslate = {}
+ self.ActivityTranslate[ACT_HL2MP_IDLE] = ACT_HL2MP_IDLE_KNIFE
+ self.ActivityTranslate[ACT_HL2MP_WALK] = ACT_HL2MP_WALK_KNIFE
+ self.ActivityTranslate[ACT_HL2MP_RUN] = ACT_HL2MP_RUN_KNIFE
+ self.ActivityTranslate[ACT_HL2MP_IDLE_CROUCH] = ACT_HL2MP_IDLE_CROUCH_PHYSGUN
+ self.ActivityTranslate[ACT_HL2MP_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH_KNIFE
+ self.ActivityTranslate[ACT_HL2MP_GESTURE_RANGE_ATTACK] = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE
+ self.ActivityTranslate[ACT_HL2MP_GESTURE_RELOAD] = ACT_HL2MP_GESTURE_RELOAD_KNIFE
+ self.ActivityTranslate[ACT_HL2MP_JUMP] = ACT_HL2MP_JUMP_KNIFE
+ self.ActivityTranslate[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_KNIFE
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zesmg.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zesmg.lua
new file mode 100644
index 0000000..1513ae6
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zesmg.lua
@@ -0,0 +1,13 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_smg"
+
+SWEP.Primary.Damage = 75
+
+SWEP.ConeMax = 0.06
+SWEP.ConeMin = 0.04
+
+SWEP.WalkSpeed = SPEED_ZOMBIEESCAPE_SLOW
+
+SWEP.Primary.KnockbackScale = ZE_KNOCKBACKSCALE
+SWEP.Primary.DefaultClip = 99999
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zestubber.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zestubber.lua
new file mode 100644
index 0000000..bf907e5
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zestubber.lua
@@ -0,0 +1,63 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_stubber"
+
+SWEP.Primary.Damage = 750
+SWEP.Primary.ClipSize = 5
+
+SWEP.WalkSpeed = SPEED_ZOMBIEESCAPE_SLOW
+
+SWEP.Primary.KnockbackScale = ZE_KNOCKBACKSCALE
+SWEP.Primary.DefaultClip = 99999
+
+if CLIENT then
+ local ghostlerp = 0
+ function SWEP:GetViewModelPosition(pos, ang)
+ if self:IsScoped() then
+ return pos + ang:Up() * 256
+ end
+
+ local bIron = self:GetIronsights()
+
+ if bIron ~= self.bLastIron then
+ self.bLastIron = bIron
+ self.fIronTime = CurTime()
+
+ if bIron then
+ self.SwayScale = 0.3
+ self.BobScale = 0.1
+ else
+ self.SwayScale = 2.0
+ self.BobScale = 1.5
+ end
+ end
+
+ local Mul = math.Clamp((CurTime() - (self.fIronTime or 0)) * 4, 0, 1)
+ if not bIron then Mul = 1 - Mul end
+
+ if Mul > 0 then
+ local Offset = self.IronSightsPos
+ if self.IronSightsAng then
+ ang = Angle(ang.p, ang.y, ang.r)
+ ang:RotateAroundAxis(ang:Right(), self.IronSightsAng.x * Mul)
+ ang:RotateAroundAxis(ang:Up(), self.IronSightsAng.y * Mul)
+ ang:RotateAroundAxis(ang:Forward(), self.IronSightsAng.z * Mul)
+ end
+
+ pos = pos + Offset.x * Mul * ang:Right() + Offset.y * Mul * ang:Forward() + Offset.z * Mul * ang:Up()
+ end
+
+ if self.Owner:GetBarricadeGhosting() then
+ ghostlerp = math.min(1, ghostlerp + FrameTime() * 4)
+ elseif ghostlerp > 0 then
+ ghostlerp = math.max(0, ghostlerp - FrameTime() * 5)
+ end
+
+ if ghostlerp > 0 then
+ pos = pos + 3.5 * ghostlerp * ang:Up()
+ ang:RotateAroundAxis(ang:Right(), -30 * ghostlerp)
+ end
+
+ return pos, ang
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zesweeper.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zesweeper.lua
new file mode 100644
index 0000000..8ebed8b
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zesweeper.lua
@@ -0,0 +1,10 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_sweepershotgun"
+
+SWEP.Primary.Damage = 70
+
+SWEP.Primary.DefaultClip = 99999
+SWEP.Primary.KnockbackScale = ZE_KNOCKBACKSCALE
+
+SWEP.WalkSpeed = SPEED_ZOMBIEESCAPE_SLOWER
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zombie/cl_init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zombie/cl_init.lua
new file mode 100644
index 0000000..367f607
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zombie/cl_init.lua
@@ -0,0 +1,21 @@
+include("shared.lua")
+
+SWEP.PrintName = "Zombie"
+SWEP.ViewModelFOV = 70
+SWEP.DrawCrosshair = false
+
+function SWEP:Reload()
+end
+
+function SWEP:DrawWorldModel()
+end
+SWEP.DrawWorldModelTranslucent = SWEP.DrawWorldModel
+
+function SWEP:DrawHUD()
+ if GetConVarNumber("crosshair") ~= 1 then return end
+ self:DrawCrosshairDot()
+end
+
+function SWEP:DrawWeaponSelection(...)
+ return self:BaseDrawWeaponSelection(...)
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zombie/init.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zombie/init.lua
new file mode 100644
index 0000000..7678ceb
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zombie/init.lua
@@ -0,0 +1,17 @@
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+include("shared.lua")
+
+SWEP.MoanDelay = 1
+
+function SWEP:Reload()
+ if CurTime() < self:GetNextSecondaryFire() then return end
+ self:SetNextSecondaryFire(CurTime() + self.MoanDelay)
+
+ if self:IsMoaning() then
+ self:StopMoaning()
+ else
+ self:StartMoaning()
+ end
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zombie/shared.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zombie/shared.lua
new file mode 100644
index 0000000..b7109c5
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zombie/shared.lua
@@ -0,0 +1,355 @@
+SWEP.ZombieOnly = true
+SWEP.IsMelee = true
+
+SWEP.ViewModel = Model("models/Weapons/v_zombiearms.mdl")
+SWEP.WorldModel = "models/weapons/w_crowbar.mdl"
+
+SWEP.MeleeDelay = 0.74
+SWEP.MeleeReach = 48
+SWEP.MeleeSize = 1.5
+SWEP.MeleeDamage = 30
+SWEP.MeleeForceScale = 1
+SWEP.MeleeDamageType = DMG_SLASH
+
+SWEP.AlertDelay = 2.5
+
+SWEP.Primary.ClipSize = -1
+SWEP.Primary.DefaultClip = -1
+SWEP.Primary.Automatic = true
+SWEP.Primary.Ammo = "none"
+SWEP.Primary.Delay = 1.2
+
+SWEP.Secondary.ClipSize = -1
+SWEP.Secondary.DefaultClip = -1
+SWEP.Secondary.Automatic = true
+SWEP.Secondary.Ammo = "none"
+
+function SWEP:StopMoaningSound()
+ local owner = self.Owner
+ owner:StopSound("NPC_BaseZombie.Moan1")
+ owner:StopSound("NPC_BaseZombie.Moan2")
+ owner:StopSound("NPC_BaseZombie.Moan3")
+ owner:StopSound("NPC_BaseZombie.Moan4")
+end
+
+function SWEP:StartMoaningSound()
+ self.Owner:EmitSound("NPC_BaseZombie.Moan"..math.random(4))
+end
+
+function SWEP:PlayHitSound()
+ self.Owner:EmitSound("npc/zombie/claw_strike"..math.random(3)..".wav")
+end
+
+function SWEP:PlayMissSound()
+ self.Owner:EmitSound("npc/zombie/claw_miss"..math.random(2)..".wav")
+end
+
+function SWEP:PlayAttackSound()
+ self.Owner:EmitSound("npc/zombie/zo_attack"..math.random(2)..".wav")
+end
+
+function SWEP:Initialize()
+ self:HideWorldModel()
+end
+
+function SWEP:CheckIdleAnimation()
+ if self.IdleAnimation and self.IdleAnimation <= CurTime() then
+ self.IdleAnimation = nil
+ self:SendWeaponAnim(ACT_VM_IDLE)
+ end
+end
+
+function SWEP:CheckAttackAnimation()
+ if self.NextAttackAnim and self.NextAttackAnim <= CurTime() then
+ self.NextAttackAnim = nil
+ self:SendAttackAnim()
+ end
+end
+
+function SWEP:CheckMoaning()
+ if self:IsMoaning() and self.Owner:Health() < self:GetMoanHealth() then
+ self:SetNextSecondaryFire(CurTime() + 1)
+ self:StopMoaning()
+ end
+end
+
+function SWEP:CheckMeleeAttack()
+ local swingend = self:GetSwingEndTime()
+ if swingend == 0 or CurTime() < swingend then return end
+ self:StopSwinging(0)
+
+ if SERVER then
+ self:Swung()
+ end
+end
+
+function SWEP:GetTracesNumPlayers(traces)
+ local numplayers = 0
+
+ for _, trace in pairs(traces) do
+ local ent = trace.Entity
+ if ent and ent:IsValid() and ent:IsPlayer() then
+ numplayers = numplayers + 1
+ end
+ end
+
+ return numplayers
+end
+
+function SWEP:GetDamage(numplayers, basedamage)
+ basedamage = basedamage or self.MeleeDamage
+
+ if numplayers then
+ return basedamage * math.Clamp(1.2 - numplayers * 0.2, 0.5, 1)
+ end
+
+ return basedamage
+end
+
+function SWEP:Swung()
+ local owner = self.Owner
+
+ owner:LagCompensation(true)
+
+ local hit = false
+ local traces = owner:PenetratingMeleeTrace(self.MeleeReach, self.MeleeSize, self.PreHit)
+ self.PreHit = nil
+
+ local damage = self:GetDamage(self:GetTracesNumPlayers(traces))
+
+ for _, trace in ipairs(traces) do
+ if not trace.Hit then continue end
+
+ hit = true
+
+ if trace.HitWorld then
+ self:MeleeHitWorld(trace)
+ else
+ local ent = trace.Entity
+ if ent and ent:IsValid() then
+ self:MeleeHit(ent, trace, damage)
+ end
+ end
+ end
+
+ if SERVER then
+ if hit then
+ self:PlayHitSound()
+ else
+ self:PlayMissSound()
+ end
+ end
+
+ owner:LagCompensation(false)
+
+ if self.FrozenWhileSwinging then
+ owner:ResetSpeed()
+ end
+end
+
+function SWEP:Think()
+ self:CheckIdleAnimation()
+ self:CheckAttackAnimation()
+ self:CheckMoaning()
+ self:CheckMeleeAttack()
+end
+
+function SWEP:MeleeHitWorld(trace)
+end
+
+function SWEP:MeleeHit(ent, trace, damage, forcescale)
+ if ent:IsPlayer() then
+ self:MeleeHitPlayer(ent, trace, damage, forcescale)
+ else
+ self:MeleeHitEntity(ent, trace, damage, forcescale)
+ end
+
+ self:ApplyMeleeDamage(ent, trace, damage)
+end
+
+function SWEP:MeleeHitEntity(ent, trace, damage, forcescale)
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() and phys:IsMoveable() then
+ if trace.IsPreHit then
+ phys:ApplyForceOffset(damage * 750 * (forcescale or self.MeleeForceScale) * self.Owner:GetAimVector(), (ent:NearestPoint(self.Owner:EyePos()) + ent:GetPos() * 5) / 6)
+ else
+ phys:ApplyForceOffset(damage * 750 * (forcescale or self.MeleeForceScale) * trace.Normal, (ent:NearestPoint(trace.StartPos) + ent:GetPos() * 2) / 3)
+ end
+
+ ent:SetPhysicsAttacker(self.Owner)
+ end
+end
+
+function SWEP:MeleeHitPlayer(ent, trace, damage, forcescale)
+ ent:ThrowFromPositionSetZ(self.Owner:GetPos(), damage * 2.5 * (forcescale or self.MeleeForceScale))
+ ent:MeleeViewPunch(damage)
+ local nearest = ent:NearestPoint(trace.StartPos)
+ util.Blood(nearest, math.Rand(damage * 0.5, damage * 0.75), (nearest - trace.StartPos):GetNormalized(), math.Rand(damage * 5, damage * 10), true)
+end
+
+function SWEP:ApplyMeleeDamage(ent, trace, damage)
+ if ent:IsPlayer() then
+ ent:TakeSpecialDamage(damage, self.MeleeDamageType, self.Owner, self, trace.HitPos)
+ else
+ local dmgtype, owner, hitpos = self.MeleeDamageType, self.Owner, trace.HitPos
+ timer.Simple(0, function() -- Avoid prediction errors.
+ if ent:IsValid() then
+ ent:TakeSpecialDamage(damage, dmgtype, owner, self, hitpos)
+ end
+ end)
+ end
+end
+
+function SWEP:PrimaryAttack()
+ if CurTime() < self:GetNextPrimaryFire() or IsValid(self.Owner.FeignDeath) then return end
+
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ self:SetNextSecondaryFire(self:GetNextPrimaryFire() + 0.5)
+
+ self:StartSwinging()
+end
+
+function SWEP:SecondaryAttack()
+ if CLIENT then return end
+
+ if CurTime() < self:GetNextSecondaryFire() then return end
+ self:SetNextSecondaryFire(CurTime() + self.AlertDelay)
+
+ self:DoAlert()
+end
+
+function SWEP:DoAlert()
+ self.Owner:LagCompensation(true)
+
+ local ent = self.Owner:MeleeTrace(4096, 24, self.Owner:GetMeleeFilter()).Entity
+ if ent:IsValid() and ent:IsPlayer() then
+ self:PlayAlertSound()
+ else
+ self:PlayIdleSound()
+ end
+
+ self.Owner:LagCompensation(false)
+end
+
+function SWEP:PlayAlertSound()
+ self.Owner:EmitSound("npc/zombie/zombie_alert"..math.random(1, 3)..".wav")
+end
+
+function SWEP:PlayIdleSound()
+ self.Owner:EmitSound("npc/zombie/zombie_voice_idle"..math.random(1, 14)..".wav")
+end
+
+function SWEP:SendAttackAnim()
+ if self.SwapAnims then
+ self:SendWeaponAnim(ACT_VM_HITCENTER)
+ else
+ self:SendWeaponAnim(ACT_VM_SECONDARYATTACK)
+ end
+ self.SwapAnims = not self.SwapAnims
+end
+
+function SWEP:StartSwinging()
+ if self.MeleeAnimationDelay then
+ self.NextAttackAnim = CurTime() + self.MeleeAnimationDelay
+ else
+ self:SendAttackAnim()
+ end
+
+ local owner = self.Owner
+ owner:DoAttackEvent()
+
+ if SERVER then
+ self:PlayAttackSound()
+ end
+ self:StopMoaning()
+
+ if self.FrozenWhileSwinging then
+ owner:SetSpeed(1)
+ end
+
+ if self.MeleeDelay > 0 then
+ self:SetSwingEndTime(CurTime() + self.MeleeDelay)
+
+ local trace = self.Owner:MeleeTrace(self.MeleeReach, self.MeleeSize, player.GetAll())
+ if trace.HitNonWorld then
+ trace.IsPreHit = true
+ self.PreHit = trace
+ end
+
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+ else
+ self:Swung()
+ end
+end
+
+function SWEP:StopSwinging()
+ self:SetSwingEndTime(0)
+end
+
+function SWEP:KnockedDown(status, exists)
+ self:StopSwinging()
+end
+
+function SWEP:StopMoaning()
+ if not self:IsMoaning() then return end
+ self:SetMoaning(false)
+
+ self:StopMoaningSound()
+end
+
+function SWEP:StartMoaning()
+ if self:IsMoaning() or IsValid(self.Owner.Revive) or IsValid(self.Owner.FeignDeath) then return end
+ self:SetMoaning(true)
+
+ self:SetMoanHealth(self.Owner:Health())
+
+ self:StartMoaningSound()
+end
+
+function SWEP:Deploy()
+ self.IdleAnimation = CurTime() + self:SequenceDuration()
+
+ if self.DelayWhenDeployed and self.Primary.Delay > 0 then
+ self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
+ self:SetNextSecondaryFire(self:GetNextPrimaryFire() + 0.5)
+ end
+
+ return true
+end
+
+function SWEP:OnRemove()
+ if IsValid(self.Owner) then
+ self:StopMoaning()
+ end
+end
+SWEP.Holster = SWEP.OnRemove
+
+function SWEP:SetMoaning(moaning)
+ self:SetDTBool(0, moaning)
+end
+
+function SWEP:GetMoaning()
+ return self:GetDTBool(0)
+end
+SWEP.IsMoaning = SWEP.GetMoaning
+
+function SWEP:SetMoanHealth(health)
+ self:SetDTInt(0, health)
+end
+
+function SWEP:GetMoanHealth()
+ return self:GetDTInt(0)
+end
+
+function SWEP:SetSwingEndTime(time)
+ self:SetDTFloat(0, time)
+end
+
+function SWEP:GetSwingEndTime()
+ return self:GetDTFloat(0)
+end
+
+function SWEP:IsSwinging()
+ return self:GetSwingEndTime() > 0
+end
+SWEP.IsAttacking = SWEP.IsSwinging
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zombielegs.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zombielegs.lua
new file mode 100644
index 0000000..99158a8
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zombielegs.lua
@@ -0,0 +1,61 @@
+AddCSLuaFile()
+
+if CLIENT then
+ SWEP.PrintName = "Zombie Kung Fu"
+end
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.MeleeDelay = 0.32
+SWEP.MeleeReach = 40
+SWEP.MeleeDamage = 17
+
+SWEP.DelayWhenDeployed = true
+
+function SWEP:Move(mv)
+ if self:IsSwinging() then
+ mv:SetMaxSpeed(0)
+ mv:SetMaxClientSpeed(0)
+ end
+end
+
+function SWEP:PrimaryAttack(fromsecondary)
+ local n = self:GetNextPrimaryAttack()
+
+ if self.Owner:IsOnGround() or self.Owner:WaterLevel() >= 2 or self.Owner:GetMoveType() ~= MOVETYPE_WALK then
+ self.BaseClass.PrimaryAttack(self)
+ end
+
+ if not fromsecondary and n ~= self:GetNextPrimaryAttack() then
+ self:SetDTBool(3, false)
+ end
+end
+
+function SWEP:SecondaryAttack()
+ local n = self:GetNextPrimaryAttack()
+ self:PrimaryAttack(true)
+ if n ~= self:GetNextPrimaryAttack() then
+ self:SetDTBool(3, true)
+ end
+end
+
+function SWEP:PlayHitSound()
+ self.Owner:EmitSound("npc/zombie/zombie_pound_door.wav")
+end
+
+function SWEP:PlayAttackSound()
+ self.Owner:EmitSound("npc/zombie/foot_slide"..math.random(3)..".wav")
+end
+
+function SWEP:Reload()
+end
+
+function SWEP:StartMoaning()
+end
+
+function SWEP:StopMoaning()
+end
+
+function SWEP:IsMoaning()
+ return false
+end
diff --git a/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zombietorso.lua b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zombietorso.lua
new file mode 100644
index 0000000..474f2de
--- /dev/null
+++ b/gamemodes/zombiesurvival/entities/weapons/weapon_zs_zombietorso.lua
@@ -0,0 +1,23 @@
+AddCSLuaFile()
+
+SWEP.Base = "weapon_zs_zombie"
+
+SWEP.MeleeDelay = 0.25
+SWEP.MeleeReach = 40
+SWEP.MeleeDamage = 25
+
+SWEP.DelayWhenDeployed = true
+
+function SWEP:Reload()
+ self:SecondaryAttack()
+end
+
+function SWEP:StartMoaning()
+end
+
+function SWEP:StopMoaning()
+end
+
+function SWEP:IsMoaning()
+ return false
+end
diff --git a/gamemodes/zombiesurvival/gamemode/buffthefps.lua b/gamemodes/zombiesurvival/gamemode/buffthefps.lua
new file mode 100644
index 0000000..2197cc5
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/buffthefps.lua
@@ -0,0 +1,262 @@
+-- This rewrites a few drawing methods to be slightly faster.
+-- This file is to be included before everything else.
+
+-- WARNING: Removes the functionality of any drawing functions returning values (except GetFontHeight).
+-- This doesn't really matter in most cases because A: nobody uses it and B: they were returning wrong values most of the time anyway.
+
+AddCSLuaFile("buffthefps.lua")
+
+if SERVER or BuffedFPS then return end
+BuffedFPS = true
+
+local surface = surface
+local Color = Color
+local color_white = color_white
+
+local TEXT_ALIGN_LEFT = 0
+local TEXT_ALIGN_CENTER = 1
+local TEXT_ALIGN_RIGHT = 2
+local TEXT_ALIGN_TOP = 3
+local TEXT_ALIGN_BOTTOM = 4
+--[[TEXT_ALIGN_LEFT = 0
+TEXT_ALIGN_CENTER = 1
+TEXT_ALIGN_RIGHT = 2
+TEXT_ALIGN_TOP = 3
+TEXT_ALIGN_BOTTOM = 4]]
+
+local surface_SetFont = surface.SetFont
+local surface_GetTextSize = surface.GetTextSize
+local surface_SetTextPos = surface.SetTextPos
+local surface_SetTextColor = surface.SetTextColor
+local surface_DrawText = surface.DrawText
+local surface_SetTexture = surface.SetTexture
+local surface_SetDrawColor = surface.SetDrawColor
+local surface_DrawRect = surface.DrawRect
+local surface_DrawTexturedRect = surface.DrawTexturedRect
+local surface_DrawTexturedRectRotated = surface.DrawTexturedRectRotated
+local surface_GetTextureID = surface.GetTextureID
+
+local string_sub = string.sub
+
+local math_ceil = math.ceil
+
+local Tex_Corner8 = surface_GetTextureID( "gui/corner8" )
+local Tex_Corner16 = surface_GetTextureID( "gui/corner16" )
+local Tex_white = surface_GetTextureID( "vgui/white" )
+
+
+-- Just an FYI that this is around 450 times faster than using surface.GetTextSize when cached.
+local CachedFontHeights = {}
+local function draw_GetFontHeight(font)
+ if CachedFontHeights[font] then
+ return CachedFontHeights[font]
+ end
+
+ surface_SetFont(font)
+ local w, h = surface_GetTextSize("W")
+ CachedFontHeights[font] = h
+
+ return h
+end
+
+local function draw_SimpleText(text, font, x, y, colour, xalign, yalign)
+ surface_SetFont(font)
+
+ if xalign == TEXT_ALIGN_CENTER then
+ local w, h = surface_GetTextSize( text )
+ x = x - w / 2
+ elseif xalign == TEXT_ALIGN_RIGHT then
+ local w, h = surface_GetTextSize( text )
+ x = x - w
+ end
+
+ if yalign == TEXT_ALIGN_CENTER then
+ local h = draw_GetFontHeight(font)
+ y = y - h / 2
+ elseif yalign == TEXT_ALIGN_BOTTOM then
+ local h = draw_GetFontHeight(font)
+ y = y - h
+ end
+
+ surface_SetTextPos(x, y)
+ if colour then
+ surface_SetTextColor(colour.r, colour.g, colour.b, colour.a)
+ else
+ surface_SetTextColor(255, 255, 255, 255)
+ end
+ surface_DrawText(text)
+end
+
+local function draw_DrawText(text, font, x, y, colour, xalign )
+ local curX = x
+ local curY = y
+ local curString = ""
+
+ surface_SetFont(font)
+ local lineHeight = draw_GetFontHeight(font)
+
+ for i=1, #text do
+ local ch = string_sub(text, i, i)
+ if ch == "\n" then
+ if #curString > 0 then
+ draw_SimpleText(curString, font, curX, curY, colour, xalign)
+ end
+
+ curY = curY + lineHeight / 2
+ curX = x
+ curString = ""
+ elseif ch == "\t" then
+ if #curString > 0 then
+ draw_SimpleText(curString, font, curX, curY, colour, xalign)
+ end
+ local tmpSizeX,tmpSizeY = surface_GetTextSize(curString)
+ curX = math_ceil( (curX + tmpSizeX) / 50 ) * 50
+ curString = ""
+ else
+ curString = curString .. ch
+ end
+ end
+ if #curString > 0 then
+ draw_SimpleText(curString, font, curX, curY, colour, xalign)
+ end
+end
+
+local function draw_RoundedBox(bordersize, x, y, w, h, color)
+ surface_SetDrawColor(color)
+
+ surface_DrawRect(x + bordersize, y, w - bordersize * 2, h)
+ surface_DrawRect(x, y + bordersize, bordersize, h - bordersize * 2)
+ surface_DrawRect(x + w - bordersize, y + bordersize, bordersize, h - bordersize * 2)
+
+ surface_SetTexture(bordersize > 8 and Tex_Corner16 or Tex_Corner8)
+ surface_DrawTexturedRectRotated( x + bordersize/2 , y + bordersize/2, bordersize, bordersize, 0 )
+ surface_DrawTexturedRectRotated( x + w - bordersize/2 , y + bordersize/2, bordersize, bordersize, 270 )
+ surface_DrawTexturedRectRotated( x + bordersize/2 , y + h -bordersize/2, bordersize, bordersize, 90 )
+ surface_DrawTexturedRectRotated( x + w - bordersize/2 , y + h - bordersize/2, bordersize, bordersize, 180 )
+end
+
+local function draw_Text(tab)
+ local text = tab.text
+ local font = tab.font or "DermaDefault"
+ local x = tab.pos[1] or 0
+ local y = tab.pos[2] or 0
+ local xalign = tab.xalign
+ local yalign = tab.yalign
+
+ surface_SetFont(font)
+
+ if xalign == TEXT_ALIGN_CENTER then
+ local w, h = surface_GetTextSize( text )
+ x = x - w / 2
+ elseif xalign == TEXT_ALIGN_RIGHT then
+ local w, h = surface_GetTextSize( text )
+ x = x - w
+ end
+
+ if yalign == TEXT_ALIGN_CENTER then
+ local h = draw_GetFontHeight(font)
+ y = y - h / 2
+ end
+
+ surface_SetTextPos(x, y)
+
+ if tab.color then
+ surface_SetTextColor(tab.color)
+ else
+ surface_SetTextColor(255, 255, 255, 255)
+ end
+
+ surface_DrawText(text)
+end
+
+function draw.WordBox( bordersize, x, y, text, font, color, fontcolor )
+ surface_SetFont( font )
+ local w, h = surface_GetTextSize( text )
+
+ draw_RoundedBox( bordersize, x, y, w+bordersize*2, h+bordersize*2, color )
+
+ surface_SetTextColor( fontcolor.r, fontcolor.g, fontcolor.b, fontcolor.a )
+ surface_SetTextPos( x + bordersize, y + bordersize )
+ surface_DrawText( text )
+end
+
+function draw.TextShadow( tab, distance, alpha )
+
+ alpha = alpha or 200
+
+ local color = tab.color
+ local pos = tab.pos
+ tab.color = Color( 0, 0, 0, alpha )
+ tab.pos = { pos[1] + distance, pos[2] + distance }
+
+ draw_Text( tab )
+
+ tab.color = color
+ tab.pos = pos
+
+ draw_Text( tab )
+end
+
+function draw.TexturedQuad(tab)
+ surface_SetTexture(tab.texture)
+ surface_SetDrawColor(tab.color or color_white)
+ surface_DrawTexturedRect(tab.x, tab.y, tab.w, tab.h)
+end
+
+function draw.NoTexture()
+ surface_SetTexture( Tex_white )
+end
+
+function draw.RoundedBoxEx( bordersize, x, y, w, h, color, a, b, c, d )
+ surface_SetDrawColor(color)
+
+ -- Draw as much of the rect as we can without textures
+ surface_DrawRect(x + bordersize, y, w - bordersize * 2, h)
+ surface_DrawRect(x, y + bordersize, bordersize, h - bordersize * 2)
+ surface_DrawRect(x + w - bordersize, y + bordersize, bordersize, h - bordersize * 2)
+
+ surface_SetTexture(bordersize > 8 and Tex_Corner16 or Tex_Corner8)
+
+ if a then
+ surface_DrawTexturedRectRotated( x + bordersize/2 , y + bordersize/2, bordersize, bordersize, 0 )
+ else
+ surface_DrawRect( x, y, bordersize, bordersize )
+ end
+
+ if b then
+ surface_DrawTexturedRectRotated( x + w - bordersize/2 , y + bordersize/2, bordersize, bordersize, 270 )
+ else
+ surface_DrawRect( x + w - bordersize, y, bordersize, bordersize )
+ end
+
+ if c then
+ surface_DrawTexturedRectRotated( x + bordersize/2 , y + h -bordersize/2, bordersize, bordersize, 90 )
+ else
+ surface_DrawRect( x, y + h - bordersize, bordersize, bordersize )
+ end
+
+ if d then
+ surface_DrawTexturedRectRotated( x + w - bordersize/2 , y + h - bordersize/2, bordersize, bordersize, 180 )
+ else
+ surface_DrawRect( x + w - bordersize, y + h - bordersize, bordersize, bordersize )
+ end
+end
+
+function draw.SimpleTextOutlined(text, font, x, y, colour, xalign, yalign, outlinewidth, outlinecolour)
+ local steps = (outlinewidth*2) / 3
+ if steps < 1 then steps = 1 end
+
+ for _x=-outlinewidth, outlinewidth, steps do
+ for _y=-outlinewidth, outlinewidth, steps do
+ draw_SimpleText(text, font, x + _x, y + _y, outlinecolour, xalign, yalign)
+ end
+ end
+
+ draw_SimpleText(text, font, x, y, colour, xalign, yalign)
+end
+
+draw.GetFontHeight = draw_GetFontHeight
+draw.SimpleText = draw_SimpleText
+draw.DrawText = draw_DrawText
+draw.RoundedBox = draw_RoundedBox
+draw.Text = draw_Text
diff --git a/gamemodes/zombiesurvival/gamemode/cl_deathnotice.lua b/gamemodes/zombiesurvival/gamemode/cl_deathnotice.lua
new file mode 100644
index 0000000..8818dd0
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/cl_deathnotice.lua
@@ -0,0 +1,282 @@
+if not killicon.GetFont then
+ killicon.OldAddFont = killicon.AddFont
+ killicon.OldAddAlias = killicon.AddAlias
+ killicon.OldAdd = killicon.Add
+
+ local storedfonts = {}
+ local storedicons = {}
+
+ function killicon.AddFont(sClass, sFont, sLetter, cColor)
+ storedfonts[sClass] = {sFont, sLetter, cColor}
+ return killicon.OldAddFont(sClass, sFont, sLetter, cColor)
+ end
+
+ function killicon.Add(sClass, sTexture, cColor)
+ storedicons[sClass] = {sTexture, cColor}
+ return killicon.OldAdd(sClass, sTexture, cColor)
+ end
+
+ function killicon.AddAlias(sClass, sBaseClass)
+ if storedfonts[sClass] then
+ return killicon.AddFont(sBaseClass, storedfonts[sClass][1], storedfonts[sClass][2], storedfonts[sClass][3])
+ elseif storedicons[sClass] then
+ return killicon.Add(sBaseClass, storedicons[sClass][1], storedicons[sClass][2])
+ end
+ end
+
+ function killicon.Get(sClass)
+ return killicon.GetFont(sClass) or killicon.GetIcon(sClass)
+ end
+
+ function killicon.GetFont(sClass)
+ return storedfonts[sClass]
+ end
+
+ function killicon.GetIcon(sClass)
+ return storedicons[sClass]
+ end
+end
+
+killicon.AddFont("default", "zsdeathnoticecs", "C", color_white)
+killicon.AddFont("suicide", "zsdeathnoticecs", "C", color_white)
+killicon.AddFont("player", "zsdeathnoticecs", "C", color_white)
+killicon.AddFont("worldspawn", "zsdeathnoticecs", "C", color_white)
+killicon.AddFont("func_move_linear", "zsdeathnoticecs", "C", color_white)
+killicon.AddFont("func_rotating", "zsdeathnoticecs", "C", color_white)
+killicon.AddFont("trigger_hurt", "zsdeathnoticecs", "C", color_white)
+
+killicon.AddFont("prop_physics", "zsdeathnotice", "9", color_white)
+killicon.AddFont("prop_physics_multiplayer", "zsdeathnotice", "9", color_white)
+killicon.AddFont("func_physbox", "zsdeathnotice", "9", color_white)
+killicon.AddFont("weapon_smg1", "zsdeathnotice", "/", color_white)
+killicon.AddFont("weapon_357", "zsdeathnotice", ".", color_white)
+killicon.AddFont("weapon_ar2", "zsdeathnotice", "2", color_white)
+killicon.AddFont("crossbow_bolt", "zsdeathnotice", "1", color_white)
+killicon.AddFont("weapon_shotgun", "zsdeathnotice", "0", color_white)
+killicon.AddFont("rpg_missile", "zsdeathnotice", "3", color_white)
+killicon.AddFont("npc_grenade_frag", "zsdeathnotice", "4", color_white)
+killicon.AddFont("weapon_pistol", "zsdeathnotice", "-", color_white)
+killicon.AddFont("prop_combine_ball", "zsdeathnotice", "8", color_white)
+killicon.AddFont("grenade_ar2", "zsdeathnotice", "7", color_white)
+killicon.AddFont("weapon_stunstick", "zsdeathnotice", "!", color_white)
+killicon.AddFont("weapon_slam", "zsdeathnotice", "*", color_white)
+killicon.AddFont("weapon_crowbar", "zsdeathnotice", "6", color_white)
+
+killicon.AddFont("headshot", "zsdeathnoticecs", "D", color_white)
+killicon.Add("redeem", "killicon/redeem", color_white)
+
+killicon.Add("weapon_zs_zombie", "zombiesurvival/killicons/zombie", color_white)
+killicon.Add("weapon_zs_freshdead", "zombiesurvival/killicons/zombie", color_white)
+killicon.Add("weapon_zs_classiczombie", "zombiesurvival/killicons/zombie", color_white)
+killicon.Add("weapon_zs_superzombie", "zombiesurvival/killicons/zombie", color_white)
+killicon.Add("weapon_zs_zombietorso", "zombiesurvival/killicons/torso", color_white)
+killicon.Add("weapon_zs_zombielegs", "zombiesurvival/killicons/legs", color_white)
+killicon.Add("weapon_zs_fastzombielegs", "zombiesurvival/killicons/legs", color_white)
+killicon.Add("weapon_zs_nightmare", "zombiesurvival/killicons/nightmare", color_white)
+killicon.Add("weapon_zs_pukepus", "zombiesurvival/killicons/pukepus", color_white)
+killicon.Add("weapon_zs_ticklemonster", "zombiesurvival/killicons/tickle", color_white)
+killicon.Add("weapon_zs_crow", "zombiesurvival/killicons/crow", color_white)
+killicon.Add("weapon_zs_fastzombie", "zombiesurvival/killicons/fastzombie", color_white)
+killicon.Add("weapon_zs_poisonzombie", "zombiesurvival/killicons/poisonzombie", color_white)
+killicon.Add("weapon_zs_chemzombie", "zombiesurvival/killicons/chemzombie", color_white)
+killicon.Add("weapon_zs_ghoul", "zombiesurvival/killicons/ghoul", color_white)
+killicon.Add("dummy_chemzombie", "zombiesurvival/killicons/chemzombie", color_white)
+killicon.Add("weapon_zs_wraith", "zombiesurvival/killicons/wraithv2", color_white)
+killicon.Add("weapon_zs_headcrab", "zombiesurvival/killicons/headcrab", color_white)
+killicon.Add("weapon_zs_fastheadcrab", "zombiesurvival/killicons/fastheadcrab", color_white)
+killicon.Add("weapon_zs_poisonheadcrab", "zombiesurvival/killicons/poisonheadcrab", color_white)
+killicon.Add("projectile_poisonspit", "zombiesurvival/killicons/projectile_poisonspit", color_white)
+killicon.Add("projectile_poisonflesh", "zombiesurvival/killicons/projectile_poisonflesh", color_white)
+killicon.Add("projectile_poisonpuke", "zombiesurvival/killicons/pukepus", color_white)
+killicon.Add("weapon_zs_special_wow", "sprites/glow04_noz", color_white)
+
+killicon.Add("prop_gunturret", "zombiesurvival/killicons/prop_gunturret", color_white)
+killicon.Add("weapon_zs_gunturret", "zombiesurvival/killicons/prop_gunturret", color_white)
+killicon.Add("weapon_zs_gunturretremove", "zombiesurvival/killicons/prop_gunturret", color_white)
+killicon.AddFont("projectile_zsgrenade", "zsdeathnotice", "4", color_white)
+killicon.AddFont("weapon_zs_grenade", "zsdeathnotice", "4", color_white)
+killicon.AddFont("prop_detpack", "zsdeathnotice", "*", color_white)
+killicon.AddFont("weapon_zs_detpack", "zsdeathnotice", "*", color_white)
+killicon.AddFont("weapon_zs_detpackremote", "zsdeathnotice", "*", color_white)
+killicon.AddFont("weapon_zs_stubber", "zsdeathnoticecs", "n", color_white)
+killicon.AddFont("weapon_zs_hunter", "zsdeathnoticecs", "r", color_white)
+killicon.AddFont("weapon_zs_tosser", "zsdeathnotice", "/", color_white)
+killicon.AddFont("weapon_zs_owens", "zsdeathnotice", "-", color_white)
+killicon.AddFont("weapon_zs_battleaxe", "zsdeathnoticecs", "c", color_white)
+killicon.AddFont("weapon_zs_boomstick", "zsdeathnotice", "0", color_white)
+killicon.AddFont("weapon_zs_annabelle", "zsdeathnotice", "0", color_white)
+killicon.AddFont("weapon_zs_silencer", "zsdeathnoticecs", "d", color_white)
+killicon.AddFont("weapon_zs_blaster", "zsdeathnotice", "0", color_white)
+killicon.AddFont("weapon_zs_eraser", "zsdeathnoticecs", "u", color_white)
+killicon.AddFont("weapon_zs_sweepershotgun", "zsdeathnoticecs", "k", color_white)
+killicon.AddFont("weapon_zs_zesweeper", "zsdeathnoticecs", "k", color_white)
+killicon.AddFont("weapon_zs_barricadekit", "zsdeathnotice", "3", color_white)
+killicon.AddFont("weapon_zs_bulletstorm", "zsdeathnoticecs", "m", color_white)
+killicon.AddFont("weapon_zs_crossbow", "zsdeathnotice", "1", color_white)
+killicon.AddFont("projectile_arrow", "zsdeathnotice", "1", color_white)
+killicon.AddFont("weapon_zs_deagle", "zsdeathnoticecs", "f", color_white)
+killicon.AddFont("weapon_zs_zedeagle", "zsdeathnoticecs", "f", color_white)
+killicon.AddFont("weapon_zs_glock3", "zsdeathnoticecs", "c", color_white)
+killicon.AddFont("weapon_zs_magnum", "zsdeathnotice", ".", color_white)
+killicon.AddFont("weapon_zs_peashooter", "zsdeathnoticecs", "a", color_white)
+killicon.AddFont("weapon_zs_slugrifle", "zsdeathnoticecs", "n", color_white)
+killicon.AddFont("weapon_zs_smg", "zsdeathnoticecs", "x", color_white)
+killicon.AddFont("weapon_zs_zesmg", "zsdeathnoticecs", "x", color_white)
+killicon.AddFont("weapon_zs_swissarmyknife", "zsdeathnoticecs", "j", color_white)
+killicon.AddFont("weapon_zs_zeknife", "zsdeathnoticecs", "j", color_white)
+killicon.AddFont("weapon_zs_uzi", "zsdeathnoticecs", "l", color_white)
+killicon.AddFont("weapon_zs_inferno", "zsdeathnoticecs", "e", color_white)
+killicon.AddFont("weapon_zs_m4", "zsdeathnoticecs", "w", color_white)
+killicon.AddFont("weapon_zs_reaper", "zsdeathnoticecs", "q", color_white)
+killicon.AddFont("weapon_zs_crackler", "zsdeathnoticecs", "t", color_white)
+killicon.AddFont("weapon_zs_pulserifle", "zsdeathnotice", "2", color_white)
+killicon.AddFont("weapon_zs_akbar", "zsdeathnoticecs", "b", color_white)
+killicon.AddFont("weapon_zs_zeakbar", "zsdeathnoticecs", "b", color_white)
+killicon.AddFont("weapon_zs_ender", "zsdeathnoticecs", "v", color_white)
+killicon.AddFont("weapon_zs_redeemers", "zsdeathnoticecs", "s", color_white)
+killicon.Add("weapon_zs_axe", "killicon/zs_axe", color_white)
+killicon.Add("weapon_zs_sawhack", "killicon/zs_axe", color_white)
+killicon.Add("weapon_zs_keyboard", "killicon/zs_keyboard", color_white)
+killicon.Add("weapon_zs_sledgehammer", "killicon/zs_sledgehammer", color_white)
+killicon.Add("weapon_zs_megamasher", "killicon/zs_sledgehammer", color_white)
+killicon.Add("weapon_zs_fryingpan", "killicon/zs_fryingpan", color_white)
+killicon.Add("weapon_zs_pot", "killicon/zs_pot", color_white)
+killicon.Add("weapon_zs_plank", "killicon/zs_plank", color_white)
+killicon.Add("weapon_zs_hammer", "killicon/zs_hammer", color_white)
+killicon.Add("weapon_zs_electrohammer", "killicon/zs_hammer", color_white)
+killicon.Add("weapon_zs_shovel", "killicon/zs_shovel", color_white)
+killicon.AddFont("weapon_zs_crowbar", "zsdeathnotice", "6", color_white)
+killicon.AddFont("weapon_zs_stunbaton", "zsdeathnotice", "!", color_white)
+
+net.Receive("zs_crow_kill_crow", function(length)
+ local victim = net.ReadString()
+ local attacker = net.ReadString()
+
+ --gamemode.Call("AddDeathNotice", attacker, TEAM_UNDEAD, "weapon_zs_crow", victim, TEAM_UNDEAD)
+ GAMEMODE:TopNotify(attacker, " ", {killicon = "weapon_zs_crow"}, " ", victim)
+end)
+
+net.Receive("zs_pl_kill_pl", function(length)
+ local victim = net.ReadEntity()
+ local attacker = net.ReadEntity()
+
+ local inflictor = net.ReadString()
+
+ local victimteam = net.ReadUInt(16)
+ local attackerteam = net.ReadUInt(16)
+
+ local headshot = net.ReadBit() == 1
+
+ if victim:IsValid() and attacker:IsValid() then
+ local attackername = attacker:Name()
+ local victimname = victim:Name()
+
+ if victim == MySelf then
+ if victimteam == TEAM_HUMAN then
+ gamemode.Call("LocalPlayerDied", attackername)
+ end
+ elseif attacker == MySelf then
+ if attacker:Team() == TEAM_UNDEAD then
+ gamemode.Call("FloatingScore", victim, "floatingscore_und", 1, 0)
+ end
+ end
+
+ victim:CallZombieFunction("OnKilled", attacker, attacker, attacker == victim, headshot, DamageInfo())
+
+ print(attackername.." killed "..victimname.." with "..inflictor)
+
+ --gamemode.Call("AddDeathNotice", attackername, attackerteam, inflictor, victimname, victimteam, headshot)
+ GAMEMODE:TopNotify(attacker, " ", {killicon = inflictor, headshot = headshot}, " ", victim)
+ end
+end)
+
+net.Receive("zs_pls_kill_pl", function(length)
+ local victim = net.ReadEntity()
+ local attacker = net.ReadEntity()
+ local assister = net.ReadEntity()
+
+ local inflictor = net.ReadString()
+
+ local victimteam = net.ReadUInt(16)
+ local attackerteam = net.ReadUInt(16)
+
+ local headshot = net.ReadBit() == 1
+
+ if victim:IsValid() and attacker:IsValid() and assister:IsValid() then
+ local victimname = victim:Name()
+ local attackername = attacker:Name()
+ local assistername = assister:Name()
+
+ if victim == MySelf and victimteam == TEAM_HUMAN then
+ gamemode.Call("LocalPlayerDied", attackername.." and "..assistername)
+ end
+
+ victim:CallZombieFunction("OnKilled", attacker, attacker, attacker == victim, headshot, DamageInfo())
+
+ print(attackername.." and "..assistername.." killed "..victimname.." with "..inflictor)
+
+ --gamemode.Call("AddDeathNotice", attackername.." and "..assistername, attackerteam, inflictor, victimname, victimteam, headshot)
+ GAMEMODE:TopNotify(attacker, " and ", assister, " ", {killicon = inflictor, headshot = headshot}, " ", victim)
+ end
+end)
+
+net.Receive("zs_pl_kill_self", function(length)
+ local victim = net.ReadEntity()
+ local victimteam = net.ReadUInt(16)
+
+ if victim:IsValid() then
+ if victim == MySelf and victimteam == TEAM_HUMAN then
+ gamemode.Call("LocalPlayerDied")
+ end
+
+ victim:CallZombieFunction("OnKilled", victim, victim, true, false, DamageInfo())
+
+ local victimname = victim:Name()
+
+ print(victimname.." killed themself")
+
+ --gamemode.Call("AddDeathNotice", nil, 0, "suicide", victimname, victimteam)
+ GAMEMODE:TopNotify({killicon = "suicide"}, " ", victim)
+ end
+end)
+
+net.Receive("zs_playerredeemed", function(length)
+ local pl = net.ReadEntity()
+ local name = net.ReadString()
+
+ --gamemode.Call("AddDeathNotice", nil, 0, "redeem", name, TEAM_HUMAN)
+
+ if pl:IsValid() then
+ GAMEMODE:TopNotify(pl, " has redeemed! ", {killicon = "redeem"})
+
+ if pl == MySelf then
+ GAMEMODE:CenterNotify(COLOR_CYAN, translate.Get("you_redeemed"))
+ end
+ end
+end)
+
+net.Receive("zs_death", function(length)
+ local victim = net.ReadEntity()
+ local inflictor = net.ReadString()
+ local attacker = "#" .. net.ReadString()
+ local victimteam = net.ReadUInt(16)
+
+ if victim:IsValid() then
+ if victim == MySelf and victimteam == TEAM_HUMAN then
+ gamemode.Call("LocalPlayerDied")
+ end
+
+ victim:CallZombieFunction("OnKilled", attacker, NULL, attacker == victim, false, DamageInfo())
+
+ local victimname = victim:Name()
+
+ print(victimname.." was killed by "..attacker.." with "..inflictor)
+
+ --gamemode.Call("AddDeathNotice", attacker, -1, inflictor, victimname, victimteam)
+ GAMEMODE:TopNotify(COLOR_RED, attacker, " ", {deathicon = inflictor}, " ", victim)
+ end
+end)
+
+-- Handled above.
+function GM:AddDeathNotice()
+end
diff --git a/gamemodes/zombiesurvival/gamemode/cl_dermaskin.lua b/gamemodes/zombiesurvival/gamemode/cl_dermaskin.lua
new file mode 100644
index 0000000..92bd518
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/cl_dermaskin.lua
@@ -0,0 +1,233 @@
+function GM:ForceDermaSkin()
+ return "zombiesurvival"
+end
+
+local SKIN = {}
+
+SKIN.PrintName = "Zombie Survival Derma Skin"
+SKIN.Author = "William \"JetBoom\" Moodhe"
+SKIN.DermaVersion = 1
+
+SKIN.bg_color = Color(50, 50, 50, 255)
+SKIN.bg_color_sleep = Color(40, 40, 40, 255)
+SKIN.bg_color_dark = Color(30, 30, 30, 255)
+SKIN.bg_color_bright = Color(80, 80, 80, 255)
+
+SKIN.Colors = {}
+SKIN.Colors.Panel = {}
+SKIN.Colors.Panel.Normal = Color(50, 50, 50, 120)
+
+function SKIN:PaintPanel(panel, w, h)
+ if not panel.m_bBackground then return end
+
+ surface.SetDrawColor(self.Colors.Panel.Normal)
+ surface.DrawRect(0, 0, w, h)
+end
+
+--SKIN.tooltip = Color(190, 190, 190, 230)
+
+local color_frame_background = Color(0, 0, 0, 220)
+SKIN.color_frame_background = color_frame_background
+SKIN.color_frame_border = Color(0, 80, 0, 255)
+
+SKIN.colTextEntryText = Color(10, 10, 10)
+SKIN.colTextEntryTextHighlight = Color(30, 255, 0)
+SKIN.colTextEntryTextBorder = Color(70, 90, 70, 255)
+
+SKIN.colPropertySheet = Color(30, 30, 30, 255)
+SKIN.colTab = SKIN.colPropertySheet
+SKIN.colTabInactive = Color(25, 25, 25, 155)
+SKIN.colTabShadow = Color(20, 30, 20, 255)
+SKIN.colTabText = Color(240, 255, 240, 255)
+SKIN.colTabTextInactive = Color(240, 255, 240, 120)
+
+--[[SKIN.colTextEntryBG = Color( 240, 240, 240, 255 )
+SKIN.colTextEntryBorder = Color( 20, 20, 20, 255 )
+SKIN.colTextEntryText = Color( 20, 20, 20, 255 )
+SKIN.colTextEntryTextHighlight = Color( 20, 200, 250, 255 )
+SKIN.colTextEntryTextCursor = Color( 0, 0, 100, 255 )]]
+
+function SKIN:PaintPropertySheet(panel, w, h)
+ local ActiveTab = panel:GetActiveTab()
+ local Offset = 0
+ if ActiveTab then Offset = ActiveTab:GetTall() - 8 end
+
+ draw.RoundedBox(8, 0, 0, w, h, self.colTab)
+end
+
+function SKIN:PaintTab(panel, w, h)
+ if panel:GetPropertySheet():GetActiveTab() == panel then
+ return self:PaintActiveTab(panel, w, h)
+ end
+
+ draw.RoundedBox(8, 0, 0, w, h, self.colTabInactive)
+end
+
+function SKIN:PaintActiveTab(panel, w, h)
+ draw.RoundedBox(8, 0, 0, w, h, self.colTab)
+end
+
+--[[SKIN.color_textentry_background = Color(40, 40, 40, 255)
+SKIN.color_textentry_border = Color(70, 90, 70, 255)]]
+
+local texCorner = surface.GetTextureID("zombiesurvival/circlegradient")
+local texUpEdge = surface.GetTextureID("gui/gradient_up")
+local texDownEdge = surface.GetTextureID("gui/gradient_down")
+local texRightEdge = surface.GetTextureID("gui/gradient")
+function PaintGenericFrame(panel, x, y, wid, hei, edgesize)
+ edgesize = edgesize or math.ceil(math.min(hei * 0.1, math.min(16, wid * 0.1)))
+ local dedgesize = edgesize * 2
+ local hedgesize = edgesize * 0.5
+ DisableClipping(true)
+ surface.DrawRect(x, y, wid, hei)
+ surface.SetTexture(texUpEdge)
+ surface.DrawTexturedRect(x, y - edgesize, wid, edgesize)
+ surface.SetTexture(texDownEdge)
+ surface.DrawTexturedRect(x, y + hei, wid, edgesize)
+ surface.SetTexture(texRightEdge)
+ surface.DrawTexturedRect(wid, y, edgesize, hei)
+ surface.DrawTexturedRectRotated(x + hedgesize * -1, y + hei * 0.5, edgesize, hei, 180)
+ surface.SetTexture(texCorner)
+ surface.DrawTexturedRect(x - edgesize, y - edgesize, edgesize, edgesize)
+ surface.DrawTexturedRectRotated(x + wid + hedgesize, y - hedgesize, edgesize, edgesize, 270)
+ surface.DrawTexturedRectRotated(x + wid + hedgesize, y + hei + hedgesize, edgesize, edgesize, 180)
+ surface.DrawTexturedRectRotated(x - hedgesize, y + hei + hedgesize, edgesize, edgesize, 90)
+ DisableClipping(false)
+end
+
+function SKIN:PaintFrame(panel, w, h)
+ surface.SetDrawColor(panel.ColorOverride or color_frame_background)
+ PaintGenericFrame(panel, 0, 0, w, h)
+end
+
+--[[function SKIN:DrawBorder(x, y, w, h, border)
+ surface.SetDrawColor(border)
+ surface.DrawOutlinedRect(x, y, w, h)
+ surface.SetDrawColor(border.r * 0.75, border.g * 0.75, border.b * 0.5, border.a)
+ surface.DrawOutlinedRect(x + 1, y + 1, w - 2, h - 2)
+ surface.SetDrawColor(border.r * 0.5, border.g * 0.5, border.b * 0.5, border.a)
+ surface.DrawOutlinedRect(x + 2, y + 2, w - 4, h - 4)
+end
+
+function SKIN:PaintTooltip(panel)
+ local w, h = panel:GetSize()
+
+ DisableClipping(true)
+
+ self:DrawGenericBackground(0, 0, w, h, self.tooltip)
+ panel:DrawArrow(0, 0)
+
+ DisableClipping(false)
+end
+
+function SKIN:PaintButton(panel)
+ local w, h = panel:GetSize()
+
+ if panel.m_bBackground then
+ local col = self.control_color
+ if panel:GetDisabled() then
+ col = self.control_color_dark
+ elseif panel.Depressed then
+ col = self.control_color_active
+ elseif panel.Hovered then
+ col = self.control_color_highlight
+ end
+
+ draw.RoundedBox(8, 0, 0, w, h, col)
+ end
+end]]
+
+SKIN.Colours = {}
+
+SKIN.Colours.Window = {}
+SKIN.Colours.Window.TitleActive = GWEN.TextureColor( 4 + 8 * 0, 508 );
+SKIN.Colours.Window.TitleInactive = GWEN.TextureColor( 4 + 8 * 1, 508 );
+
+SKIN.Colours.Button = {}
+SKIN.Colours.Button.Normal = Color(200, 200, 200, 220)
+SKIN.Colours.Button.Hover = Color(255, 255, 255, 220)
+SKIN.Colours.Button.Down = Color(255, 255, 255, 255)
+SKIN.Colours.Button.Disabled = Color(160, 160, 160, 220)
+
+SKIN.Colours.Tab = {}
+SKIN.Colours.Tab.Active = {}
+SKIN.Colours.Tab.Active.Normal = GWEN.TextureColor( 4 + 8 * 4, 508 );
+SKIN.Colours.Tab.Active.Hover = GWEN.TextureColor( 4 + 8 * 5, 508 );
+SKIN.Colours.Tab.Active.Down = GWEN.TextureColor( 4 + 8 * 4, 500 );
+SKIN.Colours.Tab.Active.Disabled = GWEN.TextureColor( 4 + 8 * 5, 500 );
+
+SKIN.Colours.Tab.Inactive = {}
+SKIN.Colours.Tab.Inactive.Normal = GWEN.TextureColor( 4 + 8 * 6, 508 );
+SKIN.Colours.Tab.Inactive.Hover = GWEN.TextureColor( 4 + 8 * 7, 508 );
+SKIN.Colours.Tab.Inactive.Down = GWEN.TextureColor( 4 + 8 * 6, 500 );
+SKIN.Colours.Tab.Inactive.Disabled = GWEN.TextureColor( 4 + 8 * 7, 500 );
+
+SKIN.Colours.Label = {}
+SKIN.Colours.Label.Default = GWEN.TextureColor( 4 + 8 * 8, 508 );
+SKIN.Colours.Label.Bright = GWEN.TextureColor( 4 + 8 * 9, 508 );
+SKIN.Colours.Label.Dark = GWEN.TextureColor( 4 + 8 * 8, 500 );
+SKIN.Colours.Label.Highlight = GWEN.TextureColor( 4 + 8 * 9, 500 );
+
+SKIN.Colours.Tree = {}
+SKIN.Colours.Tree.Lines = GWEN.TextureColor( 4 + 8 * 10, 508 ); ---- !!!
+SKIN.Colours.Tree.Normal = GWEN.TextureColor( 4 + 8 * 11, 508 );
+SKIN.Colours.Tree.Hover = GWEN.TextureColor( 4 + 8 * 10, 500 );
+SKIN.Colours.Tree.Selected = GWEN.TextureColor( 4 + 8 * 11, 500 );
+
+SKIN.Colours.Properties = {}
+SKIN.Colours.Properties.Line_Normal = GWEN.TextureColor( 4 + 8 * 12, 508 );
+SKIN.Colours.Properties.Line_Selected = GWEN.TextureColor( 4 + 8 * 13, 508 );
+SKIN.Colours.Properties.Line_Hover = GWEN.TextureColor( 4 + 8 * 12, 500 );
+SKIN.Colours.Properties.Title = GWEN.TextureColor( 4 + 8 * 13, 500 );
+SKIN.Colours.Properties.Column_Normal = GWEN.TextureColor( 4 + 8 * 14, 508 );
+SKIN.Colours.Properties.Column_Selected = GWEN.TextureColor( 4 + 8 * 15, 508 );
+SKIN.Colours.Properties.Column_Hover = GWEN.TextureColor( 4 + 8 * 14, 500 );
+SKIN.Colours.Properties.Border = GWEN.TextureColor( 4 + 8 * 15, 500 );
+SKIN.Colours.Properties.Label_Normal = GWEN.TextureColor( 4 + 8 * 16, 508 );
+SKIN.Colours.Properties.Label_Selected = GWEN.TextureColor( 4 + 8 * 17, 508 );
+SKIN.Colours.Properties.Label_Hover = GWEN.TextureColor( 4 + 8 * 16, 500 );
+
+SKIN.Colours.Category = {}
+SKIN.Colours.Category.Header = GWEN.TextureColor( 4 + 8 * 18, 500 );
+SKIN.Colours.Category.Header_Closed = GWEN.TextureColor( 4 + 8 * 19, 500 );
+SKIN.Colours.Category.Line = {}
+SKIN.Colours.Category.Line.Text = GWEN.TextureColor( 4 + 8 * 20, 508 );
+SKIN.Colours.Category.Line.Text_Hover = GWEN.TextureColor( 4 + 8 * 21, 508 );
+SKIN.Colours.Category.Line.Text_Selected = GWEN.TextureColor( 4 + 8 * 20, 500 );
+SKIN.Colours.Category.Line.Button = GWEN.TextureColor( 4 + 8 * 21, 500 );
+SKIN.Colours.Category.Line.Button_Hover = GWEN.TextureColor( 4 + 8 * 22, 508 );
+SKIN.Colours.Category.Line.Button_Selected = GWEN.TextureColor( 4 + 8 * 23, 508 );
+SKIN.Colours.Category.LineAlt = {}
+SKIN.Colours.Category.LineAlt.Text = GWEN.TextureColor( 4 + 8 * 22, 500 );
+SKIN.Colours.Category.LineAlt.Text_Hover = GWEN.TextureColor( 4 + 8 * 23, 500 );
+SKIN.Colours.Category.LineAlt.Text_Selected = GWEN.TextureColor( 4 + 8 * 24, 508 );
+SKIN.Colours.Category.LineAlt.Button = GWEN.TextureColor( 4 + 8 * 25, 508 );
+SKIN.Colours.Category.LineAlt.Button_Hover = GWEN.TextureColor( 4 + 8 * 24, 500 );
+SKIN.Colours.Category.LineAlt.Button_Selected = GWEN.TextureColor( 4 + 8 * 25, 500 );
+
+SKIN.Colours.TooltipText = GWEN.TextureColor( 4 + 8 * 26, 500 );
+
+function SKIN:PaintButton(panel, w, h)
+ if not panel.m_bBackground then return end
+
+ local col
+
+ if panel:GetDisabled() then
+ col = Color(5, 5, 5, 90)
+ elseif panel.Depressed or panel:IsSelected() or panel:GetToggle() then
+ col = Color(60, 70, 100, 160)
+ elseif panel.Hovered then
+ col = Color(45, 45, 80, 160)
+ else
+ col = Color(32, 32, 35, 160)
+ end
+
+ local edgesize = math.min(math.ceil(w * 0.2), 24)
+ surface.SetDrawColor(col)
+ surface.DrawRect(edgesize, 0, w - edgesize * 2, h)
+ surface.SetTexture(texRightEdge)
+ surface.DrawTexturedRect(w - edgesize, 0, edgesize, h)
+ surface.DrawTexturedRectRotated(math.ceil(edgesize * 0.5), math.ceil(h * 0.5), edgesize, h, 180)
+end
+
+derma.DefineSkin("zombiesurvival", "The default Derma skin for Zombie Survival", SKIN, "Default")
diff --git a/gamemodes/zombiesurvival/gamemode/cl_draw.lua b/gamemodes/zombiesurvival/gamemode/cl_draw.lua
new file mode 100644
index 0000000..3ffa9b7
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/cl_draw.lua
@@ -0,0 +1,53 @@
+local draw_SimpleText = draw.SimpleText
+local draw_DrawText = draw.DrawText
+
+local FontBlurX = 0
+local FontBlurX2 = 0
+local FontBlurY = 0
+local FontBlurY2 = 0
+
+timer.Create("fontblur", 0.1, 0, function()
+ FontBlurX = math.random(-8, 8)
+ FontBlurX2 = math.random(-8, 8)
+ FontBlurY = math.random(-8, 8)
+ FontBlurY2 = math.random(-8, 8)
+end)
+
+local color_blur1 = Color(60, 60, 60, 220)
+local color_blur2 = Color(40, 40, 40, 140)
+function draw.SimpleTextBlur(text, font, x, y, col, xalign, yalign)
+ color_blur1.a = col.a * 0.85
+ color_blur2.a = col.a * 0.55
+ draw_SimpleText(text, font, x + FontBlurX, y + FontBlurY, color_blur1, xalign, yalign)
+ draw_SimpleText(text, font, x + FontBlurX2, y + FontBlurY2, color_blur2, xalign, yalign)
+ draw_SimpleText(text, font, x, y, col, xalign, yalign)
+end
+
+function draw.DrawTextBlur(text, font, x, y, col, xalign)
+ color_blur1.a = col.a * 0.85
+ color_blur2.a = col.a * 0.55
+ draw_DrawText(text, font, x + FontBlurX, y + FontBlurY, color_blur1, xalign)
+ draw_DrawText(text, font, x + FontBlurX2, y + FontBlurY2, color_blur2, xalign)
+ draw_DrawText(text, font, x, y, col, xalign)
+end
+
+local colBlur = Color(0, 0, 0)
+function draw.SimpleTextBlurry(text, font, x, y, col, xalign, yalign)
+ colBlur.r = col.r
+ colBlur.g = col.g
+ colBlur.b = col.b
+ colBlur.a = col.a * math.Rand(0.35, 0.6)
+
+ draw_SimpleText(text, font.."Blur", x, y, colBlur, xalign, yalign)
+ draw_SimpleText(text, font, x, y, col, xalign, yalign)
+end
+
+function draw.DrawTextBlurry(text, font, x, y, col, xalign)
+ colBlur.r = col.r
+ colBlur.g = col.g
+ colBlur.b = col.b
+ colBlur.a = col.a * math.Rand(0.35, 0.6)
+
+ draw_DrawText(text, font.."Blur", x, y, colBlur, xalign)
+ draw_DrawText(text, font, x, y, col, xalign)
+end
diff --git a/gamemodes/zombiesurvival/gamemode/cl_fix_emitters.lua b/gamemodes/zombiesurvival/gamemode/cl_fix_emitters.lua
new file mode 100644
index 0000000..9c12ecf
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/cl_fix_emitters.lua
@@ -0,0 +1,37 @@
+AddCSLuaFile()
+
+if _FIXEDEMITTERS_ or not CLIENT then return end
+_FIXEDEMITTERS_ = true
+
+local emitter3d, emitter2d
+local ParticleEmitterOld = ParticleEmitter
+
+function ParticleEmitter(vec, threedee)
+ if threedee then
+ if emitter3d == nil then
+ emitter3d = ParticleEmitterOld(vec, true)
+ else
+ emitter3d:SetPos(vec)
+ end
+
+ return emitter3d
+ end
+
+ if emitter2d == nil then
+ emitter2d = ParticleEmitterOld(vec)
+ else
+ emitter2d:SetPos(vec)
+ end
+
+ return emitter2d
+end
+
+local meta = FindMetaTable("CLuaEmitter")
+if not meta then return end
+
+local oldadd = meta.Add
+function meta:Add(a, b, c)
+ self:SetPos(b)
+
+ return oldadd(self, a, b, c)
+end
diff --git a/gamemodes/zombiesurvival/gamemode/cl_floatingscore.lua b/gamemodes/zombiesurvival/gamemode/cl_floatingscore.lua
new file mode 100644
index 0000000..81fd591
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/cl_floatingscore.lua
@@ -0,0 +1,44 @@
+net.Receive("zs_healother", function(length)
+ gamemode.Call("HealedOtherPlayer", net.ReadEntity(), net.ReadUInt(16))
+end)
+
+net.Receive("zs_repairobject", function(length)
+ gamemode.Call("RepairedObject", net.ReadEntity(), net.ReadUInt(16))
+end)
+
+net.Receive("zs_commission", function(length)
+ gamemode.Call("ReceivedCommission", net.ReadEntity(), net.ReadEntity(), net.ReadUInt(16))
+end)
+
+function GM:ReceivedCommission(crate, buyer, points)
+ gamemode.Call("FloatingScore", crate, "floatingscore_com", points)
+end
+
+function GM:HealedOtherPlayer(other, points)
+ gamemode.Call("FloatingScore", other, "floatingscore", points)
+end
+
+function GM:RepairedObject(other, points)
+ gamemode.Call("FloatingScore", other, "floatingscore", points)
+end
+
+local cvarNoFloatingScore = CreateClientConVar("zs_nofloatingscore", 0, true, false)
+function GM:FloatingScore(victim, effectname, frags, flags)
+ local isvec = type(victim) == "Vector"
+
+ if cvarNoFloatingScore:GetBool() or not isvec and (not victim:IsValid() or victim:IsPlayer() and victim:Team() == MySelf:Team()) then return end
+
+ effectname = effectname or "floatingscore"
+
+ local pos = isvec and victim or victim:NearestPoint(EyePos())
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(pos)
+ effectdata:SetScale(flags or 0)
+ if effectname == "floatingscore_und" then
+ effectdata:SetMagnitude(frags or GAMEMODE.ZombieClasses[victim:GetZombieClass()].Points or 1)
+ else
+ effectdata:SetMagnitude(frags or 1)
+ end
+ util.Effect(effectname, effectdata, true, true)
+end
diff --git a/gamemodes/zombiesurvival/gamemode/cl_hint.lua b/gamemodes/zombiesurvival/gamemode/cl_hint.lua
new file mode 100644
index 0000000..bbf534e
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/cl_hint.lua
@@ -0,0 +1,79 @@
+local Hints = {}
+
+function GM:DrawPointWorldHints()
+ for _, ent in pairs(ents.FindByClass("point_worldhint")) do ent:DrawHint() end
+end
+
+function GM:WorldHint(hint, pos, ent, lifetime)
+ lifetime = lifetime or 8
+
+ if ent and ent:IsValid() then
+ if pos then
+ pos = ent:WorldToLocal(pos)
+ else
+ pos = ent:OBBCenter()
+ end
+ end
+
+ local hint = {Hint = hint, Pos = pos, Entity = ent, StartTime = CurTime(), EndTime = CurTime() + lifetime}
+ table.insert(Hints, hint)
+
+ return hint
+end
+
+net.Receive("zs_worldhint", function(length)
+ GAMEMODE:WorldHint(net.ReadString(), net.ReadVector(), net.ReadEntity(), net.ReadFloat())
+end)
+
+local matRing = Material("effects/select_ring")
+local colFG = Color(220, 220, 220, 255)
+function DrawWorldHint(hint, pos, delta, scale)
+ local eyepos = EyePos()
+
+ delta = delta or 1
+
+ colFG.a = math.min(220, delta * 220)
+
+ local ang = (eyepos - pos):Angle()
+ ang:RotateAroundAxis(ang:Right(), 270)
+ ang:RotateAroundAxis(ang:Up(), 90)
+
+ cam.IgnoreZ(true)
+ cam.Start3D2D(pos, ang, (scale or 1) * math.max(250, eyepos:Distance(pos)) * delta * 0.0005)
+
+ draw.SimpleText("!", "zshintfont", 0, 0, colFG, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+ draw.SimpleText(hint, "ZS3D2DFont2Small", 0, 64, colFG, TEXT_ALIGN_CENTER)
+
+ surface.SetMaterial(matRing)
+ for i=1, 4 do
+ colFG.a = colFG.a * (1 / i)
+ surface.SetDrawColor(colFG)
+ local pulse = math.max(0.25, math.abs(math.sin(RealTime() * 6))) * 30 * i
+ surface.DrawTexturedRectRotated(0, 0, 128 + pulse, 128 + pulse, 0)
+ end
+
+ cam.End3D2D()
+ cam.IgnoreZ(false)
+end
+local DrawWorldHint = DrawWorldHint
+
+function GM:DrawWorldHints()
+ if #Hints > 0 then
+ local curtime = CurTime()
+
+ local done = true
+
+ for _, hint in pairs(Hints) do
+ local ent = hint.Entity
+ if curtime < hint.EndTime and not (ent and not ent:IsValid()) then
+ done = false
+
+ DrawWorldHint(hint.Hint, ent and ent:LocalToWorld(hint.Pos) or hint.Pos, math.Clamp(hint.EndTime - curtime, 0, 1))
+ end
+ end
+
+ if done then
+ Hints = {}
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/gamemode/cl_init.lua b/gamemodes/zombiesurvival/gamemode/cl_init.lua
new file mode 100644
index 0000000..0b0eb50
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/cl_init.lua
@@ -0,0 +1,1827 @@
+-- Sometimes persistent ones don't get created.
+local dummy = CreateClientConVar("_zs_dummyconvar", 1, false, false)
+local oldCreateClientConVar = CreateClientConVar
+function CreateClientConVar(...)
+ return oldCreateClientConVar(...) or dummy
+end
+
+include("shared.lua")
+include("cl_draw.lua")
+include("cl_util.lua")
+include("cl_options.lua")
+include("obj_player_extend_cl.lua")
+include("cl_scoreboard.lua")
+include("cl_targetid.lua")
+include("cl_postprocess.lua")
+
+include("vgui/dgamestate.lua")
+include("vgui/dteamcounter.lua")
+include("vgui/dmodelpanelex.lua")
+include("vgui/dammocounter.lua")
+include("vgui/dteamheading.lua")
+
+include("vgui/dexroundedpanel.lua")
+include("vgui/dexroundedframe.lua")
+include("vgui/dexrotatedimage.lua")
+include("vgui/dexnotificationslist.lua")
+include("vgui/dexchanginglabel.lua")
+
+include("vgui/pmainmenu.lua")
+include("vgui/poptions.lua")
+include("vgui/phelp.lua")
+include("vgui/pclassselect.lua")
+include("vgui/pweapons.lua")
+include("vgui/pendboard.lua")
+include("vgui/pworth.lua")
+include("vgui/ppointshop.lua")
+include("vgui/dpingmeter.lua")
+include("vgui/dsidemenu.lua")
+include("vgui/zshealtharea.lua")
+
+include("cl_dermaskin.lua")
+include("cl_deathnotice.lua")
+include("cl_floatingscore.lua")
+include("cl_hint.lua")
+
+include("cl_zombieescape.lua")
+
+w, h = ScrW(), ScrH()
+
+MySelf = MySelf or NULL
+hook.Add("InitPostEntity", "GetLocal", function()
+ MySelf = LocalPlayer()
+
+ GAMEMODE.HookGetLocal = GAMEMODE.HookGetLocal or (function(g) end)
+ gamemode.Call("HookGetLocal", MySelf)
+ RunConsoleCommand("initpostentity")
+end)
+
+-- Remove when model decal crash is fixed.
+function util.Decal()
+end
+
+-- Save on global lookup time.
+local render = render
+local surface = surface
+local draw = draw
+local cam = cam
+local player = player
+local ents = ents
+local util = util
+local math = math
+local string = string
+local bit = bit
+local gamemode = gamemode
+local hook = hook
+local Vector = Vector
+local VectorRand = VectorRand
+local Angle = Angle
+local AngleRand = AngleRand
+local Entity = Entity
+local Color = Color
+local FrameTime = FrameTime
+local RealTime = RealTime
+local CurTime = CurTime
+local SysTime = SysTime
+local EyePos = EyePos
+local EyeAngles = EyeAngles
+local pairs = pairs
+local ipairs = ipairs
+local tostring = tostring
+local tonumber = tonumber
+local type = type
+local ScrW = ScrW
+local ScrH = ScrH
+local TEXT_ALIGN_CENTER = TEXT_ALIGN_CENTER
+local TEXT_ALIGN_LEFT = TEXT_ALIGN_LEFT
+local TEXT_ALIGN_RIGHT = TEXT_ALIGN_RIGHT
+local TEXT_ALIGN_TOP = TEXT_ALIGN_TOP
+local TEXT_ALIGN_BOTTOM = TEXT_ALIGN_BOTTOM
+
+local TEAM_HUMAN = TEAM_HUMAN
+local TEAM_UNDEAD = TEAM_UNDEAD
+local translate = translate
+
+local COLOR_PURPLE = COLOR_PURPLE
+local COLOR_GRAY = COLOR_GRAY
+local COLOR_RED = COLOR_RED
+local COLOR_DARKRED = COLOR_DARKRED
+local COLOR_DARKGREEN = COLOR_DARKGREEN
+local COLOR_GREEN = COLOR_GREEN
+local COLOR_WHITE = COLOR_WHITE
+
+local surface_SetFont = surface.SetFont
+local surface_SetTexture = surface.SetTexture
+local surface_SetMaterial = surface.SetMaterial
+local surface_SetDrawColor = surface.SetDrawColor
+local surface_DrawRect = surface.DrawRect
+local surface_DrawOutlinedRect = surface.DrawOutlinedRect
+local surface_DrawTexturedRect = surface.DrawTexturedRect
+local surface_DrawTexturedRectRotated = surface.DrawTexturedRectRotated
+local surface_DrawTexturedRectUV = surface.DrawTexturedRectUV
+local surface_PlaySound = surface.PlaySound
+
+local draw_SimpleText = draw.SimpleText
+local draw_SimpleTextBlurry = draw.SimpleTextBlurry
+local draw_SimpleTextBlur = draw.SimpleTextBlur
+local draw_GetFontHeight = draw.GetFontHeight
+
+local MedicalAuraDistance = 400
+
+function GM:ClickedPlayerButton(pl, button)
+end
+
+function GM:ClickedEndBoardPlayerButton(pl, button)
+end
+
+function GM:CenterNotify(...)
+ if self.CenterNotificationHUD and self.CenterNotificationHUD:Valid() then
+ return self.CenterNotificationHUD:AddNotification(...)
+ end
+end
+
+function GM:TopNotify(...)
+ if self.TopNotificationHUD and self.TopNotificationHUD:Valid() then
+ return self.TopNotificationHUD:AddNotification(...)
+ end
+end
+
+GM.InputMouseX = 0
+GM.InputMouseY = 0
+function GM:_InputMouseApply(cmd, x, y, ang)
+ self.InputMouseX = x
+ self.InputMouseY = y
+
+ if MySelf:KeyDown(IN_WALK) and MySelf:IsHolding() then
+ RunConsoleCommand("_zs_rotateang", self.InputMouseX, self.InputMouseY)
+ return true
+ end
+end
+
+function GM:_GUIMousePressed(mc)
+ if self.HumanMenuPanel and self.HumanMenuPanel:Valid() and self.HumanMenuPanel:IsVisible() and MySelf:KeyDown(self.MenuKey) then
+ local dir = gui.ScreenToVector(gui.MousePos())
+ local ent = util.TraceLine({start = MySelf:EyePos(), endpos = MySelf:EyePos() + dir * self.CraftingRange, filter = MySelf, mask = MASK_SOLID}).Entity
+ if ent:IsValid() and not ent:IsPlayer() and (ent:GetMoveType() == MOVETYPE_NONE or ent:GetMoveType() == MOVETYPE_VPHYSICS) and ent:GetSolid() == SOLID_VPHYSICS then
+ if mc == MOUSE_LEFT then
+ if ent == self.CraftingEntity then
+ self.CraftingEntity = nil
+ else
+ self.CraftingEntity = ent
+ end
+ elseif mc == MOUSE_RIGHT and self.CraftingEntity and self.CraftingEntity:IsValid() then
+ RunConsoleCommand("_zs_craftcombine", self.CraftingEntity:EntIndex(), ent:EntIndex())
+ self.CraftingEntity = nil
+ end
+ end
+ end
+end
+
+function GM:TryHumanPickup(pl, entity)
+end
+
+function GM:AddExtraOptions(list, window)
+end
+
+function GM:SpawnMenuEnabled()
+ return false
+end
+
+function GM:SpawnMenuOpen()
+ return false
+end
+
+function GM:ContextMenuOpen()
+ return false
+end
+
+function GM:HUDWeaponPickedUp(wep)
+end
+
+function GM:_HUDWeaponPickedUp(wep)
+ if MySelf:Team() == TEAM_HUMAN and not wep.NoPickupNotification then
+ self:Rewarded(wep:GetClass())
+ end
+end
+
+function GM:HUDItemPickedUp(itemname)
+end
+
+function GM:HUDAmmoPickedUp(itemname, amount)
+end
+
+function GM:InitPostEntity()
+ if not self.HealthHUD then
+ self.HealthHUD = vgui.Create("ZSHealthArea")
+ end
+
+ self:LocalPlayerFound()
+
+ self:EvaluateFilmMode()
+
+ timer.Simple(2, function() GAMEMODE:GetFogData() end)
+end
+
+function GM:SetupWorldFog()
+ if self.DeathFog == 0 then return end
+
+ local power = self.DeathFog
+ local rpower = 1 - self.DeathFog
+
+ local fogstart = self.FogStart * rpower
+ local fogend = self.FogEnd * rpower + 150 * power
+ local fogr = self.FogRed * rpower
+ local fogg = self.FogGreen * rpower + 40 * power
+ local fogb = self.FogBlue * rpower
+
+ render.FogMode(1)
+
+ render.FogStart(fogstart)
+ render.FogEnd(fogend)
+ render.FogColor(fogr, fogg, fogb)
+ render.FogMaxDensity(1)
+
+ return true
+end
+
+function GM:SetupSkyboxFog(skyboxscale)
+ if self.DeathFog == 0 then return end
+
+ local power = self.DeathFog
+ local rpower = 1 - self.DeathFog
+
+ local fogstart = self.FogStart * rpower
+ local fogend = self.FogEnd * rpower + 150 * power
+ local fogr = self.FogRed * rpower
+ local fogg = self.FogGreen * rpower + 40 * power
+ local fogb = self.FogBlue * rpower
+ local fogdensity = 1 - power * 0.1
+
+ render.FogMode(1)
+
+ render.FogStart(fogstart * skyboxscale)
+ render.FogEnd(fogend * skyboxscale)
+ render.FogColor(fogr, fogg, fogb)
+ render.FogMaxDensity(1)
+
+ return true
+end
+
+function GM:PreDrawSkyBox()
+ self.DrawingInSky = true
+end
+
+local matSky = CreateMaterial("SkyOverride", "UnlitGeneric", {["$basetexture"] = "color/white", ["$vertexcolor"] = 1, ["$vertexalpha"] = 1, ["$model"] = 1})
+local colSky = Color(0, 30, 0)
+function GM:PostDrawSkyBox()
+ self.DrawingInSky = false
+
+ if self.DeathFog == 0 then return end
+
+ colSky.a = self.DeathFog * 230
+
+ cam.Start3D(EyePos(), EyeAngles())
+ render.SuppressEngineLighting(true)
+
+ render.SetMaterial(matSky)
+
+ render.DrawQuadEasy(Vector(0, 0, 10240), Vector(0, 0, -1), 20480, 20480, colSky, 0)
+ render.DrawQuadEasy(Vector(0, 10240, 0), Vector(0, -1, 0), 20480, 20480, colSky, 0)
+ render.DrawQuadEasy(Vector(0, -10240, 0), Vector(0, 1, 0), 20480, 20480, colSky, 0)
+ render.DrawQuadEasy(Vector(10240, 0, 0), Vector(-1, 0, 0), 20480, 20480, colSky, 0)
+ render.DrawQuadEasy(Vector(-10240, 0, 0), Vector(1, 0, 0), 20480, 20480, colSky, 0)
+
+ render.SuppressEngineLighting(false)
+ cam.End3D()
+end
+
+GM.DeathFog = 0
+GM.FogStart = 0
+GM.FogEnd = 8000
+GM.FogRed = 30
+GM.FogGreen = 30
+GM.FogBlue = 30
+function GM:GetFogData()
+ local fogstart, fogend = render.GetFogDistances()
+ local fogr, fogg, fogb = render.GetFogColor()
+
+ self.FogStart = fogstart
+ self.FogEnd = fogend
+ self.FogRed = fogr
+ self.FogGreen = fogg
+ self.FogBlue = fogb
+end
+
+local matAura = Material("models/debug/debugwhite")
+local skip = false
+function GM.PostPlayerDrawMedical(pl)
+ if not skip and pl:Team() == TEAM_HUMAN and pl ~= LocalPlayer() then
+ local eyepos = EyePos()
+ local dist = pl:NearestPoint(eyepos):Distance(eyepos)
+ if dist < MedicalAuraDistance then
+ local green = pl:Health() / pl:GetMaxHealth()
+
+ pl.SkipDrawHooks = true
+ skip = true
+
+ render.SuppressEngineLighting(true)
+ render.ModelMaterialOverride(matAura)
+ render.SetBlend((1 - (dist / MedicalAuraDistance)) * 0.1 * (1 + math.abs(math.sin((CurTime() + pl:EntIndex()) * 4)) * 0.05))
+ render.SetColorModulation(1 - green, green, 0)
+ pl:DrawModel()
+ render.SetColorModulation(1, 1, 1)
+ render.SetBlend(1)
+ render.ModelMaterialOverride()
+ render.SuppressEngineLighting(false)
+
+ skip = false
+ pl.SkipDrawHooks = false
+ end
+ end
+end
+
+function GM:OnReloaded()
+ self.BaseClass.OnReloaded(self)
+
+ self:LocalPlayerFound()
+end
+
+-- The whole point of this is so we don't need to check if the local player is valid 1000 times a second.
+function GM:LocalPlayerFound()
+ self.Think = self._Think
+ self.HUDShouldDraw = self._HUDShouldDraw
+ self.CachedFearPower = self._CachedFearPower
+ self.CalcView = self._CalcView
+ self.ShouldDrawLocalPlayer = self._ShouldDrawLocalPlayer
+ self.PostDrawOpaqueRenderables = self._PostDrawOpaqueRenderables
+ self.PostDrawTranslucentRenderables = self._PostDrawTranslucentRenderables
+ self.HUDPaint = self._HUDPaint
+ self.HUDPaintBackground = self._HUDPaintBackground
+ self.CreateMove = self._CreateMove
+ self.PrePlayerDraw = self._PrePlayerDraw
+ self.PostPlayerDraw = self._PostPlayerDraw
+ self.InputMouseApply = self._InputMouseApply
+ self.GUIMousePressed = self._GUIMousePressed
+ self.HUDWeaponPickedUp = self._HUDWeaponPickedUp
+
+ if render.GetDXLevel() >= 80 then
+ self.RenderScreenspaceEffects = self._RenderScreenspaceEffects
+ end
+end
+
+local currentpower = 0
+local spawngreen = 0
+local matFearMeter = Material("zombiesurvival/fearometer")
+local matNeedle = Material("zombiesurvival/fearometerneedle")
+local matEyeGlow = Material("Sprites/light_glow02_add_noz")
+function GM:DrawFearMeter(power, screenscale)
+ if currentpower < power then
+ currentpower = math.min(power, currentpower + FrameTime() * (math.tan(currentpower) * 2 + 0.05))
+ elseif power < currentpower then
+ currentpower = math.max(power, currentpower - FrameTime() * (math.tan(currentpower) * 2 + 0.05))
+ end
+
+ local w, h = ScrW(), ScrH()
+ local wid, hei = 192 * screenscale, 192 * screenscale
+ local mx, my = w * 0.5 - wid * 0.5, h - hei
+
+ surface_SetMaterial(matFearMeter)
+ surface_SetDrawColor(140, 140, 140, 240)
+ surface_DrawTexturedRect(mx, my, wid, hei)
+ if currentpower >= 0.75 then
+ local pulse = CurTime() % 3 - 1
+ if pulse > 0 then
+ pulse = pulse ^ 2
+ local pulsesize = pulse * screenscale * 28
+ surface_SetDrawColor(140, 140, 140, 120 - pulse * 120)
+ surface_DrawTexturedRect(mx - pulsesize, my - pulsesize, wid + pulsesize * 2, hei + pulsesize * 2)
+ end
+ end
+
+ surface_SetMaterial(matNeedle)
+ surface_SetDrawColor(160, 160, 160, 225)
+ local rot = math.Clamp((0.5 - currentpower) + math.sin(RealTime() * 10) * 0.01, -0.5, 0.5) * 300
+ surface_DrawTexturedRectRotated(w * 0.5 - math.max(0, rot * wid * -0.0001), h - hei * 0.5 - math.abs(rot) * hei * 0.00015, wid, hei, rot)
+
+ if MySelf:Team() == TEAM_UNDEAD then
+ if self:GetDynamicSpawning() and self:ShouldUseAlternateDynamicSpawn() then
+ local obs = MySelf:GetObserverTarget()
+ spawngreen = math.Approach(spawngreen, self:DynamicSpawnIsValid(obs and obs:IsValid() and obs:IsPlayer() and obs:Team() == TEAM_UNDEAD and obs or MySelf) and 1 or 0, FrameTime() * 4)
+
+ local sy = my + hei * 0.6953
+ local size = wid * 0.085
+
+ surface_SetMaterial(matEyeGlow)
+ surface_SetDrawColor(220 * (1 - spawngreen), 220 * spawngreen, 0, 240)
+ surface_DrawTexturedRectRotated(mx + wid * 0.459, sy, size, size, 0)
+ surface_DrawTexturedRectRotated(mx + wid * 0.525, sy, size, size, 0)
+ end
+
+ if currentpower > 0 and not self.ZombieEscape then
+ draw_SimpleTextBlurry(translate.Format("resist_x", math.ceil(self:GetDamageResistance(currentpower) * 100)), "ZSDamageResistance", w * 0.5, my + hei * 0.75, Color(currentpower * 200, 200 - currentpower * 200, 0, 255), TEXT_ALIGN_CENTER)
+ end
+ end
+end
+
+function GM:GetDynamicSpawning()
+ return not GetGlobalBool("DynamicSpawningDisabled", false)
+end
+
+GM.LastTimeDead = 0
+GM.LastTimeAlive = 0
+
+function GM:TrackLastDeath()
+ if MySelf:Alive() then
+ self.LastTimeAlive = CurTime()
+ else
+ self.LastTimeDead = CurTime()
+ end
+end
+
+function GM:IsClassicMode()
+ return GetGlobalBool("classicmode", false)
+end
+
+function GM:IsBabyMode()
+ return GetGlobalBool("babymode", false)
+end
+
+function GM:PostRender()
+ if self.m_ZombieVision and MySelf:IsValid() and MySelf:Team() == TEAM_UNDEAD then
+ local eyepos = EyePos()
+ local eyedir = EyeAngles():Forward()
+ local tr = util.TraceLine({start = eyepos, endpos = eyepos + eyedir * 128, mask = MASK_SOLID_BRUSHONLY})
+
+ local dlight = DynamicLight(MySelf:EntIndex())
+ if dlight then
+ dlight.Pos = tr.HitPos + tr.HitNormal * 2
+ dlight.r = 10
+ dlight.g = 255
+ dlight.b = 80
+ dlight.Brightness = 3
+ dlight.Size = 300
+ dlight.Decay = 900
+ dlight.DieTime = CurTime() + 1
+ end
+ end
+end
+
+local lastwarntim = -1
+GM.HeartBeatTime = 0
+GM.FOVLerp = 1
+GM.HurtEffect = 0
+GM.PrevHealth = 0
+local NextGas = 0
+function GM:_Think()
+ if self:GetEscapeStage() == ESCAPESTAGE_DEATH then
+ self.DeathFog = math.min(self.DeathFog + FrameTime() / 5, 1)
+
+ if CurTime() >= NextGas then
+ NextGas = CurTime() + 0.01
+
+ local eyepos = EyePos()
+
+ local emitter = ParticleEmitter(eyepos)
+
+ for i=1, 3 do
+ local randdir = VectorRand()
+ randdir.z = math.abs(randdir.z)
+ randdir:Normalize()
+ local emitpos = eyepos + randdir * math.Rand(0, 1200)
+
+ local particle = emitter:Add("particles/smokey", emitpos)
+ particle:SetVelocity(randdir * math.Rand(8, 256))
+ particle:SetAirResistance(16)
+ particle:SetDieTime(math.Rand(2.2, 3.5))
+ particle:SetStartAlpha(math.Rand(70, 90))
+ particle:SetEndAlpha(0)
+ particle:SetStartSize(1)
+ particle:SetEndSize(math.Rand(150, 325))
+ particle:SetRoll(math.Rand(0, 360))
+ particle:SetRollDelta(math.Rand(-1, 1))
+ particle:SetColor(0, math.Rand(20, 45), 0)
+ end
+
+ emitter:Finish()
+ end
+ elseif self.DeathFog > 0 then
+ self.DeathFog = math.max(self.DeathFog - FrameTime() / 5, 0)
+ end
+
+ local health = MySelf:Health()
+ if self.PrevHealth and health < self.PrevHealth then
+ self.HurtEffect = math.min(self.HurtEffect + (self.PrevHealth - health) * 0.02, 1.5)
+ elseif self.HurtEffect > 0 then
+ self.HurtEffect = math.max(0, self.HurtEffect - FrameTime() * 0.65)
+ end
+ self.PrevHealth = health
+
+ self:TrackLastDeath()
+
+ local endtime = self:GetWaveActive() and self:GetWaveEnd() or self:GetWaveStart()
+ if endtime ~= -1 then
+ local timleft = math.max(0, endtime - CurTime())
+ if timleft <= 10 and lastwarntim ~= math.ceil(timleft) then
+ lastwarntim = math.ceil(timleft)
+ if 0 < lastwarntim then
+ surface_PlaySound("buttons/lightswitch2.wav")
+ end
+ end
+ end
+
+ local myteam = MySelf:Team()
+
+ self:PlayBeats(myteam, self:CachedFearPower())
+
+ if myteam == TEAM_HUMAN then
+ local wep = MySelf:GetActiveWeapon()
+ if wep:IsValid() and wep.GetIronsights and wep:GetIronsights() then
+ self.FOVLerp = math.Approach(self.FOVLerp, wep.IronsightsMultiplier or 0.6, FrameTime() * 4)
+ elseif self.FOVLerp ~= 1 then
+ self.FOVLerp = math.Approach(self.FOVLerp, 1, FrameTime() * 5)
+ end
+
+ if MySelf:GetBarricadeGhosting() then
+ MySelf:BarricadeGhostingThink()
+ end
+ else
+ self.HeartBeatTime = self.HeartBeatTime + (6 + self:CachedFearPower() * 5) * FrameTime()
+
+ if not MySelf:Alive() then
+ self:ToggleZombieVision(false)
+ end
+ end
+
+ for _, pl in pairs(player.GetAll()) do
+ if pl:Team() == TEAM_UNDEAD then
+ local tab = pl:GetZombieClassTable()
+ if tab.BuildBonePositions then
+ pl.WasBuildingBonePositions = true
+ pl:ResetBones()
+ tab.BuildBonePositions(tab, pl)
+ elseif pl.WasBuildingBonePositions then
+ pl.WasBuildingBonePositions = nil
+ pl:ResetBones()
+ end
+ elseif pl.WasBuildingBonePositions then
+ pl.WasBuildingBonePositions = nil
+ pl:ResetBones()
+ end
+ end
+end
+
+function GM:ShouldPlayBeats(teamid, fear)
+ return not self.RoundEnded and not self.ZombieEscape and not GetGlobalBool("beatsdisabled", false)
+end
+
+local cv_ShouldPlayMusic = CreateClientConVar("zs_playmusic", 1, true, false)
+local NextBeat = 0
+local LastBeatLevel = 0
+function GM:PlayBeats(teamid, fear)
+ if RealTime() <= NextBeat or not gamemode.Call("ShouldPlayBeats", teamid, fear) then return end
+
+ if LASTHUMAN and cv_ShouldPlayMusic:GetBool() then
+ MySelf:EmitSound(self.LastHumanSound, 0, 100, self.BeatsVolume)
+ NextBeat = RealTime() + (self.SoundDuration[snd] or SoundDuration(self.LastHumanSound)) - 0.025
+ return
+ end
+
+ if fear <= 0 or not self.BeatsEnabled then return end
+
+ local beats = self.Beats[teamid == TEAM_HUMAN and self.BeatSetHuman or self.BeatSetZombie]
+ if not beats then return end
+
+ LastBeatLevel = math.Approach(LastBeatLevel, math.ceil(fear * 10), 3)
+
+ local snd = beats[LastBeatLevel]
+ if snd then
+ MySelf:EmitSound(snd, 0, 100, self.BeatsVolume)
+ NextBeat = RealTime() + (self.SoundDuration[snd] or SoundDuration(snd)) - 0.025
+ end
+end
+
+local colPackUp = Color(20, 255, 20, 220)
+local colPackUpNotOwner = Color(255, 240, 10, 220)
+function GM:DrawPackUpBar(x, y, fraction, notowner, screenscale)
+ local col = notowner and colPackUpNotOwner or colPackUp
+
+ local maxbarwidth = 270 * screenscale
+ local barheight = 11 * screenscale
+ local barwidth = maxbarwidth * math.Clamp(fraction, 0, 1)
+ local startx = x - maxbarwidth * 0.5
+
+ surface_SetDrawColor(0, 0, 0, 220)
+ surface_DrawRect(startx, y, maxbarwidth, barheight)
+ surface_SetDrawColor(col)
+ surface_DrawRect(startx + 3, y + 3, barwidth - 6, barheight - 6)
+ surface_DrawOutlinedRect(startx, y, maxbarwidth, barheight)
+
+ draw_SimpleText(notowner and CurTime() % 2 < 1 and translate.Format("requires_x_people", 4) or notowner and translate.Get("packing_others_object") or translate.Get("packing"), "ZSHUDFontSmall", x, y - draw_GetFontHeight("ZSHUDFontSmall") - 2, col, TEXT_ALIGN_CENTER)
+end
+
+function GM:HumanHUD(screenscale)
+ local curtime = CurTime()
+ local w, h = ScrW(), ScrH()
+
+ local packup = MySelf.PackUp
+ if packup and packup:IsValid() then
+ self:DrawPackUpBar(w * 0.5, h * 0.55, 1 - packup:GetTimeRemaining() / packup:GetMaxTime(), packup:GetNotOwner(), screenscale)
+ end
+
+ if not self.RoundEnded then
+ if self:GetWave() == 0 and not self:GetWaveActive() then
+ local txth = draw_GetFontHeight("ZSHUDFontSmall")
+ draw_SimpleTextBlurry(translate.Get("waiting_for_players").." "..util.ToMinutesSeconds(math.max(0, self:GetWaveStart() - curtime)), "ZSHUDFontSmall", w * 0.5, h * 0.25, COLOR_GRAY, TEXT_ALIGN_CENTER)
+ draw_SimpleTextBlurry(translate.Get("humans_closest_to_spawns_are_zombies"), "ZSHUDFontSmall", w * 0.5, h * 0.25 + txth, COLOR_GRAY, TEXT_ALIGN_CENTER)
+
+ local desiredzombies = self:GetDesiredStartingZombies()
+
+ draw_SimpleTextBlurry(translate.Format("number_of_initial_zombies_this_game", self.WaveOneZombies * 100, desiredzombies), "ZSHUDFontSmall", w * 0.5, h * 0.75, COLOR_GRAY, TEXT_ALIGN_CENTER)
+
+ draw_SimpleTextBlurry(translate.Get("zombie_volunteers"), "ZSHUDFontSmall", w * 0.5, h * 0.75 + txth, COLOR_GRAY, TEXT_ALIGN_CENTER)
+ local y = h * 0.75 + txth * 2
+
+ txth = draw_GetFontHeight("ZSHUDFontTiny")
+ for i, pl in ipairs(self.ZombieVolunteers) do
+ if pl:IsValid() then
+ draw_SimpleTextBlurry(pl:Name(), "ZSHUDFontTiny", w * 0.5, y, pl == MySelf and COLOR_RED or COLOR_GRAY, TEXT_ALIGN_CENTER)
+ y = y + txth
+ end
+ end
+ end
+
+ local drown = MySelf.status_drown
+ if drown and drown:IsValid() then
+ surface_SetDrawColor(0, 0, 0, 60)
+ surface_DrawRect(w * 0.4, h * 0.35, w * 0.2, 12)
+ surface_SetDrawColor(30, 30, 230, 180)
+ surface_DrawOutlinedRect(w * 0.4, h * 0.35, w * 0.2, 12)
+ surface_DrawRect(w * 0.4, h * 0.35, w * 0.2 * (1 - drown:GetDrown()), 12)
+ draw_SimpleTextBlurry(translate.Get("breath").." ", "ZSHUDFontSmall", w * 0.4, h * 0.35 + 6, COLOR_BLUE, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER)
+ end
+ end
+
+ if gamemode.Call("PlayerCanPurchase", MySelf) then
+ if self:GetWaveActive() then
+ draw_SimpleTextBlurry(translate.Get("press_f2_for_the_points_shop"), "ZSHUDFontSmall", w * 0.5, 8, COLOR_GRAY, TEXT_ALIGN_CENTER)
+ else
+ local th = draw_GetFontHeight("ZSHUDFontSmall")
+ draw_SimpleTextBlurry(translate.Get("press_f2_for_the_points_shop"), "ZSHUDFontSmall", w * 0.5, 8, COLOR_GRAY, TEXT_ALIGN_CENTER)
+ draw_SimpleTextBlurry(translate.Format("x_discount_for_buying_between_waves", self.ArsenalCrateDiscountPercentage), "ZSHUDFontSmall", w * 0.5, 9 + th, COLOR_GRAY, TEXT_ALIGN_CENTER)
+ end
+ end
+end
+
+function GM:HUDPaint()
+end
+
+function GM:_HUDPaint()
+ if self.FilmMode then return end
+
+ local screenscale = BetterScreenScale()
+
+ local myteam = MySelf:Team()
+
+ self:HUDDrawTargetID(myteam, screenscale)
+
+ if self:GetWave() > 0 then
+ self:DrawFearMeter(self:CachedFearPower(), screenscale)
+ end
+
+ if myteam == TEAM_UNDEAD then
+ self:ZombieHUD()
+ else
+ self:HumanHUD(screenscale)
+ end
+
+ if GetGlobalBool("classicmode") then
+ draw_SimpleTextBlurry(translate.Get("classic_mode"), "ZSHUDFontSmaller", 4, ScrH() - 4, COLOR_GRAY, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
+ end
+end
+
+function GM:ZombieObserverHUD(obsmode)
+ local w, h = ScrW(), ScrH()
+ local texh = draw_GetFontHeight("ZSHUDFontSmall")
+
+ local dyn
+
+ if obsmode == OBS_MODE_CHASE then
+ local target = MySelf:GetObserverTarget()
+ if target and target:IsValid() then
+ if target:IsPlayer() and target:Team() == TEAM_UNDEAD then
+ draw_SimpleTextBlur(translate.Format("observing_x", target:Name(), math.max(0, target:Health())), "ZSHUDFontSmall", w * 0.5, h * 0.75 - texh - 32, COLOR_DARKRED, TEXT_ALIGN_CENTER)
+ end
+
+ dyn = self:GetDynamicSpawning() and self:DynamicSpawnIsValid(target)
+ end
+ end
+
+ if self:GetWaveActive() then
+ draw_SimpleTextBlur(dyn and translate.Get("press_lmb_to_spawn_on_them") or translate.Get("press_lmb_to_spawn"), "ZSHUDFontSmall", w * 0.5, h * 0.75, dyn and COLOR_DARKGREEN or COLOR_DARKRED, TEXT_ALIGN_CENTER)
+ end
+
+ local space = texh + 8
+ draw_SimpleTextBlur(translate.Get("press_rmb_to_cycle_targets"), "ZSHUDFontSmall", w * 0.5, h * 0.75 + space, COLOR_DARKRED, TEXT_ALIGN_CENTER)
+ draw_SimpleTextBlur(translate.Get("press_reload_to_spawn_at_normal_point"), "ZSHUDFontSmall", w * 0.5, h * 0.75 + space * 2, COLOR_DARKRED, TEXT_ALIGN_CENTER)
+ draw_SimpleTextBlur(translate.Get("press_jump_to_free_roam"), "ZSHUDFontSmall", w * 0.5, h * 0.75 + space * 3, COLOR_DARKRED, TEXT_ALIGN_CENTER)
+
+ for _, ent in pairs(ents.FindByClass("prop_thrownbaby")) do
+ if ent:GetSettled() then
+ draw_SimpleTextBlur(translate.Format("press_walk_to_spawn_as_x", self.ZombieClasses["Gore Child"].Name), "ZSHUDFontSmall", w * 0.5, h * 0.75 + space * 3, COLOR_DARKRED, TEXT_ALIGN_CENTER)
+ break
+ end
+ end
+end
+
+local matHumanHeadID = Material("zombiesurvival/humanhead")
+local matZombieHeadID = Material("zombiesurvival/zombiehead")
+local colLifeStats = Color(255, 0, 0, 255)
+function GM:ZombieHUD()
+ if self.LifeStatsEndTime and CurTime() < self.LifeStatsEndTime and (self.LifeStatsBarricadeDamage > 0 or self.LifeStatsHumanDamage > 0 or self.LifeStatsBrainsEaten > 0) then
+ colLifeStats.a = math.Clamp((self.LifeStatsEndTime - CurTime()) / (self.LifeStatsLifeTime * 0.33), 0, 1) * 255
+
+ local th = draw_GetFontHeight("ZSHUDFontSmall")
+ local x = ScrW() * 0.75
+ local y = ScrH() * 0.75
+
+ draw_SimpleTextBlur(translate.Get("that_life"), "ZSHUDFontSmall", x, y, colLifeStats, TEXT_ALIGN_LEFT)
+ y = y + th
+
+ if self.LifeStatsBarricadeDamage > 0 then
+ draw_SimpleTextBlur(translate.Format("x_damage_to_barricades", self.LifeStatsBarricadeDamage), "ZSHUDFontSmall", x, y, colLifeStats, TEXT_ALIGN_LEFT)
+ y = y + th
+ end
+ if self.LifeStatsHumanDamage > 0 then
+ draw_SimpleTextBlur(translate.Format("x_damage_to_humans", self.LifeStatsHumanDamage), "ZSHUDFontSmall", x, y, colLifeStats, TEXT_ALIGN_LEFT)
+ y = y + th
+ end
+ if self.LifeStatsBrainsEaten > 0 then
+ draw_SimpleTextBlur(translate.Format("x_brains_eaten", self.LifeStatsBrainsEaten), "ZSHUDFontSmall", x, y, colLifeStats, TEXT_ALIGN_LEFT)
+ y = y + th
+ end
+ end
+
+ local obsmode = MySelf:GetObserverMode()
+ if obsmode ~= OBS_MODE_NONE then
+ self:ZombieObserverHUD(obsmode)
+ elseif not self:GetWaveActive() and not MySelf:Alive() then
+ draw_SimpleTextBlur(translate.Get("waiting_for_next_wave"), "ZSHUDFont", ScrW() * 0.5, ScrH() * 0.3, COLOR_DARKRED, TEXT_ALIGN_CENTER)
+
+ if MySelf:GetZombieClassTable().NeverAlive then
+ for _, ent in pairs(ents.FindByClass("prop_thrownbaby")) do
+ if ent:GetSettled() then
+ draw_SimpleTextBlur(translate.Format("press_walk_to_spawn_as_x", self.ZombieClasses["Gore Child"].Name), "ZSHUDFontSmall", w * 0.5, h * 0.75, COLOR_DARKRED, TEXT_ALIGN_CENTER)
+ break
+ end
+ end
+ end
+ end
+end
+
+function GM:RequestedDefaultCart()
+ local defaultcart = GetConVarString("zs_defaultcart")
+ if #defaultcart > 0 then
+ defaultcart = string.lower(defaultcart)
+
+ for i, carttab in ipairs(self.SavedCarts) do
+ if carttab[1] and string.lower(carttab[1]) == defaultcart then
+ gamemode.Call("SuppressArsenalUpgrades", 1)
+ RunConsoleCommand("worthcheckout", unpack(carttab[2]))
+
+ return
+ end
+ end
+
+ RunConsoleCommand("worthrandom")
+ end
+end
+
+function GM:_PostDrawTranslucentRenderables()
+ if not self.DrawingInSky then
+ self:DrawPointWorldHints()
+ self:DrawWorldHints()
+ end
+end
+
+function GM:RestartRound()
+ self.TheLastHuman = nil
+ self.RoundEnded = nil
+ LASTHUMAN = nil
+
+ if pEndBoard and pEndBoard:Valid() then
+ pEndBoard:Remove()
+ pEndBoard = nil
+ end
+
+ self:InitPostEntity()
+
+ self:RevertZombieClasses()
+end
+
+function GM:_HUDShouldDraw(name)
+ if self.FilmMode and name ~= "CHudWeaponSelection" then return false end
+
+ return name ~= "CHudHealth" and name ~= "CHudBattery"
+ and name ~= "CHudAmmo" and name ~= "CHudSecondaryAmmo"
+ and name ~= "CHudDamageIndicator"
+end
+
+local Current = 0
+local NextCalculate = 0
+function GM:_CachedFearPower()
+ if CurTime() >= NextCalculate then
+ NextCalculate = CurTime() + 0.15
+ Current = self:GetFearMeterPower(EyePos(), TEAM_UNDEAD, MySelf)
+ end
+
+ return Current
+end
+
+function surface.CreateLegacyFont(font, size, weight, antialias, additive, name, shadow, outline, blursize)
+ surface.CreateFont(name, {font = font, size = size, weight = weight, antialias = antialias, additive = additive, shadow = shadow, outline = outline, blursize = blursize})
+end
+
+function GM:CreateFonts()
+ local fontfamily = "Typenoksidi"
+ local fontfamily3d = "hidden"
+ local fontweight = 0
+ local fontweight3D = 0
+ local fontaa = true
+ local fontshadow = false
+ local fontoutline = true
+
+ surface.CreateLegacyFont("csd", 42, 500, true, false, "healthsign", false, true)
+ surface.CreateLegacyFont("tahoma", 96, 1000, true, false, "zshintfont", false, true)
+
+ surface.CreateLegacyFont(fontfamily3d, 48, fontweight3D, false, false, "ZS3D2DFontSmall", false, true)
+ surface.CreateLegacyFont(fontfamily3d, 72, fontweight3D, false, false, "ZS3D2DFont", false, true)
+ surface.CreateLegacyFont(fontfamily3d, 128, fontweight3D, false, false, "ZS3D2DFontBig", false, true)
+ surface.CreateLegacyFont(fontfamily3d, 48, fontweight3D, false, false, "ZS3D2DFontSmallBlur", false, false, 16)
+ surface.CreateLegacyFont(fontfamily3d, 72, fontweight3D, false, false, "ZS3D2DFontBlur", false, false, 16)
+ surface.CreateLegacyFont(fontfamily3d, 128, fontweight3D, false, false, "ZS3D2DFontBigBlur", false, false, 16)
+ surface.CreateLegacyFont(fontfamily, 40, fontweight3D, false, false, "ZS3D2DFont2Smaller", false, true)
+ surface.CreateLegacyFont(fontfamily, 48, fontweight3D, false, false, "ZS3D2DFont2Small", false, true)
+ surface.CreateLegacyFont(fontfamily, 72, fontweight3D, false, false, "ZS3D2DFont2", false, true)
+ surface.CreateLegacyFont(fontfamily, 128, fontweight3D, false, false, "ZS3D2DFont2Big", false, true)
+ surface.CreateLegacyFont(fontfamily, 40, fontweight3D, false, false, "ZS3D2DFont2SmallerBlur", false, false, 16)
+ surface.CreateLegacyFont(fontfamily, 48, fontweight3D, false, false, "ZS3D2DFont2SmallBlur", false, false, 16)
+ surface.CreateLegacyFont(fontfamily, 72, fontweight3D, false, false, "ZS3D2DFont2Blur", false, false, 16)
+ surface.CreateLegacyFont(fontfamily, 128, fontweight3D, false, false, "ZS3D2DFont2BigBlur", false, false, 16)
+
+ local screenscale = BetterScreenScale()
+
+ surface.CreateLegacyFont("csd", screenscale * 36, 100, true, false, "zsdeathnoticecs", false, true)
+ surface.CreateLegacyFont("HL2MP", screenscale * 36, 100, true, false, "zsdeathnotice", false, true)
+
+ surface.CreateLegacyFont(fontfamily, screenscale * 16, fontweight, fontaa, false, "ZSHUDFontTiny", fontshadow, fontoutline)
+ surface.CreateLegacyFont(fontfamily, screenscale * 20, fontweight, fontaa, false, "ZSHUDFontSmallest", fontshadow, fontoutline)
+ surface.CreateLegacyFont(fontfamily, screenscale * 22, fontweight, fontaa, false, "ZSHUDFontSmaller", fontshadow, fontoutline)
+ surface.CreateLegacyFont(fontfamily, screenscale * 28, fontweight, fontaa, false, "ZSHUDFontSmall", fontshadow, fontoutline)
+ surface.CreateLegacyFont(fontfamily, screenscale * 42, fontweight, fontaa, false, "ZSHUDFont", fontshadow, fontoutline)
+ surface.CreateLegacyFont(fontfamily, screenscale * 72, fontweight, fontaa, false, "ZSHUDFontBig", fontshadow, fontoutline)
+ surface.CreateLegacyFont(fontfamily, screenscale * 16, fontweight, fontaa, false, "ZSHUDFontTinyBlur", false, false, 8)
+ surface.CreateLegacyFont(fontfamily, screenscale * 22, fontweight, fontaa, false, "ZSHUDFontSmallerBlur", false, false, 8)
+ surface.CreateLegacyFont(fontfamily, screenscale * 28, fontweight, fontaa, false, "ZSHUDFontSmallBlur", false, false, 8)
+ surface.CreateLegacyFont(fontfamily, screenscale * 42, fontweight, fontaa, false, "ZSHUDFontBlur", false, false, 8)
+ surface.CreateLegacyFont(fontfamily, screenscale * 72, fontweight, fontaa, false, "ZSHUDFontBigBlur", false, false, 8)
+
+ surface.CreateLegacyFont(fontfamily, screenscale * 16, 0, fontaa, false, "ZSAmmoName", false, false)
+ surface.CreateLegacyFont(fontfamily, screenscale * 16, fontweight, fontaa, false, "ZSHUDFontTinyNS", false, false)
+ surface.CreateLegacyFont(fontfamily, screenscale * 20, fontweight, fontaa, false, "ZSHUDFontSmallestNS", false, false)
+ surface.CreateLegacyFont(fontfamily, screenscale * 22, fontweight, fontaa, false, "ZSHUDFontSmallerNS", false, false)
+ surface.CreateLegacyFont(fontfamily, screenscale * 28, fontweight, fontaa, false, "ZSHUDFontSmallNS", false, false)
+ surface.CreateLegacyFont(fontfamily, screenscale * 42, fontweight, fontaa, false, "ZSHUDFontNS", false, false)
+ surface.CreateLegacyFont(fontfamily, screenscale * 72, fontweight, fontaa, false, "ZSHUDFontBigNS", false, false)
+
+ surface.CreateLegacyFont(fontfamily, screenscale * 16, 0, true, false, "ZSDamageResistance", false, true)
+ surface.CreateLegacyFont(fontfamily, screenscale * 16, 0, true, false, "ZSDamageResistanceBlur", false, true)
+
+ surface.CreateLegacyFont(fontfamily, 32, fontweight, true, false, "ZSScoreBoardTitle", false, true)
+ surface.CreateLegacyFont(fontfamily, 22, fontweight, true, false, "ZSScoreBoardSubTitle", false, true)
+ surface.CreateLegacyFont(fontfamily, 16, fontweight, true, false, "ZSScoreBoardPlayer", false, true)
+ surface.CreateLegacyFont(fontfamily, 24, fontweight, true, false, "ZSScoreBoardHeading", false, false)
+ surface.CreateLegacyFont("arial", 20, 0, true, false, "ZSScoreBoardPlayerSmall", false, true)
+
+ -- Default, DefaultBold, DefaultSmall, etc. were changed when gmod13 hit. These are renamed fonts that have the old values.
+ surface.CreateFont("DefaultFontVerySmall", {font = "tahoma", size = 10, weight = 0, antialias = false})
+ surface.CreateFont("DefaultFontSmall", {font = "tahoma", size = 11, weight = 0, antialias = false})
+ surface.CreateFont("DefaultFontSmallDropShadow", {font = "tahoma", size = 11, weight = 0, shadow = true, antialias = false})
+ surface.CreateFont("DefaultFont", {font = "tahoma", size = 13, weight = 500, antialias = false})
+ surface.CreateFont("DefaultFontBold", {font = "tahoma", size = 13, weight = 1000, antialias = false})
+ surface.CreateFont("DefaultFontLarge", {font = "tahoma", size = 16, weight = 0, antialias = false})
+end
+
+function GM:EvaluateFilmMode()
+ local visible = not self.FilmMode
+
+ if self.GameStatePanel and self.GameStatePanel:Valid() then
+ self.GameStatePanel:SetVisible(visible)
+ end
+
+ if self.TopNotificationHUD and self.TopNotificationHUD:Valid() then
+ self.TopNotificationHUD:SetVisible(visible)
+ end
+
+ if self.CenterNotificationHUD and self.CenterNotificationHUD:Valid() then
+ self.CenterNotificationHUD:SetVisible(visible)
+ end
+
+ if self.HealthHUD and self.HealthHUD:Valid() then
+ self.HealthHUD:SetVisible(visible)
+ end
+end
+
+function GM:CreateVGUI()
+ local screenscale = BetterScreenScale()
+ self.GameStatePanel = vgui.Create("DGameState")
+ self.GameStatePanel:SetTextFont("ZSHUDFontSmaller")
+ self.GameStatePanel:SetAlpha(220)
+ self.GameStatePanel:SetSize(screenscale * 420, screenscale * 80)
+ self.GameStatePanel:ParentToHUD()
+
+ self.TopNotificationHUD = vgui.Create("DEXNotificationsList")
+ self.TopNotificationHUD:SetAlign(RIGHT)
+ self.TopNotificationHUD.PerformLayout = function(pan)
+ local screenscale = BetterScreenScale()
+ pan:SetSize(ScrW() * 0.4, ScrH() * 0.6)
+ pan:AlignTop(16 * screenscale)
+ pan:AlignRight()
+ end
+ self.TopNotificationHUD:InvalidateLayout()
+ self.TopNotificationHUD:ParentToHUD()
+
+ self.CenterNotificationHUD = vgui.Create("DEXNotificationsList")
+ self.CenterNotificationHUD:SetAlign(CENTER)
+ self.CenterNotificationHUD:SetMessageHeight(36)
+ self.CenterNotificationHUD.PerformLayout = function(pan)
+ local screenscale = BetterScreenScale()
+ pan:SetSize(ScrW() * 0.5, ScrH() * 0.35)
+ pan:CenterHorizontal()
+ pan:AlignBottom(16 * screenscale)
+ end
+ self.CenterNotificationHUD:InvalidateLayout()
+ self.CenterNotificationHUD:ParentToHUD()
+end
+
+function GM:Initialize()
+ self:CreateFonts()
+ self:PrecacheResources()
+ self:CreateVGUI()
+ self:InitializeBeats()
+ self:AddCustomAmmo()
+end
+
+local function FirstOfGoodType(a)
+ for _, v in pairs(a) do
+ local ext = string.sub(v, -4)
+ if ext == ".ogg" or ext == ".wav" or ext == ".mp3" then
+ return v
+ end
+ end
+end
+
+GM.Beats = {}
+function GM:InitializeBeats()
+ local _, dirs = file.Find("sound/zombiesurvival/beats/*", "GAME")
+ for _, dirname in pairs(dirs) do
+ if dirname == "none" or dirname == "default" then continue end
+
+ self.Beats[dirname] = {}
+ local highestexist
+ for i=1, 10 do
+ local a, __ = file.Find("sound/zombiesurvival/beats/"..dirname.."/"..i..".*", "GAME")
+ local a1 = FirstOfGoodType(a)
+ if a1 then
+ local filename = "zombiesurvival/beats/"..dirname.."/"..a1
+ if file.Exists("sound/"..filename, "GAME") then
+ self.Beats[dirname][i] = Sound(filename)
+ highestexist = filename
+
+ continue
+ end
+ end
+
+ if highestexist then
+ self.Beats[dirname][i] = highestexist
+ end
+ end
+ end
+end
+
+function GM:PlayerDeath(pl, attacker)
+end
+
+function GM:OnPlayerHitGround(pl, inwater, hitfloater, speed)
+ if inwater then return true end
+
+ if pl:Team() == TEAM_UNDEAD then
+ if pl:GetZombieClassTable().NoFallDamage then return true end
+
+ speed = math.max(0, speed - 200)
+ end
+
+ if pl:Team() ~= TEAM_UNDEAD or not pl:GetZombieClassTable().NoFallSlowdown then
+ pl:RawCapLegDamage(CurTime() + math.min(2, speed * 0.0035))
+ end
+
+ return true
+end
+
+function GM:LastHuman(pl)
+ if not IsValid(pl) then pl = nil end
+
+ self.TheLastHuman = pl
+
+ if not LASTHUMAN then
+ LASTHUMAN = true
+ timer.Simple(0.5, function() GAMEMODE:LastHumanMessage() end)
+ end
+end
+
+function GM:LastHumanMessage()
+ if self.RoundEnded or not MySelf:IsValid() then return end
+
+ local icon = self.PantsMode and "weapon_zs_legs" or "default"
+ if MySelf:Team() == TEAM_UNDEAD or not MySelf:Alive() then
+ self:CenterNotify({killicon = icon}, {font = "ZSHUDFont"}, " ", COLOR_RED, translate.Get(self.PantsMode and "kick_the_last_human" or "kill_the_last_human"), {killicon = icon})
+ else
+ self:CenterNotify({font = "ZSHUDFont"}, " ", COLOR_RED, translate.Get("you_are_the_last_human"))
+ self:CenterNotify({killicon = icon}, " ", COLOR_RED, translate.Format(self.PantsMode and "x_pants_out_to_get_you" or "x_zombies_out_to_get_you", team.NumPlayers(TEAM_UNDEAD)), {killicon = icon})
+ end
+end
+
+function GM:PlayerShouldTakeDamage(pl, attacker)
+ return pl == attacker or not attacker:IsPlayer() or pl:Team() ~= attacker:Team() or pl.AllowTeamDamage or attacker.AllowTeamDamage
+end
+
+function GM:SetWave(wave)
+ SetGlobalInt("wave", wave)
+end
+
+--[[local texGradientUp = surface.GetTextureID("vgui/gradient_up")
+local texGradientDown = surface.GetTextureID("vgui/gradient_down")
+local texGradientRight = surface.GetTextureID("vgui/gradient-r")]]
+local matFilmGrain = Material("zombiesurvival/filmgrain/filmgrain")
+--local color_black = color_black
+function GM:_HUDPaintBackground()
+ --[[local w, h = ScrW(), ScrH()
+ local bordersize = BetterScreenScale() * 32
+
+ surface_SetDrawColor(color_black)
+
+ surface_SetTexture(texGradientDown)
+ surface_DrawTexturedRect(0, 0, w, bordersize)
+ surface_SetTexture(texGradientUp)
+ surface_DrawTexturedRect(0, h - bordersize, w, bordersize)
+ surface_SetTexture(texGradientRight)
+ surface_DrawTexturedRectRotated(bordersize / 2, h / 2, bordersize, h, 180)
+ surface_DrawTexturedRect(w - bordersize, 0, bordersize, h)]]
+
+ if self.FilmGrainEnabled and MySelf:Team() == TEAM_HUMAN then
+ surface_SetMaterial(matFilmGrain)
+ surface_SetDrawColor(0, 0, 0, (0.25 + 0.75 * self:CachedFearPower()) * self.FilmGrainOpacity)
+ surface_DrawTexturedRectUV(0, 0, ScrW(), ScrH(), 2, 2, 0, 0)
+ end
+
+ local wep = MySelf:GetActiveWeapon()
+ if wep:IsValid() and wep.DrawHUDBackground then
+ wep:DrawHUDBackground()
+ end
+end
+
+local function GiveWeapon()
+ RunConsoleCommand("zsgiveweapon")
+end
+local function GiveWeaponClip()
+ RunConsoleCommand("zsgiveweaponclip")
+end
+local function DropWeapon()
+ RunConsoleCommand("zsdropweapon")
+end
+local function EmptyClip()
+ RunConsoleCommand("zsemptyclip")
+end
+function GM:HumanMenu()
+ if self.ZombieEscape then return end
+
+ local ent = MySelf:MeleeTrace(48, 2).Entity
+ if self:ValidMenuLockOnTarget(MySelf, ent) then
+ self.HumanMenuLockOn = ent
+ else
+ self.HumanMenuLockOn = nil
+ end
+
+ if self.HumanMenuPanel and self.HumanMenuPanel:Valid() then
+ self.HumanMenuPanel:SetVisible(true)
+ self.HumanMenuPanel:OpenMenu()
+ return
+ end
+
+ local panel = vgui.Create("DSideMenu")
+ self.HumanMenuPanel = panel
+
+ local screenscale = BetterScreenScale()
+ for k, v in pairs(self.AmmoNames) do
+ local b = vgui.Create("DAmmoCounter", panel)
+ b:SetAmmoType(k)
+ b:SetTall(screenscale * 36)
+ panel:AddItem(b)
+ end
+
+ local b = EasyButton(panel, "Give Weapon", 8, 4)
+ b.DoClick = GiveWeapon
+ panel:AddItem(b)
+ b = EasyButton(panel, "Give Weapon and 5 clips", 8, 4)
+ b.DoClick = GiveWeaponClip
+ panel:AddItem(b)
+ b = EasyButton(panel, "Drop weapon", 8, 4)
+ b.DoClick = DropWeapon
+ panel:AddItem(b)
+ b = EasyButton(panel, "Empty clip", 8, 4)
+ b.DoClick = EmptyClip
+ panel:AddItem(b)
+
+ panel:OpenMenu()
+end
+
+GM.ZombieThirdPerson = false
+function GM:PlayerBindPress(pl, bind, wasin)
+ if bind == "gmod_undo" or bind == "undo" then
+ RunConsoleCommand("+zoom")
+ timer.CreateEx("ReleaseZoom", 1, 1, RunConsoleCommand, "-zoom")
+ elseif bind == "+menu_context" then
+ self.ZombieThirdPerson = not self.ZombieThirdPerson
+ end
+end
+
+function GM:_ShouldDrawLocalPlayer(pl)
+ return pl:Team() == TEAM_UNDEAD and (self.ZombieThirdPerson or pl:CallZombieFunction("ShouldDrawLocalPlayer")) or pl:IsPlayingTaunt()
+end
+
+local roll = 0
+function GM:_CalcView(pl, origin, angles, fov, znear, zfar)
+ if pl.Confusion and pl.Confusion:IsValid() then
+ pl.Confusion:CalcView(pl, origin, angles, fov, znear, zfar)
+ end
+
+ if pl.Revive and pl.Revive:IsValid() and pl.Revive.GetRagdollEyes then
+ local rpos, rang = pl.Revive:GetRagdollEyes(pl)
+ if rpos then
+ origin = rpos
+ angles = rang
+ end
+ elseif pl.KnockedDown and pl.KnockedDown:IsValid() then
+ local rpos, rang = self:GetRagdollEyes(pl)
+ if rpos then
+ origin = rpos
+ angles = rang
+ end
+ elseif pl:ShouldDrawLocalPlayer() and pl:OldAlive() then
+ origin = pl:GetThirdPersonCameraPos(origin, angles)
+ end
+
+ local targetroll = 0
+ if self.MovementViewRoll then
+ local dir = pl:GetVelocity()
+ local speed = dir:Length()
+ dir:Normalize()
+
+ targetroll = targetroll + dir:Dot(angles:Right()) * math.min(30, speed / 100)
+ end
+
+ if pl:WaterLevel() >= 3 then
+ targetroll = targetroll + math.sin(CurTime()) * 7
+ end
+
+ roll = math.Approach(roll, targetroll, math.max(0.25, math.sqrt(math.abs(roll))) * 30 * FrameTime())
+ angles.roll = angles.roll + roll
+
+ if pl:IsPlayingTaunt() then
+ self:CalcViewTaunt(pl, origin, angles, fov, zclose, zfar)
+ end
+
+ local target = pl:GetObserverTarget()
+ if target and target:IsValid() then
+ local lasttarget = self.LastObserverTarget
+ if lasttarget and lasttarget:IsValid() and target ~= lasttarget then
+ if self.LastObserverTargetLerp then
+ if CurTime() >= self.LastObserverTargetLerp then
+ self.LastObserverTarget = nil
+ self.LastObserverTargetLerp = nil
+ else
+ local delta = math.Clamp((self.LastObserverTargetLerp - CurTime()) / 0.3333, 0, 1) ^ 0.5
+ origin:Set(self.LastObserverTargetPos * delta + origin * (1 - delta))
+ end
+ else
+ self.LastObserverTargetLerp = CurTime() + 0.3333
+ end
+ else
+ self.LastObserverTarget = target
+ self.LastObserverTargetPos = origin
+ end
+ end
+
+ pl:CallZombieFunction("CalcView", origin, angles)
+
+ return self.BaseClass.CalcView(self, pl, origin, angles, fov, znear, zfar)
+end
+
+function GM:CalcViewTaunt(pl, origin, angles, fov, zclose, zfar)
+ local tr = util.TraceHull({start = origin, endpos = origin - angles:Forward() * 72, mins = Vector(-2, -2, -2), maxs = Vector(2, 2, 2), mask = MASK_OPAQUE, filter = pl})
+ origin:Set(tr.HitPos + tr.HitNormal * 2)
+end
+
+local staggerdir = VectorRand():GetNormalized()
+function GM:_CreateMove(cmd)
+ if MySelf:IsPlayingTaunt() and MySelf:Alive() then
+ self:CreateMoveTaunt(cmd)
+ return
+ end
+
+ if MySelf:GetLegDamage() >= 0.5 then
+ local buttons = cmd:GetButtons()
+ if bit.band(buttons, IN_JUMP) ~= 0 then
+ cmd:SetButtons(buttons - IN_JUMP)
+ end
+ end
+
+ if MySelf:Team() == TEAM_HUMAN then
+ if MySelf:Alive() then
+ local lockon = self.HumanMenuLockOn
+ if lockon then
+ if self:ValidMenuLockOnTarget(MySelf, lockon) and self.HumanMenuPanel and self.HumanMenuPanel:Valid() and self.HumanMenuPanel:IsVisible() and MySelf:KeyDown(self.MenuKey) then
+ local oldang = cmd:GetViewAngles()
+ local newang = (lockon:EyePos() - EyePos()):Angle()
+ --oldang.pitch = math.ApproachAngle(oldang.pitch, newang.pitch, FrameTime() * math.max(45, math.abs(math.AngleDifference(oldang.pitch, newang.pitch)) ^ 1.3))
+ oldang.yaw = math.ApproachAngle(oldang.yaw, newang.yaw, FrameTime() * math.max(45, math.abs(math.AngleDifference(oldang.yaw, newang.yaw)) ^ 1.3))
+ cmd:SetViewAngles(oldang)
+ else
+ self.HumanMenuLockOn = nil
+ end
+ else
+ local maxhealth = MySelf:GetMaxHealth()
+ local threshold = MySelf:GetPalsy() and maxhealth - 1 or maxhealth * 0.25
+ local health = MySelf:Health()
+ if health <= threshold then
+ local ft = FrameTime()
+
+ staggerdir = (staggerdir + ft * 8 * VectorRand()):GetNormalized()
+
+ local ang = cmd:GetViewAngles()
+ local rate = ft * ((threshold - health) / threshold) * 7
+ ang.pitch = math.NormalizeAngle(ang.pitch + staggerdir.z * rate)
+ ang.yaw = math.NormalizeAngle(ang.yaw + staggerdir.x * rate)
+ cmd:SetViewAngles(ang)
+ end
+ end
+ end
+ else
+ MySelf:CallZombieFunction("CreateMove", cmd)
+ end
+end
+
+function GM:CreateMoveTaunt(cmd)
+ cmd:ClearButtons(0)
+ cmd:ClearMovement()
+end
+
+function GM:PostProcessPermitted(str)
+ return false
+end
+
+function GM:HUDPaintEndRound()
+end
+
+function GM:PreDrawViewModel(vm, pl, wep)
+ if pl and pl:IsValid() and pl:IsHolding() then return true end
+
+ if wep and wep:IsValid() and wep.PreDrawViewModel then
+ return wep:PreDrawViewModel(vm)
+ end
+end
+
+function GM:PostDrawViewModel(vm, pl, wep)
+ if wep and wep:IsValid() then
+ if wep.UseHands or not wep:IsScripted() then
+ local hands = pl:GetHands()
+ if hands and hands:IsValid() then
+ hands:DrawModel()
+ end
+ end
+
+ if wep.PostDrawViewModel then
+ wep:PostDrawViewModel(vm)
+ end
+ end
+end
+
+local undomodelblend = false
+local undozombievision = false
+local matWhite = Material("models/debug/debugwhite")
+function GM:_PrePlayerDraw(pl)
+ if pl:CallZombieFunction("PrePlayerDraw") then return true end
+
+ local shadowman = false
+
+ if pl.status_overridemodel and pl.status_overridemodel:IsValid() and self:ShouldDrawLocalPlayer(MySelf) then -- We need to do this otherwise the player's real model shows up for some reason.
+ undomodelblend = true
+ render.SetBlend(0)
+ elseif MySelf:Team() == TEAM_HUMAN and pl ~= MySelf and pl:Team() == TEAM_HUMAN then
+ local radius = self.TransparencyRadius
+ if radius > 0 then
+ local eyepos = EyePos()
+ local dist = pl:NearestPoint(eyepos):Distance(eyepos)
+ if dist < radius then
+ local blend = math.max((dist / radius) ^ 1.4, 0.04)
+ render.SetBlend(blend)
+ if blend < 0.4 then
+ render.ModelMaterialOverride(matWhite)
+ render.SetColorModulation(0.2, 0.2, 0.2)
+ shadowman = true
+ end
+ undomodelblend = true
+ end
+ end
+ end
+
+ pl.ShadowMan = shadowman
+
+ if self.m_ZombieVision and MySelf:Team() == TEAM_UNDEAD and pl:Team() == TEAM_HUMAN and pl:GetPos():Distance(EyePos()) <= pl:GetAuraRange() then
+ undozombievision = true
+
+ local green = math.Clamp(pl:Health() / pl:GetMaxHealth(), 0, 1)
+ render.ModelMaterialOverride(matWhite)
+ render.SetColorModulation(1 - green, green, 0)
+ render.SuppressEngineLighting(true)
+ cam.IgnoreZ(true)
+ end
+end
+
+local colFriend = Color(10, 255, 10, 60)
+local matFriendRing = Material("SGM/playercircle")
+function GM:_PostPlayerDraw(pl)
+ pl:CallZombieFunction("PostPlayerDraw")
+
+ if undomodelblend then
+ render.SetBlend(1)
+ render.ModelMaterialOverride()
+ render.SetColorModulation(1, 1, 1)
+
+ undomodelblend = false
+ end
+ if undozombievision then
+ render.ModelMaterialOverride()
+ render.SetColorModulation(1, 1, 1)
+ render.SuppressEngineLighting(false)
+ cam.IgnoreZ(false)
+
+ undozombievision = false
+ end
+
+ if pl ~= MySelf and MySelf:Team() == pl:Team() and pl:IsFriend() then
+ local pos = pl:GetPos() + Vector(0, 0, 2)
+ render.SetMaterial(matFriendRing)
+ render.DrawQuadEasy(pos, Vector(0, 0, 1), 32, 32, colFriend)
+ render.DrawQuadEasy(pos, Vector(0, 0, -1), 32, 32, colFriend)
+ end
+end
+
+function GM:DrawCraftingEntity()
+ local craftingentity = self.CraftingEntity
+ if craftingentity and craftingentity:IsValid() then
+ if self.HumanMenuPanel and self.HumanMenuPanel:Valid() and self.HumanMenuPanel:IsVisible() and MySelf:KeyDown(self.MenuKey) then
+ local scale = craftingentity:GetModelScale()
+ if not scale then return end
+
+ render.ModelMaterialOverride(matWhite)
+ render.SuppressEngineLighting(true)
+ render.SetBlend(0.025)
+ local extrascale = 1.05 + math.abs(math.sin(RealTime() * 7)) * 0.1
+ craftingentity:SetModelScale(scale * extrascale, 0)
+
+ local oldpos = craftingentity:GetPos()
+ craftingentity:SetPos(oldpos - craftingentity:LocalToWorld(oldpos))
+ craftingentity:DrawModel()
+ craftingentity:SetPos(oldpos)
+
+ craftingentity:SetModelScale(scale, 0)
+ render.SetBlend(1)
+ render.SuppressEngineLighting(false)
+ render.ModelMaterialOverride(0)
+ else
+ self.CraftingEntity = nil
+ end
+ end
+end
+
+function GM:HUDPaintBackgroundEndRound()
+ local w, h = ScrW(), ScrH()
+ local timleft = math.max(0, self.EndTime + self.EndGameTime - CurTime())
+
+ if timleft <= 0 then
+ draw_SimpleTextBlur(translate.Get("loading"), "ZSHUDFont", w * 0.5, h * 0.8, COLOR_WHITE, TEXT_ALIGN_CENTER)
+ else
+ draw_SimpleTextBlur(translate.Format("next_round_in_x", util.ToMinutesSeconds(timleft)), "ZSHUDFontSmall", w * 0.5, h * 0.8, COLOR_WHITE, TEXT_ALIGN_CENTER)
+ end
+end
+
+local function EndRoundCalcView(pl, origin, angles, fov, znear, zfar)
+ if GAMEMODE.EndTime and CurTime() < GAMEMODE.EndTime + 5 then
+ local endposition = GAMEMODE.LastHumanPosition
+ local override = GetGlobalVector("endcamerapos", 1)
+ if type(override) ~= "number" then
+ endposition = override
+ end
+ if endposition then
+ local delta = math.Clamp((CurTime() - GAMEMODE.EndTime) * 2, 0, 1)
+
+ local start = endposition * delta + origin * (1 - delta)
+ local tr = util.TraceHull({start = start, endpos = start + delta * 64 * Angle(0, CurTime() * 30, 0):Forward(), mins = Vector(-2, -2, -2), maxs = Vector(2, 2, 2), filter = player.GetAll(), mask = MASK_SOLID})
+ return {origin = tr.HitPos + tr.HitNormal, angles = (start - tr.HitPos):Angle()}
+ end
+
+ return
+ end
+
+ hook.Remove("CalcView", "EndRoundCalcView")
+end
+
+local function EndRoundShouldDrawLocalPlayer(pl)
+ if GAMEMODE.EndTime and CurTime() < GAMEMODE.EndTime + 5 then
+ return true
+ end
+
+ hook.Remove("ShouldDrawLocalPlayer", "EndRoundShouldDrawLocalPlayer")
+end
+
+local function EndRoundGetMeleeFilter(self) return {self} end
+function GM:EndRound(winner, nextmap)
+ if self.RoundEnded then return end
+ self.RoundEnded = true
+
+ ROUNDWINNER = winner
+
+ self.EndTime = CurTime()
+
+ RunConsoleCommand("stopsound")
+
+ FindMetaTable("Player").GetMeleeFilter = EndRoundGetMeleeFilter
+
+ self.HUDPaint = self.HUDPaintEndRound
+ self.HUDPaintBackground = self.HUDPaintBackgroundEndRound
+
+ if winner == TEAM_UNDEAD and GetGlobalBool("endcamera", true) then
+ hook.Add("CalcView", "EndRoundCalcView", EndRoundCalcView)
+ hook.Add("ShouldDrawLocalPlayer", "EndRoundShouldDrawLocalPlayer", EndRoundShouldDrawLocalPlayer)
+ end
+
+ local dvar = winner == TEAM_UNDEAD and self.AllLoseSound or self.HumanWinSound
+ local snd = GetGlobalString(winner == TEAM_UNDEAD and "losemusic" or "winmusic", dvar)
+ if snd == "default" then
+ snd = dvar
+ elseif snd == "none" then
+ snd = nil
+ end
+ if snd then
+ timer.Simple(0.5, function() surface_PlaySound(snd) end)
+ end
+
+ timer.Simple(5, function()
+ if not (pEndBoard and pEndBoard:IsValid()) then
+ MakepEndBoard(winner)
+ end
+ end)
+end
+
+function GM:WeaponDeployed(pl, wep)
+end
+
+function GM:LocalPlayerDied(attackername)
+ LASTDEATH = RealTime()
+
+ surface_PlaySound(self.DeathSound)
+ if attackername then
+ self:CenterNotify(COLOR_RED, {font = "ZSHUDFont"}, translate.Get("you_have_died"))
+ self:CenterNotify(COLOR_RED, translate.Format(self.PantsMode and "you_were_kicked_by_x" or "you_were_killed_by_x", tostring(attackername)))
+ else
+ self:CenterNotify(COLOR_RED, {font = "ZSHUDFont"}, translate.Get("you_have_died"))
+ end
+end
+
+function GM:KeyPress(pl, key)
+ if key == self.MenuKey then
+ if pl:Team() == TEAM_HUMAN and pl:Alive() and not pl:IsHolding() then
+ gamemode.Call("HumanMenu")
+ end
+ elseif key == IN_SPEED then
+ if pl:Alive() then
+ if pl:Team() == TEAM_HUMAN then
+ pl:DispatchAltUse()
+ elseif pl:Team() == TEAM_UNDEAD then
+ pl:CallZombieFunction("AltUse")
+ end
+ end
+ end
+end
+
+function GM:PlayerStepSoundTime(pl, iType, bWalking)
+ local time = pl:CallZombieFunction("PlayerStepSoundTime", iType, bWalking)
+ if time then
+ return time
+ end
+
+ if iType == STEPSOUNDTIME_NORMAL or iType == STEPSOUNDTIME_WATER_FOOT then
+ return 520 - pl:GetVelocity():Length()
+ end
+
+ if iType == STEPSOUNDTIME_ON_LADDER then
+ return 500
+ end
+
+ if iType == STEPSOUNDTIME_WATER_KNEE then
+ return 650
+ end
+
+ return 350
+end
+
+function GM:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume)
+ return pl:CallZombieFunction("PlayerFootstep", vFootPos, iFoot, strSoundName, fVolume)
+end
+
+function GM:PlayerCanCheckout(pl)
+ return pl:IsValid() and pl:Team() == TEAM_HUMAN and pl:Alive() and self:GetWave() <= 0
+end
+
+function GM:OpenWorth()
+ if gamemode.Call("PlayerCanCheckout", MySelf) then
+ MakepWorth()
+ end
+end
+
+function GM:CloseWorth()
+ if pWorth and pWorth:Valid() then
+ pWorth:Remove()
+ pWorth = nil
+ end
+end
+
+GM.SuppressArsenalTime = 0
+function GM:SuppressArsenalUpgrades(suppresstime)
+ self.SuppressArsenalTime = math.max(CurTime() + suppresstime, self.SuppressArsenalTime)
+end
+
+function GM:Rewarded(class, amount)
+ if CurTime() < self.SuppressArsenalTime then return end
+
+ class = class or "0"
+
+ local toptext = translate.Get("arsenal_upgraded")
+
+ local wep = weapons.GetStored(class)
+ if wep and wep.PrintName then
+ if killicon.Get(class) == killicon.Get("default") then
+ self:CenterNotify(COLOR_PURPLE, toptext..": ", color_white, wep.PrintName)
+ else
+ self:CenterNotify({killicon = class}, " ", COLOR_PURPLE, toptext..": ", color_white, wep.PrintName)
+ end
+ elseif amount then
+ self:CenterNotify(COLOR_PURPLE, toptext..": ", color_white, amount.." "..class)
+ else
+ self:CenterNotify(COLOR_PURPLE, toptext)
+ end
+end
+
+function PlayMenuOpenSound()
+ LocalPlayer():EmitSound("buttons/lightswitch2.wav", 100, 30)
+end
+
+function PlayMenuCloseSound()
+ LocalPlayer():EmitSound("buttons/lightswitch2.wav", 100, 20)
+end
+
+local DamageFloaters = CreateClientConVar("zs_damagefloaters", "1", true, false):GetBool()
+cvars.AddChangeCallback("zs_damagefloaters", function(cvar, oldvalue, newvalue)
+ DamageFloaters = newvalue ~= "0"
+end)
+
+net.Receive("zs_legdamage", function(length)
+ LocalPlayer().LegDamage = net.ReadFloat()
+end)
+
+net.Receive("zs_zvols", function(length)
+ local volunteers = {}
+ local count = net.ReadUInt(8)
+ for i=1, count do
+ volunteers[i] = net.ReadEntity()
+ end
+
+ GAMEMODE.ZombieVolunteers = volunteers
+end)
+
+net.Receive("zs_dmg", function(length)
+ local damage = net.ReadUInt(16)
+ local pos = net.ReadVector()
+
+ if DamageFloaters then
+ local effectdata = EffectData()
+ effectdata:SetOrigin(pos)
+ effectdata:SetMagnitude(damage)
+ effectdata:SetScale(0)
+ util.Effect("damagenumber", effectdata)
+ end
+end)
+
+net.Receive("zs_dmg_prop", function(length)
+ local damage = net.ReadUInt(16)
+ local pos = net.ReadVector()
+
+ if DamageFloaters then
+ local effectdata = EffectData()
+ effectdata:SetOrigin(pos)
+ effectdata:SetMagnitude(damage)
+ effectdata:SetScale(1)
+ util.Effect("damagenumber", effectdata)
+ end
+end)
+
+net.Receive("zs_lifestats", function(length)
+ local barricadedamage = net.ReadUInt(24)
+ local humandamage = net.ReadUInt(24)
+ local brainseaten = net.ReadUInt(16)
+
+ GAMEMODE.LifeStatsEndTime = CurTime() + GAMEMODE.LifeStatsLifeTime
+ GAMEMODE.LifeStatsBarricadeDamage = barricadedamage
+ GAMEMODE.LifeStatsHumanDamage = humandamage
+ GAMEMODE.LifeStatsBrainsEaten = brainseaten
+end)
+
+net.Receive("zs_lifestatsbd", function(length)
+ local barricadedamage = net.ReadUInt(24)
+
+ GAMEMODE.LifeStatsEndTime = CurTime() + GAMEMODE.LifeStatsLifeTime
+ GAMEMODE.LifeStatsBarricadeDamage = barricadedamage
+end)
+
+net.Receive("zs_lifestatshd", function(length)
+ local humandamage = net.ReadUInt(24)
+
+ GAMEMODE.LifeStatsEndTime = CurTime() + GAMEMODE.LifeStatsLifeTime
+ GAMEMODE.LifeStatsHumanDamage = humandamage
+end)
+
+net.Receive("zs_lifestatsbe", function(length)
+ local brainseaten = net.ReadUInt(16)
+
+ GAMEMODE.LifeStatsEndTime = CurTime() + GAMEMODE.LifeStatsLifeTime
+ GAMEMODE.LifeStatsBrainsEaten = brainseaten
+end)
+
+net.Receive("zs_honmention", function(length)
+ local pl = net.ReadEntity()
+ local mentionid = net.ReadUInt(8)
+ local etc = net.ReadInt(32)
+
+ if pl:IsValid() then
+ gamemode.Call("AddHonorableMention", pl, mentionid, etc)
+ end
+end)
+
+net.Receive("zs_wavestart", function(length)
+ local wave = net.ReadInt(16)
+ local time = net.ReadFloat()
+
+ gamemode.Call("SetWave", wave)
+ gamemode.Call("SetWaveEnd", time)
+
+ if GAMEMODE.ZombieEscape then
+ GAMEMODE:CenterNotify(COLOR_RED, {font = "ZSHUDFont"}, translate.Get("escape_from_the_zombies"))
+ elseif wave == GAMEMODE:GetNumberOfWaves() then
+ GAMEMODE:CenterNotify({killicon = "default"}, {font = "ZSHUDFont"}, " ", COLOR_RED, translate.Get("final_wave"), {killicon = "default"})
+ GAMEMODE:CenterNotify(translate.Get("final_wave_sub"))
+ else
+ local UnlockedClasses = {}
+ for i, tab in ipairs(GAMEMODE.ZombieClasses) do
+ if tab.Wave <= wave and not tab.Unlocked then
+ tab.Unlocked = true
+ UnlockedClasses[#UnlockedClasses + 1] = translate.Get(tab.TranslationName)
+ end
+ end
+
+ GAMEMODE:CenterNotify({killicon = "default"}, {font = "ZSHUDFont"}, " ", COLOR_RED, translate.Format("wave_x_has_begun", wave), {killicon = "default"})
+ if #UnlockedClasses > 0 then
+ GAMEMODE:CenterNotify(COLOR_GREEN, translate.Format("x_unlocked", string.AndSeparate(UnlockedClasses)))
+ end
+ end
+
+ surface_PlaySound("ambient/creatures/town_zombie_call1.wav")
+end)
+
+net.Receive("zs_waveend", function(length)
+ local wave = net.ReadInt(16)
+ local time = net.ReadFloat()
+
+ gamemode.Call("SetWaveStart", time)
+
+ if wave < GAMEMODE:GetNumberOfWaves() and wave > 0 then
+ GAMEMODE:CenterNotify(COLOR_RED, {font = "ZSHUDFont"}, translate.Format("wave_x_is_over", wave))
+ GAMEMODE:CenterNotify(translate.Format("wave_x_is_over_sub", GAMEMODE.ArsenalCrateDiscountPercentage))
+
+ surface_PlaySound("ambient/atmosphere/cave_hit"..math.random(6)..".wav")
+ end
+end)
+
+net.Receive("zs_gamestate", function(length)
+ local wave = net.ReadInt(16)
+ local wavestart = net.ReadFloat()
+ local waveend = net.ReadFloat()
+
+ gamemode.Call("SetWave", wave)
+ gamemode.Call("SetWaveStart", wavestart)
+ gamemode.Call("SetWaveEnd", waveend)
+end)
+
+local matSkull = Material("zombiesurvival/horderally")
+local bossspawnedend
+local function BossSpawnedPaint()
+ if CurTime() > bossspawnedend then
+ hook.Remove("HUDPaint", "BossSpawnedPaint")
+ return
+ end
+
+ local delta = math.Clamp(bossspawnedend - CurTime(), 0, 1)
+ local size = (1 - delta) * math.max(ScrW(), ScrH())
+
+ surface_SetMaterial(matSkull)
+ surface_SetDrawColor(160, 0, 0, math.min(delta * 400, 180))
+ surface_DrawTexturedRectRotated(ScrW() / 2, ScrH() / 2, size, size, delta * 25)
+end
+net.Receive("zs_boss_spawned", function(length)
+ local ent = net.ReadEntity()
+ local classindex = net.ReadUInt(8)
+
+ if ent == MySelf and ent:IsValid() then
+ GAMEMODE:CenterNotify({killicon = "default"}, " ", COLOR_RED, translate.Format("you_are_x", translate.Get(GAMEMODE.ZombieClasses[classindex].TranslationName)), {killicon = "default"})
+ elseif ent:IsValid() then
+ GAMEMODE:CenterNotify({killicon = "default"}, " ", COLOR_RED, (translate.Format("x_has_risen_as_y", ent:Name(), translate.Get(GAMEMODE.ZombieClasses[classindex].TranslationName))), {killicon = "default"})
+ else
+ GAMEMODE:CenterNotify({killicon = "default"}, " ", COLOR_RED, translate.Format("x_has_risen", translate.Get(GAMEMODE.ZombieClasses[classindex].TranslationName)), {killicon = "default"})
+ end
+
+ if MySelf:IsValid() then
+ MySelf:EmitSound("npc/zombie_poison/pz_alert1.wav", 0)
+ end
+
+ bossspawnedend = CurTime() + 1
+ hook.Add("HUDPaint", "BossSpawnedPaint", BossSpawnedPaint)
+end)
+
+net.Receive("zs_centernotify", function(length)
+ local tab = net.ReadTable()
+
+ GAMEMODE:CenterNotify(unpack(tab))
+end)
+
+net.Receive("zs_topnotify", function(length)
+ local tab = net.ReadTable()
+
+ GAMEMODE:TopNotify(unpack(tab))
+end)
+
+net.Receive("zs_lasthuman", function(length)
+ local pl = net.ReadEntity()
+
+ gamemode.Call("LastHuman", pl)
+end)
+
+net.Receive("zs_gamemodecall", function(length)
+ gamemode.Call(net.ReadString())
+end)
+
+net.Receive("zs_lasthumanpos", function(length)
+ GAMEMODE.LastHumanPosition = net.ReadVector()
+end)
+
+net.Receive("zs_endround", function(length)
+ local winner = net.ReadUInt(8)
+ local nextmap = net.ReadString()
+
+ gamemode.Call("EndRound", winner, nextmap)
+end)
+
+-- Temporary fix
+function render.DrawQuadEasy(pos, dir, xsize, ysize, color, rotation)
+ xsize = xsize / 2
+ ysize = ysize / 2
+
+ local ang = dir:Angle()
+
+ if rotation then
+ ang:RotateAroundAxis(ang:Forward(), rotation)
+ end
+
+ local upoffset = ang:Up() * ysize
+ local rightoffset = ang:Right() * xsize
+
+ render.DrawQuad(pos - upoffset - rightoffset, pos - upoffset + rightoffset, pos + upoffset + rightoffset, pos + upoffset - rightoffset, color)
+end
diff --git a/gamemodes/zombiesurvival/gamemode/cl_options.lua b/gamemodes/zombiesurvival/gamemode/cl_options.lua
new file mode 100644
index 0000000..489fa66
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/cl_options.lua
@@ -0,0 +1,104 @@
+GM.BeatSetHumanDefault = "defaulthuman"
+GM.BeatSetZombieDefault = "defaultzombiev2"
+
+GM.ItemCategoryIcons = {
+ [ITEMCAT_GUNS] = "icon16/gun.png",
+ [ITEMCAT_AMMO] = "icon16/box.png",
+ [ITEMCAT_MELEE] = "icon16/cog.png",
+ [ITEMCAT_TOOLS] = "icon16/wrench.png",
+ [ITEMCAT_OTHER] = "icon16/world.png",
+ [ITEMCAT_RETURNS] = "icon16/user_delete.png"
+}
+
+GM.LifeStatsLifeTime = 5
+
+GM.RewardIcons = {}
+GM.RewardIcons["weapon_zs_barricadekit"] = "models/props_debris/wood_board05a.mdl"
+
+GM.CrosshairColor = Color(CreateClientConVar("zs_crosshair_colr", "255", true, false):GetInt(), CreateClientConVar("zs_crosshair_colg", "255", true, false):GetInt(), CreateClientConVar("zs_crosshair_colb", "255", true, false):GetInt(), 220)
+GM.CrosshairColor2 = Color(CreateClientConVar("zs_crosshair_colr2", "220", true, false):GetInt(), CreateClientConVar("zs_crosshair_colg2", "0", true, false):GetInt(), CreateClientConVar("zs_crosshair_colb2", "0", true, false):GetInt(), 220)
+cvars.AddChangeCallback("zs_crosshair_colr", function(cvar, oldvalue, newvalue) GAMEMODE.CrosshairColor.r = tonumber(newvalue) or 255 end)
+cvars.AddChangeCallback("zs_crosshair_colg", function(cvar, oldvalue, newvalue) GAMEMODE.CrosshairColor.g = tonumber(newvalue) or 255 end)
+cvars.AddChangeCallback("zs_crosshair_colb", function(cvar, oldvalue, newvalue) GAMEMODE.CrosshairColor.b = tonumber(newvalue) or 255 end)
+cvars.AddChangeCallback("zs_crosshair_colr2", function(cvar, oldvalue, newvalue) GAMEMODE.CrosshairColor2.r = tonumber(newvalue) or 255 end)
+cvars.AddChangeCallback("zs_crosshair_colg2", function(cvar, oldvalue, newvalue) GAMEMODE.CrosshairColor2.g = tonumber(newvalue) or 255 end)
+cvars.AddChangeCallback("zs_crosshair_colb2", function(cvar, oldvalue, newvalue) GAMEMODE.CrosshairColor2.b = tonumber(newvalue) or 255 end)
+
+GM.FilmMode = CreateClientConVar("zs_filmmode", "0", true, false):GetBool()
+cvars.AddChangeCallback("zs_filmmode", function(cvar, oldvalue, newvalue)
+ GAMEMODE.FilmMode = tonumber(newvalue) == 1
+
+ GAMEMODE:EvaluateFilmMode()
+end)
+
+CreateClientConVar("zs_noredeem", "0", true, true)
+CreateClientConVar("zs_alwaysvolunteer", "0", true, true)
+
+GM.BeatsEnabled = CreateClientConVar("zs_beats", "1", true, false):GetBool()
+cvars.AddChangeCallback("zs_beats", function(cvar, oldvalue, newvalue)
+ GAMEMODE.BeatsEnabled = tonumber(newvalue) == 1
+end)
+
+GM.BeatsVolume = math.Clamp(CreateClientConVar("zs_beatsvolume", 80, true, false):GetInt(), 0, 100) / 100
+cvars.AddChangeCallback("zs_beatsvolume", function(cvar, oldvalue, newvalue)
+ GAMEMODE.BeatsVolume = math.Clamp(tonumber(newvalue) or 0, 0, 100) / 100
+end)
+
+GM.AlwaysShowNails = CreateClientConVar("zs_alwaysshownails", "0", true, false):GetBool()
+cvars.AddChangeCallback("zs_alwaysshownails", function(cvar, oldvalue, newvalue)
+ GAMEMODE.AlwaysShowNails = tonumber(newvalue) == 1
+end)
+
+GM.NoCrosshairRotate = CreateClientConVar("zs_nocrosshairrotate", "0", true, false):GetBool()
+cvars.AddChangeCallback("zs_nocrosshairrotate", function(cvar, oldvalue, newvalue)
+ GAMEMODE.NoCrosshairRotate = tonumber(newvalue) == 1
+end)
+
+GM.TransparencyRadius = math.Clamp(CreateClientConVar("zs_transparencyradius", 140, true, false):GetInt(), 0, 512)
+cvars.AddChangeCallback("zs_transparencyradius", function(cvar, oldvalue, newvalue)
+ GAMEMODE.TransparencyRadius = math.Clamp(tonumber(newvalue) or 0, 0, 512)
+end)
+
+GM.MovementViewRoll = CreateClientConVar("zs_movementviewroll", "1", true, false):GetBool()
+cvars.AddChangeCallback("zs_movementviewroll", function(cvar, oldvalue, newvalue)
+ GAMEMODE.MovementViewRoll = tonumber(newvalue) == 1
+end)
+
+GM.WeaponHUDMode = CreateClientConVar("zs_weaponhudmode", "0", true, false):GetInt()
+cvars.AddChangeCallback("zs_weaponhudmode", function(cvar, oldvalue, newvalue)
+ GAMEMODE.WeaponHUDMode = tonumber(newvalue) or 0
+end)
+
+GM.DrawPainFlash = CreateClientConVar("zs_drawpainflash", "1", true, false):GetBool()
+cvars.AddChangeCallback("zs_drawpainflash", function(cvar, oldvalue, newvalue)
+ GAMEMODE.DrawPainFlash = tonumber(newvalue) == 1
+end)
+
+CreateConVar( "cl_playercolor", "0.24 0.34 0.41", { FCVAR_ARCHIVE, FCVAR_USERINFO }, "The value is a Vector - so between 0-1 - not between 0-255" )
+CreateConVar( "cl_weaponcolor", "0.30 1.80 2.10", { FCVAR_ARCHIVE, FCVAR_USERINFO }, "The value is a Vector - so between 0-1 - not between 0-255" )
+
+GM.BeatSetHuman = CreateClientConVar("zs_beatset_human", "default", true, false):GetString()
+cvars.AddChangeCallback("zs_beatset_human", function(cvar, oldvalue, newvalue)
+ newvalue = tostring(newvalue)
+ if newvalue == "default" then
+ GAMEMODE.BeatSetHuman = GAMEMODE.BeatSetHumanDefault
+ else
+ GAMEMODE.BeatSetHuman = newvalue
+ end
+end)
+if GM.BeatSetHuman == "default" then
+ GM.BeatSetHuman = GM.BeatSetHumanDefault
+end
+
+GM.BeatSetZombie = CreateClientConVar("zs_beatset_zombie", "default", true, false):GetString()
+cvars.AddChangeCallback("zs_beatset_zombie", function(cvar, oldvalue, newvalue)
+ newvalue = tostring(newvalue)
+ if newvalue == "default" then
+ GAMEMODE.BeatSetZombie = GAMEMODE.BeatSetZombieDefault
+ else
+ GAMEMODE.BeatSetZombie = newvalue
+ end
+end)
+if GM.BeatSetZombie == "default" then
+ GM.BeatSetZombie = GM.BeatSetZombieDefault
+end
diff --git a/gamemodes/zombiesurvival/gamemode/cl_postprocess.lua b/gamemodes/zombiesurvival/gamemode/cl_postprocess.lua
new file mode 100644
index 0000000..ce3d025
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/cl_postprocess.lua
@@ -0,0 +1,253 @@
+function GM:RenderScreenspaceEffects()
+end
+
+GM.PostProcessingEnabled = CreateClientConVar("zs_postprocessing", 1, true, false):GetBool()
+cvars.AddChangeCallback("zs_postprocessing", function(cvar, oldvalue, newvalue)
+ GAMEMODE.PostProcessingEnabled = tonumber(newvalue) == 1
+end)
+
+GM.FilmGrainEnabled = CreateClientConVar("zs_filmgrain", 1, true, false):GetBool()
+cvars.AddChangeCallback("zs_filmgrain", function(cvar, oldvalue, newvalue)
+ GAMEMODE.FilmGrainEnabled = tonumber(newvalue) == 1
+end)
+
+GM.FilmGrainOpacity = CreateClientConVar("zs_filmgrainopacity", 50, true, false):GetInt()
+cvars.AddChangeCallback("zs_filmgrainopacity", function(cvar, oldvalue, newvalue)
+ GAMEMODE.FilmGrainOpacity = math.Clamp(tonumber(newvalue) or 0, 0, 255)
+end)
+
+GM.ColorModEnabled = CreateClientConVar("zs_colormod", "1", true, false):GetBool()
+cvars.AddChangeCallback("zs_colormod", function(cvar, oldvalue, newvalue)
+ GAMEMODE.ColorModEnabled = tonumber(newvalue) == 1
+end)
+
+GM.Auras = CreateClientConVar("zs_auras", 1, true, false):GetBool()
+cvars.AddChangeCallback("zs_auras", function(cvar, oldvalue, newvalue)
+ GAMEMODE.Auras = tonumber(newvalue) == 1
+end)
+
+GM.AuraColorEmpty = Color(CreateClientConVar("zs_auracolor_empty_r", 255, true, false):GetInt(), CreateClientConVar("zs_auracolor_empty_g", 0, true, false):GetInt(), CreateClientConVar("zs_auracolor_empty_b", 0, true, false):GetInt(), 255)
+GM.AuraColorFull = Color(CreateClientConVar("zs_auracolor_full_r", 20, true, false):GetInt(), CreateClientConVar("zs_auracolor_full_g", 255, true, false):GetInt(), CreateClientConVar("zs_auracolor_full_b", 20, true, false):GetInt(), 255)
+
+cvars.AddChangeCallback("zs_auracolor_empty_r", function(cvar, oldvalue, newvalue)
+ GAMEMODE.AuraColorEmpty.r = math.Clamp(math.ceil(tonumber(newvalue) or 0), 0, 255)
+end)
+
+cvars.AddChangeCallback("zs_auracolor_empty_g", function(cvar, oldvalue, newvalue)
+ GAMEMODE.AuraColorEmpty.g = math.Clamp(math.ceil(tonumber(newvalue) or 0), 0, 255)
+end)
+
+cvars.AddChangeCallback("zs_auracolor_empty_b", function(cvar, oldvalue, newvalue)
+ GAMEMODE.AuraColorEmpty.b = math.Clamp(math.ceil(tonumber(newvalue) or 0), 0, 255)
+end)
+
+cvars.AddChangeCallback("zs_auracolor_full_r", function(cvar, oldvalue, newvalue)
+ GAMEMODE.AuraColorFull.r = math.Clamp(math.ceil(tonumber(newvalue) or 0), 0, 255)
+end)
+
+cvars.AddChangeCallback("zs_auracolor_full_g", function(cvar, oldvalue, newvalue)
+ GAMEMODE.AuraColorFull.g = math.Clamp(math.ceil(tonumber(newvalue) or 0), 0, 255)
+end)
+
+cvars.AddChangeCallback("zs_auracolor_full_b", function(cvar, oldvalue, newvalue)
+ GAMEMODE.AuraColorFull.b = math.Clamp(math.ceil(tonumber(newvalue) or 0), 0, 255)
+end)
+
+
+local DrawColorModify = DrawColorModify
+local DrawSharpen = DrawSharpen
+local EyePos = EyePos
+local TEAM_HUMAN = TEAM_HUMAN
+local TEAM_UNDEAD = TEAM_UNDEAD
+local render_UpdateScreenEffectTexture = render.UpdateScreenEffectTexture
+local render_SetMaterial = render.SetMaterial
+local render_DrawScreenQuad = render.DrawScreenQuad
+local render_DrawSprite = render.DrawSprite
+local render_DrawBeam = render.DrawBeam
+local render_GetLightRGB = render.GetLightRGB
+local math_Approach = math.Approach
+local FrameTime = FrameTime
+local CurTime = CurTime
+local math_sin = math.sin
+local math_min = math.min
+local math_max = math.max
+local math_abs = math.abs
+local team_GetPlayers = team.GetPlayers
+
+local tColorModDead = {
+ ["$pp_colour_contrast"] = 1.25,
+ ["$pp_colour_colour"] = 0,
+ ["$pp_colour_addr"] = 0,
+ ["$pp_colour_addg"] = 0,
+ ["$pp_colour_addb"] = 0,
+ ["$pp_colour_brightness"] = -0.02,
+ ["$pp_colour_mulr"] = 0,
+ ["$pp_colour_mulg"] = 0,
+ ["$pp_colour_mulb"] = 0
+}
+
+local tColorModHuman = {
+ ["$pp_colour_addr"] = 0,
+ ["$pp_colour_addg"] = 0,
+ ["$pp_colour_addb"] = 0,
+ ["$pp_colour_brightness"] = 0,
+ ["$pp_colour_contrast"] = 1,
+ ["$pp_colour_colour"] = 1,
+ ["$pp_colour_mulr"] = 0,
+ ["$pp_colour_mulg"] = 0,
+ ["$pp_colour_mulb"] = 0
+}
+
+local tColorModZombie = {
+ ["$pp_colour_brightness"] = 0,
+ ["$pp_colour_contrast"] = 1.25,
+ ["$pp_colour_colour"] = 0.5,
+ ["$pp_colour_addr"] = 0,
+ ["$pp_colour_addg"] = 0,
+ ["$pp_colour_addb"] = 0,
+ ["$pp_colour_mulr"] = 0,
+ ["$pp_colour_mulg"] = 0,
+ ["$pp_colour_mulb"] = 0
+}
+
+local tColorModZombieVision = {
+ ["$pp_colour_colour"] = 0.75,
+ ["$pp_colour_brightness"] = -0.15,
+ ["$pp_colour_contrast"] = 1.5,
+ ["$pp_colour_mulr"] = 0,
+ ["$pp_colour_mulg"] = 0,
+ ["$pp_colour_mulb"] = 0,
+ ["$pp_colour_addr"] = 0,
+ ["$pp_colour_addg"] = 0,
+ ["$pp_colour_addb"] = 0
+}
+
+local redview = 0
+local fear = 0
+local matTankGlass = Material("models/props_lab/Tank_Glass001")
+function GM:_RenderScreenspaceEffects()
+ if MySelf.Confusion and MySelf.Confusion:IsValid() then
+ MySelf.Confusion:RenderScreenSpaceEffects()
+ end
+
+ fear = math_Approach(fear, self:CachedFearPower(), FrameTime())
+
+ if not self.PostProcessingEnabled then return end
+
+ if self.DrawPainFlash and self.HurtEffect > 0 then
+ DrawSharpen(1, math_min(6, self.HurtEffect * 3))
+ end
+
+ if MySelf:Team() == TEAM_UNDEAD and self.m_ZombieVision and not matTankGlass:IsError() then
+ render_UpdateScreenEffectTexture()
+ matTankGlass:SetFloat("$envmap", 0)
+ matTankGlass:SetFloat("$envmaptint", 0)
+ matTankGlass:SetFloat("$refractamount", 0.035)
+ matTankGlass:SetInt("$ignorez", 1)
+ render_SetMaterial(matTankGlass)
+ render_DrawScreenQuad()
+ end
+
+ if self.ColorModEnabled then
+ if not MySelf:Alive() and MySelf:GetObserverMode() ~= OBS_MODE_CHASE then
+ if not MySelf:HasWon() then
+ tColorModDead["$pp_colour_colour"] = (1 - math_min(1, CurTime() - self.LastTimeAlive)) * 0.5
+ DrawColorModify(tColorModDead)
+ end
+ elseif MySelf:Team() == TEAM_UNDEAD then
+ if self.m_ZombieVision then
+ DrawColorModify(tColorModZombieVision)
+ else
+ tColorModZombie["$pp_colour_colour"] = math_min(1, 0.25 + math_min(1, (CurTime() - self.LastTimeDead) * 0.5) * 1.75 * fear)
+
+ DrawColorModify(tColorModZombie)
+ end
+ else
+ local curr = tColorModHuman["$pp_colour_addr"]
+ local health = MySelf:Health()
+ if health <= 50 then
+ --tColorModHuman["$pp_colour_addr"] = math_min(0.3 - health * 0.006, curr + FrameTime() * 0.055)
+ redview = math_Approach(redview, 1 - health / 50, FrameTime() * 0.2)
+ elseif 0 < curr then
+ --tColorModHuman["$pp_colour_addr"] = math_max(0, curr - FrameTime() * 0.1)
+ redview = math_Approach(redview, 0, FrameTime() * 0.2)
+ end
+
+ tColorModHuman["$pp_colour_addr"] = redview * (0.035 + math_abs(math.sin(CurTime() * 2)) * 0.14)
+ tColorModHuman["$pp_colour_brightness"] = fear * -0.045
+ tColorModHuman["$pp_colour_contrast"] = 1 + fear * 0.15
+ tColorModHuman["$pp_colour_colour"] = 1 - fear * 0.725 --0.85
+
+ DrawColorModify(tColorModHuman)
+ end
+ end
+end
+
+local matGlow = Material("Sprites/light_glow02_add_noz")
+local colHealthEmpty = GM.AuraColorEmpty
+local colHealthFull = GM.AuraColorFull
+local colHealth = Color(255, 255, 255, 255)
+local matPullBeam = Material("cable/rope")
+local colPullBeam = Color(255, 255, 255, 255)
+function GM:_PostDrawOpaqueRenderables()
+ if MySelf:Team() == TEAM_UNDEAD then
+ if self.Auras then
+ local eyepos = EyePos()
+ for _, pl in pairs(team_GetPlayers(TEAM_HUMAN)) do
+ if pl:Alive() and pl:GetPos():Distance(eyepos) <= pl:GetAuraRange() then
+ local healthfrac = math_max(pl:Health(), 0) / pl:GetMaxHealth()
+ colHealth.r = math_Approach(colHealthEmpty.r, colHealthFull.r, math_abs(colHealthEmpty.r - colHealthFull.r) * healthfrac)
+ colHealth.g = math_Approach(colHealthEmpty.g, colHealthFull.g, math_abs(colHealthEmpty.g - colHealthFull.g) * healthfrac)
+ colHealth.b = math_Approach(colHealthEmpty.b, colHealthFull.b, math_abs(colHealthEmpty.b - colHealthFull.b) * healthfrac)
+
+ --local attach = pl:GetAttachment(pl:LookupAttachment("chest")) -- This probably lagged so much.
+ --local pos = attach and attach.Pos or pl:WorldSpaceCenter()
+ local pos = pl:WorldSpaceCenter()
+
+ render_SetMaterial(matGlow)
+ render_DrawSprite(pos, 13, 13, colHealth)
+ local size = math_sin(self.HeartBeatTime + pl:EntIndex()) * 50 - 21
+ if size > 0 then
+ render_DrawSprite(pos, size * 1.5, size, colHealth)
+ render_DrawSprite(pos, size, size * 1.5, colHealth)
+ end
+ end
+ end
+ end
+ else
+ self:DrawCraftingEntity()
+
+ local holding = MySelf.status_human_holding
+ if holding and holding:IsValid() and holding:GetIsHeavy() then
+ local object = holding:GetObject()
+ if object:IsValid() then
+ local pullpos = holding:GetPullPos()
+ local hingepos = holding:GetHingePos()
+ local r, g, b = render_GetLightRGB(hingepos)
+ colPullBeam.r = r * 255
+ colPullBeam.g = g * 255
+ colPullBeam.b = b * 255
+ render_SetMaterial(matPullBeam)
+ render_DrawBeam(hingepos, pullpos, 0.5, 0, pullpos:Distance(hingepos) / 128, colPullBeam)
+ end
+ end
+ end
+end
+
+function GM:ToggleZombieVision(onoff)
+ if onoff == nil then
+ onoff = not self.m_ZombieVision
+ end
+
+ if onoff then
+ if not self.m_ZombieVision then
+ self.m_ZombieVision = true
+ MySelf:EmitSound("npc/stalker/breathing3.wav", 0, 230)
+ MySelf:SetDSP(5)
+ end
+ elseif self.m_ZombieVision then
+ self.m_ZombieVision = nil
+ MySelf:EmitSound("npc/zombie/zombie_pain6.wav", 0, 110)
+ MySelf:SetDSP(0)
+ end
+end
diff --git a/gamemodes/zombiesurvival/gamemode/cl_scoreboard.lua b/gamemodes/zombiesurvival/gamemode/cl_scoreboard.lua
new file mode 100644
index 0000000..b5e19c8
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/cl_scoreboard.lua
@@ -0,0 +1,383 @@
+local ScoreBoard
+function GM:ScoreboardShow()
+ gui.EnableScreenClicker(true)
+ PlayMenuOpenSound()
+
+ if not ScoreBoard then
+ ScoreBoard = vgui.Create("ZSScoreBoard")
+ end
+
+ ScoreBoard:SetSize(math.min(ScrW(), ScrH()) * 0.8, ScrH() * 0.85)
+ ScoreBoard:AlignTop(ScrH() * 0.05)
+ ScoreBoard:CenterHorizontal()
+ ScoreBoard:SetAlpha(0)
+ ScoreBoard:AlphaTo(255, 0.5, 0)
+ ScoreBoard:SetVisible(true)
+end
+
+function GM:ScoreboardHide()
+ gui.EnableScreenClicker(false)
+
+ if ScoreBoard then
+ PlayMenuCloseSound()
+ ScoreBoard:SetVisible(false)
+ end
+end
+
+local PANEL = {}
+
+PANEL.RefreshTime = 2
+PANEL.NextRefresh = 0
+PANEL.m_MaximumScroll = 0
+
+local function BlurPaint(self)
+ draw.SimpleTextBlur(self:GetValue(), self.Font, 0, 0, self:GetTextColor())
+
+ return true
+end
+local function emptypaint(self)
+ return true
+end
+
+function PANEL:Init()
+ self.NextRefresh = RealTime() + 0.1
+
+ self.m_TitleLabel = vgui.Create("DLabel", self)
+ self.m_TitleLabel.Font = "ZSScoreBoardTitle"
+ self.m_TitleLabel:SetFont(self.m_TitleLabel.Font)
+ self.m_TitleLabel:SetText(GAMEMODE.Name)
+ self.m_TitleLabel:SetTextColor(COLOR_GRAY)
+ self.m_TitleLabel:SizeToContents()
+ self.m_TitleLabel:NoClipping(true)
+ self.m_TitleLabel.Paint = BlurPaint
+
+ self.m_ServerNameLabel = vgui.Create("DLabel", self)
+ self.m_ServerNameLabel.Font = "ZSScoreBoardSubTitle"
+ self.m_ServerNameLabel:SetFont(self.m_ServerNameLabel.Font)
+ self.m_ServerNameLabel:SetText(GetHostName())
+ self.m_ServerNameLabel:SetTextColor(COLOR_GRAY)
+ self.m_ServerNameLabel:SizeToContents()
+ self.m_ServerNameLabel:NoClipping(true)
+ self.m_ServerNameLabel.Paint = BlurPaint
+
+ self.m_AuthorLabel = EasyLabel(self, "by "..GAMEMODE.Author.." ("..GAMEMODE.Email..")", "DefaultFontSmall", COLOR_GRAY)
+ self.m_ContactLabel = EasyLabel(self, GAMEMODE.Website, "DefaultFontSmall", COLOR_GRAY)
+
+ self.m_HumanHeading = vgui.Create("DTeamHeading", self)
+ self.m_HumanHeading:SetTeam(TEAM_HUMAN)
+
+ self.m_ZombieHeading = vgui.Create("DTeamHeading", self)
+ self.m_ZombieHeading:SetTeam(TEAM_UNDEAD)
+
+ self.ZombieList = vgui.Create("DScrollPanel", self)
+ self.ZombieList.Team = TEAM_UNDEAD
+
+ self.HumanList = vgui.Create("DScrollPanel", self)
+ self.HumanList.Team = TEAM_HUMAN
+
+ self:InvalidateLayout()
+end
+
+function PANEL:PerformLayout()
+ self.m_AuthorLabel:MoveBelow(self.m_TitleLabel)
+ self.m_ContactLabel:MoveBelow(self.m_AuthorLabel)
+
+ self.m_ServerNameLabel:SetPos(math.min(self:GetWide() - self.m_ServerNameLabel:GetWide(), self:GetWide() * 0.75 - self.m_ServerNameLabel:GetWide() * 0.5), 32 - self.m_ServerNameLabel:GetTall() / 2)
+
+ self.m_HumanHeading:SetSize(self:GetWide() / 2 - 32, 28)
+ self.m_HumanHeading:SetPos(self:GetWide() * 0.25 - self.m_HumanHeading:GetWide() * 0.5, 110 - self.m_HumanHeading:GetTall())
+
+ self.m_ZombieHeading:SetSize(self:GetWide() / 2 - 32, 28)
+ self.m_ZombieHeading:SetPos(self:GetWide() * 0.75 - self.m_ZombieHeading:GetWide() * 0.5, 110 - self.m_ZombieHeading:GetTall())
+
+ self.HumanList:SetSize(self:GetWide() / 2 - 24, self:GetTall() - 150)
+ self.HumanList:AlignBottom(16)
+ self.HumanList:AlignLeft(8)
+
+ self.ZombieList:SetSize(self:GetWide() / 2 - 24, self:GetTall() - 150)
+ self.ZombieList:AlignBottom(16)
+ self.ZombieList:AlignRight(8)
+end
+
+function PANEL:Think()
+ if RealTime() >= self.NextRefresh then
+ self.NextRefresh = RealTime() + self.RefreshTime
+ self:Refresh()
+ end
+end
+
+local texRightEdge = surface.GetTextureID("gui/gradient")
+local texCorner = surface.GetTextureID("zombiesurvival/circlegradient")
+local texDownEdge = surface.GetTextureID("gui/gradient_down")
+function PANEL:Paint()
+ local wid, hei = self:GetSize()
+ local barw = 64
+
+ surface.SetDrawColor(5, 5, 5, 180)
+ surface.DrawRect(0, 64, wid, hei - 64)
+ surface.SetDrawColor(90, 90, 90, 180)
+ surface.DrawOutlinedRect(0, 64, wid, hei - 64)
+
+ surface.SetDrawColor(5, 5, 5, 220)
+ PaintGenericFrame(self, 0, 0, wid, 64, 32)
+
+ surface.SetDrawColor(5, 5, 5, 160)
+ surface.DrawRect(wid * 0.5 - 16, 64, 32, hei - 128)
+ surface.SetTexture(texRightEdge)
+ surface.DrawTexturedRect(wid * 0.5 + 16, 64, barw, hei - 128)
+ surface.DrawTexturedRectRotated(wid * 0.5 - 16 - barw / 2, 64 + (hei - 128) / 2, barw, hei - 128, 180)
+ surface.SetTexture(texCorner)
+ surface.DrawTexturedRectRotated(wid * 0.5 - 16 - barw / 2, hei - 32, barw, 64, 90)
+ surface.DrawTexturedRectRotated(wid * 0.5 + 16 + barw / 2, hei - 32, barw, 64, 180)
+ surface.SetTexture(texDownEdge)
+ surface.DrawTexturedRect(wid * 0.5 - 16, hei - 64, 32, 64)
+end
+
+function PANEL:GetPlayerPanel(pl)
+ for _, panel in pairs(self.PlayerPanels) do
+ if panel:Valid() and panel:GetPlayer() == pl then
+ return panel
+ end
+ end
+end
+
+function PANEL:CreatePlayerPanel(pl)
+ local curpan = self:GetPlayerPanel(pl)
+ if curpan and curpan:Valid() then return curpan end
+
+ local panel = vgui.Create("ZSPlayerPanel", pl:Team() == TEAM_UNDEAD and self.ZombieList or self.HumanList)
+ panel:SetPlayer(pl)
+ panel:Dock(TOP)
+ panel:DockMargin(8, 2, 8, 2)
+
+ self.PlayerPanels[pl] = panel
+
+ return panel
+end
+
+function PANEL:Refresh()
+ self.m_ServerNameLabel:SetText(GetHostName())
+ self.m_ServerNameLabel:SizeToContents()
+ self.m_ServerNameLabel:SetPos(math.min(self:GetWide() - self.m_ServerNameLabel:GetWide(), self:GetWide() * 0.75 - self.m_ServerNameLabel:GetWide() * 0.5), 32 - self.m_ServerNameLabel:GetTall() / 2)
+
+ if self.PlayerPanels == nil then self.PlayerPanels = {} end
+
+ for _, panel in pairs(self.PlayerPanels) do
+ if not panel:Valid() then
+ self:RemovePlayerPanel(panel)
+ end
+ end
+
+ for _, pl in pairs(player.GetAll()) do
+ self:CreatePlayerPanel(pl)
+ end
+end
+
+function PANEL:RemovePlayerPanel(panel)
+ if panel:Valid() then
+ self.PlayerPanels[panel:GetPlayer()] = nil
+ panel:Remove()
+ end
+end
+
+vgui.Register("ZSScoreBoard", PANEL, "Panel")
+
+local PANEL = {}
+
+PANEL.RefreshTime = 1
+
+PANEL.m_Player = NULL
+PANEL.NextRefresh = 0
+
+local function MuteDoClick(self)
+ local pl = self:GetParent():GetPlayer()
+ if pl:IsValid() then
+ pl:SetMuted(not pl:IsMuted())
+ self:GetParent().NextRefresh = RealTime()
+ end
+end
+
+local function AvatarDoClick(self)
+ local pl = self.PlayerPanel:GetPlayer()
+ if pl:IsValid() and pl:IsPlayer() then
+ pl:ShowProfile()
+ end
+end
+
+local function empty() end
+
+function PANEL:Init()
+ self:SetTall(32)
+
+ self.m_AvatarButton = self:Add("DButton", self)
+ self.m_AvatarButton:SetText(" ")
+ self.m_AvatarButton:SetSize(32, 32)
+ self.m_AvatarButton:Center()
+ self.m_AvatarButton.DoClick = AvatarDoClick
+ self.m_AvatarButton.Paint = empty
+ self.m_AvatarButton.PlayerPanel = self
+
+ self.m_Avatar = vgui.Create("AvatarImage", self.m_AvatarButton)
+ self.m_Avatar:SetSize(32, 32)
+ self.m_Avatar:SetVisible(false)
+ self.m_Avatar:SetMouseInputEnabled(false)
+
+ self.m_SpecialImage = vgui.Create("DImage", self)
+ self.m_SpecialImage:SetSize(16, 16)
+ self.m_SpecialImage:SetMouseInputEnabled(true)
+ self.m_SpecialImage:SetVisible(false)
+
+ self.m_ClassImage = vgui.Create("DImage", self)
+ self.m_ClassImage:SetSize(22, 22)
+ self.m_ClassImage:SetMouseInputEnabled(false)
+ self.m_ClassImage:SetVisible(false)
+
+ self.m_PlayerLabel = EasyLabel(self, " ", "ZSScoreBoardPlayer", COLOR_WHITE)
+ self.m_ScoreLabel = EasyLabel(self, " ", "ZSScoreBoardPlayerSmall", COLOR_WHITE)
+
+ self.m_PingMeter = vgui.Create("DPingMeter", self)
+ self.m_PingMeter.PingBars = 5
+
+ self.m_Mute = vgui.Create("DImageButton", self)
+ self.m_Mute.DoClick = MuteDoClick
+end
+
+local colTemp = Color(255, 255, 255, 220)
+function PANEL:Paint()
+ local col = color_black_alpha220
+ local mul = 0.5
+ local pl = self:GetPlayer()
+ if pl:IsValid() then
+ col = team.GetColor(pl:Team())
+
+ if pl:SteamID() == "STEAM_0:1:3307510" then
+ mul = 0.6 + math.abs(math.sin(RealTime() * 6)) * 0.4
+ elseif pl == MySelf then
+ mul = 0.8
+ end
+ end
+
+ if self.Hovered then
+ mul = math.min(1, mul * 1.5)
+ end
+
+ colTemp.r = col.r * mul
+ colTemp.g = col.g * mul
+ colTemp.b = col.b * mul
+ draw.RoundedBox(8, 0, 0, self:GetWide(), self:GetTall(), colTemp)
+
+ return true
+end
+
+function PANEL:DoClick()
+ local pl = self:GetPlayer()
+ if pl:IsValid() then
+ gamemode.Call("ClickedPlayerButton", pl, self)
+ end
+end
+
+function PANEL:PerformLayout()
+ self.m_AvatarButton:AlignLeft(16)
+ self.m_AvatarButton:CenterVertical()
+
+ self.m_PlayerLabel:SizeToContents()
+ self.m_PlayerLabel:MoveRightOf(self.m_AvatarButton, 4)
+ self.m_PlayerLabel:CenterVertical()
+
+ self.m_ScoreLabel:SizeToContents()
+ self.m_ScoreLabel:SetPos(self:GetWide() * 0.666 - self.m_ScoreLabel:GetWide() / 2, 0)
+ self.m_ScoreLabel:CenterVertical()
+
+ self.m_SpecialImage:CenterVertical()
+
+ self.m_ClassImage:SetSize(self:GetTall(), self:GetTall())
+ self.m_ClassImage:SetPos(self:GetWide() * 0.75 - self.m_ClassImage:GetWide() * 0.5, 0)
+ self.m_ClassImage:CenterVertical()
+
+ local pingsize = self:GetTall() - 4
+
+ self.m_PingMeter:SetSize(pingsize, pingsize)
+ self.m_PingMeter:AlignRight(8)
+ self.m_PingMeter:CenterVertical()
+
+ self.m_Mute:SetSize(16, 16)
+ self.m_Mute:MoveLeftOf(self.m_PingMeter, 8)
+ self.m_Mute:CenterVertical()
+end
+
+function PANEL:Refresh()
+ local pl = self:GetPlayer()
+ if not pl:IsValid() then
+ self:Remove()
+ return
+ end
+
+ local name = pl:Name()
+ if #name > 26 then
+ name = string.sub(name, 1, 24)..".."
+ end
+ self.m_PlayerLabel:SetText(name)
+ self.m_ScoreLabel:SetText(pl:Frags())
+
+ if pl:Team() == TEAM_UNDEAD and pl:GetZombieClassTable().Icon then
+ self.m_ClassImage:SetVisible(true)
+ self.m_ClassImage:SetImage(pl:GetZombieClassTable().Icon)
+ else
+ self.m_ClassImage:SetVisible(false)
+ end
+
+ if pl == LocalPlayer() then
+ self.m_Mute:SetVisible(false)
+ else
+ if pl:IsMuted() then
+ self.m_Mute:SetImage("icon16/sound_mute.png")
+ else
+ self.m_Mute:SetImage("icon16/sound.png")
+ end
+ end
+
+ self:SetZPos(-pl:Frags())
+
+ if pl:Team() ~= self._LastTeam then
+ self._LastTeam = pl:Team()
+ self:SetParent(self._LastTeam == TEAM_HUMAN and ScoreBoard.HumanList or ScoreBoard.ZombieList)
+ end
+
+ self:InvalidateLayout()
+end
+
+function PANEL:Think()
+ if RealTime() >= self.NextRefresh then
+ self.NextRefresh = RealTime() + self.RefreshTime
+ self:Refresh()
+ end
+end
+
+function PANEL:SetPlayer(pl)
+ self.m_Player = pl or NULL
+
+ if pl:IsValid() and pl:IsPlayer() then
+ self.m_Avatar:SetPlayer(pl)
+ self.m_Avatar:SetVisible(true)
+
+ if gamemode.Call("IsSpecialPerson", pl, self.m_SpecialImage) then
+ self.m_SpecialImage:SetVisible(true)
+ else
+ self.m_SpecialImage:SetTooltip()
+ self.m_SpecialImage:SetVisible(false)
+ end
+ else
+ self.m_Avatar:SetVisible(false)
+ self.m_SpecialImage:SetVisible(false)
+ end
+
+ self.m_PingMeter:SetPlayer(pl)
+
+ self:Refresh()
+end
+
+function PANEL:GetPlayer()
+ return self.m_Player
+end
+
+vgui.Register("ZSPlayerPanel", PANEL, "Button")
diff --git a/gamemodes/zombiesurvival/gamemode/cl_targetid.lua b/gamemodes/zombiesurvival/gamemode/cl_targetid.lua
new file mode 100644
index 0000000..ec34668
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/cl_targetid.lua
@@ -0,0 +1,68 @@
+local trace = {mask = MASK_SHOT, mins = Vector(-2, -2, -2), maxs = Vector(2, 2, 2), filter = {}}
+local entitylist = {}
+
+local colTemp = Color(255, 255, 255)
+function GM:DrawTargetID(ent, fade)
+ fade = fade or 1
+ local ts = ent:GetPos():ToScreen()
+ local x, y = ts.x, math.Clamp(ts.y, 0, ScrH() * 0.95)
+
+ colTemp.a = fade * 255
+ util.ColorCopy(COLOR_FRIENDLY, colTemp)
+
+ local name = ent:Name()
+ draw.SimpleTextBlur(name, "ZSHUDFontSmaller", x, y, colTemp, TEXT_ALIGN_CENTER)
+ y = y + draw.GetFontHeight("ZSHUDFontSmaller") + 4
+
+ local healthfraction = math.max(ent:Health() / (ent:Team() == TEAM_UNDEAD and ent:GetMaxZombieHealth() or ent:GetMaxHealth()), 0)
+ if healthfraction ~= 1 then
+ util.ColorCopy(0.75 <= healthfraction and COLOR_HEALTHY or 0.5 <= healthfraction and COLOR_SCRATCHED or 0.25 <= healthfraction and COLOR_HURT or COLOR_CRITICAL, colTemp)
+
+ local healthdisplay = math.ceil(healthfraction * 100).."%"
+ draw.SimpleTextBlur(healthdisplay, "ZSHUDFont", x, y, colTemp, TEXT_ALIGN_CENTER)
+ y = y + draw.GetFontHeight("ZSHUDFont") + 4
+ end
+
+ util.ColorCopy(color_white, colTemp)
+
+ if ent:Team() == TEAM_UNDEAD then
+ local classtab = ent:GetZombieClassTable()
+ local classname = classtab.TranslationName and translate.Get(classtab.TranslationName) or classtab.Name
+ if classname then
+ draw.SimpleTextBlur(classname, "ZSHUDFontTiny", x, y, colTemp, TEXT_ALIGN_CENTER)
+ end
+ else
+ local holding = ent:GetHolding()
+ if holding:IsValid() then
+ local mdl = holding:GetModel()
+ local name = string.match(mdl, ".*/(.+)%.mdl") or "object"
+ draw.SimpleTextBlur("Carrying ["..name.."]", "ZSHUDFontTiny", x, y, colTemp, TEXT_ALIGN_CENTER)
+ else
+ local wep = ent:GetActiveWeapon()
+ if wep:IsValid() then
+ draw.SimpleTextBlur(wep:GetPrintName(), "ZSHUDFontTiny", x, y, colTemp, TEXT_ALIGN_CENTER)
+ end
+ end
+ end
+end
+
+function GM:HUDDrawTargetID(teamid)
+ local start = EyePos()
+ trace.start = start
+ trace.endpos = start + EyeAngles():Forward() * 2048
+ trace.filter[1] = MySelf
+ trace.filter[2] = MySelf:GetObserverTarget()
+
+ local entity = util.TraceHull(trace).Entity
+ if entity:IsValid() and entity:IsPlayer() and entity:Team() == teamid then
+ entitylist[entity] = CurTime()
+ end
+
+ for ent, time in pairs(entitylist) do
+ if ent:IsValid() and not (ent:IsPlayer() and ent:Team() ~= teamid) and CurTime() < time + 2 then
+ self:DrawTargetID(ent, 1 - math.Clamp((CurTime() - time) / 2, 0, 1))
+ else
+ entitylist[ent] = nil
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/gamemode/cl_util.lua b/gamemodes/zombiesurvival/gamemode/cl_util.lua
new file mode 100644
index 0000000..f0ceec8
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/cl_util.lua
@@ -0,0 +1,64 @@
+concommand.Add("printdxinfo", function()
+ print("DX Level: "..tostring(render.GetDXLevel()))
+ print("Supports HDR: "..tostring(render.SupportsHDR()))
+ print("Supports Pixel Shaders 1.4: "..tostring(render.SupportsPixelShaders_1_4()))
+ print("Supports Pixel Shaders 2.0: "..tostring(render.SupportsPixelShaders_2_0()))
+ print("Supports Vertex Shaders 2.0: "..tostring(render.SupportsVertexShaders_2_0()))
+end)
+
+local function GetViewModelPosition(self, pos, ang)
+ return pos + ang:Forward() * -256, ang
+end
+
+function DontDrawViewModel()
+ if SWEP then
+ SWEP.GetViewModelPosition = GetViewModelPosition
+ end
+end
+
+-- Scales the screen based around 1080p but doesn't make things TOO tiny on low resolutions.
+function BetterScreenScale()
+ return math.Clamp(ScrH() / 1080, 0.6, 1)
+end
+
+function render.GetLightRGB(pos)
+ local vec = render.GetLightColor(pos)
+ return vec.r, vec.g, vec.b
+end
+
+function EasyLabel(parent, text, font, textcolor)
+ local dpanel = vgui.Create("DLabel", parent)
+ if font then
+ dpanel:SetFont(font or "DefaultFont")
+ end
+ dpanel:SetText(text)
+ dpanel:SizeToContents()
+ if textcolor then
+ dpanel:SetTextColor(textcolor)
+ end
+ dpanel:SetKeyboardInputEnabled(false)
+ dpanel:SetMouseInputEnabled(false)
+
+ return dpanel
+end
+
+function EasyButton(parent, text, xpadding, ypadding)
+ local dpanel = vgui.Create("DButton", parent)
+ if textcolor then
+ dpanel:SetFGColor(textcolor or color_white)
+ end
+ if text then
+ dpanel:SetText(text)
+ end
+ dpanel:SizeToContents()
+
+ if xpadding then
+ dpanel:SetWide(dpanel:GetWide() + xpadding * 2)
+ end
+
+ if ypadding then
+ dpanel:SetTall(dpanel:GetTall() + ypadding * 2)
+ end
+
+ return dpanel
+end
diff --git a/gamemodes/zombiesurvival/gamemode/cl_zombieescape.lua b/gamemodes/zombiesurvival/gamemode/cl_zombieescape.lua
new file mode 100644
index 0000000..720ee59
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/cl_zombieescape.lua
@@ -0,0 +1,11 @@
+include("sh_zombieescape.lua")
+
+if not GM.ZombieEscape then return end
+
+hook.Add("HUDPaint", "zombieescape", function()
+ if not MySelf:IsValid() then return end
+
+ if GAMEMODE:GetWave() == 0 and not GAMEMODE:GetWaveActive() and (MySelf:Team() == TEAM_UNDEAD or CurTime() < GAMEMODE:GetWaveStart() - GAMEMODE.ZE_FreezeTime) then
+ draw.SimpleTextBlur(translate.Format("ze_humans_are_frozen_until_x", GAMEMODE.ZE_FreezeTime), "ZSHUDFontSmall", ScrW() / 2, ScrH() / 2, COLOR_DARKRED, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/init.lua b/gamemodes/zombiesurvival/gamemode/init.lua
new file mode 100644
index 0000000..319a308
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/init.lua
@@ -0,0 +1,3777 @@
+--[[
+
+Zombie Survival
+by William "JetBoom" Moodhe
+williammoodhe@gmail.com -or- jetboom@noxiousnet.com
+http://www.noxiousnet.com/
+
+Further credits displayed by pressing F1 in-game.
+This was my first ever gamemode. A lot of stuff is from years ago and some stuff is very recent.
+
+]]
+
+-- CRAFTING AND ITEM IDEAS
+--[[
+ITEMS
+nighkeez: you run a bit faster while wearing them. Also attaches white boot props to your feet.
+AWTH barrel: if it so much as bangs in to something then it blows up with a huge explosion (like fire bomb size).
+stabber: stubber with a knife in the barrel. A melee weapon with very low size but high reach.
+hot milk: puts you to sleep for a stupid amount of time and you regenerate health a little bit.
+gelbanana: green gel banana. using it gives you 8 health.
+body armor: nullifies one hit that does 20 or more damage and then immediately breaks.
+
+RECIPEES
+boot prop + boot prop = nighkeez
+nighkeez + bananas prop = clown shoes
+explosive barrel + explosive barrel = big explosive barrel
+oxygen canister + big explosive barrel = AWTH barrel
+stubber + knife = stabber
+milk + heat source = hot milk
+ammonia + bleach = mustard gas on the spot. spams yellow fumes everywhere and lethally poisons the user.
+bananas + microwave = gelbanana
+metal barrel + something = body armor
+--]]
+
+AddCSLuaFile("cl_init.lua")
+AddCSLuaFile("shared.lua")
+
+AddCSLuaFile("sh_translate.lua")
+AddCSLuaFile("sh_colors.lua")
+AddCSLuaFile("sh_serialization.lua")
+AddCSLuaFile("sh_globals.lua")
+AddCSLuaFile("sh_crafts.lua")
+AddCSLuaFile("sh_util.lua")
+AddCSLuaFile("sh_options.lua")
+AddCSLuaFile("sh_zombieclasses.lua")
+AddCSLuaFile("sh_animations.lua")
+AddCSLuaFile("sh_sigils.lua")
+
+AddCSLuaFile("cl_draw.lua")
+AddCSLuaFile("cl_util.lua")
+AddCSLuaFile("cl_options.lua")
+AddCSLuaFile("cl_scoreboard.lua")
+AddCSLuaFile("cl_targetid.lua")
+AddCSLuaFile("cl_postprocess.lua")
+AddCSLuaFile("cl_deathnotice.lua")
+AddCSLuaFile("cl_floatingscore.lua")
+AddCSLuaFile("cl_dermaskin.lua")
+AddCSLuaFile("cl_hint.lua")
+
+AddCSLuaFile("obj_vector_extend.lua")
+AddCSLuaFile("obj_player_extend.lua")
+AddCSLuaFile("obj_player_extend_cl.lua")
+AddCSLuaFile("obj_weapon_extend.lua")
+AddCSLuaFile("obj_entity_extend.lua")
+
+AddCSLuaFile("vgui/dgamestate.lua")
+AddCSLuaFile("vgui/dteamcounter.lua")
+AddCSLuaFile("vgui/dmodelpanelex.lua")
+AddCSLuaFile("vgui/dammocounter.lua")
+AddCSLuaFile("vgui/dpingmeter.lua")
+AddCSLuaFile("vgui/dteamheading.lua")
+AddCSLuaFile("vgui/dsidemenu.lua")
+
+AddCSLuaFile("vgui/dexroundedpanel.lua")
+AddCSLuaFile("vgui/dexroundedframe.lua")
+AddCSLuaFile("vgui/dexrotatedimage.lua")
+AddCSLuaFile("vgui/dexnotificationslist.lua")
+AddCSLuaFile("vgui/dexchanginglabel.lua")
+
+AddCSLuaFile("vgui/pmainmenu.lua")
+AddCSLuaFile("vgui/poptions.lua")
+AddCSLuaFile("vgui/phelp.lua")
+AddCSLuaFile("vgui/pclassselect.lua")
+AddCSLuaFile("vgui/pweapons.lua")
+AddCSLuaFile("vgui/pendboard.lua")
+AddCSLuaFile("vgui/pworth.lua")
+AddCSLuaFile("vgui/ppointshop.lua")
+AddCSLuaFile("vgui/zshealtharea.lua")
+
+include("shared.lua")
+include("sv_options.lua")
+include("sv_crafts.lua")
+include("obj_entity_extend_sv.lua")
+include("obj_player_extend_sv.lua")
+include("mapeditor.lua")
+include("sv_playerspawnentities.lua")
+include("sv_profiling.lua")
+include("sv_sigils.lua")
+
+include("sv_zombieescape.lua")
+
+if file.Exists(GM.FolderName.."/gamemode/maps/"..game.GetMap()..".lua", "LUA") then
+ include("maps/"..game.GetMap()..".lua")
+end
+
+function BroadcastLua(code)
+ for _, pl in pairs(player.GetAll()) do
+ pl:SendLua(code)
+ end
+end
+
+player.GetByUniqueID = player.GetByUniqueID or function(uid)
+ for _, pl in pairs(player.GetAll()) do
+ if pl:UniqueID() == uid then return pl end
+ end
+end
+
+function GM:WorldHint(hint, pos, ent, lifetime, filter)
+ net.Start("zs_worldhint")
+ net.WriteString(hint)
+ net.WriteVector(pos or ent and ent:IsValid() and ent:GetPos() or vector_origin)
+ net.WriteEntity(ent or NULL)
+ net.WriteFloat(lifetime or 8)
+ if filter then
+ net.Send(filter)
+ else
+ net.Broadcast()
+ end
+end
+
+function GM:CreateGibs(pos, headoffset)
+ headoffset = headoffset or 0
+
+ local headpos = Vector(pos.x, pos.y, pos.z + headoffset)
+ for i = 1, 2 do
+ local ent = ents.CreateLimited("prop_playergib")
+ if ent:IsValid() then
+ ent:SetPos(headpos + VectorRand() * 5)
+ ent:SetAngles(VectorRand():Angle())
+ ent:SetGibType(i)
+ ent:Spawn()
+ end
+ end
+
+ for i=1, 4 do
+ local ent = ents.CreateLimited("prop_playergib")
+ if ent:IsValid() then
+ ent:SetPos(pos + VectorRand() * 12)
+ ent:SetAngles(VectorRand():Angle())
+ ent:SetGibType(math.random(3, #GAMEMODE.HumanGibs))
+ ent:Spawn()
+ end
+ end
+end
+
+function GM:TryHumanPickup(pl, entity)
+ if self.ZombieEscape or pl.NoObjectPickup then return end
+
+ if entity:IsValid() and not entity.m_NoPickup then
+ local entclass = entity:GetClass()
+ if (string.sub(entclass, 1, 12) == "prop_physics" or entclass == "func_physbox" or entity.HumanHoldable and entity:HumanHoldable(pl)) and pl:Team() == TEAM_HUMAN and not entity:IsNailed() and pl:Alive() and entity:GetMoveType() == MOVETYPE_VPHYSICS and entity:GetPhysicsObject():IsValid() and entity:GetPhysicsObject():GetMass() <= CARRY_MAXIMUM_MASS and entity:GetPhysicsObject():IsMoveable() and entity:OBBMins():Length() + entity:OBBMaxs():Length() <= CARRY_MAXIMUM_VOLUME then
+ local holder, status = entity:GetHolder()
+ if not holder and not pl:IsHolding() and CurTime() >= (pl.NextHold or 0)
+ and pl:GetShootPos():Distance(entity:NearestPoint(pl:GetShootPos())) <= 64 and pl:GetGroundEntity() ~= entity then
+ local newstatus = ents.Create("status_human_holding")
+ if newstatus:IsValid() then
+ pl.NextHold = CurTime() + 0.25
+ pl.NextUnHold = CurTime() + 0.05
+ newstatus:SetPos(pl:GetShootPos())
+ newstatus:SetOwner(pl)
+ newstatus:SetParent(pl)
+ newstatus:SetObject(entity)
+ newstatus:Spawn()
+ end
+ end
+ end
+ end
+end
+
+function GM:AddResources()
+ resource.AddFile("resource/fonts/typenoksidi.ttf")
+ resource.AddFile("resource/fonts/hidden.ttf")
+
+ for _, filename in pairs(file.Find("materials/zombiesurvival/*.vmt", "GAME")) do
+ resource.AddFile("materials/zombiesurvival/"..filename)
+ end
+
+ for _, filename in pairs(file.Find("materials/zombiesurvival/killicons/*.vmt", "GAME")) do
+ resource.AddFile("materials/zombiesurvival/killicons/"..filename)
+ end
+
+ resource.AddFile("materials/zombiesurvival/filmgrain/filmgrain.vmt")
+ resource.AddFile("materials/zombiesurvival/filmgrain/filmgrain.vtf")
+
+ for _, filename in pairs(file.Find("sound/zombiesurvival/*.ogg", "GAME")) do
+ resource.AddFile("sound/zombiesurvival/"..filename)
+ end
+ for _, filename in pairs(file.Find("sound/zombiesurvival/*.wav", "GAME")) do
+ resource.AddFile("sound/zombiesurvival/"..filename)
+ end
+ for _, filename in pairs(file.Find("sound/zombiesurvival/*.mp3", "GAME")) do
+ resource.AddFile("sound/zombiesurvival/"..filename)
+ end
+
+ local _____, dirs = file.Find("sound/zombiesurvival/beats/*", "GAME")
+ for _, dirname in pairs(dirs) do
+ for __, filename in pairs(file.Find("sound/zombiesurvival/beats/"..dirname.."/*.ogg", "GAME")) do
+ resource.AddFile("sound/zombiesurvival/beats/"..dirname.."/"..filename)
+ end
+ for __, filename in pairs(file.Find("sound/zombiesurvival/beats/"..dirname.."/*.wav", "GAME")) do
+ resource.AddFile("sound/zombiesurvival/beats/"..dirname.."/"..filename)
+ end
+ for __, filename in pairs(file.Find("sound/zombiesurvival/beats/"..dirname.."/*.mp3", "GAME")) do
+ resource.AddFile("sound/zombiesurvival/beats/"..dirname.."/"..filename)
+ end
+ end
+
+ resource.AddFile("materials/refract_ring.vmt")
+ resource.AddFile("materials/killicon/redeem.vtf")
+ resource.AddFile("materials/killicon/redeem.vmt")
+ resource.AddFile("materials/killicon/zs_axe.vtf")
+ resource.AddFile("materials/killicon/zs_keyboard.vtf")
+ resource.AddFile("materials/killicon/zs_sledgehammer.vtf")
+ resource.AddFile("materials/killicon/zs_fryingpan.vtf")
+ resource.AddFile("materials/killicon/zs_pot.vtf")
+ resource.AddFile("materials/killicon/zs_plank.vtf")
+ resource.AddFile("materials/killicon/zs_hammer.vtf")
+ resource.AddFile("materials/killicon/zs_shovel.vtf")
+ resource.AddFile("materials/killicon/zs_axe.vmt")
+ resource.AddFile("materials/killicon/zs_keyboard.vmt")
+ resource.AddFile("materials/killicon/zs_sledgehammer.vmt")
+ resource.AddFile("materials/killicon/zs_fryingpan.vmt")
+ resource.AddFile("materials/killicon/zs_pot.vmt")
+ resource.AddFile("materials/killicon/zs_plank.vmt")
+ resource.AddFile("materials/killicon/zs_hammer.vmt")
+ resource.AddFile("materials/killicon/zs_shovel.vmt")
+ resource.AddFile("models/weapons/v_zombiearms.mdl")
+ resource.AddFile("materials/models/weapons/v_zombiearms/Zombie_Classic_sheet.vmt")
+ resource.AddFile("materials/models/weapons/v_zombiearms/Zombie_Classic_sheet.vtf")
+ resource.AddFile("materials/models/weapons/v_zombiearms/Zombie_Classic_sheet_normal.vtf")
+ resource.AddFile("materials/models/weapons/v_zombiearms/ghoulsheet.vmt")
+ resource.AddFile("materials/models/weapons/v_zombiearms/ghoulsheet.vtf")
+ resource.AddFile("models/weapons/v_fza.mdl")
+ resource.AddFile("models/weapons/v_pza.mdl")
+ resource.AddFile("materials/models/weapons/v_fza/fast_zombie_sheet.vmt")
+ resource.AddFile("materials/models/weapons/v_fza/fast_zombie_sheet.vtf")
+ resource.AddFile("materials/models/weapons/v_fza/fast_zombie_sheet_normal.vtf")
+ resource.AddFile("models/weapons/v_annabelle.mdl")
+ resource.AddFile("materials/models/weapons/w_annabelle/gun.vtf")
+ resource.AddFile("materials/models/weapons/sledge.vtf")
+ resource.AddFile("materials/models/weapons/sledge.vmt")
+ resource.AddFile("materials/models/weapons/temptexture/handsmesh1.vtf")
+ resource.AddFile("materials/models/weapons/temptexture/handsmesh1.vmt")
+ resource.AddFile("materials/models/weapons/hammer2.vtf")
+ resource.AddFile("materials/models/weapons/hammer2.vmt")
+ resource.AddFile("materials/models/weapons/hammer.vtf")
+ resource.AddFile("materials/models/weapons/hammer.vmt")
+ resource.AddFile("models/weapons/w_sledgehammer.mdl")
+ resource.AddFile("models/weapons/v_sledgehammer/v_sledgehammer.mdl")
+ resource.AddFile("models/weapons/w_hammer.mdl")
+ resource.AddFile("models/weapons/v_hammer/v_hammer.mdl")
+
+ resource.AddFile("models/weapons/v_aegiskit.mdl")
+
+ resource.AddFile("materials/models/weapons/v_hand/armtexture.vmt")
+
+ resource.AddFile("models/wraith_zsv1.mdl")
+ for _, filename in pairs(file.Find("materials/models/wraith1/*.vmt", "GAME")) do
+ resource.AddFile("materials/models/wraith1/"..filename)
+ end
+ for _, filename in pairs(file.Find("materials/models/wraith1/*.vtf", "GAME")) do
+ resource.AddFile("materials/models/wraith1/"..filename)
+ end
+
+ resource.AddFile("models/weapons/v_supershorty/v_supershorty.mdl")
+ resource.AddFile("models/weapons/w_supershorty.mdl")
+ for _, filename in pairs(file.Find("materials/weapons/v_supershorty/*.vmt", "GAME")) do
+ resource.AddFile("materials/weapons/v_supershorty/"..filename)
+ end
+ for _, filename in pairs(file.Find("materials/weapons/v_supershorty/*.vtf", "GAME")) do
+ resource.AddFile("materials/weapons/v_supershorty/"..filename)
+ end
+ for _, filename in pairs(file.Find("materials/weapons/w_supershorty/*.vmt", "GAME")) do
+ resource.AddFile("materials/weapons/w_supershorty/"..filename)
+ end
+ for _, filename in pairs(file.Find("materials/weapons/w_supershorty/*.vtf", "GAME")) do
+ resource.AddFile("materials/weapons/w_supershorty/"..filename)
+ end
+ for _, filename in pairs(file.Find("materials/weapons/survivor01_hands/*.vmt", "GAME")) do
+ resource.AddFile("materials/weapons/survivor01_hands/"..filename)
+ end
+ for _, filename in pairs(file.Find("materials/weapons/survivor01_hands/*.vtf", "GAME")) do
+ resource.AddFile("materials/weapons/survivor01_hands/"..filename)
+ end
+
+ for _, filename in pairs(file.Find("materials/models/weapons/v_pza/*.*", "GAME")) do
+ resource.AddFile("materials/models/weapons/v_pza/"..string.lower(filename))
+ end
+
+ resource.AddFile("models/player/fatty/fatty.mdl")
+ resource.AddFile("materials/models/player/elis/fty/001.vmt")
+ resource.AddFile("materials/models/player/elis/fty/001.vtf")
+ resource.AddFile("materials/models/player/elis/fty/001_normal.vtf")
+
+ resource.AddFile("models/vinrax/player/doll_player.mdl")
+
+ resource.AddFile("sound/weapons/melee/golf club/golf_hit-01.ogg")
+ resource.AddFile("sound/weapons/melee/golf club/golf_hit-02.ogg")
+ resource.AddFile("sound/weapons/melee/golf club/golf_hit-03.ogg")
+ resource.AddFile("sound/weapons/melee/golf club/golf_hit-04.ogg")
+ resource.AddFile("sound/weapons/melee/crowbar/crowbar_hit-1.ogg")
+ resource.AddFile("sound/weapons/melee/crowbar/crowbar_hit-2.ogg")
+ resource.AddFile("sound/weapons/melee/crowbar/crowbar_hit-3.ogg")
+ resource.AddFile("sound/weapons/melee/crowbar/crowbar_hit-4.ogg")
+ resource.AddFile("sound/weapons/melee/shovel/shovel_hit-01.ogg")
+ resource.AddFile("sound/weapons/melee/shovel/shovel_hit-02.ogg")
+ resource.AddFile("sound/weapons/melee/shovel/shovel_hit-03.ogg")
+ resource.AddFile("sound/weapons/melee/shovel/shovel_hit-04.ogg")
+ resource.AddFile("sound/weapons/melee/frying_pan/pan_hit-01.ogg")
+ resource.AddFile("sound/weapons/melee/frying_pan/pan_hit-02.ogg")
+ resource.AddFile("sound/weapons/melee/frying_pan/pan_hit-03.ogg")
+ resource.AddFile("sound/weapons/melee/frying_pan/pan_hit-04.ogg")
+ resource.AddFile("sound/weapons/melee/keyboard/keyboard_hit-01.ogg")
+ resource.AddFile("sound/weapons/melee/keyboard/keyboard_hit-02.ogg")
+ resource.AddFile("sound/weapons/melee/keyboard/keyboard_hit-03.ogg")
+ resource.AddFile("sound/weapons/melee/keyboard/keyboard_hit-04.ogg")
+
+ resource.AddFile("materials/noxctf/sprite_bloodspray1.vmt")
+ resource.AddFile("materials/noxctf/sprite_bloodspray2.vmt")
+ resource.AddFile("materials/noxctf/sprite_bloodspray3.vmt")
+ resource.AddFile("materials/noxctf/sprite_bloodspray4.vmt")
+ resource.AddFile("materials/noxctf/sprite_bloodspray5.vmt")
+ resource.AddFile("materials/noxctf/sprite_bloodspray6.vmt")
+ resource.AddFile("materials/noxctf/sprite_bloodspray7.vmt")
+ resource.AddFile("materials/noxctf/sprite_bloodspray8.vmt")
+
+ resource.AddFile("sound/"..tostring(self.LastHumanSound))
+ resource.AddFile("sound/"..tostring(self.AllLoseSound))
+ resource.AddFile("sound/"..tostring(self.HumanWinSound))
+ resource.AddFile("sound/"..tostring(self.DeathSound))
+end
+
+function GM:Initialize()
+ self:RegisterPlayerSpawnEntities()
+ self:AddResources()
+ self:PrecacheResources()
+ self:AddCustomAmmo()
+ self:AddNetworkStrings()
+ self:LoadProfiler()
+
+ self:SetPantsMode(self.PantsMode, true)
+ self:SetClassicMode(self:IsClassicMode(), true)
+ self:SetBabyMode(self:IsBabyMode(), true)
+
+ local mapname = string.lower(game.GetMap())
+ if string.find(mapname, "_obj_", 1, true) or string.find(mapname, "objective", 1, true) then
+ self.ObjectiveMap = true
+ end
+
+ if string.sub(mapname, 1, 3) == "zm_" then
+ NOZOMBIEGASSES = true
+ end
+
+ game.ConsoleCommand("fire_dmgscale 1\n")
+ game.ConsoleCommand("mp_flashlight 1\n")
+ game.ConsoleCommand("sv_gravity 600\n")
+end
+
+function GM:AddNetworkStrings()
+ util.AddNetworkString("zs_gamestate")
+ util.AddNetworkString("zs_wavestart")
+ util.AddNetworkString("zs_waveend")
+ util.AddNetworkString("zs_lasthuman")
+ util.AddNetworkString("zs_gamemodecall")
+ util.AddNetworkString("zs_lasthumanpos")
+ util.AddNetworkString("zs_endround")
+ util.AddNetworkString("zs_centernotify")
+ util.AddNetworkString("zs_topnotify")
+ util.AddNetworkString("zs_zvols")
+
+ util.AddNetworkString("zs_playerredeemed")
+ util.AddNetworkString("zs_dohulls")
+ util.AddNetworkString("zs_penalty")
+ util.AddNetworkString("zs_nextresupplyuse")
+ util.AddNetworkString("zs_lifestats")
+ util.AddNetworkString("zs_lifestatsbd")
+ util.AddNetworkString("zs_lifestatshd")
+ util.AddNetworkString("zs_lifestatsbe")
+ util.AddNetworkString("zs_boss_spawned")
+ util.AddNetworkString("zs_commission")
+ util.AddNetworkString("zs_healother")
+ util.AddNetworkString("zs_repairobject")
+ util.AddNetworkString("zs_worldhint")
+ util.AddNetworkString("zs_honmention")
+ util.AddNetworkString("zs_floatscore")
+ util.AddNetworkString("zs_floatscore_vec")
+ util.AddNetworkString("zs_zclass")
+ util.AddNetworkString("zs_dmg")
+ util.AddNetworkString("zs_dmg_prop")
+ util.AddNetworkString("zs_legdamage")
+
+ util.AddNetworkString("zs_crow_kill_crow")
+ util.AddNetworkString("zs_pl_kill_pl")
+ util.AddNetworkString("zs_pls_kill_pl")
+ util.AddNetworkString("zs_pl_kill_self")
+ util.AddNetworkString("zs_death")
+end
+
+function GM:IsClassicMode()
+ return self.ClassicMode
+end
+
+function GM:IsBabyMode()
+ return self.BabyMode
+end
+
+function GM:CenterNotifyAll(...)
+ net.Start("zs_centernotify")
+ net.WriteTable({...})
+ net.Broadcast()
+end
+GM.CenterNotify = GM.CenterNotifyAll
+
+function GM:TopNotifyAll(...)
+ net.Start("zs_topnotify")
+ net.WriteTable({...})
+ net.Broadcast()
+end
+GM.TopNotify = GM.TopNotifyAll
+
+function GM:ShowHelp(pl)
+ pl:SendLua("GAMEMODE:ShowHelp()")
+end
+
+function GM:ShowTeam(pl)
+ if pl:Team() == TEAM_HUMAN and not self.ZombieEscape then
+ pl:SendLua(self:GetWave() > 0 and "GAMEMODE:OpenPointsShop()" or "MakepWorth()")
+ end
+end
+
+function GM:ShowSpare1(pl)
+ if pl:Team() == TEAM_UNDEAD then
+ if self:ShouldUseAlternateDynamicSpawn() then
+ pl:CenterNotify(COLOR_RED, translate.ClientGet(pl, "no_class_switch_in_this_mode"))
+ else
+ pl:SendLua("GAMEMODE:OpenClassSelect()")
+ end
+ else
+ pl:SendLua("MakepWeapons()")
+ end
+end
+
+function GM:ShowSpare2(pl)
+ pl:SendLua("MakepOptions()")
+end
+
+function GM:SetupSpawnPoints()
+ local ztab = ents.FindByClass("info_player_undead")
+ ztab = table.Add(ztab, ents.FindByClass("info_player_zombie"))
+ ztab = table.Add(ztab, ents.FindByClass("info_player_rebel"))
+
+ local htab = ents.FindByClass("info_player_human")
+ htab = table.Add(htab, ents.FindByClass("info_player_combine"))
+
+ local mapname = string.lower(game.GetMap())
+ -- Terrorist spawns are usually in some kind of house or a main base in CS_ in order to guard the hosties. Put the humans there.
+ if string.sub(mapname, 1, 3) == "cs_" or string.sub(mapname, 1, 3) == "zs_" then
+ ztab = table.Add(ztab, ents.FindByClass("info_player_counterterrorist"))
+ htab = table.Add(htab, ents.FindByClass("info_player_terrorist"))
+ else -- Otherwise, this is probably a DE_, ZM_, or ZH_ map. In DE_ maps, the T's spawn away from the main part of the map and are zombies in zombie plugins so let's do the same.
+ ztab = table.Add(ztab, ents.FindByClass("info_player_terrorist"))
+ htab = table.Add(htab, ents.FindByClass("info_player_counterterrorist"))
+ end
+
+ -- Add all the old ZS spawns from GMod9.
+ for _, oldspawn in pairs(ents.FindByClass("gmod_player_start")) do
+ if oldspawn.BlueTeam then
+ table.insert(htab, oldspawn)
+ else
+ table.insert(ztab, oldspawn)
+ end
+ end
+
+ -- You shouldn't play a DM map since spawns are shared but whatever. Let's make sure that there aren't team spawns first.
+ if #htab == 0 then
+ htab = ents.FindByClass("info_player_start")
+ htab = table.Add(htab, ents.FindByClass("info_player_deathmatch")) -- Zombie Master
+ end
+ if #ztab == 0 then
+ ztab = ents.FindByClass("info_player_start")
+ ztab = table.Add(ztab, ents.FindByClass("info_zombiespawn")) -- Zombie Master
+ end
+
+ team.SetSpawnPoint(TEAM_UNDEAD, ztab)
+ team.SetSpawnPoint(TEAM_HUMAN, htab)
+
+ self.RedeemSpawnPoints = ents.FindByClass("info_player_redeemed")
+ self.BossSpawnPoints = table.Add(ents.FindByClass("info_player_zombie_boss"), ents.FindByClass("info_player_undead_boss"))
+end
+
+function GM:PlayerPointsAdded(pl, amount)
+end
+
+local weaponmodelstoweapon = {}
+weaponmodelstoweapon["models/props/cs_office/computer_keyboard.mdl"] = "weapon_zs_keyboard"
+weaponmodelstoweapon["models/props_c17/computer01_keyboard.mdl"] = "weapon_zs_keyboard"
+weaponmodelstoweapon["models/props_c17/metalpot001a.mdl"] = "weapon_zs_pot"
+weaponmodelstoweapon["models/props_interiors/pot02a.mdl"] = "weapon_zs_fryingpan"
+weaponmodelstoweapon["models/props_c17/metalpot002a.mdl"] = "weapon_zs_fryingpan"
+weaponmodelstoweapon["models/props_junk/shovel01a.mdl"] = "weapon_zs_shovel"
+weaponmodelstoweapon["models/props/cs_militia/axe.mdl"] = "weapon_zs_axe"
+weaponmodelstoweapon["models/props_c17/tools_wrench01a.mdl"] = "weapon_zs_hammer"
+weaponmodelstoweapon["models/weapons/w_knife_t.mdl"] = "weapon_zs_swissarmyknife"
+weaponmodelstoweapon["models/weapons/w_knife_ct.mdl"] = "weapon_zs_swissarmyknife"
+weaponmodelstoweapon["models/weapons/w_crowbar.mdl"] = "weapon_zs_crowbar"
+weaponmodelstoweapon["models/weapons/w_stunbaton.mdl"] = "weapon_zs_stunbaton"
+weaponmodelstoweapon["models/props_interiors/furniture_lamp01a.mdl"] = "weapon_zs_lamp"
+weaponmodelstoweapon["models/props_junk/rock001a.mdl"] = "weapon_zs_stone"
+weaponmodelstoweapon["models/props_c17/canister01a.mdl"] = "weapon_zs_oxygentank"
+weaponmodelstoweapon["models/props_canal/mattpipe.mdl"] = "weapon_zs_pipe"
+weaponmodelstoweapon["models/props_junk/meathook001a.mdl"] = "weapon_zs_hook"
+function GM:InitPostEntity()
+ gamemode.Call("InitPostEntityMap")
+
+ RunConsoleCommand("mapcyclefile", "mapcycle_zombiesurvival.txt")
+
+ if string.find(string.lower(GetConVarString("hostname")), "hellsgamers", 1, true) then
+ self.Think = function() end
+ self.DoPlayerDeath = self.Think
+ self.SetWave = self.Think
+ timer.Simple(20, function() RunConsoleCommand("quit") end)
+
+ ErrorNoHalt("You are literally not allowed to host this version. See license.txt")
+ end
+end
+
+function GM:SetupProps()
+ for _, ent in pairs(ents.FindByClass("prop_physics*")) do
+ local mdl = ent:GetModel()
+ if mdl then
+ mdl = string.lower(mdl)
+ if table.HasValue(self.BannedProps, mdl) then
+ ent:Remove()
+ elseif weaponmodelstoweapon[mdl] then
+ local wep = ents.Create("prop_weapon")
+ if wep:IsValid() then
+ wep:SetPos(ent:GetPos())
+ wep:SetAngles(ent:GetAngles())
+ wep:SetWeaponType(weaponmodelstoweapon[mdl])
+ wep:SetShouldRemoveAmmo(false)
+ wep:Spawn()
+
+ ent:Remove()
+ end
+ elseif ent:GetMaxHealth() == 1 and ent:Health() == 0 and ent:GetKeyValues().damagefilter ~= "invul" and ent:GetName() == "" then
+ local health = math.min(2500, math.ceil((ent:OBBMins():Length() + ent:OBBMaxs():Length()) * 10))
+ local hmul = self.PropHealthMultipliers[mdl]
+ if hmul then
+ health = health * hmul
+ end
+
+ ent.PropHealth = health
+ ent.TotalHealth = health
+ else
+ ent:SetHealth(math.ceil(ent:Health() * 3))
+ ent:SetMaxHealth(ent:Health())
+ end
+ end
+ end
+end
+
+function GM:RemoveUnusedEntities()
+ -- Causes a lot of needless lag.
+ util.RemoveAll("prop_ragdoll")
+
+ -- Remove NPCs because first of all this game is PvP and NPCs can cause crashes.
+ util.RemoveAll("npc_maker")
+ util.RemoveAll("npc_template_maker")
+ util.RemoveAll("npc_zombie")
+ util.RemoveAll("npc_zombie_torso")
+ util.RemoveAll("npc_fastzombie")
+ util.RemoveAll("npc_headcrab")
+ util.RemoveAll("npc_headcrab_fast")
+ util.RemoveAll("npc_headcrab_black")
+ util.RemoveAll("npc_poisonzombie")
+
+ -- Such a headache. Just remove them all.
+ util.RemoveAll("item_ammo_crate")
+
+ -- Shouldn't exist.
+ util.RemoveAll("item_suitcharger")
+end
+
+function GM:ReplaceMapWeapons()
+ for _, ent in pairs(ents.FindByClass("weapon_*")) do
+ if string.sub(ent:GetClass(), 1, 10) == "weapon_zs_" then
+ local wep = ents.Create("prop_weapon")
+ if wep:IsValid() then
+ wep:SetPos(ent:GetPos())
+ wep:SetAngles(ent:GetAngles())
+ wep:SetWeaponType(ent:GetClass())
+ wep:SetShouldRemoveAmmo(false)
+ wep:Spawn()
+ wep.IsPreplaced = true
+ end
+ end
+
+ ent:Remove()
+ end
+end
+
+local ammoreplacements = {
+ ["item_ammo_357"] = "357",
+ ["item_ammo_357_large"] = "357",
+ ["item_ammo_pistol"] = "pistol",
+ ["item_ammo_pistol_large"] = "pistol",
+ ["item_ammo_buckshot"] = "buckshot",
+ ["item_ammo_ar2"] = "ar2",
+ ["item_ammo_ar2_large"] = "ar2",
+ ["item_ammo_ar2_altfire"] = "pulse",
+ ["item_ammo_crossbow"] = "xbowbolt",
+ ["item_ammo_smg1"] = "smg1",
+ ["item_ammo_smg1_large"] = "smg1",
+ ["item_box_buckshot"] = "buckshot"
+}
+function GM:ReplaceMapAmmo()
+ for classname, ammotype in pairs(ammoreplacements) do
+ for _, ent in pairs(ents.FindByClass(classname)) do
+ local newent = ents.Create("prop_ammo")
+ if newent:IsValid() then
+ newent:SetAmmoType(ammotype)
+ newent.PlacedInMap = true
+ newent:SetPos(ent:GetPos())
+ newent:SetAngles(ent:GetAngles())
+ newent:Spawn()
+ newent:SetAmmo(self.AmmoCache[ammotype] or 1)
+ end
+ ent:Remove()
+ end
+ end
+
+ util.RemoveAll("item_item_crate")
+end
+
+function GM:ReplaceMapBatteries()
+ util.RemoveAll("item_battery")
+end
+
+function GM:CreateZombieGas()
+ if NOZOMBIEGASSES then return end
+
+ local humanspawns = team.GetValidSpawnPoint(TEAM_HUMAN)
+
+ for _, spawn in pairs(team.GetValidSpawnPoint(TEAM_UNDEAD)) do
+ local gasses = ents.FindByClass("zombiegasses")
+ local numgasses = #gasses
+ if 4 < numgasses then
+ break
+ elseif numgasses == 0 or math.random(4) == 1 then
+ local spawnpos = spawn:GetPos() + Vector(0, 0, 24)
+ local near = false
+
+ if not self.ZombieEscape then
+ for _, humspawn in pairs(humanspawns) do
+ if humspawn:IsValid() and humspawn:GetPos():Distance(spawnpos) < 400 then
+ near = true
+ break
+ end
+ end
+ end
+ if not near then
+ for _, gas in pairs(gasses) do
+ if gas:GetPos():Distance(spawnpos) < 300 then
+ near = true
+ break
+ end
+ end
+ end
+
+ if not near then
+ local ent = ents.Create("zombiegasses")
+ if ent:IsValid() then
+ ent:SetPos(spawnpos)
+ ent:Spawn()
+ end
+ end
+ end
+ end
+end
+
+function GM:CheckDynamicSpawnHR(ent)
+ if ent and ent:IsValid() and ent:IsPlayer() and ent:Team() == TEAM_UNDEAD then
+ ent.DynamicSpawnedOn = ent.DynamicSpawnedOn + 1
+ end
+end
+
+local playermins = Vector(-17, -17, 0)
+local playermaxs = Vector(17, 17, 4)
+local LastSpawnPoints = {}
+
+function GM:PlayerSelectSpawn(pl)
+ local spawninplayer = false
+ local teamid = pl:Team()
+ local tab
+ local epicenter
+ if pl.m_PreRedeem and teamid == TEAM_HUMAN and #self.RedeemSpawnPoints >= 1 then
+ tab = self.RedeemSpawnPoints
+ elseif teamid == TEAM_UNDEAD then
+ if pl:GetZombieClassTable().Boss and #self.BossSpawnPoints >= 1 then
+ tab = self.BossSpawnPoints
+ elseif self.DynamicSpawning --[[and CurTime() >= self:GetWaveStart() + 1]] then -- If we're a bit in the wave then we can spawn on top of heavily dense groups with no humans looking at us.
+ if self:ShouldUseAlternateDynamicSpawn() then
+ -- If they're near a human, use position where they died.
+ for _, h in pairs(team.GetPlayers(TEAM_HUMAN)) do
+ if h:GetPos():Distance(epicenter or pl:GetPos()) < 1024 then
+ epicenter = pl.KilledPos
+ break
+ end
+ end
+
+ -- Not near a human when they died, so use best dynamic spawn based on human epicenter.
+ if not epicenter then
+ local best = self:GetBestDynamicSpawn(pl)
+ if IsValid(best) then return best end
+ end
+
+ tab = table.Copy(team.GetValidSpawnPoint(TEAM_UNDEAD))
+ local dynamicspawns = self:GetDynamicSpawns(pl)
+ if #dynamicspawns > 0 then
+ spawninplayer = true
+ table.Add(tab, dynamicspawns)
+ end
+ else
+ local dyn = pl.ForceDynamicSpawn
+ if dyn then
+ pl.ForceDynamicSpawn = nil
+ if self:DynamicSpawnIsValid(dyn) then
+ self:CheckDynamicSpawnHR(dyn)
+
+ if dyn:GetClass() == "prop_creepernest" then
+ local owner = dyn.Owner
+ if owner and owner:IsValid() and owner:Team() == TEAM_UNDEAD then
+ owner.NestSpawns = owner.NestSpawns + 1
+ end
+ end
+
+ return dyn
+ end
+
+ epicenter = dyn:GetPos() -- Ok, at least skew our epicenter to what they tried to spawn at.
+ tab = table.Copy(team.GetValidSpawnPoint(TEAM_UNDEAD))
+ local dynamicspawns = self:GetDynamicSpawns(pl)
+ if #dynamicspawns > 0 then
+ spawninplayer = true
+ table.Add(tab, dynamicspawns)
+ end
+ else
+ tab = table.Copy(team.GetValidSpawnPoint(TEAM_UNDEAD))
+ local dynamicspawns = self:GetDynamicSpawns(pl)
+ if #dynamicspawns > 0 then
+ spawninplayer = true
+ table.Add(tab, dynamicspawns)
+ end
+ end
+ end
+ end
+ end
+
+ if not tab or #tab == 0 then tab = team.GetValidSpawnPoint(teamid) or {} end
+
+ -- Now we have a table of our potential spawn points, including dynamic spawns (other players).
+ -- We validate if the spawn is blocked, disabled, or otherwise not suitable below.
+
+ local count = #tab
+ if count > 0 then
+ local potential = {}
+
+ for _, spawn in pairs(tab) do
+ if spawn:IsValid() and not spawn.Disabled and (spawn:IsPlayer() or spawn ~= LastSpawnPoints[teamid] or #tab == 1) and spawn:IsInWorld() then
+ local blocked
+ local spawnpos = spawn:GetPos()
+ for _, ent in pairs(ents.FindInBox(spawnpos + playermins, spawnpos + playermaxs)) do
+ if ent:IsPlayer() and not spawninplayer or string.sub(ent:GetClass(), 1, 5) == "prop_" then
+ blocked = true
+ break
+ end
+ end
+ if not blocked then
+ potential[#potential + 1] = spawn
+ end
+ end
+ end
+
+ -- Now our final spawn list. Pick the one that's closest to the humans if we're a zombie. Otherwise use a random spawn.
+ if #potential > 0 then
+ local spawn = teamid == TEAM_UNDEAD and self:GetClosestSpawnPoint(potential, epicenter or self:GetTeamEpicentre(TEAM_HUMAN)) or table.Random(potential)
+ if spawn then
+ LastSpawnPoints[teamid] = spawn
+ self:CheckDynamicSpawnHR(spawn)
+ return spawn
+ end
+ end
+ end
+
+ -- Fallback.
+ return LastSpawnPoints[teamid] or #tab > 0 and table.Random(tab) or pl
+end
+
+local function BossZombieSort(a, b)
+ local ascore = a.BarricadeDamage * 0.2 + a.DamageDealt[TEAM_UNDEAD]
+ local bscore = b.BarricadeDamage * 0.2 + b.DamageDealt[TEAM_UNDEAD]
+ if ascore == bscore then
+ return a:Deaths() < b:Deaths()
+ end
+
+ return ascore > bscore
+end
+function GM:SpawnBossZombie(bossplayer, silent)
+ if not bossplayer then
+ local livingbosses = 0
+ local zombies = {}
+ for _, ent in pairs(team.GetPlayers(TEAM_UNDEAD)) do
+ if ent:GetZombieClassTable().Boss and ent:Alive() then
+ livingbosses = livingbosses + 1
+ if livingbosses >= 3 then return end
+ else
+ table.insert(zombies, ent)
+ end
+ end
+ table.sort(zombies, BossZombieSort)
+
+ bossplayer = zombies[1]
+ end
+
+ if not bossplayer then return end
+
+ local bossindex = bossplayer:GetBossZombieIndex()
+ if bossindex == -1 then return end
+
+ self.LastBossZombieSpawned = self:GetWave()
+
+ local curclass = bossplayer.DeathClass or bossplayer:GetZombieClass()
+ bossplayer:KillSilent()
+ bossplayer:SetZombieClass(bossindex)
+ bossplayer:DoHulls(bossindex, TEAM_UNDEAD)
+ bossplayer.DeathClass = nil
+ bossplayer:UnSpectateAndSpawn()
+ bossplayer.DeathClass = curclass
+
+ if not silent then
+ net.Start("zs_boss_spawned")
+ net.WriteEntity(bossplayer)
+ net.WriteUInt(bossindex, 8)
+ net.Broadcast()
+ end
+end
+
+function GM:SendZombieVolunteers(pl, nonemptyonly)
+ if nonemptyonly and #self.ZombieVolunteers == 0 then return end
+
+ net.Start("zs_zvols")
+ net.WriteUInt(#self.ZombieVolunteers, 8)
+ for _, p in ipairs(self.ZombieVolunteers) do
+ net.WriteEntity(p)
+ end
+ if pl then
+ net.Send(pl)
+ else
+ net.Broadcast()
+ end
+end
+
+local NextTick = 0
+function GM:Think()
+ local time = CurTime()
+ local wave = self:GetWave()
+
+ if not self.RoundEnded then
+ if self:GetWaveActive() then
+ if self:GetWaveEnd() <= time and self:GetWaveEnd() ~= -1 then
+ gamemode.Call("SetWaveActive", false)
+ end
+ elseif self:GetWaveStart() ~= -1 then
+ if self:GetWaveStart() <= time then
+ gamemode.Call("SetWaveActive", true)
+ elseif self.BossZombies and not self.PantsMode and not self:IsClassicMode() and not self.ZombieEscape
+ and self.LastBossZombieSpawned ~= wave and wave > 0 and self:GetWaveStart() - 10 <= time and not self.RoundEnded
+ and (self.BossZombiePlayersRequired <= 0 or #player.GetAll() >= self.BossZombiePlayersRequired) then
+ self:SpawnBossZombie()
+ end
+ end
+ end
+
+ local humans = team.GetPlayers(TEAM_HUMAN)
+ for _, pl in pairs(humans) do
+ if pl:Team() == TEAM_HUMAN then
+ if pl:GetBarricadeGhosting() then
+ pl:BarricadeGhostingThink()
+ end
+
+ if pl.m_PointQueue >= 1 and time >= pl.m_LastDamageDealt + 3 then
+ pl:PointCashOut((pl.m_LastDamageDealtPosition or pl:GetPos()) + Vector(0, 0, 32), FM_NONE)
+ end
+ end
+ end
+
+ if wave == 0 then
+ self:CalculateZombieVolunteers()
+ end
+
+ if NextTick <= time then
+ NextTick = time + 1
+
+ local doafk = not self:GetWaveActive() and wave == 0
+ local dopoison = self:GetEscapeStage() == ESCAPESTAGE_DEATH
+
+ for _, pl in pairs(humans) do
+ if pl:Alive() then
+ if doafk then
+ local plpos = pl:GetPos()
+ if pl.LastAFKPosition and (pl.LastAFKPosition.x ~= plpos.x or pl.LastAFKPosition.y ~= plpos.y) then
+ pl.LastNotAFK = CurTime()
+ end
+ pl.LastAFKPosition = plpos
+ end
+
+ if pl:WaterLevel() >= 3 and not (pl.status_drown and pl.status_drown:IsValid()) then
+ pl:GiveStatus("drown")
+ else
+ pl:PreventSkyCade()
+ end
+
+ if self:GetWave() >= 1 and time >= pl.BonusDamageCheck + 60 then
+ pl.BonusDamageCheck = time
+ pl:AddPoints(2)
+ pl:PrintTranslatedMessage(HUD_PRINTCONSOLE, "minute_points_added", 2)
+ end
+
+ if pl.BuffRegenerative and time >= pl.NextRegenerate and pl:Health() < pl:GetMaxHealth() / 2 then
+ pl.NextRegenerate = time + 5
+ pl:SetHealth(pl:Health() + 1)
+ end
+
+ if dopoison then
+ pl:TakeSpecialDamage(5, DMG_POISON)
+ end
+ end
+ end
+ end
+end
+
+-- We calculate the volunteers. If the list changed then broadcast the new list.
+function GM:CalculateZombieVolunteers()
+ local volunteers = {}
+ local allplayers = player.GetAll()
+ self:SortZombieSpawnDistances(allplayers)
+ for i = 1, self:GetDesiredStartingZombies() do
+ volunteers[i] = allplayers[i]
+ end
+
+ local mismatch = false
+ if #volunteers ~= #self.ZombieVolunteers then
+ mismatch = true
+ else
+ for i=1, #volunteers do
+ if volunteers[i] ~= self.ZombieVolunteers[i] then
+ mismatch = true
+ break
+ end
+ end
+ end
+ if mismatch then
+ self.ZombieVolunteers = volunteers
+ self:SendZombieVolunteers()
+ end
+end
+
+function GM:LastBite(victim, attacker)
+ LAST_BITE = attacker
+end
+
+function GM:CalculateInfliction(victim, attacker)
+ if self.RoundEnded or self:GetWave() == 0 then return self.CappedInfliction end
+
+ local players = 0
+ local zombies = 0
+ local humans = 0
+ local wonhumans = 0
+ local hum
+ for _, pl in pairs(player.GetAll()) do
+ if not pl.Disconnecting then
+ if pl:Team() == TEAM_UNDEAD then
+ zombies = zombies + 1
+ elseif pl:HasWon() then
+ wonhumans = wonhumans + 1
+ else
+ humans = humans + 1
+ hum = pl
+ end
+ end
+ end
+
+ players = humans + zombies
+
+ if players == 0 then return self.CappedInfliction end
+
+ local infliction = math.max(zombies / players, self.CappedInfliction)
+ self.CappedInfliction = infliction
+
+ if humans == 1 and 2 < zombies then
+ gamemode.Call("LastHuman", hum)
+ elseif 1 <= infliction then
+ infliction = 1
+
+ if wonhumans >= 1 then
+ gamemode.Call("EndRound", TEAM_HUMAN)
+ else
+ gamemode.Call("EndRound", TEAM_UNDEAD)
+
+ if attacker and attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_UNDEAD and attacker ~= victim then
+ gamemode.Call("LastBite", victim, attacker)
+ end
+ end
+ end
+
+ if not self:IsClassicMode() and not self.ZombieEscape and not self:IsBabyMode() and not self.PantsMode then
+ for k, v in ipairs(self.ZombieClasses) do
+ if v.Infliction and infliction >= v.Infliction and not self:IsClassUnlocked(v.Name) then
+ v.Unlocked = true
+
+ if not self.PantsMode and not self:IsClassicMode() and not self:IsBabyMode() and not self.ZombieEscape then
+ if not v.Locked then
+ for _, pl in pairs(player.GetAll()) do
+ pl:CenterNotify(COLOR_RED, translate.ClientFormat(pl, "infliction_reached", v.Infliction * 100))
+ pl:CenterNotify(translate.ClientFormat(pl, "x_unlocked", translate.ClientGet(pl, v.TranslationName)))
+ end
+ end
+ end
+ end
+ end
+ end
+
+ for _, ent in pairs(ents.FindByClass("logic_infliction")) do
+ if ent.Infliction <= infliction then
+ ent:Input("oninflictionreached", NULL, NULL, infliction)
+ end
+ end
+
+ return infliction
+end
+timer.Create("CalculateInfliction", 2, 0, function() gamemode.Call("CalculateInfliction") end)
+
+function GM:OnNPCKilled(ent, attacker, inflictor)
+end
+
+function GM:LastHuman(pl)
+ if not LASTHUMAN then
+ net.Start("zs_lasthuman")
+ net.WriteEntity(pl or NULL)
+ net.Broadcast()
+
+ LASTHUMAN = true
+ end
+
+ self.TheLastHuman = pl
+
+ for _, ent in pairs(ents.FindByClass("logic_infliction")) do
+ ent:Input("onlasthuman", pl, pl, pl and pl:IsValid() and pl:EntIndex() or -1)
+ end
+end
+
+function GM:PlayerHealedTeamMember(pl, other, health, wep)
+ if self:GetWave() == 0 then return end
+
+ pl.HealedThisRound = pl.HealedThisRound + health
+ pl.CarryOverHealth = (pl.CarryOverHealth or 0) + health
+
+ local hpperpoint = self.MedkitPointsPerHealth
+ if hpperpoint <= 0 then return end
+
+ local points = math.floor(pl.CarryOverHealth / hpperpoint)
+
+ if 1 <= points then
+ pl:AddPoints(points)
+
+ pl.CarryOverHealth = pl.CarryOverHealth - points * hpperpoint
+
+ net.Start("zs_healother")
+ net.WriteEntity(other)
+ net.WriteUInt(points, 16)
+ net.Send(pl)
+ end
+end
+
+function GM:ObjectPackedUp(pack, packer, owner)
+end
+
+function GM:PlayerRepairedObject(pl, other, health, wep)
+ if self:GetWave() == 0 then return end
+
+ pl.RepairedThisRound = pl.RepairedThisRound + health
+ pl.CarryOverRepair = (pl.CarryOverRepair or 0) + health
+
+ local hpperpoint = self.RepairPointsPerHealth
+ if hpperpoint <= 0 then return end
+
+ local points = math.floor(pl.CarryOverRepair / hpperpoint)
+
+ if 1 <= points then
+ pl:AddPoints(points)
+
+ pl.CarryOverRepair = pl.CarryOverRepair - points * hpperpoint
+
+ net.Start("zs_repairobject")
+ net.WriteEntity(other)
+ net.WriteUInt(points, 16)
+ net.Send(pl)
+ end
+end
+
+function GM:CacheHonorableMentions()
+ if self.CachedHMs then return end
+
+ self.CachedHMs = {}
+
+ for i, hm in ipairs(self.HonorableMentions) do
+ if hm.GetPlayer then
+ local pl, magnitude = hm.GetPlayer(self)
+ if pl then
+ self.CachedHMs[i] = {pl, i, magnitude or 0}
+ end
+ end
+ end
+
+ gamemode.Call("PostDoHonorableMentions")
+end
+
+function GM:DoHonorableMentions(filter)
+ self:CacheHonorableMentions()
+
+ for i, tab in pairs(self.CachedHMs) do
+ net.Start("zs_honmention")
+ net.WriteEntity(tab[1])
+ net.WriteUInt(tab[2], 8)
+ net.WriteInt(tab[3], 32)
+ if filter then
+ net.Send(filter)
+ else
+ net.Broadcast()
+ end
+ end
+end
+
+function GM:PostDoHonorableMentions()
+end
+
+function GM:PostEndRound(winner)
+end
+
+-- You can override or hook and return false in case you have your own map change system.
+local function RealMap(map)
+ return string.match(map, "(.+)%.bsp")
+end
+function GM:LoadNextMap()
+ -- Just in case.
+ timer.Simple(10, game.LoadNextMap)
+ timer.Simple(15, function() RunConsoleCommand("changelevel", game.GetMap()) end)
+
+ if file.Exists(GetConVarString("mapcyclefile"), "GAME") then
+ game.LoadNextMap()
+ else
+ local maps = file.Find("maps/zs_*.bsp", "GAME")
+ maps = table.Add(maps, file.Find("maps/ze_*.bsp", "GAME"))
+ maps = table.Add(maps, file.Find("maps/zm_*.bsp", "GAME"))
+ table.sort(maps)
+ if #maps > 0 then
+ local currentmap = game.GetMap()
+ for i, map in ipairs(maps) do
+ local lowermap = string.lower(map)
+ local realmap = RealMap(lowermap)
+ if realmap == currentmap then
+ if maps[i + 1] then
+ local nextmap = RealMap(maps[i + 1])
+ if nextmap then
+ RunConsoleCommand("changelevel", nextmap)
+ end
+ else
+ local nextmap = RealMap(maps[1])
+ if nextmap then
+ RunConsoleCommand("changelevel", nextmap)
+ end
+ end
+
+ break
+ end
+ end
+ end
+ end
+end
+
+function GM:PreRestartRound()
+ for _, pl in pairs(player.GetAll()) do
+ pl:StripWeapons()
+ pl:Spectate(OBS_MODE_ROAMING)
+ pl:GodDisable()
+ end
+end
+
+GM.CurrentRound = 1
+function GM:RestartRound()
+ self.CurrentRound = self.CurrentRound + 1
+
+ self:RestartLua()
+ self:RestartGame()
+
+ net.Start("zs_gamemodecall")
+ net.WriteString("RestartRound")
+ net.Broadcast()
+end
+
+GM.DynamicSpawning = true
+GM.CappedInfliction = 0
+GM.StartingZombie = {}
+GM.CheckedOut = {}
+GM.PreviouslyDied = {}
+GM.StoredUndeadFrags = {}
+
+function GM:RestartLua()
+ self.CachedHMs = nil
+ self.TheLastHuman = nil
+ self.LastBossZombieSpawned = nil
+ self.UseSigils = nil
+
+ self.OverrideEndSlomo = nil
+ if type(GetGlobalBool("endcamera", 1)) ~= "number" then
+ SetGlobalBool("endcamera", nil)
+ end
+ if GetGlobalString("winmusic", "-") ~= "-" then
+ SetGlobalString("winmusic", nil)
+ end
+ if GetGlobalString("losemusic", "-") ~= "-" then
+ SetGlobalString("losemusic", nil)
+ end
+ if type(GetGlobalVector("endcamerapos", 1)) ~= "number" then
+ SetGlobalVector("endcamerapos", nil)
+ end
+
+ self.CappedInfliction = 0
+
+ self.StartingZombie = {}
+ self.CheckedOut = {}
+ self.PreviouslyDied = {}
+ self.StoredUndeadFrags = {}
+
+ ROUNDWINNER = nil
+ LAST_BITE = nil
+ LASTHUMAN = nil
+
+ hook.Remove("PlayerShouldTakeDamage", "EndRoundShouldTakeDamage")
+ hook.Remove("PlayerCanHearPlayersVoice", "EndRoundCanHearPlayersVoice")
+
+ self:RevertZombieClasses()
+end
+
+-- I don't know.
+local function CheckBroken()
+ for _, pl in pairs(player.GetAll()) do
+ if pl:Alive() and (pl:Health() <= 0 or pl:GetObserverMode() ~= OBS_MODE_NONE or pl:OBBMaxs().x ~= 16) then
+ pl:SetObserverMode(OBS_MODE_NONE)
+ pl:UnSpectateAndSpawn()
+ end
+ end
+end
+
+function GM:DoRestartGame()
+ self.RoundEnded = nil
+
+ for _, ent in pairs(ents.FindByClass("prop_weapon")) do
+ ent:Remove()
+ end
+
+ for _, ent in pairs(ents.FindByClass("prop_ammo")) do
+ ent:Remove()
+ end
+
+ self:SetUseSigils(false)
+ self:SetEscapeStage(ESCAPESTAGE_NONE)
+
+ self:SetWave(0)
+ if GAMEMODE.ZombieEscape then
+ self:SetWaveStart(CurTime() + 30)
+ else
+ self:SetWaveStart(CurTime() + self.WaveZeroLength)
+ end
+ self:SetWaveEnd(self:GetWaveStart() + self:GetWaveOneLength())
+ self:SetWaveActive(false)
+
+ SetGlobalInt("numwaves", -2)
+
+ timer.Create("CheckBroken", 10, 1, CheckBroken)
+
+ game.CleanUpMap(false, self.CleanupFilter)
+ gamemode.Call("InitPostEntityMap")
+
+ for _, pl in pairs(player.GetAll()) do
+ pl:UnSpectateAndSpawn()
+ pl:GodDisable()
+ gamemode.Call("PlayerInitialSpawnRound", pl)
+ gamemode.Call("PlayerReadyRound", pl)
+ end
+end
+
+function GM:RestartGame()
+ for _, pl in pairs(player.GetAll()) do
+ pl:StripWeapons()
+ pl:StripAmmo()
+ pl:SetFrags(0)
+ pl:SetDeaths(0)
+ pl:SetPoints(0)
+ pl:ChangeTeam(TEAM_HUMAN)
+ pl:DoHulls()
+ pl:SetZombieClass(self.DefaultZombieClass)
+ pl.DeathClass = nil
+ end
+
+ self:SetWave(0)
+ if GAMEMODE.ZombieEscape then
+ self:SetWaveStart(CurTime() + 30)
+ else
+ self:SetWaveStart(CurTime() + self.WaveZeroLength)
+ end
+ self:SetWaveEnd(self:GetWaveStart() + self:GetWaveOneLength())
+ self:SetWaveActive(false)
+
+ SetGlobalInt("numwaves", -2)
+ if GetGlobalString("hudoverride"..TEAM_UNDEAD, "") ~= "" then
+ SetGlobalString("hudoverride"..TEAM_UNDEAD, "")
+ end
+ if GetGlobalString("hudoverride"..TEAM_HUMAN, "") ~= "" then
+ SetGlobalString("hudoverride"..TEAM_HUMAN, "")
+ end
+
+ timer.Simple(0.25, function() GAMEMODE:DoRestartGame() end)
+end
+
+function GM:InitPostEntityMap(fromze)
+ pcall(gamemode.Call, "LoadMapEditorFile")
+
+ gamemode.Call("SetupSpawnPoints")
+ gamemode.Call("RemoveUnusedEntities")
+ if not fromze then
+ gamemode.Call("ReplaceMapWeapons")
+ gamemode.Call("ReplaceMapAmmo")
+ gamemode.Call("ReplaceMapBatteries")
+ end
+ gamemode.Call("CreateZombieGas")
+ gamemode.Call("SetupProps")
+
+ for _, ent in pairs(ents.FindByClass("prop_ammo")) do ent.PlacedInMap = true end
+ for _, ent in pairs(ents.FindByClass("prop_weapon")) do ent.PlacedInMap = true end
+ for _, ent in pairs(ents.FindByClass("prop_flashlightbattery")) do ent.PlacedInMap = true end
+
+ if self.ObjectiveMap then
+ self:SetDynamicSpawning(false)
+ self.BossZombies = false
+ end
+
+ --[[if not game.IsDedicated() then
+ gamemode.Call("CreateSigils")
+ end]]
+end
+
+local function EndRoundPlayerShouldTakeDamage(pl, attacker) return pl:Team() ~= TEAM_HUMAN or not attacker:IsPlayer() end
+local function EndRoundPlayerCanSuicide(pl) return pl:Team() ~= TEAM_HUMAN end
+
+local function EndRoundSetupPlayerVisibility(pl)
+ if GAMEMODE.LastHumanPosition and GAMEMODE.RoundEnded then
+ AddOriginToPVS(GAMEMODE.LastHumanPosition)
+ else
+ hook.Remove("SetupPlayerVisibility", "EndRoundSetupPlayerVisibility")
+ end
+end
+
+function GM:EndRound(winner)
+ if self.RoundEnded then return end
+ self.RoundEnded = true
+ self.RoundEndedTime = CurTime()
+ ROUNDWINNER = winner
+
+ if self.OverrideEndSlomo == nil or self.OverrideEndSlomo then
+ game.SetTimeScale(0.25)
+ timer.Simple(2, function() game.SetTimeScale(1) end)
+ end
+
+ hook.Add("PlayerCanHearPlayersVoice", "EndRoundCanHearPlayersVoice", function() return true end)
+
+ if self.OverrideEndCamera == nil or self.OverrideEndCamera then
+ hook.Add("SetupPlayerVisibility", "EndRoundSetupPlayerVisibility", EndRoundSetupPlayerVisibility)
+ end
+
+ if self:ShouldRestartRound() then
+ timer.Simple(self.EndGameTime - 3, function() gamemode.Call("PreRestartRound") end)
+ timer.Simple(self.EndGameTime, function() gamemode.Call("RestartRound") end)
+ else
+ timer.Simple(self.EndGameTime, function() gamemode.Call("LoadNextMap") end)
+ end
+
+ -- Get rid of some lag.
+ util.RemoveAll("prop_ammo")
+ util.RemoveAll("prop_weapon")
+
+ timer.Simple(5, function() gamemode.Call("DoHonorableMentions") end)
+
+ if winner == TEAM_HUMAN then
+ self.LastHumanPosition = nil
+
+ hook.Add("PlayerShouldTakeDamage", "EndRoundShouldTakeDamage", EndRoundPlayerShouldTakeDamage)
+ elseif winner == TEAM_UNDEAD then
+ hook.Add("PlayerShouldTakeDamage", "EndRoundShouldTakeDamage", EndRoundPlayerCanSuicide)
+ end
+
+ net.Start("zs_endround")
+ net.WriteUInt(winner or -1, 8)
+ net.WriteString(game.GetMapNext())
+ net.Broadcast()
+
+ if winner == TEAM_HUMAN then
+ for _, ent in pairs(ents.FindByClass("logic_winlose")) do
+ ent:Input("onwin")
+ end
+ else
+ for _, ent in pairs(ents.FindByClass("logic_winlose")) do
+ ent:Input("onlose")
+ end
+ end
+
+ gamemode.Call("PostEndRound", winner)
+
+ self:SetWaveStart(CurTime() + 9999)
+end
+
+function GM:PlayerReady(pl)
+ gamemode.Call("PlayerReadyRound", pl)
+end
+
+function GM:PlayerReadyRound(pl)
+ if not pl:IsValid() then return end
+
+ self:FullGameUpdate(pl)
+ pl:UpdateAllZombieClasses()
+
+ local classid = pl:GetZombieClass()
+ pl:SetZombieClass(classid, true, pl)
+
+ if pl:Team() == TEAM_UNDEAD then
+ -- This is just so they get updated on what class they are and have their hulls set up right.
+ pl:DoHulls(classid, TEAM_UNDEAD)
+ elseif self:GetWave() <= 0 and self.StartingWorth > 0 and not self.StartingLoadout and not self.ZombieEscape then
+ pl:SendLua("MakepWorth()")
+ else
+ gamemode.Call("GiveDefaultOrRandomEquipment", pl)
+ end
+
+ if self.RoundEnded then
+ pl:SendLua("gamemode.Call(\"EndRound\", "..tostring(ROUNDWINNER)..", \""..game.GetMapNext().."\")")
+ gamemode.Call("DoHonorableMentions", pl)
+ end
+
+ if self.OverrideStartingWorth then
+ pl:SendLua("GAMEMODE.StartingWorth="..tostring(self.StartingWorth))
+ end
+
+ if pl:GetInfo("zs_noredeem") == "1" then
+ pl.NoRedeeming = true
+ end
+
+ if self:GetWave() == 0 then
+ self:SendZombieVolunteers(pl, true)
+ end
+
+ if self:IsClassicMode() then
+ pl:SendLua("SetGlobalBool(\"classicmode\", true)")
+ elseif self:IsBabyMode() then
+ pl:SendLua("SetGlobalBool(\"babymode\", true)")
+ end
+end
+
+function GM:FullGameUpdate(pl)
+ net.Start("zs_gamestate")
+ net.WriteInt(self:GetWave(), 16)
+ net.WriteFloat(self:GetWaveStart())
+ net.WriteFloat(self:GetWaveEnd())
+ if pl then
+ net.Send(pl)
+ else
+ net.Broadcast()
+ end
+end
+
+concommand.Add("initpostentity", function(sender, command, arguments)
+ if not sender.DidInitPostEntity then
+ sender.DidInitPostEntity = true
+
+ gamemode.Call("PlayerReady", sender)
+ end
+end)
+
+local playerheight = Vector(0, 0, 72)
+local playermins = Vector(-17, -17, 0)
+local playermaxs = Vector(17, 17, 4)
+local function groupsort(a, b)
+ return #a > #b
+end
+function GM:AttemptHumanDynamicSpawn(pl)
+ if pl:IsValid() and pl:IsPlayer() and pl:Alive() and pl:Team() == TEAM_HUMAN and self.DynamicSpawning then
+ local groups = self:GetTeamRallyGroups(TEAM_HUMAN)
+ table.sort(groups, groupsort)
+ for i=1, #groups do
+ local group = groups[i]
+
+ local allplayers = team.GetPlayers(TEAM_HUMAN)
+ for _, otherpl in pairs(group) do
+ if otherpl ~= pl then
+ local pos = otherpl:GetPos() + Vector(0, 0, 1)
+ if otherpl:Alive() and otherpl:GetMoveType() == MOVETYPE_WALK and not util.TraceHull({start = pos, endpos = pos + playerheight, mins = playermins, maxs = playermaxs, mask = MASK_SOLID, filter = allplayers}).Hit then
+ local nearzombie = false
+ for __, ent in pairs(team.GetPlayers(TEAM_UNDEAD)) do
+ if ent:Alive() and ent:GetPos():Distance(pos) <= 256 then
+ nearzombie = true
+ end
+ end
+
+ if not nearzombie then
+ pl:SetPos(otherpl:GetPos())
+ return true
+ end
+ end
+ end
+ end
+ end
+ end
+
+ return false
+end
+
+function GM:PlayerInitialSpawn(pl)
+ gamemode.Call("PlayerInitialSpawnRound", pl)
+end
+
+function GM:PlayerInitialSpawnRound(pl)
+ pl:SprintDisable()
+ if pl:KeyDown(IN_WALK) then
+ pl:ConCommand("-walk")
+ end
+
+ pl:SetCanWalk(false)
+ pl:SetCanZoom(false)
+ pl:SetNoCollideWithTeammates(true)
+ pl:SetCustomCollisionCheck(true)
+
+ pl.ZombiesKilled = 0
+ pl.ZombiesKilledAssists = 0
+ pl.BrainsEaten = 0
+
+ pl.ResupplyBoxUsedByOthers = 0
+
+ pl.WaveJoined = self:GetWave()
+
+ pl.CrowKills = 0
+ pl.CrowVsCrowKills = 0
+ pl.CrowBarricadeDamage = 0
+
+ pl.BarricadeDamage = 0
+ pl.DynamicSpawnedOn = 0
+
+ pl.NextPainSound = 0
+
+ pl.BonusDamageCheck = 0
+
+ pl.DamageDealt = {}
+ pl.DamageDealt[TEAM_UNDEAD] = 0
+ pl.DamageDealt[TEAM_HUMAN] = 0
+
+ pl.HealedThisRound = 0
+ pl.CarryOverHealth = 0
+ pl.RepairedThisRound = 0
+ pl.CarryOverRepair = 0
+ pl.PointsCommission = 0
+ pl.CarryOverCommision = 0
+ pl.NextRegenerate = 0
+ pl.NestsDestroyed = 0
+ pl.NestSpawns = 0
+
+ local nosend = not pl.DidInitPostEntity
+ pl.HumanSpeedAdder = nil
+ pl.HumanSpeedAdder = nil
+ pl.HumanRepairMultiplier = nil
+ pl.HumanHealMultiplier = nil
+ pl.BuffResistant = nil
+ pl.BuffRegenerative = nil
+ pl.BuffMuscular = nil
+ pl.IsWeak = nil
+ pl.HumanSpeedAdder = nil
+ pl:SetPalsy(false, nosend)
+ pl:SetHemophilia(false, nosend)
+ pl:SetUnlucky(false)
+ pl.Clumsy = nil
+ pl.NoGhosting = nil
+ pl.NoObjectPickup = nil
+ pl.DamageVulnerability = nil
+
+ local uniqueid = pl:UniqueID()
+
+ if table.HasValue(self.FanList, uniqueid) then
+ pl.DamageVulnerability = (pl.DamageVulnerability or 1) + 10
+ pl:PrintTranslatedMessage(HUD_PRINTTALK, "thanks_for_being_a_fan_of_zs")
+ end
+
+ if self.PreviouslyDied[uniqueid] then
+ -- They already died and reconnected.
+ pl:ChangeTeam(TEAM_UNDEAD)
+ elseif LASTHUMAN then
+ -- Joined during last human.
+ pl.SpawnedTime = CurTime()
+ pl:ChangeTeam(TEAM_UNDEAD)
+ elseif self:GetWave() <= 0 then
+ -- Joined during ready phase.
+ pl.SpawnedTime = CurTime()
+ pl:ChangeTeam(TEAM_HUMAN)
+ elseif self:GetNumberOfWaves() == -1 or self.NoNewHumansWave <= self:GetWave() or team.NumPlayers(TEAM_UNDEAD) == 0 and 1 <= team.NumPlayers(TEAM_HUMAN) then -- Joined during game, no zombies, some humans or joined past the deadline.
+ pl:ChangeTeam(TEAM_UNDEAD)
+ self.PreviouslyDied[uniqueid] = CurTime()
+ else
+ -- Joined past the ready phase but before the deadline.
+ pl.SpawnedTime = CurTime()
+ pl:ChangeTeam(TEAM_HUMAN)
+ if self.DynamicSpawning then
+ timer.Simple(0, function() GAMEMODE:AttemptHumanDynamicSpawn(pl) end)
+ end
+ end
+
+ if pl:Team() == TEAM_UNDEAD and not self:GetWaveActive() and self.ZombieClasses["Crow"] then
+ pl:SetZombieClass(self.ZombieClasses["Crow"].Index)
+ pl.DeathClass = self.DefaultZombieClass
+ else
+ pl:SetZombieClass(self.DefaultZombieClass)
+ end
+
+ if pl:Team() == TEAM_UNDEAD and self.StoredUndeadFrags[uniqueid] then
+ pl:SetFrags(self.StoredUndeadFrags[uniqueid])
+ self.StoredUndeadFrags[uniqueid] = nil
+ end
+end
+
+function GM:GetDynamicSpawning()
+ return self.DynamicSpawning
+end
+
+function GM:PlayerRedeemed(pl, silent, noequip)
+ if not silent then
+ net.Start("zs_playerredeemed")
+ net.WriteEntity(pl)
+ net.WriteString(pl:Name())
+ net.Broadcast()
+ end
+
+ pl:RemoveStatus("overridemodel", false, true)
+
+ pl:ChangeTeam(TEAM_HUMAN)
+ pl:DoHulls()
+ if not noequip then pl.m_PreRedeem = true end
+ pl:UnSpectateAndSpawn()
+ pl.m_PreRedeem = nil
+
+ local frags = pl:Frags()
+ if frags < 0 then
+ pl:SetFrags(frags * 5)
+ else
+ pl:SetFrags(0)
+ end
+ pl:SetDeaths(0)
+
+ pl.DeathClass = nil
+ pl:SetZombieClass(self.DefaultZombieClass)
+
+ pl.SpawnedTime = CurTime()
+end
+
+function GM:PlayerDisconnected(pl)
+ pl.Disconnecting = true
+
+ local uid = pl:UniqueID()
+
+ self.PreviouslyDied[uid] = CurTime()
+
+ if pl:Team() == TEAM_HUMAN then
+ pl:DropAll()
+ elseif pl:Team() == TEAM_UNDEAD then
+ self.StoredUndeadFrags[uid] = pl:Frags()
+ end
+
+ if pl:Health() > 0 then
+ local lastattacker = pl:GetLastAttacker()
+ if IsValid(lastattacker) then
+ pl:TakeDamage(1000, lastattacker, lastattacker)
+
+ PrintTranslatedMessage(HUD_PRINTCONSOLE, "disconnect_killed", pl:Name(), lastattacker:Name())
+ end
+ end
+
+ gamemode.Call("CalculateInfliction")
+end
+
+-- Reevaluates a prop and its constraint system (or all props if no arguments) to determine if they should be frozen or not from nails.
+function GM:EvaluatePropFreeze(ent, neighbors)
+ if not ent then
+ for _, e in pairs(ents.GetAll()) do
+ self:EvaluatePropFreeze(e)
+ end
+
+ return
+ end
+
+ if ent:IsNailedToWorldHierarchy() then
+ ent:SetNailFrozen(true)
+ elseif ent:GetNailFrozen() then
+ ent:SetNailFrozen(false)
+ end
+
+ neighbors = neighbors or {}
+ table.insert(neighbors, ent)
+
+ for _, nail in pairs(ent:GetNails()) do
+ if nail:IsValid() then
+ local baseent = nail:GetBaseEntity()
+ local attachent = nail:GetAttachEntity()
+ if baseent:IsValid() and not baseent:IsWorld() and not table.HasValue(neighbors, baseent) then
+ self:EvaluatePropFreeze(baseent, neighbors)
+ end
+ if attachent:IsValid() and not attachent:IsWorld() and not table.HasValue(neighbors, attachent) then
+ self:EvaluatePropFreeze(attachent, neighbors)
+ end
+ end
+ end
+end
+
+-- A nail takes some damage. isdead is true if the damage is enough to remove the nail. The nail is invalid after this function call if it dies.
+function GM:OnNailDamaged(ent, attacker, inflictor, damage, dmginfo)
+end
+
+-- A nail is removed between two entities. The nail is no longer considered valid right after this function and is not in the entities' Nails tables. remover may not be nil if it was removed with the hammer's unnail ability.
+local function evalfreeze(ent)
+ if ent and ent:IsValid() then
+ gamemode.Call("EvaluatePropFreeze", ent)
+ end
+end
+function GM:OnNailRemoved(nail, ent1, ent2, remover)
+ if ent1 and ent1:IsValid() and not ent1:IsWorld() then
+ timer.Simple(0, function() evalfreeze(ent1) end)
+ timer.Simple(0.2, function() evalfreeze(ent1) end)
+ end
+ if ent2 and ent2:IsValid() and not ent2:IsWorld() then
+ timer.Simple(0, function() evalfreeze(ent2) end)
+ timer.Simple(0.2, function() evalfreeze(ent2) end)
+ end
+
+ if remover and remover:IsValid() and remover:IsPlayer() then
+ local deployer = nail:GetDeployer()
+ if deployer:IsValid() and deployer ~= remover and deployer:Team() == TEAM_HUMAN then
+ PrintTranslatedMessage(HUD_PRINTCONSOLE, "nail_removed_by", remover:Name(), deployer:Name())
+ end
+ end
+end
+
+-- A nail is created between two entities.
+function GM:OnNailCreated(ent1, ent2, nail)
+ if ent1 and ent1:IsValid() and not ent1:IsWorld() then
+ timer.Simple(0, function() evalfreeze(ent1) end)
+ end
+ if ent2 and ent2:IsValid() and not ent2:IsWorld() then
+ timer.Simple(0, function() evalfreeze(ent2) end)
+ end
+end
+
+function GM:RemoveDuplicateAmmo(pl)
+ local AmmoCounts = {}
+ local WepAmmos = {}
+ for _, wep in pairs(pl:GetWeapons()) do
+ if wep.Primary then
+ local ammotype = wep:ValidPrimaryAmmo()
+ if ammotype and wep.Primary.DefaultClip > 0 then
+ AmmoCounts[ammotype] = (AmmoCounts[ammotype] or 0) + 1
+ WepAmmos[wep] = wep.Primary.DefaultClip - wep.Primary.ClipSize
+ end
+ local ammotype2 = wep:ValidSecondaryAmmo()
+ if ammotype2 and wep.Secondary.DefaultClip > 0 then
+ AmmoCounts[ammotype2] = (AmmoCounts[ammotype2] or 0) + 1
+ WepAmmos[wep] = wep.Secondary.DefaultClip - wep.Secondary.ClipSize
+ end
+ end
+ end
+ for ammotype, count in pairs(AmmoCounts) do
+ if count > 1 then
+ local highest = 0
+ local highestwep
+ for wep, extraammo in pairs(WepAmmos) do
+ if wep.Primary.Ammo == ammotype then
+ highest = math.max(highest, extraammo)
+ highestwep = wep
+ end
+ end
+ if highestwep then
+ for wep, extraammo in pairs(WepAmmos) do
+ if wep ~= highestwep and wep.Primary.Ammo == ammotype then
+ pl:RemoveAmmo(extraammo, ammotype)
+ end
+ end
+ end
+ end
+ end
+end
+
+local function TimedOut(pl)
+ if pl:IsValid() and pl:Team() == TEAM_HUMAN and pl:Alive() and not GAMEMODE.CheckedOut[pl:UniqueID()] then
+ gamemode.Call("GiveRandomEquipment", pl)
+ end
+end
+
+function GM:GiveDefaultOrRandomEquipment(pl)
+ if not self.CheckedOut[pl:UniqueID()] and not self.ZombieEscape then
+ if self.StartingLoadout then
+ self:GiveStartingLoadout(pl)
+ else
+ pl:SendLua("GAMEMODE:RequestedDefaultCart()")
+ if self.StartingWorth > 0 then
+ timer.Simple(4, function() TimedOut(pl) end)
+ end
+ end
+ end
+end
+
+function GM:GiveStartingLoadout(pl)
+ for item, amount in pairs(self.StartingLoadout) do
+ for i=1, amount do
+ pl:Give(item)
+ end
+ end
+end
+
+function GM:GiveRandomEquipment(pl)
+ if self.CheckedOut[pl:UniqueID()] or self.ZombieEscape then return end
+ self.CheckedOut[pl:UniqueID()] = true
+
+ if self.StartingLoadout then
+ self:GiveStartingLoadout(pl)
+ elseif GAMEMODE.OverrideStartingWorth then
+ pl:Give("weapon_zs_swissarmyknife")
+ elseif #self.StartLoadouts >= 1 then
+ for _, id in pairs(self.StartLoadouts[math.random(#self.StartLoadouts)]) do
+ local tab = FindStartingItem(id)
+ if tab then
+ if tab.Callback then
+ tab.Callback(pl)
+ elseif tab.SWEP then
+ pl:StripWeapon(tab.SWEP)
+ pl:Give(tab.SWEP)
+ end
+ end
+ end
+ end
+end
+
+function GM:PlayerCanCheckout(pl)
+ return pl:IsValid() and pl:Team() == TEAM_HUMAN and pl:Alive() and not self.CheckedOut[pl:UniqueID()] and not self.StartingLoadout and not self.ZombieEscape and self.StartingWorth > 0
+end
+
+concommand.Add("zs_pointsshopbuy", function(sender, command, arguments)
+ if not (sender:IsValid() and sender:IsConnected()) or #arguments == 0 then return end
+
+ if sender:GetUnlucky() then
+ sender:CenterNotify(COLOR_RED, translate.ClientGet(sender, "banned_for_life_warning"))
+ sender:SendLua("surface.PlaySound(\"buttons/button10.wav\")")
+ return
+ end
+
+ if not sender:NearArsenalCrate() then
+ sender:CenterNotify(COLOR_RED, translate.ClientGet(sender, "need_to_be_near_arsenal_crate"))
+ sender:SendLua("surface.PlaySound(\"buttons/button10.wav\")")
+ return
+ end
+
+ if not gamemode.Call("PlayerCanPurchase", sender) then
+ sender:CenterNotify(COLOR_RED, translate.ClientGet(sender, "cant_purchase_right_now"))
+ sender:SendLua("surface.PlaySound(\"buttons/button10.wav\")")
+ return
+ end
+
+ local itemtab
+ local id = arguments[1]
+ local num = tonumber(id)
+ if num then
+ itemtab = GAMEMODE.Items[num]
+ else
+ for i, tab in pairs(GAMEMODE.Items) do
+ if tab.Signature == id then
+ itemtab = tab
+ break
+ end
+ end
+ end
+
+ if not itemtab or not itemtab.PointShop then return end
+
+ local points = sender:GetPoints()
+ local cost = itemtab.Worth
+ if not GAMEMODE:GetWaveActive() then
+ cost = cost * GAMEMODE.ArsenalCrateMultiplier
+ end
+
+ if GAMEMODE:IsClassicMode() and itemtab.NoClassicMode then
+ sender:CenterNotify(COLOR_RED, translate.ClientFormat(sender, "cant_use_x_in_classic", itemtab.Name))
+ sender:SendLua("surface.PlaySound(\"buttons/button10.wav\")")
+ return
+ end
+
+ if GAMEMODE.ZombieEscape and itemtab.NoZombieEscape then
+ sender:CenterNotify(COLOR_RED, translate.ClientFormat(sender, "cant_use_x_in_zombie_escape", itemtab.Name))
+ sender:SendLua("surface.PlaySound(\"buttons/button10.wav\")")
+ return
+ end
+
+ cost = math.ceil(cost)
+
+ if points < cost then
+ sender:CenterNotify(COLOR_RED, translate.ClientGet(sender, "dont_have_enough_points"))
+ sender:SendLua("surface.PlaySound(\"buttons/button10.wav\")")
+ return
+ end
+
+ if itemtab.Callback then
+ itemtab.Callback(sender)
+ elseif itemtab.SWEP then
+ if sender:HasWeapon(itemtab.SWEP) then
+ local stored = weapons.GetStored(itemtab.SWEP)
+ if stored and stored.AmmoIfHas then
+ sender:GiveAmmo(stored.Primary.DefaultClip, stored.Primary.Ammo)
+ else
+ local wep = ents.Create("prop_weapon")
+ if wep:IsValid() then
+ wep:SetPos(sender:GetShootPos())
+ wep:SetAngles(sender:GetAngles())
+ wep:SetWeaponType(itemtab.SWEP)
+ wep:SetShouldRemoveAmmo(true)
+ wep:Spawn()
+ end
+ end
+ else
+ local wep = sender:Give(itemtab.SWEP)
+ if wep and wep:IsValid() and wep.EmptyWhenPurchased and wep:GetOwner():IsValid() then
+ if wep.Primary then
+ local primary = wep:ValidPrimaryAmmo()
+ if primary then
+ sender:RemoveAmmo(math.max(0, wep.Primary.DefaultClip - wep.Primary.ClipSize), primary)
+ end
+ end
+ if wep.Secondary then
+ local secondary = wep:ValidSecondaryAmmo()
+ if secondary then
+ sender:RemoveAmmo(math.max(0, wep.Secondary.DefaultClip - wep.Secondary.ClipSize), secondary)
+ end
+ end
+ end
+ end
+ else
+ return
+ end
+
+ sender:TakePoints(cost)
+ sender:PrintTranslatedMessage(HUD_PRINTTALK, "purchased_x_for_y_points", itemtab.Name, cost)
+ sender:SendLua("surface.PlaySound(\"ambient/levels/labs/coinslot1.wav\")")
+
+ local nearest = sender:NearestArsenalCrateOwnedByOther()
+ if nearest then
+ local owner = nearest:GetObjectOwner()
+ if owner:IsValid() then
+ local nonfloorcommission = cost * 0.07
+ local commission = math.floor(nonfloorcommission)
+ if commission > 0 then
+ owner.PointsCommission = owner.PointsCommission + cost
+
+ owner:AddPoints(commission)
+
+ net.Start("zs_commission")
+ net.WriteEntity(nearest)
+ net.WriteEntity(sender)
+ net.WriteUInt(commission, 16)
+ net.Send(owner)
+ end
+
+ local leftover = nonfloorcommission - commission
+ if leftover > 0 then
+ owner.CarryOverCommision = owner.CarryOverCommision + leftover
+ if owner.CarryOverCommision >= 1 then
+ local carried = math.floor(owner.CarryOverCommision)
+ owner.CarryOverCommision = owner.CarryOverCommision - carried
+ owner:AddPoints(carried)
+
+ net.Start("zs_commission")
+ net.WriteEntity(nearest)
+ net.WriteEntity(sender)
+ net.WriteUInt(carried, 16)
+ net.Send(owner)
+ end
+ end
+ end
+ end
+end)
+
+concommand.Add("worthrandom", function(sender, command, arguments)
+ if sender:IsValid() and sender:IsConnected() and gamemode.Call("PlayerCanCheckout", sender) then
+ gamemode.Call("GiveRandomEquipment", sender)
+ end
+end)
+
+concommand.Add("worthcheckout", function(sender, command, arguments)
+ if not (sender:IsValid() and sender:IsConnected()) or #arguments == 0 then return end
+
+ if not gamemode.Call("PlayerCanCheckout", sender) then
+ sender:CenterNotify(COLOR_RED, translate.ClientGet(sender, "cant_use_worth_anymore"))
+ return
+ end
+
+ local cost = 0
+ local hasalready = {}
+
+ for _, id in pairs(arguments) do
+ local tab = FindStartingItem(id)
+ if tab and not hasalready[id] then
+ cost = cost + tab.Worth
+ hasalready[id] = true
+ end
+ end
+
+ if cost > GAMEMODE.StartingWorth then return end
+
+ local hasalready = {}
+
+ for _, id in pairs(arguments) do
+ local tab = FindStartingItem(id)
+ if tab and not hasalready[id] then
+ if tab.NoClassicMode and GAMEMODE:IsClassicMode() then
+ sender:PrintMessage(HUD_PRINTTALK, translate.ClientFormat(sender, "cant_use_x_in_classic_mode", tab.Name))
+ elseif tab.Callback then
+ tab.Callback(sender)
+ hasalready[id] = true
+ elseif tab.SWEP then
+ sender:StripWeapon(tab.SWEP) -- "Fixes" players giving each other empty weapons to make it so they get no ammo from the Worth menu purchase.
+ sender:Give(tab.SWEP)
+ hasalready[id] = true
+ end
+ end
+ end
+
+ if table.Count(hasalready) > 0 then
+ GAMEMODE.CheckedOut[sender:UniqueID()] = true
+ end
+
+ gamemode.Call("RemoveDuplicateAmmo", sender)
+end)
+
+function GM:PlayerDeathThink(pl)
+ if self.RoundEnded or pl.Revive or self:GetWave() == 0 then return end
+
+ if pl:GetObserverMode() == OBS_MODE_CHASE then
+ local target = pl:GetObserverTarget()
+ if not target or not target:IsValid() or target:IsPlayer() and (not target:Alive() or target:Team() ~= pl:Team()) then
+ pl:StripWeapons()
+ pl:Spectate(OBS_MODE_ROAMING)
+ pl:SpectateEntity(NULL)
+ end
+ end
+
+ if pl:Team() ~= TEAM_UNDEAD then
+ pl.StartCrowing = nil
+ pl.StartSpectating = nil
+ return
+ end
+
+ if pl.NextSpawnTime and pl.NextSpawnTime <= CurTime() then -- Force spawn.
+ pl.NextSpawnTime = nil
+
+ pl:RefreshDynamicSpawnPoint()
+ pl:UnSpectateAndSpawn()
+ elseif pl:GetObserverMode() == OBS_MODE_NONE then -- Not in spectator yet.
+ if self:GetWaveActive() then -- During wave.
+ if not pl.StartSpectating or CurTime() >= pl.StartSpectating then
+ pl.StartSpectating = nil
+
+ pl:StripWeapons()
+ local best = self:GetBestDynamicSpawn(pl)
+ if best then
+ pl:Spectate(OBS_MODE_CHASE)
+ pl:SpectateEntity(best)
+ else
+ pl:Spectate(OBS_MODE_ROAMING)
+ pl:SpectateEntity(NULL)
+ end
+ end
+ elseif not pl.StartCrowing or CurTime() >= pl.StartCrowing then -- Not during wave. Turn in to a crow. If we die as a crow then we get turned to spectator anyway.
+ pl:ChangeToCrow()
+ end
+ else -- In spectator.
+ if pl:KeyDown(IN_RELOAD) then
+ if self:GetWaveActive() then
+ pl.ForceDynamicSpawn = nil
+ local prev = self.DynamicSpawning
+ self.DynamicSpawning = false
+ pl:UnSpectateAndSpawn()
+ self.DynamicSpawning = prev
+ else
+ pl:ChangeToCrow()
+ end
+ elseif pl:KeyDown(IN_WALK) then
+ pl:TrySpawnAsGoreChild()
+ elseif pl:KeyDown(IN_ATTACK) then
+ if self:GetWaveActive() then
+ pl:RefreshDynamicSpawnPoint()
+ pl:UnSpectateAndSpawn()
+ else
+ pl:ChangeToCrow()
+ end
+ elseif pl:KeyPressed(IN_ATTACK2) then
+ pl.SpectatedPlayerKey = (pl.SpectatedPlayerKey or 0) + 1
+
+ local livingzombies = {}
+ for _, v in pairs(ents.FindByClass("prop_creepernest")) do
+ if v:GetNestBuilt() then table.insert(livingzombies, v) end
+ end
+ for _, v in pairs(team.GetPlayers(TEAM_ZOMBIE)) do
+ if v:Alive() then table.insert(livingzombies, v) end
+ end
+ --[[for _, v in pairs(team.GetSpawnPointGrouped(TEAM_UNDEAD)) do
+ table.insert(livingzombies, v)
+ end]]
+
+ pl:StripWeapons()
+
+ if pl.SpectatedPlayerKey > #livingzombies then
+ pl.SpectatedPlayerKey = 1
+ end
+
+ local specplayer = livingzombies[pl.SpectatedPlayerKey]
+ if specplayer then
+ pl:Spectate(OBS_MODE_CHASE)
+ pl:SpectateEntity(specplayer)
+ end
+ elseif pl:KeyPressed(IN_JUMP) then
+ pl:Spectate(OBS_MODE_ROAMING)
+ pl:SpectateEntity(NULL)
+ pl.SpectatedPlayerKey = nil
+ end
+ end
+end
+
+function GM:ShouldAntiGrief(ent, attacker, dmginfo, health)
+ return ent.m_AntiGrief and self.GriefMinimumHealth <= health and attacker:IsPlayer() and attacker:Team() == TEAM_HUMAN and not dmginfo:IsExplosionDamage()
+end
+
+function GM:PropBreak(attacker, ent)
+ gamemode.Call("PropBroken", ent, attacker)
+end
+
+function GM:PropBroken(ent, attacker)
+end
+
+function GM:NestDestroyed(ent, attacker)
+end
+
+function GM:EntityTakeDamage(ent, dmginfo)
+ local attacker, inflictor = dmginfo:GetAttacker(), dmginfo:GetInflictor()
+
+ if attacker == inflictor and attacker:IsProjectile() and dmginfo:GetDamageType() == DMG_CRUSH then -- Fixes projectiles doing physics-based damage.
+ dmginfo:SetDamage(0)
+ dmginfo:ScaleDamage(0)
+ return
+ end
+
+ if ent._BARRICADEBROKEN and not (attacker:IsPlayer() and attacker:Team() == TEAM_UNDEAD) then
+ dmginfo:SetDamage(dmginfo:GetDamage() * 3)
+ end
+
+ if ent.GetObjectHealth and not (attacker:IsPlayer() and attacker:Team() == TEAM_HUMAN) then
+ ent.m_LastDamaged = CurTime()
+ end
+
+ if ent.ProcessDamage and ent:ProcessDamage(dmginfo) then return end
+ attacker, inflictor = dmginfo:GetAttacker(), dmginfo:GetInflictor()
+
+ -- Don't allow blowing up props during wave 0.
+ if self:GetWave() <= 0 and string.sub(ent:GetClass(), 1, 12) == "prop_physics" and inflictor.NoPropDamageDuringWave0 then
+ dmginfo:SetDamage(0)
+ dmginfo:SetDamageType(DMG_BULLET)
+ return
+ end
+
+ -- We need to stop explosive chains team killing.
+ if inflictor:IsValid() then
+ local dmgtype = dmginfo:GetDamageType()
+ if dmgtype == DMG_BLAST or dmgtype == DMG_BURN or dmgtype == DMG_SLOWBURN then
+ if ent:IsPlayer() then
+ if inflictor.LastExplosionTeam == ent:Team() and inflictor.LastExplosionAttacker ~= ent and inflictor.LastExplosionTime and CurTime() < inflictor.LastExplosionTime + 10 then -- Player damaged by physics object explosion.
+ dmginfo:SetDamage(0)
+ dmginfo:ScaleDamage(0)
+ return
+ end
+ elseif inflictor ~= ent and string.sub(ent:GetClass(), 1, 12) == "prop_physics" and string.sub(inflictor:GetClass(), 1, 12) == "prop_physics" then -- Physics object damaged by physics object explosion.
+ ent.LastExplosionAttacker = inflictor.LastExplosionAttacker
+ ent.LastExplosionTeam = inflictor.LastExplosionTeam
+ ent.LastExplosionTime = CurTime()
+ end
+ elseif inflictor:IsPlayer() and string.sub(ent:GetClass(), 1, 12) == "prop_physics" then -- Physics object damaged by player.
+ ent.LastExplosionAttacker = inflictor
+ ent.LastExplosionTeam = inflictor:Team()
+ ent.LastExplosionTime = CurTime()
+ end
+ end
+
+ -- Prop is nailed. Forward damage to the nails.
+ if ent:DamageNails(attacker, inflictor, dmginfo:GetDamage(), dmginfo) then return end
+
+ local dispatchdamagedisplay = false
+
+ local entclass = ent:GetClass()
+
+ if ent:IsPlayer() then
+ dispatchdamagedisplay = true
+ elseif ent.PropHealth then -- A prop that was invulnerable and converted to vulnerable.
+ if self.NoPropDamageFromHumanMelee and attacker:IsPlayer() and attacker:Team() == TEAM_HUMAN and inflictor.IsMelee then
+ dmginfo:SetDamage(0)
+ return
+ end
+
+ if gamemode.Call("ShouldAntiGrief", ent, attacker, dmginfo, ent.PropHealth) then
+ attacker:AntiGrief(dmginfo)
+ if dmginfo:GetDamage() <= 0 then return end
+ end
+
+ ent.PropHealth = ent.PropHealth - dmginfo:GetDamage()
+
+ dispatchdamagedisplay = true
+
+ if ent.PropHealth <= 0 then
+ local effectdata = EffectData()
+ effectdata:SetOrigin(ent:GetPos())
+ util.Effect("Explosion", effectdata, true, true)
+ ent:Fire("break")
+
+ gamemode.Call("PropBroken", ent, attacker)
+ else
+ local brit = math.Clamp(ent.PropHealth / ent.TotalHealth, 0, 1)
+ local col = ent:GetColor()
+ col.r = 255
+ col.g = 255 * brit
+ col.b = 255 * brit
+ ent:SetColor(col)
+ end
+ elseif entclass == "func_door_rotating" then
+ if ent:GetKeyValues().damagefilter == "invul" or ent.Broken then return end
+
+ if not ent.Heal then
+ local br = ent:BoundingRadius()
+ if br > 80 then return end -- Don't break these kinds of doors that are bigger than this.
+
+ local health = br * 35
+ ent.Heal = health
+ ent.TotalHeal = health
+ end
+
+ if gamemode.Call("ShouldAntiGrief", ent, attacker, dmginfo, ent.TotalHeal) then
+ attacker:AntiGrief(dmginfo)
+ if dmginfo:GetDamage() <= 0 then return end
+ end
+
+ if dmginfo:GetDamage() >= 20 and attacker:IsPlayer() and attacker:Team() == TEAM_UNDEAD then
+ ent:EmitSound(math.random(2) == 1 and "npc/zombie/zombie_pound_door.wav" or "ambient/materials/door_hit1.wav")
+ end
+
+ ent.Heal = ent.Heal - dmginfo:GetDamage()
+ local brit = math.Clamp(ent.Heal / ent.TotalHeal, 0, 1)
+ local col = ent:GetColor()
+ col.r = 255
+ col.g = 255 * brit
+ col.b = 255 * brit
+ ent:SetColor(col)
+
+ dispatchdamagedisplay = true
+
+ if ent.Heal <= 0 then
+ ent.Broken = true
+
+ ent:EmitSound("Breakable.Metal")
+ ent:Fire("unlock", "", 0)
+ ent:Fire("open", "", 0.01) -- Trigger any area portals.
+ ent:Fire("break", "", 0.1)
+ ent:Fire("kill", "", 0.15)
+ end
+ elseif entclass == "prop_door_rotating" then
+ if ent:GetKeyValues().damagefilter == "invul" or ent:HasSpawnFlags(2048) or ent.Broken then return end
+
+ ent.Heal = ent.Heal or ent:BoundingRadius() * 35
+ ent.TotalHeal = ent.TotalHeal or ent.Heal
+
+ if gamemode.Call("ShouldAntiGrief", ent, attacker, dmginfo, ent.TotalHeal) then
+ attacker:AntiGrief(dmginfo)
+ if dmginfo:GetDamage() <= 0 then return end
+ end
+
+ if dmginfo:GetDamage() >= 20 and attacker:IsPlayer() and attacker:Team() == TEAM_UNDEAD then
+ ent:EmitSound(math.random(2) == 1 and "npc/zombie/zombie_pound_door.wav" or "ambient/materials/door_hit1.wav")
+ end
+
+ ent.Heal = ent.Heal - dmginfo:GetDamage()
+ local brit = math.Clamp(ent.Heal / ent.TotalHeal, 0, 1)
+ local col = ent:GetColor()
+ col.r = 255
+ col.g = 255 * brit
+ col.b = 255 * brit
+ ent:SetColor(col)
+
+ dispatchdamagedisplay = true
+
+ if ent.Heal <= 0 then
+ ent.Broken = true
+
+ ent:EmitSound("Breakable.Metal")
+ ent:Fire("unlock", "", 0)
+ ent:Fire("open", "", 0.01) -- Trigger any area portals.
+ ent:Fire("break", "", 0.1)
+ ent:Fire("kill", "", 0.15)
+
+ local physprop = ents.Create("prop_physics")
+ if physprop:IsValid() then
+ physprop:SetPos(ent:GetPos())
+ physprop:SetAngles(ent:GetAngles())
+ physprop:SetSkin(ent:GetSkin() or 0)
+ physprop:SetMaterial(ent:GetMaterial())
+ physprop:SetModel(ent:GetModel())
+ physprop:Spawn()
+ physprop:SetPhysicsAttacker(attacker)
+ if attacker:IsValid() then
+ local phys = physprop:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetVelocityInstantaneous((physprop:NearestPoint(attacker:EyePos()) - attacker:EyePos()):GetNormalized() * math.Clamp(dmginfo:GetDamage() * 3, 40, 300))
+ end
+ end
+ if physprop:GetMaxHealth() == 1 and physprop:Health() == 0 then
+ local health = math.ceil((physprop:OBBMins():Length() + physprop:OBBMaxs():Length()) * 2)
+ if health < 2000 then
+ physprop.PropHealth = health
+ physprop.TotalHealth = health
+ end
+ end
+ end
+ end
+ elseif entclass == "func_physbox" then
+ local holder, status = ent:GetHolder()
+ if holder then status:Remove() end
+
+ if ent:GetKeyValues().damagefilter == "invul" then return end
+
+ ent.Heal = ent.Heal or ent:BoundingRadius() * 35
+ ent.TotalHeal = ent.TotalHeal or ent.Heal
+
+ if gamemode.Call("ShouldAntiGrief", ent, attacker, dmginfo, ent.TotalHeal) then
+ attacker:AntiGrief(dmginfo)
+ if dmginfo:GetDamage() <= 0 then return end
+ end
+
+ ent.Heal = ent.Heal - dmginfo:GetDamage()
+ local brit = math.Clamp(ent.Heal / ent.TotalHeal, 0, 1)
+ local col = ent:GetColor()
+ col.r = 255
+ col.g = 255 * brit
+ col.b = 255 * brit
+ ent:SetColor(col)
+
+ dispatchdamagedisplay = true
+
+ if ent.Heal <= 0 then
+ local foundaxis = false
+ local entname = ent:GetName()
+ local allaxis = ents.FindByClass("phys_hinge")
+ for _, axis in pairs(allaxis) do
+ local keyvalues = axis:GetKeyValues()
+ if keyvalues.attach1 == entname or keyvalues.attach2 == entname then
+ foundaxis = true
+ axis:Remove()
+ ent.Heal = ent.Heal + 120
+ end
+ end
+
+ if not foundaxis then
+ ent:Fire("break", "", 0)
+ end
+ end
+ elseif entclass == "func_breakable" then
+ if ent:GetKeyValues().damagefilter == "invul" then return end
+
+ if gamemode.Call("ShouldAntiGrief", ent, attacker, dmginfo, ent:GetMaxHealth()) then
+ attacker:AntiGrief(dmginfo, true)
+ if dmginfo:GetDamage() <= 0 then return end
+ end
+
+ if ent:Health() == 0 and ent:GetMaxHealth() == 1 then return end
+
+ local brit = math.Clamp(ent:Health() / ent:GetMaxHealth(), 0, 1)
+ local col = ent:GetColor()
+ col.r = 255
+ col.g = 255 * brit
+ col.b = 255 * brit
+ ent:SetColor(col)
+
+ dispatchdamagedisplay = true
+ elseif ent:IsBarricadeProp() and attacker:IsPlayer() and attacker:Team() == TEAM_UNDEAD then
+ dispatchdamagedisplay = true
+ end
+
+ if dmginfo:GetDamage() > 0 or ent:IsPlayer() and ent:GetZombieClassTable().Name == "Shade" then
+ local holder, status = ent:GetHolder()
+ if holder then status:Remove() end
+
+ if attacker:IsPlayer() and dispatchdamagedisplay then
+ self:DamageFloater(attacker, ent, dmginfo)
+ end
+ end
+end
+
+function GM:DamageFloater(attacker, victim, dmginfo)
+ local dmgpos = dmginfo:GetDamagePosition()
+ if dmgpos == vector_origin then dmgpos = victim:NearestPoint(attacker:EyePos()) end
+
+ net.Start(victim:IsPlayer() and "zs_dmg" or "zs_dmg_prop")
+ net.WriteUInt(math.ceil(dmginfo:GetDamage()), 16)
+ net.WriteVector(dmgpos)
+ net.Send(attacker)
+end
+
+function GM:SetRandomToZombie()
+ local plays = team.GetPlayers(TEAM_HUMAN)
+ local pl = plays[math.random(#plays)]
+
+ if not pl then return end
+
+ pl:ChangeTeam(TEAM_UNDEAD)
+ pl:SetFrags(0)
+ pl:SetDeaths(0)
+
+ self.StartingZombie[pl:UniqueID()] = true
+ self.PreviouslyDied[pl:UniqueID()] = CurTime()
+ pl:UnSpectateAndSpawn()
+
+ return pl
+end
+
+function GM:OnPlayerChangedTeam(pl, oldteam, newteam)
+ if newteam == TEAM_UNDEAD then
+ pl:SetPoints(0)
+ pl.DamagedBy = {}
+ pl:SetBarricadeGhosting(false)
+ elseif newteam == TEAM_HUMAN then
+ self.PreviouslyDied[pl:UniqueID()] = nil
+ end
+
+ pl.m_PointQueue = 0
+
+ timer.Simple(0, function() gamemode.Call("CalculateInfliction") end)
+end
+
+function GM:SetPantsMode(mode)
+ if self.ZombieEscape then return end
+
+ self.PantsMode = mode and self.ZombieClasses["Zombie Legs"] ~= nil and not self:IsClassicMode() and not self:IsBabyMode()
+
+ if self.PantsMode then
+ local index = self.ZombieClasses["Zombie Legs"].Index
+
+ self.PreOverrideDefaultZombieClass = self.PreOverrideDefaultZombieClass or self.DefaultZombieClass
+ self.DefaultZombieClass = index
+
+ for _, pl in pairs(player.GetAll()) do
+ local classname = pl:GetZombieClassTable().Name
+ if classname ~= "Zombie Legs" and classname ~= "Crow" then
+ if pl:Team() == TEAM_UNDEAD then
+ pl:KillSilent()
+ pl:SetZombieClass(index)
+ pl:UnSpectateAndSpawn()
+ else
+ pl:SetZombieClass(index)
+ end
+ end
+ pl.DeathClass = index
+ end
+ else
+ self.DefaultZombieClass = self.PreOverrideDefaultZombieClass or self.DefaultZombieClass
+
+ for _, pl in pairs(player.GetAll()) do
+ if pl:GetZombieClassTable().Name == "Zombie Legs" then
+ if pl:Team() == TEAM_UNDEAD then
+ pl:KillSilent()
+ pl:SetZombieClass(self.DefaultZombieClass or 1)
+ pl:UnSpectateAndSpawn()
+ else
+ pl:SetZombieClass(self.DefaultZombieClass or 1)
+ end
+ end
+ end
+ end
+end
+
+function GM:SetClassicMode(mode)
+ if self.ZombieEscape then return end
+
+ self.ClassicMode = mode and self.ZombieClasses["Classic Zombie"] ~= nil and not self.PantsMode and not self:IsBabyMode()
+
+ SetGlobalBool("classicmode", self.ClassicMode)
+
+ if self:IsClassicMode() then
+ util.RemoveAll("prop_nail")
+
+ local index = self.ZombieClasses["Classic Zombie"].Index
+
+ self.PreOverrideDefaultZombieClass = self.PreOverrideDefaultZombieClass or self.DefaultZombieClass
+ self.DefaultZombieClass = index
+
+ for _, pl in pairs(player.GetAll()) do
+ local classname = pl:GetZombieClassTable().Name
+ if classname ~= "Classic Zombie" and classname ~= "Crow" then
+ if pl:Team() == TEAM_UNDEAD then
+ pl:KillSilent()
+ pl:SetZombieClass(index)
+ pl:UnSpectateAndSpawn()
+ else
+ pl:SetZombieClass(index)
+ end
+ end
+ pl.DeathClass = index
+ end
+ else
+ self.DefaultZombieClass = self.PreOverrideDefaultZombieClass or self.DefaultZombieClass
+
+ for _, pl in pairs(player.GetAll()) do
+ if pl:GetZombieClassTable().Name == "Classic Zombie" then
+ if pl:Team() == TEAM_UNDEAD then
+ pl:KillSilent()
+ pl:SetZombieClass(self.DefaultZombieClass or 1)
+ pl:UnSpectateAndSpawn()
+ else
+ pl:SetZombieClass(self.DefaultZombieClass or 1)
+ end
+ end
+ end
+ end
+end
+
+function GM:SetBabyMode(mode)
+ if self.ZombieEscape then return end
+
+ self.BabyMode = mode and self.ZombieClasses["Gore Child"] ~= nil and not self.PantsMode and not self:IsClassicMode()
+
+ SetGlobalBool("babymode", self.BabyMode)
+
+ if self:IsBabyMode() then
+ local index = self.ZombieClasses["Gore Child"].Index
+
+ self.PreOverrideDefaultZombieClass = self.PreOverrideDefaultZombieClass or self.DefaultZombieClass
+ self.DefaultZombieClass = index
+
+ for _, pl in pairs(player.GetAll()) do
+ local classname = pl:GetZombieClassTable().Name
+ if classname ~= "Gore Child" and classname ~= "Giga Gore Child" and classname ~= "Crow" then
+ if pl:Team() == TEAM_UNDEAD then
+ pl:KillSilent()
+ pl:SetZombieClass(index)
+ pl:UnSpectateAndSpawn()
+ else
+ pl:SetZombieClass(index)
+ end
+ end
+ pl.DeathClass = index
+ end
+ else
+ self.DefaultZombieClass = self.PreOverrideDefaultZombieClass or self.DefaultZombieClass
+
+ for _, pl in pairs(player.GetAll()) do
+ if pl:GetZombieClassTable().Name == "Gore Child" then
+ if pl:Team() == TEAM_UNDEAD then
+ pl:KillSilent()
+ pl:SetZombieClass(self.DefaultZombieClass or 1)
+ pl:UnSpectateAndSpawn()
+ else
+ pl:SetZombieClass(self.DefaultZombieClass or 1)
+ end
+ end
+ end
+ end
+end
+
+function GM:SetClosestsToZombie()
+ local allplayers = player.GetAll()
+ local numplayers = #allplayers
+ if numplayers <= 1 then return end
+
+ local desiredzombies = self:GetDesiredStartingZombies()
+
+ self:SortZombieSpawnDistances(allplayers)
+
+ local zombies = {}
+ for _, pl in pairs(allplayers) do
+ if pl:Team() ~= TEAM_HUMAN or not pl:Alive() then
+ table.insert(zombies, pl)
+ end
+ end
+
+ -- Need to place some people back on the human team.
+ if #zombies > desiredzombies then
+ local toswap = #zombies - desiredzombies
+ for _, pl in pairs(zombies) do
+ if pl.DiedDuringWave0 and pl:GetInfo("zs_alwaysvolunteer") ~= "1" then
+ pl:SetTeam(TEAM_HUMAN)
+ pl:UnSpectateAndSpawn()
+ toswap = toswap - 1
+ if toswap <= 0 then
+ break
+ end
+ end
+ end
+ end
+
+ for i = 1, desiredzombies do
+ local pl = allplayers[i]
+ if pl:Team() ~= TEAM_UNDEAD then
+ pl:ChangeTeam(TEAM_UNDEAD)
+ self.PreviouslyDied[pl:UniqueID()] = CurTime()
+ end
+ pl:SetFrags(0)
+ pl:SetDeaths(0)
+ self.StartingZombie[pl:UniqueID()] = true
+ pl:UnSpectateAndSpawn()
+ end
+
+ for _, pl in pairs(allplayers) do
+ if pl:Team() == TEAM_HUMAN and pl._ZombieSpawnDistance <= 128 then
+ pl:SetPos(self:PlayerSelectSpawn(pl):GetPos())
+ end
+ end
+end
+
+function GM:AllowPlayerPickup(pl, ent)
+ return false
+end
+
+function GM:PlayerShouldTakeDamage(pl, attacker)
+ if attacker.PBAttacker and attacker.PBAttacker:IsValid() and CurTime() < attacker.NPBAttacker then -- Protection against prop_physbox team killing. physboxes don't respond to SetPhysicsAttacker()
+ attacker = attacker.PBAttacker
+ end
+
+ if attacker:IsPlayer() and attacker ~= pl and not attacker.AllowTeamDamage and not pl.AllowTeamDamage and attacker:Team() == pl:Team() then return false end
+
+ return true
+end
+
+function GM:PlayerHurt(victim, attacker, healthremaining, damage)
+ if 0 < healthremaining then
+ victim:PlayPainSound()
+ end
+
+ if victim:Team() == TEAM_HUMAN then
+ victim.BonusDamageCheck = CurTime()
+
+ if healthremaining < 75 and 1 <= healthremaining then
+ victim:ResetSpeed(nil, healthremaining)
+ end
+ end
+
+ if attacker:IsValid() then
+ if attacker:IsPlayer() then
+ victim:SetLastAttacker(attacker)
+
+ local myteam = attacker:Team()
+ local otherteam = victim:Team()
+ if myteam ~= otherteam then
+ damage = math.min(damage, victim.m_PreHurtHealth)
+ victim.m_PreHurtHealth = healthremaining
+
+ attacker.DamageDealt[myteam] = attacker.DamageDealt[myteam] + damage
+
+ if myteam == TEAM_UNDEAD then
+ attacker:AddLifeHumanDamage(damage)
+ elseif otherteam == TEAM_UNDEAD then
+ victim.DamagedBy[attacker] = (victim.DamagedBy[attacker] or 0) + damage
+ if (not victim.m_LastWaveStartSpawn or CurTime() >= victim.m_LastWaveStartSpawn + 3)
+ and (healthremaining <= 0 or not victim.m_LastGasHeal or CurTime() >= victim.m_LastGasHeal + 2) then
+ attacker.m_PointQueue = attacker.m_PointQueue + damage / victim:GetMaxHealth() * (victim:GetZombieClassTable().Points or 0)
+ end
+ attacker.m_LastDamageDealtPosition = victim:GetPos()
+ attacker.m_LastDamageDealt = CurTime()
+ end
+ end
+ elseif attacker:GetClass() == "trigger_hurt" then
+ victim.LastHitWithTriggerHurt = CurTime()
+ end
+ end
+end
+
+-- Don't change speed instantly to stop people from shooting and then running away with a faster weapon.
+function GM:WeaponDeployed(pl, wep)
+ local timername = tostring(pl).."speedchange"
+ timer.Destroy(timername)
+
+ local speed = pl:ResetSpeed(true) -- Determine what speed we SHOULD get without actually setting it.
+ if speed < pl:GetMaxSpeed() then
+ pl:SetSpeed(speed)
+ elseif pl:GetMaxSpeed() < speed then
+ timer.CreateEx(timername, 0.333, 1, ValidFunction, pl, "SetHumanSpeed", speed)
+ end
+end
+
+function GM:KeyPress(pl, key)
+ if key == IN_USE then
+ if pl:Team() == TEAM_HUMAN and pl:Alive() then
+ if pl:IsCarrying() then
+ pl.status_human_holding:RemoveNextFrame()
+ else
+ self:TryHumanPickup(pl, pl:TraceLine(64).Entity)
+ end
+ end
+ elseif key == IN_SPEED then
+ if pl:Alive() then
+ if pl:Team() == TEAM_HUMAN then
+ pl:DispatchAltUse()
+ elseif pl:Team() == TEAM_UNDEAD then
+ pl:CallZombieFunction("AltUse")
+ end
+ end
+ elseif key == IN_ZOOM then
+ if pl:Team() == TEAM_HUMAN and pl:Alive() and pl:IsOnGround() and not self.ZombieEscape then --and pl:GetGroundEntity():IsWorld() then
+ pl:SetBarricadeGhosting(true)
+ end
+ end
+end
+
+function GM:GetNearestSpawn(pos, teamid)
+ local nearest = NULL
+
+ local nearestdist = math.huge
+ for _, ent in pairs(team.GetValidSpawnPoint(teamid)) do
+ if ent.Disabled then continue end
+
+ local dist = ent:GetPos():Distance(pos)
+ if dist < nearestdist then
+ nearestdist = dist
+ nearest = ent
+ end
+ end
+
+ return nearest
+end
+
+function GM:EntityWouldBlockSpawn(ent)
+ local spawnpoint = self:GetNearestSpawn(ent:GetPos(), TEAM_UNDEAD)
+
+ if spawnpoint:IsValid() then
+ local spawnpos = spawnpoint:GetPos()
+ if spawnpos:Distance(ent:NearestPoint(spawnpos)) <= 40 then return true end
+ end
+
+ return false
+end
+
+function GM:GetNearestSpawnDistance(pos, teamid)
+ local nearest = self:GetNearestSpawn(pos, teamid)
+ if nearest:IsValid() then
+ return nearest:GetPos():Distance(pos)
+ end
+
+ return -1
+end
+
+function GM:PlayerUse(pl, ent)
+ if not pl:Alive() or pl:Team() == TEAM_UNDEAD and pl:GetZombieClassTable().NoUse or pl:GetBarricadeGhosting() then return false end
+
+ if pl:IsHolding() and pl:GetHolding() ~= ent then return false end
+
+ local entclass = ent:GetClass()
+ if entclass == "prop_door_rotating" then
+ if CurTime() < (ent.m_AntiDoorSpam or 0) then -- Prop doors can be glitched shut by mashing the use button.
+ return false
+ end
+ ent.m_AntiDoorSpam = CurTime() + 0.85
+ elseif entclass == "item_healthcharger" then
+ if pl:Team() == TEAM_UNDEAD then return false end
+ elseif pl:Team() == TEAM_HUMAN and not pl:IsCarrying() and pl:KeyPressed(IN_USE) then
+ self:TryHumanPickup(pl, ent)
+ end
+
+ return true
+end
+
+function GM:PlayerDeath(pl, inflictor, attacker)
+end
+
+function GM:PlayerDeathSound()
+ return true
+end
+
+local function SortDist(a, b)
+ return a._temp < b._temp
+end
+function GM:CanPlayerSuicide(pl)
+ if self.RoundEnded or pl:HasWon() then return false end
+
+ if pl:Team() == TEAM_HUMAN then
+ if self:GetWave() <= self.NoSuicideWave then
+ pl:PrintTranslatedMessage(HUD_PRINTCENTER, "give_time_before_suicide")
+ return false
+ end
+
+ -- If a person is going to suicide with no last attacker, give the kill to the closest zombie.
+ if not IsValid(pl:GetLastAttacker()) then
+ local plpos = pl:EyePos()
+ local tosort = {}
+ for _, zom in pairs(team.GetPlayers(TEAM_UNDEAD)) do
+ if zom:Alive() then
+ local dist = zom:GetPos():Distance(plpos)
+ if dist <= 512 then
+ zom._temp = dist
+ table.insert(tosort, zom)
+ end
+ end
+ end
+
+ table.sort(tosort, SortDist)
+
+ if tosort[1] then
+ pl:SetLastAttacker(tosort[1])
+ end
+ end
+ elseif pl:Team() == TEAM_UNDEAD then
+ local ret = pl:CallZombieFunction("CanPlayerSuicide")
+ if ret == false then return false end
+ end
+
+ return pl:GetObserverMode() == OBS_MODE_NONE and pl:Alive() and (not pl.SpawnNoSuicide or pl.SpawnNoSuicide < CurTime())
+end
+
+function GM:DefaultRevive(pl)
+ local status = pl:GiveStatus("revive")
+ if status and status:IsValid() then
+ status:SetReviveTime(CurTime() + 2)
+ end
+end
+
+function GM:HumanKilledZombie(pl, attacker, inflictor, dmginfo, headshot, suicide)
+ if (pl:GetZombieClassTable().Points or 0) == 0 or self.RoundEnded then return end
+
+ -- Simply distributes based on damage but also do some stuff for assists.
+
+ local totaldamage = 0
+ for otherpl, dmg in pairs(pl.DamagedBy) do
+ if otherpl:IsValid() and otherpl:Team() == TEAM_HUMAN then
+ totaldamage = totaldamage + dmg
+ end
+ end
+
+ local mostassistdamage = 0
+ local halftotaldamage = totaldamage / 2
+ local mostdamager
+ for otherpl, dmg in pairs(pl.DamagedBy) do
+ if otherpl ~= attacker and otherpl:IsValid() and otherpl:Team() == TEAM_HUMAN and dmg > mostassistdamage and dmg >= halftotaldamage then
+ mostassistdamage = dmg
+ mostdamager = otherpl
+ end
+ end
+
+ attacker.ZombiesKilled = attacker.ZombiesKilled + 1
+
+ if mostdamager then
+ attacker:PointCashOut(pl, FM_LOCALKILLOTHERASSIST)
+ mostdamager:PointCashOut(pl, FM_LOCALASSISTOTHERKILL)
+
+ mostdamager.ZombiesKilledAssists = mostdamager.ZombiesKilledAssists + 1
+ else
+ attacker:PointCashOut(pl, FM_NONE)
+ end
+
+ gamemode.Call("PostHumanKilledZombie", pl, attacker, inflictor, dmginfo, mostdamager, mostassistdamage, headshot)
+
+ return mostdamager
+end
+
+function GM:PostHumanKilledZombie(pl, attacker, inflictor, dmginfo, assistpl, assistamount, headshot)
+end
+
+function GM:ZombieKilledHuman(pl, attacker, inflictor, dmginfo, headshot, suicide)
+ if self.RoundEnded then return end
+
+ local plpos = pl:GetPos()
+ local dist = 99999
+ for _, ent in pairs(team.GetValidSpawnPoint(TEAM_UNDEAD)) do
+ dist = math.min(math.ceil(ent:GetPos():Distance(plpos)), dist)
+ end
+ pl.ZombieSpawnDeathDistance = dist
+
+ attacker:AddBrains(1)
+ attacker:AddLifeBrainsEaten(1)
+
+ if not pl.Gibbed and not suicide then
+ local status = pl:GiveStatus("revive_slump_human")
+ if status then
+ status:SetReviveTime(CurTime() + 4)
+ status:SetZombieInitializeTime(CurTime() + 2)
+ end
+
+ local classtab = self.ZombieEscape and self.ZombieClasses["Super Zombie"] or self:IsClassicMode() and self.ZombieClasses["Classic Zombie"] or self:IsBabyMode() and GAMEMODE.ZombieClasses["Gore Child"] or GAMEMODE.ZombieClasses["Fresh Dead"]
+ if classtab then
+ pl:SetZombieClass(classtab.Index)
+ end
+ end
+
+ gamemode.Call("PostZombieKilledHuman", pl, attacker, inflictor, dmginfo, headshot, suicide)
+
+ return attacker:Frags()
+end
+
+function GM:PostZombieKilledHuman(pl, attacker, inflictor, dmginfo, headshot, suicide)
+end
+
+local function DelayedChangeToZombie(pl)
+ if pl:IsValid() then
+ if pl.ChangeTeamFrags then
+ pl:SetFrags(pl.ChangeTeamFrags)
+ pl.ChangeTeamFrags = 0
+ end
+
+ pl:ChangeTeam(TEAM_UNDEAD)
+ end
+end
+
+function GM:DoPlayerDeath(pl, attacker, dmginfo)
+ pl:RemoveStatus("confusion", false, true)
+
+ local inflictor = dmginfo:GetInflictor()
+ local plteam = pl:Team()
+ local ct = CurTime()
+ local suicide = attacker == pl or attacker:IsWorld()
+
+ pl:Freeze(false)
+
+ local headshot = pl:LastHitGroup() == HITGROUP_HEAD and pl.m_LastHeadShot and CurTime() <= pl.m_LastHeadShot + 0.1
+
+ if suicide then attacker = pl:GetLastAttacker() or attacker end
+ pl:SetLastAttacker()
+
+ if inflictor == NULL then inflictor = attacker end
+
+ if inflictor == attacker and attacker:IsPlayer() then
+ local wep = attacker:GetActiveWeapon()
+ if wep:IsValid() then
+ inflictor = wep
+ end
+ end
+
+ if headshot then
+ local effectdata = EffectData()
+ effectdata:SetOrigin(dmginfo:GetDamagePosition())
+ local force = dmginfo:GetDamageForce()
+ effectdata:SetMagnitude(force:Length() * 3)
+ effectdata:SetNormal(force:GetNormalized())
+ effectdata:SetEntity(pl)
+ util.Effect("headshot", effectdata, true, true)
+ end
+
+ if not pl:CallZombieFunction("OnKilled", attacker, inflictor, suicide, headshot, dmginfo) then
+ if pl:Health() <= -70 and not pl.NoGibs and not self.ZombieEscape then
+ pl:Gib(dmginfo)
+ elseif not pl.KnockedDown then
+ pl:CreateRagdoll()
+ end
+ end
+
+ pl:RemoveStatus("overridemodel", false, true)
+
+ local revive
+ local assistpl
+ if plteam == TEAM_UNDEAD then
+ local classtable = pl:GetZombieClassTable()
+
+ pl:PlayZombieDeathSound()
+
+ if not classtable.NoDeaths then
+ pl:AddDeaths(1)
+ end
+
+ if self:GetWaveActive() then
+ pl.StartSpectating = ct + 2
+ else
+ pl.StartCrowing = ct + 3
+ end
+
+ if attacker:IsValid() and attacker:IsPlayer() and attacker ~= pl then
+ if classtable.Revives and not pl.Gibbed and not headshot then
+ if classtable.ReviveCallback then
+ revive = classtable:ReviveCallback(pl, attacker, dmginfo)
+ elseif math.random(1, 4) ~= 1 then
+ self:DefaultRevive(pl)
+ revive = true
+ end
+ end
+
+ if not revive and attacker:Team() ~= TEAM_UNDEAD then
+ assistpl = gamemode.Call("HumanKilledZombie", pl, attacker, inflictor, dmginfo, headshot, suicide)
+ end
+ end
+
+ if not revive and (pl.LifeBarricadeDamage ~= 0 or pl.LifeHumanDamage ~= 0 or pl.LifeBrainsEaten ~= 0) then
+ net.Start("zs_lifestats")
+ net.WriteUInt(math.ceil(pl.LifeBarricadeDamage or 0), 24)
+ net.WriteUInt(math.ceil(pl.LifeHumanDamage or 0), 24)
+ net.WriteUInt(pl.LifeBrainsEaten or 0, 16)
+ net.Send(pl)
+ end
+
+ pl:CallZombieFunction("PostOnKilled", attacker, inflictor, suicide, headshot, dmginfo)
+ else
+ pl.NextSpawnTime = ct + 4
+
+ pl:PlayDeathSound()
+
+ if attacker:IsPlayer() and attacker ~= pl then
+ gamemode.Call("ZombieKilledHuman", pl, attacker, inflictor, dmginfo, headshot, suicide)
+ end
+
+ pl:DropAll()
+ timer.Simple(0, function() DelayedChangeToZombie(pl) end) -- We don't want people shooting barrels near teammates.
+ self.PreviouslyDied[pl:UniqueID()] = CurTime()
+ if self:GetWave() == 0 then
+ pl.DiedDuringWave0 = true
+ end
+
+ local frags = pl:Frags()
+ if frags < 0 then
+ pl.ChangeTeamFrags = math.ceil(frags / 5)
+ else
+ pl.ChangeTeamFrags = 0
+ end
+
+ if pl.SpawnedTime then
+ pl.SurvivalTime = math.max(ct - pl.SpawnedTime, pl.SurvivalTime or 0)
+ pl.SpawnedTime = nil
+ end
+
+ if team.NumPlayers(TEAM_HUMAN) <= 1 then
+ self.LastHumanPosition = pl:WorldSpaceCenter()
+
+ net.Start("zs_lasthumanpos")
+ net.WriteVector(self.LastHumanPosition)
+ net.Broadcast()
+ end
+
+ local hands = pl:GetHands()
+ if IsValid(hands) then
+ hands:Remove()
+ end
+ end
+
+ if revive or pl:CallZombieFunction("NoDeathMessage", attacker, dmginfo) then return end
+
+ if attacker == pl then
+ net.Start("zs_pl_kill_self")
+ net.WriteEntity(pl)
+ net.WriteUInt(plteam, 16)
+ net.Broadcast()
+ elseif attacker:IsPlayer() then
+ if assistpl then
+ net.Start("zs_pls_kill_pl")
+ net.WriteEntity(pl)
+ net.WriteEntity(attacker)
+ net.WriteEntity(assistpl)
+ net.WriteString(inflictor:GetClass())
+ net.WriteUInt(plteam, 16)
+ net.WriteUInt(attacker:Team(), 16) -- Assuming assistants are always on the same team.
+ net.WriteBit(headshot)
+ net.Broadcast()
+
+ gamemode.Call("PlayerKilledByPlayer", pl, assistpl, inflictor, headshot, dmginfo, true)
+ else
+ net.Start("zs_pl_kill_pl")
+ net.WriteEntity(pl)
+ net.WriteEntity(attacker)
+ net.WriteString(inflictor:GetClass())
+ net.WriteUInt(plteam, 16)
+ net.WriteUInt(attacker:Team(), 16)
+ net.WriteBit(headshot)
+ net.Broadcast()
+ end
+
+ gamemode.Call("PlayerKilledByPlayer", pl, attacker, inflictor, headshot, dmginfo)
+ else
+ net.Start("zs_death")
+ net.WriteEntity(pl)
+ net.WriteString(inflictor:GetClass())
+ net.WriteString(attacker:GetClass())
+ net.WriteUInt(plteam, 16)
+ net.Broadcast()
+ end
+end
+
+function GM:PlayerKilledByPlayer(pl, attacker, inflictor, headshot, dmginfo)
+end
+
+function GM:PlayerCanPickupWeapon(pl, ent)
+ if pl:Team() == TEAM_UNDEAD then return ent:GetClass() == pl:GetZombieClassTable().SWEP end
+
+ return not ent.ZombieOnly and ent:GetClass() ~= "weapon_stunstick"
+end
+
+function GM:PlayerFootstep(pl, vPos, iFoot, strSoundName, fVolume, pFilter)
+end
+
+function GM:PlayerStepSoundTime(pl, iType, bWalking)
+ local fStepTime = 350
+
+ if iType == STEPSOUNDTIME_NORMAL or iType == STEPSOUNDTIME_WATER_FOOT then
+ local fMaxSpeed = pl:GetMaxSpeed()
+ if fMaxSpeed <= 100 then
+ fStepTime = 400
+ elseif fMaxSpeed <= 300 then
+ fStepTime = 350
+ else
+ fStepTime = 250
+ end
+ elseif iType == STEPSOUNDTIME_ON_LADDER then
+ fStepTime = 450
+ elseif iType == STEPSOUNDTIME_WATER_KNEE then
+ fStepTime = 600
+ end
+
+ if pl:Crouching() then
+ fStepTime = fStepTime + 50
+ end
+
+ return fStepTime
+end
+
+concommand.Add("zsdropweapon", function(sender, command, arguments)
+ if GAMEMODE.ZombieEscape then return end
+
+ if not (sender:IsValid() and sender:Alive() and sender:Team() == TEAM_HUMAN) or CurTime() < (sender.NextWeaponDrop or 0) or GAMEMODE.ZombieEscape then return end
+ sender.NextWeaponDrop = CurTime() + 0.15
+
+ local currentwep = sender:GetActiveWeapon()
+ if currentwep and currentwep:IsValid() then
+ local ent = sender:DropWeaponByType(currentwep:GetClass())
+ if ent and ent:IsValid() then
+ local shootpos = sender:GetShootPos()
+ local aimvec = sender:GetAimVector()
+ ent:SetPos(util.TraceHull({start = shootpos, endpos = shootpos + aimvec * 32, mask = MASK_SOLID, filter = sender, mins = Vector(-2, -2, -2), maxs = Vector(2, 2, 2)}).HitPos)
+ ent:SetAngles(sender:GetAngles())
+ end
+ end
+end)
+
+concommand.Add("zsemptyclip", function(sender, command, arguments)
+ if GAMEMODE.ZombieEscape then return end
+
+ if not (sender:IsValid() and sender:Alive() and sender:Team() == TEAM_HUMAN) then return end
+
+ sender.NextEmptyClip = sender.NextEmptyClip or 0
+ if sender.NextEmptyClip <= CurTime() then
+ sender.NextEmptyClip = CurTime() + 0.1
+
+ local wep = sender:GetActiveWeapon()
+ if wep:IsValid() and not wep.NoMagazine then
+ local primary = wep:ValidPrimaryAmmo()
+ if primary and 0 < wep:Clip1() then
+ sender:GiveAmmo(wep:Clip1(), primary, true)
+ wep:SetClip1(0)
+ end
+ local secondary = wep:ValidSecondaryAmmo()
+ if secondary and 0 < wep:Clip2() then
+ sender:GiveAmmo(wep:Clip2(), secondary, true)
+ wep:SetClip2(0)
+ end
+ end
+ end
+end)
+
+concommand.Add("zsgiveammo", function(sender, command, arguments)
+ if GAMEMODE.ZombieEscape then return end
+
+ if not sender:IsValid() or not sender:Alive() or sender:Team() ~= TEAM_HUMAN then return end
+
+ local ammotype = arguments[1]
+ if not ammotype or #ammotype == 0 or not GAMEMODE.AmmoCache[ammotype] then return end
+
+ local count = sender:GetAmmoCount(ammotype)
+ if count <= 0 then
+ sender:SendLua("surface.PlaySound(\"buttons/button10.wav\")")
+ sender:PrintTranslatedMessage(HUD_PRINTCENTER, "no_spare_ammo_to_give")
+ return
+ end
+
+ local ent
+ local dent = Entity(tonumbersafe(arguments[2] or 0) or 0)
+ if GAMEMODE:ValidMenuLockOnTarget(sender, dent) then
+ ent = dent
+ end
+
+ if not ent then
+ ent = sender:MeleeTrace(48, 2).Entity
+ end
+
+ if ent and ent:IsValid() and ent:IsPlayer() and ent:Team() == TEAM_HUMAN and ent:Alive() then
+ local desiredgive = math.min(count, GAMEMODE.AmmoCache[ammotype])
+ if desiredgive >= 1 then
+ sender:RemoveAmmo(desiredgive, ammotype)
+ ent:GiveAmmo(desiredgive, ammotype)
+
+ if CurTime() >= (sender.NextGiveAmmoSound or 0) then
+ sender.NextGiveAmmoSound = CurTime() + 1
+ sender:PlayGiveAmmoSound()
+ end
+
+ sender:RestartGesture(ACT_GMOD_GESTURE_ITEM_GIVE)
+
+ return
+ end
+ else
+ sender:SendLua("surface.PlaySound(\"buttons/button10.wav\")")
+ sender:PrintTranslatedMessage(HUD_PRINTCENTER, "no_person_in_range")
+ end
+end)
+
+concommand.Add("zsgiveweapon", function(sender, command, arguments)
+ if GAMEMODE.ZombieEscape then return end
+
+ if not (sender:IsValid() and sender:Alive() and sender:Team() == TEAM_HUMAN) or GAMEMODE.ZombieEscape then return end
+
+ local currentwep = sender:GetActiveWeapon()
+ if currentwep and currentwep:IsValid() then
+ local ent
+ local dent = Entity(tonumbersafe(arguments[2] or 0) or 0)
+ if GAMEMODE:ValidMenuLockOnTarget(sender, dent) then
+ ent = dent
+ end
+
+ if not ent then
+ ent = sender:MeleeTrace(48, 2).Entity
+ end
+
+ if ent and ent:IsValid() and ent:IsPlayer() and ent:Team() == TEAM_HUMAN and ent:Alive() then
+ if not ent:HasWeapon(currentwep:GetClass()) then
+ sender:GiveWeaponByType(currentwep, ent, false)
+ else
+ sender:SendLua("surface.PlaySound(\"buttons/button10.wav\")")
+ sender:PrintTranslatedMessage(HUD_PRINTCENTER, "person_has_weapon")
+ end
+ else
+ sender:SendLua("surface.PlaySound(\"buttons/button10.wav\")")
+ sender:PrintTranslatedMessage(HUD_PRINTCENTER, "no_person_in_range")
+ end
+ end
+end)
+
+concommand.Add("zsgiveweaponclip", function(sender, command, arguments)
+ if GAMEMODE.ZombieEscape then return end
+
+ if not (sender:IsValid() and sender:Alive() and sender:Team() == TEAM_HUMAN) then return end
+
+ local currentwep = sender:GetActiveWeapon()
+ if currentwep and currentwep:IsValid() then
+ local ent
+ local dent = Entity(tonumbersafe(arguments[2] or 0) or 0)
+ if GAMEMODE:ValidMenuLockOnTarget(sender, dent) then
+ ent = dent
+ end
+
+ if not ent then
+ ent = sender:MeleeTrace(48, 2).Entity
+ end
+
+ if ent and ent:IsValid() and ent:IsPlayer() and ent:Team() == TEAM_HUMAN and ent:Alive() then
+ if not ent:HasWeapon(currentwep:GetClass()) then
+ sender:GiveWeaponByType(currentwep, ent, true)
+ else
+ sender:SendLua("surface.PlaySound(\"buttons/button10.wav\")")
+ sender:PrintTranslatedMessage(HUD_PRINTCENTER, "person_has_weapon")
+ end
+ else
+ sender:SendLua("surface.PlaySound(\"buttons/button10.wav\")")
+ sender:PrintTranslatedMessage(HUD_PRINTCENTER, "no_person_in_range")
+ end
+ end
+end)
+
+concommand.Add("zsdropammo", function(sender, command, arguments)
+ if GAMEMODE.ZombieEscape then return end
+
+ if not sender:IsValid() or not sender:Alive() or sender:Team() ~= TEAM_HUMAN or CurTime() < (sender.NextDropClip or 0) then return end
+
+ sender.NextDropClip = CurTime() + 0.2
+
+ local wep = sender:GetActiveWeapon()
+ if not wep:IsValid() then return end
+
+ local ammotype = arguments[1] or wep:GetPrimaryAmmoTypeString()
+ if GAMEMODE.AmmoNames[ammotype] and GAMEMODE.AmmoCache[ammotype] then
+ local ent = sender:DropAmmoByType(ammotype, GAMEMODE.AmmoCache[ammotype] * 2)
+ if ent and ent:IsValid() then
+ ent:SetPos(sender:EyePos() + sender:GetAimVector() * 8)
+ ent:SetAngles(sender:GetAngles())
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:SetVelocityInstantaneous(sender:GetVelocity() * 0.85)
+ end
+ end
+ end
+end)
+
+local VoiceSetTranslate = {}
+VoiceSetTranslate["models/player/alyx.mdl"] = "alyx"
+VoiceSetTranslate["models/player/barney.mdl"] = "barney"
+VoiceSetTranslate["models/player/breen.mdl"] = "male"
+VoiceSetTranslate["models/player/combine_soldier.mdl"] = "combine"
+VoiceSetTranslate["models/player/combine_soldier_prisonguard.mdl"] = "combine"
+VoiceSetTranslate["models/player/combine_super_soldier.mdl"] = "combine"
+VoiceSetTranslate["models/player/eli.mdl"] = "male"
+VoiceSetTranslate["models/player/gman_high.mdl"] = "male"
+VoiceSetTranslate["models/player/kleiner.mdl"] = "male"
+VoiceSetTranslate["models/player/monk.mdl"] = "monk"
+VoiceSetTranslate["models/player/mossman.mdl"] = "female"
+VoiceSetTranslate["models/player/odessa.mdl"] = "male"
+VoiceSetTranslate["models/player/police.mdl"] = "combine"
+VoiceSetTranslate["models/player/brsp.mdl"] = "female"
+VoiceSetTranslate["models/player/moe_glados_p.mdl"] = "female"
+VoiceSetTranslate["models/grim.mdl"] = "combine"
+VoiceSetTranslate["models/jason278-players/gabe_3.mdl"] = "monk"
+function GM:PlayerSpawn(pl)
+ pl:StripWeapons()
+ pl:RemoveStatus("confusion", false, true)
+
+ if pl:GetMaterial() ~= "" then
+ pl:SetMaterial("")
+ end
+
+ pl:UnSpectate()
+
+ pl.StartCrowing = nil
+ pl.StartSpectating = nil
+ pl.NextSpawnTime = nil
+ pl.Gibbed = nil
+
+ pl.SpawnNoSuicide = CurTime() + 1
+ pl.SpawnedTime = CurTime()
+
+ pl:ShouldDropWeapon(false)
+
+ pl:SetLegDamage(0)
+ pl:SetLastAttacker()
+
+ if pl:Team() == TEAM_UNDEAD then
+ pl:RemoveStatus("overridemodel", false, true)
+
+ if not pl.Revived then
+ pl.DamagedBy = {}
+ end
+
+ pl.LifeBarricadeDamage = 0
+ pl.LifeHumanDamage = 0
+ pl.LifeBrainsEaten = 0
+
+ if self:GetEscapeSequence() and self:GetEscapeStage() >= ESCAPESTAGE_BOSS then
+ local bossindex = pl:GetBossZombieIndex()
+ if bossindex ~= -1 then
+ pl:SetZombieClass(bossindex)
+ end
+ elseif pl.DeathClass and self:GetWaveActive() then
+ pl:SetZombieClass(pl.DeathClass)
+ pl.DeathClass = nil
+ end
+
+ local classtab = pl:GetZombieClassTable()
+ pl:DoHulls(pl:GetZombieClass(), TEAM_UNDEAD)
+
+ if classtab.Model then
+ pl:SetModel(classtab.Model)
+ elseif classtab.UsePlayerModel then
+ local desiredname = pl:GetInfo("cl_playermodel")
+ if #desiredname == 0 then
+ pl:SelectRandomPlayerModel()
+ else
+ pl:SetModel(player_manager.TranslatePlayerModel(desiredname))
+ end
+ elseif classtab.UsePreviousModel then
+ local curmodel = string.lower(pl:GetModel())
+ if table.HasValue(self.RestrictedModels, curmodel) or string.sub(curmodel, 1, 14) ~= "models/player/" then
+ pl:SelectRandomPlayerModel()
+ end
+ elseif classtab.UseRandomModel then
+ pl:SelectRandomPlayerModel()
+ else
+ pl:SetModel("models/player/zombie_classic.mdl")
+ end
+
+ local numundead = team.NumPlayers(TEAM_UNDEAD)
+ if self.OutnumberedHealthBonus <= numundead or classtab.Boss then
+ pl:SetHealth(classtab.Health)
+ else
+ pl:SetHealth(classtab.Health * 1.5)
+ end
+
+ if classtab.SWEP then
+ pl:Give(classtab.SWEP)
+ end
+
+ pl:SetNoTarget(true)
+ pl:SetMaxHealth(1)
+
+ pl:ResetSpeed()
+ pl:SetCrouchedWalkSpeed(classtab.CrouchedWalkSpeed or 0.70)
+
+ if not pl.Revived or not self:GetWaveActive() or CurTime() > self:GetWaveEnd() then
+ pl.StartCrowing = 0
+ end
+
+ if pl.ForceSpawnAngles then
+ pl:SetEyeAngles(pl.ForceSpawnAngles)
+ pl.ForceSpawnAngles = nil
+ end
+
+ pl:CallZombieFunction("OnSpawned")
+ else
+ pl.m_PointQueue = 0
+ pl.PackedItems = {}
+
+ local desiredname = pl:GetInfo("cl_playermodel")
+ local modelname = player_manager.TranslatePlayerModel(#desiredname == 0 and self.RandomPlayerModels[math.random(#self.RandomPlayerModels)] or desiredname)
+ local lowermodelname = string.lower(modelname)
+ if table.HasValue(self.RestrictedModels, lowermodelname) then
+ modelname = "models/player/alyx.mdl"
+ lowermodelname = modelname
+ end
+ pl:SetModel(modelname)
+
+ -- Cache the voice set.
+ if VoiceSetTranslate[lowermodelname] then
+ pl.VoiceSet = VoiceSetTranslate[lowermodelname]
+ elseif string.find(lowermodelname, "female", 1, true) then
+ pl.VoiceSet = "female"
+ else
+ pl.VoiceSet = "male"
+ end
+
+ pl.HumanSpeedAdder = nil
+
+ pl.BonusDamageCheck = CurTime()
+
+ pl:ResetSpeed()
+ pl:SetJumpPower(DEFAULT_JUMP_POWER)
+ pl:SetCrouchedWalkSpeed(0.65)
+
+ pl:SetNoTarget(false)
+ pl:SetMaxHealth(100)
+
+ if self.ZombieEscape then
+ pl:Give("weapon_zs_zeknife")
+ pl:Give("weapon_zs_zegrenade")
+ pl:Give(table.Random(self.ZombieEscapeWeapons))
+ elseif self.StartingLoadout then
+ self:GiveStartingLoadout(pl)
+ elseif pl.m_PreRedeem then
+ if self.RedeemLoadout then
+ for _, class in pairs(self.RedeemLoadout) do
+ pl:Give(class)
+ end
+ else
+ pl:Give("weapon_zs_redeemers")
+ pl:Give("weapon_zs_swissarmyknife")
+ end
+ end
+
+ local oldhands = pl:GetHands()
+ if IsValid(oldhands) then
+ oldhands:Remove()
+ end
+
+ local hands = ents.Create("zs_hands")
+ if hands:IsValid() then
+ hands:DoSetup(pl)
+ hands:Spawn()
+ end
+ end
+
+ pl:DoMuscularBones()
+ pl:DoNoodleArmBones()
+
+ local pcol = Vector(pl:GetInfo("cl_playercolor"))
+ pcol.x = math.Clamp(pcol.x, 0, 2.5)
+ pcol.y = math.Clamp(pcol.y, 0, 2.5)
+ pcol.z = math.Clamp(pcol.z, 0, 2.5)
+ pl:SetPlayerColor(pcol)
+
+ local wcol = Vector(pl:GetInfo("cl_weaponcolor"))
+ wcol.x = math.Clamp(wcol.x, 0, 2.5)
+ wcol.y = math.Clamp(wcol.y, 0, 2.5)
+ wcol.z = math.Clamp(wcol.z, 0, 2.5)
+ pl:SetWeaponColor(wcol)
+
+ pl.m_PreHurtHealth = pl:Health()
+end
+
+function GM:SetWave(wave)
+ local previouslylocked = {}
+ for i, classtab in ipairs(GAMEMODE.ZombieClasses) do
+ if not gamemode.Call("IsClassUnlocked", classid) then
+ previouslylocked[i] = true
+ end
+ end
+
+ SetGlobalInt("wave", wave)
+
+ for classid in pairs(previouslylocked) do
+ if gamemode.Call("IsClassUnlocked", classid) then
+ for _, ent in pairs(ents.FindByClass("logic_classunlock")) do
+ local classname = GAMEMODE.ZombieClasses[classid].Name
+ if ent.Class == string.lower(classname) then
+ ent:Input("onclassunlocked", ent, ent, classname)
+ end
+ end
+ end
+ end
+end
+
+GM.NextEscapeDamage = 0
+function GM:WaveStateChanged(newstate)
+ if newstate then
+ if self:GetWave() == 0 then
+ self:SetClosestsToZombie()
+
+ local humans = {}
+ for _, pl in pairs(player.GetAll()) do
+ if pl:Team() == TEAM_HUMAN and pl:Alive() then
+ table.insert(humans, pl)
+ end
+ end
+
+ if #humans >= 1 then
+ for _, pl in pairs(humans) do
+ gamemode.Call("GiveDefaultOrRandomEquipment", pl)
+ pl.BonusDamageCheck = CurTime()
+ end
+ end
+
+ -- We should spawn a crate in a random spawn point if no one has any.
+ if not self.ZombieEscape and #ents.FindByClass("prop_arsenalcrate") == 0 then
+ local have = false
+ for _, pl in pairs(humans) do
+ if pl:HasWeapon("weapon_zs_arsenalcrate") then
+ have = true
+ break
+ end
+ end
+
+ if not have and #humans >= 1 then
+ local spawn = self:PlayerSelectSpawn(humans[math.random(#humans)])
+ if spawn and spawn:IsValid() then
+ local ent = ents.Create("prop_arsenalcrate")
+ if ent:IsValid() then
+ ent:SetPos(spawn:GetPos())
+ ent:Spawn()
+ ent:DropToFloor()
+ ent:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER) -- Just so no one gets stuck in it.
+ end
+ end
+ end
+ end
+ end
+
+ local prevwave = self:GetWave()
+
+ if self:GetUseSigils() and prevwave >= self:GetNumberOfWaves() then return end
+
+ gamemode.Call("SetWave", prevwave + 1)
+ gamemode.Call("SetWaveStart", CurTime())
+ if self.ZombieEscape then
+ gamemode.Call("SetWaveEnd", -1)
+ SetGlobalInt("numwaves", -1)
+ else
+ gamemode.Call("SetWaveEnd", self:GetWaveStart() + self:GetWaveOneLength() + (self:GetWave() - 1) * (GetGlobalBool("classicmode") and self.TimeAddedPerWaveClassic or self.TimeAddedPerWave))
+ end
+
+ net.Start("zs_wavestart")
+ net.WriteInt(self:GetWave(), 16)
+ net.WriteFloat(self:GetWaveEnd())
+ net.Broadcast()
+
+ for _, pl in pairs(player.GetAll()) do
+ if pl:Team() == TEAM_UNDEAD then
+ pl.m_LastWaveStartSpawn = CurTime()
+ if pl:GetZombieClassTable().Name == "Crow" then
+ pl:SetZombieClass(pl.DeathClass or 1)
+ pl:UnSpectateAndSpawn()
+ elseif not pl:Alive() and not pl.Revive then
+ pl:UnSpectateAndSpawn()
+ end
+ end
+ end
+
+ local curwave = self:GetWave()
+ for _, ent in pairs(ents.FindByClass("logic_waves")) do
+ if ent.Wave == curwave or ent.Wave == -1 then
+ ent:Input("onwavestart", ent, ent, curwave)
+ end
+ end
+ for _, ent in pairs(ents.FindByClass("logic_wavestart")) do
+ if ent.Wave == curwave or ent.Wave == -1 then
+ ent:Input("onwavestart", ent, ent, curwave)
+ end
+ end
+ elseif self:GetWave() >= self:GetNumberOfWaves() then -- Last wave is over
+ if self:GetUseSigils() then
+ if self:GetEscapeStage() == ESCAPESTAGE_BOSS then
+ self:SetEscapeStage(ESCAPESTAGE_DEATH)
+
+ PrintMessage(3, "Escape sequence death fog stage")
+
+ gamemode.Call("SetWaveEnd", -1)
+ elseif self:GetEscapeStage() == ESCAPESTAGE_ESCAPE then
+ self:SetEscapeStage(ESCAPESTAGE_BOSS)
+
+ -- 2 minutes to get out with everyone spawning as bosses.
+ gamemode.Call("SetWaveEnd", CurTime() + 120)
+
+ PrintMessage(3, "Escape sequence boss stage")
+
+ -- Start spawning boss zombies.
+ elseif self:GetEscapeStage() == ESCAPESTAGE_NONE then
+ -- If we're using sigils, remove them all and spawn the doors.
+ for _, sigil in pairs(ents.FindByClass("prop_obj_sigil")) do
+ local ent = ents.Create("prop_obj_exit")
+ if ent:IsValid() then
+ ent:SetPos(sigil.NodePos or sigil:GetPos())
+ ent:SetAngles(sigil:GetAngles())
+ ent:Spawn()
+ end
+
+ sigil:Destroy()
+ end
+
+ --[[net.Start("zs_waveend")
+ net.WriteInt(self:GetWave(), 16)
+ net.WriteFloat(CurTime())
+ net.Broadcast()]]
+ PrintMessage(3, "Escape sequence started")
+
+ -- 2 minutes to escape.
+ gamemode.Call("SetWaveActive", true)
+ gamemode.Call("SetWaveEnd", CurTime() + 120)
+ self:SetEscapeStage(ESCAPESTAGE_ESCAPE)
+
+ local curwave = self:GetWave()
+ for _, ent in pairs(ents.FindByClass("logic_waves")) do
+ if ent.Wave == curwave or ent.Wave == -1 then
+ ent:Input("onwaveend", ent, ent, curwave)
+ end
+ end
+ for _, ent in pairs(ents.FindByClass("logic_waveend")) do
+ if ent.Wave == curwave or ent.Wave == -1 then
+ ent:Input("onwaveend", ent, ent, curwave)
+ end
+ end
+ end
+ else
+ -- If not using sigils then humans all win.
+ gamemode.Call("EndRound", TEAM_HUMAN)
+
+ local curwave = self:GetWave()
+ for _, ent in pairs(ents.FindByClass("logic_waves")) do
+ if ent.Wave == curwave or ent.Wave == -1 then
+ ent:Input("onwaveend", ent, ent, curwave)
+ end
+ end
+ for _, ent in pairs(ents.FindByClass("logic_waveend")) do
+ if ent.Wave == curwave or ent.Wave == -1 then
+ ent:Input("onwaveend", ent, ent, curwave)
+ end
+ end
+ end
+ else
+ gamemode.Call("SetWaveStart", CurTime() + (GetGlobalBool("classicmode") and self.WaveIntermissionLengthClassic or self.WaveIntermissionLength))
+
+ net.Start("zs_waveend")
+ net.WriteInt(self:GetWave(), 16)
+ net.WriteFloat(self:GetWaveStart())
+ net.Broadcast()
+
+ for _, pl in pairs(player.GetAll()) do
+ if pl:Team() == TEAM_HUMAN and pl:Alive() then
+ if self.EndWaveHealthBonus > 0 then
+ pl:SetHealth(math.min(pl:GetMaxHealth(), pl:Health() + self.EndWaveHealthBonus))
+ end
+ elseif pl:Team() == TEAM_UNDEAD and not pl:Alive() and not pl.Revive then
+ local curclass = pl.DeathClass or pl:GetZombieClass()
+ local crowindex = GAMEMODE.ZombieClasses["Crow"].Index
+ pl:SetZombieClass(crowindex)
+ pl:DoHulls(crowindex, TEAM_UNDEAD)
+ pl.DeathClass = nil
+ pl:UnSpectateAndSpawn()
+ pl.DeathClass = curclass
+ end
+
+ pl.SkipCrow = nil
+ end
+
+ local curwave = self:GetWave()
+ for _, ent in pairs(ents.FindByClass("logic_waves")) do
+ if ent.Wave == curwave or ent.Wave == -1 then
+ ent:Input("onwaveend", ent, ent, curwave)
+ end
+ end
+ for _, ent in pairs(ents.FindByClass("logic_waveend")) do
+ if ent.Wave == curwave or ent.Wave == -1 then
+ ent:Input("onwaveend", ent, ent, curwave)
+ end
+ end
+ end
+
+ gamemode.Call("OnWaveStateChanged")
+end
+
+function GM:PlayerSwitchFlashlight(pl, newstate)
+ if pl:Team() == TEAM_UNDEAD then
+ if pl:Alive() then
+ pl:SendLua("gamemode.Call(\"ToggleZombieVision\")")
+ end
+
+ return false
+ end
+
+ return true
+end
+
+function GM:PlayerStepSoundTime(pl, iType, bWalking)
+ return 350
+end
+
+concommand.Add("zs_class", function(sender, command, arguments)
+ if sender:Team() ~= TEAM_UNDEAD or sender.Revive or GAMEMODE.PantsMode or GAMEMODE:IsClassicMode() or GAMEMODE:IsBabyMode() or GAMEMODE.ZombieEscape then return end
+
+ local classname = table.concat(arguments, " ")
+ local classtab = GAMEMODE.ZombieClasses[classname]
+ if not classtab or classtab.Hidden and not (classtab.CanUse and classtab:CanUse(sender)) then return end
+
+ if not gamemode.Call("IsClassUnlocked", classname) then
+ sender:CenterNotify(COLOR_RED, translate.ClientFormat(sender, "class_not_unlocked_will_be_unlocked_x", classtab.Wave))
+ elseif sender:GetZombieClassTable().Name == classname and not sender.DeathClass then
+ sender:CenterNotify(COLOR_RED, translate.ClientFormat(sender, "you_are_already_a_x", translate.ClientGet(sender, classtab.TranslationName)))
+ else
+ sender.DeathClass = classtab.Index
+ sender:CenterNotify(translate.ClientFormat(sender, "you_will_spawn_as_a_x", translate.ClientGet(sender, classtab.TranslationName)))
+
+ if sender:Alive() and not sender:GetZombieClassTable().Boss and gamemode.Call("CanPlayerSuicide", sender) then
+ sender:Kill()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/languages/danish.lua b/gamemodes/zombiesurvival/gamemode/languages/danish.lua
new file mode 100644
index 0000000..d02602e
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/languages/danish.lua
@@ -0,0 +1,211 @@
+-- Translated by The Special Duckling (http://www.noxiousnet.com/forums/index.php?action=profile;u=8557)
+
+translate.AddLanguage("da", "Danish")
+
+-- Various gamemode stuff
+LANGUAGE.minute_points_added = "Ingen skade modtaget, i et helt minut! Tilføjet %d point."
+LANGUAGE.infliction_reached_class_unlocked = "%d%% påførelse er blevet opnået! %s oplåst!"
+LANGUAGE.infliction_reached = "%d%% mennesker overlevede!"
+LANGUAGE.x_unlocked = "%s oplåst!"
+LANGUAGE.disconnect_killed = "%s var afbrudt dræbt af %s."
+LANGUAGE.nail_removed_by = "%s fjernede et søm, placeret af %s."
+LANGUAGE.banned_for_life_warning = "Du har ikke adgang til butikken resten af dit liv!"
+LANGUAGE.need_to_be_near_arsenal_crate = "Du skal være nær en Arsenal Kasse!"
+LANGUAGE.cant_purchase_right_now = "Du kan ikke købe noget lige nu."
+LANGUAGE.dont_have_enough_points = "Du har ikke nok point."
+LANGUAGE.prepare_yourself = "Gør dig klar..."
+LANGUAGE.purchased_x_for_y_points = "Købt %s for %d point!"
+LANGUAGE.give_time_before_suicide = "Giv de andre tid til at komme til live, før du begår selvmord."
+LANGUAGE.no_spare_ammo_to_give = "Ingen ammunition til overs at give!"
+LANGUAGE.no_person_in_range = "Ingen personer inden for rækkevidde!!"
+LANGUAGE.that_life = "Det liv..."
+LANGUAGE.x_damage_to_barricades = "%d skade tilført barrikade"
+LANGUAGE.x_damage_to_humans = "%d skade tilført mennesker."
+LANGUAGE.x_brains_eaten = "%d hjerne blevet spist"
+LANGUAGE.press_rmb_to_cycle_targets = "Tryk RMB for at skifte mellem mål"
+LANGUAGE.press_lmb_to_spawn_on_them = "Tryk LMB for at komme i live oven på dem"
+LANGUAGE.press_lmb_to_spawn = "Tryk LMB for at komme i live"
+LANGUAGE.observing_x = "Observerer %s (%d)"
+LANGUAGE.waiting_for_next_wave = "Venter på at næste runde begynder..."
+LANGUAGE.impossible = "Umuligt."
+LANGUAGE.trying_to_put_nails_in_glass = "At prøve at hamre et objekt fast til noget glas, er bare idiotisk."
+LANGUAGE.boss_class_select = "Du vil blive %s næste gang du er en zombie boss."
+LANGUAGE.person_has_weapon = "Du ejer allerede det våben."
+LANGUAGE.cant_do_that_in_classic_mode = "Det der kan ikke lade sig gøre i Classic Mode."
+LANGUAGE.cant_use_x_in_classic_mode = "Du kan ikke bruge %s i Classic Mode."
+LANGUAGE.cant_use_x_in_zombie_escape = "Du kan ikke bruge %s i Zombie Escape."
+LANGUAGE.no_class_switch_in_this_mode = "Den nuværende spillemåde tillader dig ikke at skifte person."
+LANGUAGE.press_sprint_to_get_up = "Tryk SPRINT for at gå op."
+LANGUAGE.zombie_escape = "Zombie undslippelse!"
+LANGUAGE.nothing_for_this_ammo = "Du ejer intet som bruger denne type ammunition."
+LANGUAGE.you_decide_to_leave_some = "Du beslutter dig at gemme noget til dit hold."
+LANGUAGE.you_cant_purchase_now = "Du kan ikke købe ting lige nu."
+LANGUAGE.no_ammo_here = "Der er intet ammunition lige nu."
+LANGUAGE.you_redeemed = "Du er blevet genoplivet!"
+LANGUAGE.kill_the_last_human = "Dræb det sidste menneske!"
+LANGUAGE.kick_the_last_human = "Spark det sidste menneske!"
+LANGUAGE.you_are_the_last_human = "DU ER DEN SIDSTE OVERLEVENDE!"
+LANGUAGE.x_zombies_out_to_get_you = "%d ZOMBIER VIL ÆDE DIN HJERNE!"
+LANGUAGE.x_pants_out_to_get_you = "%d PAR BUKSER ER UDE EFTER DIN ÆRE!"
+LANGUAGE.you_have_died = "Du er død."
+LANGUAGE.you_were_killed_by_x = "Du blev dræbt af %s"
+LANGUAGE.you_were_kicked_by_x = "Du blev sparket i skinnebenene af %s"
+LANGUAGE.arsenal_upgraded = "Arsenal Opgraderet"
+LANGUAGE.final_wave = "SIDSTE RUNDE ER PÃ…BEGYNDT!"
+LANGUAGE.final_wave_sub = "ALLE personer oplåst, og chancen for genoplivelse er sluttet!"
+LANGUAGE.wave_x_has_begun = "Runde %d er påbegyndt!"
+LANGUAGE.x_unlocked = "%s oplåst!"
+LANGUAGE.wave_x_is_over = "Runde %d er sluttet!"
+LANGUAGE.wave_x_is_over_sub = "De udøde er stoppet med at komme op fra deres grave, og point butikken har %d%% lukket."
+LANGUAGE.you_are_x = "Du er %s!"
+LANGUAGE.x_has_risen_as_y = "%s er genoplivet som %s!!"
+LANGUAGE.x_has_risen = "%s er genoplivet!"
+LANGUAGE.cant_use_worth_anymore = "Du kan ikke bruge Worth menuen længere!"
+LANGUAGE.class_not_unlocked_will_be_unlocked_x = "Den person er ikke oplåst endnu. Personen vil blive oplåst i starten af runde %d."
+LANGUAGE.you_are_already_a_x = "Du er allerede en %s."
+LANGUAGE.you_will_spawn_as_a_x = "Du vil komme til live som en %s."
+LANGUAGE.crafting_successful = "Skabelse fuldført!"
+LANGUAGE.x_crafted_y = "%s skabte %s."
+LANGUAGE.escape_from_the_zombies = "Flygt fra de udøde!"
+LANGUAGE.too_close_to_another_nail = "For tæt på et andet søm."
+LANGUAGE.object_too_damaged_to_be_used = "Objektet er for ødelagt til at kunne blive brugt."
+LANGUAGE.thanks_for_being_a_fan_of_zs = "Tak fordi at du er en fan af Zombie Survival!"
+LANGUAGE.cant_remove_nails_of_superior_player = "Du kan ikke fjerne sømmene placeret af en spiller som er så meget bedre end dig.."
+LANGUAGE.x_turned_on_noclip = "%s afbrudte NoClip."
+LANGUAGE.x_turned_off_noclip = "%s Tændte NoClip."
+LANGUAGE.unlocked_on_wave_x = "Oplåst i runde %d"
+LANGUAGE.brains_eaten_x = "Hjerner spist: %s"
+LANGUAGE.points_x = "Point: %s"
+LANGUAGE.next_wave_in_x = "Næste runde om %s"
+LANGUAGE.wave_ends_in_x = "Runden slutter om %s"
+LANGUAGE.wave_x_of_y = "Runde %d af %d"
+LANGUAGE.zombie_invasion_in_x = "Zombie invasion om %s"
+LANGUAGE.intermission = "Pause"
+LANGUAGE.press_f2_for_the_points_shop = "Tryk på F2 for Point Butik!"
+LANGUAGE.breath = "Ã…nde"
+LANGUAGE.zombie_volunteers = "Frivillige zombier"
+LANGUAGE.x_discount_for_buying_between_waves = "%d%% discount for at købe mellem runder!"
+LANGUAGE.number_of_initial_zombies_this_game = "Antal initiale zombier dette spil (%d%%): %d"
+LANGUAGE.humans_closest_to_spawns_are_zombies = "Menneskerne tættest på zombiernes gravsted vil starte som zombier."
+LANGUAGE.waiting_for_players = "Venter på spillere..."
+LANGUAGE.requires_x_people = "Kræver %d spillere"
+LANGUAGE.packing_others_object = "Pakker anden persons ting"
+LANGUAGE.packing = "Pakker"
+LANGUAGE.ze_humans_are_frozen_until_x = "Mennesker er frosne %d sekunder før runden starter."
+LANGUAGE.loading = "Indlæser..."
+LANGUAGE.next_round_in_x = "Næste runde er: %s"
+LANGUAGE.warning = "Advarsel!"
+LANGUAGE.ok_and_no_reminder = "OK, og ikke lad den besked komme til verden igen."
+LANGUAGE.classic_mode_warning = "Denne server kører Zombie Survival i 'Classic Mode'\nClassic Mode er en indstilling som hæftigt ændre spillet. Ting som er ændrede:\n* Du kan ikke vælge zombier specifikationer. Alle bruger Classic Zombie specifikationen\n* Ingen Mulighed for at kunne lave barrikader \n* Flere, men hurtigere runder\n\nDette er IKKE den originale Zombie Survival!\n\n-- Servere som kører classic version vil fremvise CLASSIC MODE i venstre bund af skærmen --"
+LANGUAGE.classic_mode = "CLASSIC MODE"
+LANGUAGE.resist_x = "Undgåelse: %d%%"
+LANGUAGE.right_click_to_hammer_nail = "Højre klik, for at hamre et søm."
+LANGUAGE.nails_x = "Søm: %d"
+LANGUAGE.resupply_box = "Genfyldnings Kasse"
+LANGUAGE.purchase_now = "Køb nu!"
+LANGUAGE.integrity_x = "Helhed: %d%%"
+LANGUAGE.empty = "TOM"
+LANGUAGE.manual_control = "MANUAL KONTROL"
+LANGUAGE.arsenal_crate = "Arsenal Kasse"
+
+-- Exit point objectives
+LANGUAGE.exit_destroyed = "De udøde har nedbrudt udgangen!"
+LANGUAGE.exit_destroyed_only_one_remain_h = "Kun en resterer! Hvis den falder, vil der ikke være nogen mulighed for flugt!"
+LANGUAGE.exit_destroyed_only_one_remain_z = "Kun en resterer!"
+LANGUAGE.exit_destroyed_x_remain = "%d udgange resterer."
+LANGUAGE.last_exit_destroyed_all_is_lost = "De udøde har ødelagt den sidste udgang."
+LANGUAGE.last_exit_destroyed_all_is_lost2 = "Der er ingen håb for undslippelse."
+
+-- Message beacon messages
+LANGUAGE.message_beacon_1 = "Kom her op"
+LANGUAGE.message_beacon_2 = "Har brug for beskyttelse her"
+LANGUAGE.message_beacon_3 = "Har brug for automatisk maskingeværer her"
+LANGUAGE.message_beacon_4 = "Har brug for arenal kasser her"
+LANGUAGE.message_beacon_5 = "Har brug for læger her"
+LANGUAGE.message_beacon_6 = "Ammunitions kasse her"
+LANGUAGE.message_beacon_7 = "Arsenal kasse her"
+LANGUAGE.message_beacon_8 = "Har brug for kraftfelter her"
+LANGUAGE.message_beacon_9 = "Har brug for eksplosive genstande her"
+LANGUAGE.message_beacon_10 = "De udøde kommer her fra"
+LANGUAGE.message_beacon_11 = "GÃ¥ ikke ind!!"
+LANGUAGE.message_beacon_12 = "GÃ¥ ikke ud"
+LANGUAGE.message_beacon_13 = "Beskyt dette område"
+LANGUAGE.message_beacon_14 = "Beskyt dette sted"
+LANGUAGE.message_beacon_15 = "Læger her"
+LANGUAGE.message_beacon_16 = "Køb fra min kasse"
+LANGUAGE.message_beacon_17 = "Barrikade her"
+LANGUAGE.message_beacon_18 = "Ikke barrikader her"
+LANGUAGE.message_beacon_19 = "Luk ikke de udøde her ind"
+LANGUAGE.message_beacon_20 = "Det her går i stykker"
+LANGUAGE.message_beacon_21 = "Dette sted er ikke sikkert!"
+LANGUAGE.message_beacon_22 = "Pas på giften!"
+LANGUAGE.message_beacon_23 = "De udøde kommer igennem her!"
+LANGUAGE.message_beacon_24 = "De udøde kommer. Byg en barrikade!"
+LANGUAGE.message_beacon_25 = "Plan B her"
+
+-- Class names
+LANGUAGE.class_zombie = "Zombie"
+LANGUAGE.class_poison_zombie = "Poison Zombie"
+LANGUAGE.class_fast_zombie = "Fast Zombie"
+LANGUAGE.class_bloated_zombie = "Bloated Zombie"
+LANGUAGE.class_classic_zombie = "Classic Zombie"
+LANGUAGE.class_super_zombie = "Super Zombie"
+LANGUAGE.class_fresh_dead = "Fresh Dead"
+LANGUAGE.class_ghoul = "Ghoul"
+LANGUAGE.class_headcrab = "Headcrab"
+LANGUAGE.class_fast_headcrab = "Fast Headcrab"
+LANGUAGE.class_poison_headcrab = "Poison Headcrab"
+LANGUAGE.class_the_tickle_monster = "The Tickle Monster"
+LANGUAGE.class_nightmare = "Nightmare"
+LANGUAGE.class_pukepus = "Pukepus"
+LANGUAGE.class_bonemesh = "Bonemesh"
+LANGUAGE.class_crow = "Crow"
+LANGUAGE.class_wilowisp = "Wil O' Wisp"
+LANGUAGE.class_zombie_torso = "Zombie Torso"
+LANGUAGE.class_zombie_legs = "Zombie Legs"
+LANGUAGE.class_wraith = "Wraith"
+LANGUAGE.class_flesh_creeper = "Flesh Creeper"
+LANGUAGE.class_fast_zombie_legs = "Fast Zombie Legs"
+LANGUAGE.class_chem_zombie = "Chem Zombie"
+LANGUAGE.class_shade = "Shade"
+
+-- Class descriptions
+LANGUAGE.description_zombie = "Dette er den mest normale af de udøde. Den er meget kraftig, og har kraftige klør. \nDen er svær at holde nede, specielt hvis den ikke bliver skudt i hovedet."
+LANGUAGE.description_poison_zombie = "Denne muterede udøde er ikke kun ekstremt kraftig, men ejer også unormal styrke. \n Dens krop er ekstremt giftig, og den vil rive sit eget kød af og kaste det, efter ting som ikke kan slås med dens klør."
+LANGUAGE.description_fast_zombie = "Dette knoglede kadaver er meget hurtigere end andre udøde. \nDe gør ikke megen skade alene, men de kan kravle op næsten over alt, og smadre overlevende som ikke er på vagt. \nDe har heller ikke noget problem med at fange svage, eller sårede mennesker."
+LANGUAGE.description_bloated_zombie = "Deres krop består af råddent kød, blandet med meget giftige kemikalier. \nSelvom de er langsommere, kan de tage en smule flere kugler end andre udøde."
+LANGUAGE.description_ghoul = "Denne udøde har enormt giftigt kød. \nDen er lidt svagere end andre udøde, men i dens beskyttelse er dens angreb dybt giftige. \nDens klør vil svække en overlevende i et kort øjeblik, og den vil spytte gift ud af dens sår, hvis den tager nok skade."
+LANGUAGE.description_headcrab = "Hoverkrabber er hvad startede infektionen. \nIngen ved hvor de virkelig stammede fra. \nDeres metode af angreb, er ved hjælp af deres skarpe næb under deres mave."
+LANGUAGE.description_fast_headcrab = "Den mandelige hovedkrappe er betydeligt hurtigere, men mindre kraftig end den kvindelige. \nUanset hvad, er de lige irriterende og dødelige i grupper."
+LANGUAGE.description_poison_headcrab = "Denne hovedkrappe er fuldt med dødelige giftstoffer. \nEn bid er normalt nok til at dræbe et voksent menneske. \nDen har også evnen til at spytte en mindre giftig version af dens giftstoffer. \nSpyttet er lige så giftigt, hvis offeret bliver ramt i ansigtet."
+LANGUAGE.description_the_tickle_monster = "Det siges at dette monster gemmer sig i dit skab om natten, for at trække dig ud af din seng. \nTickle Monsterets næsten elastiske arme gør det ekstremt svært at løbe væk fra, og så er de også de ideale barrikade ødelæggere."
+LANGUAGE.description_nightmare = "En enormt sjælden mutation giver Nightmare dens anormale egenskaber. \nStærkere end en normal udød på næsten alle måder, Nightmare er ikke en kræft som du ønsker at slås med. \nEt stik fra dens klør er nok til at dræbe næsten hvilken som helst person."
+LANGUAGE.description_pukepus = "Den rådne krop af Puke Pus består kun af organer som bruges til at genere gift. \nDen er i stand til at kaste litervis af gift op, hvilket gør den ekstremt farlig."
+LANGUAGE.description_bonemesh = "Vansiret og lemlæstet, Bonemesh har egenskaben af at kunne kaste blod bomber. \nHver bombe består af knogler of kød, som skader mennesker, mens den udleverer mad til andre udøde."
+LANGUAGE.description_crow = "Carrion Kraver er mere af en pest end de var før infektionen. \nDe spiser af de udødes kød, og slæber sygdommen med sig. \nHvofor fanden er den her overhovedet tilgængelig? \nHvad er der galt med dig?"
+LANGUAGE.description_wilowisp = "Nogle gang hentydet til som ånderne af død."
+LANGUAGE.description_zombie_torso = "Du burde ikke kunne se det her… Men nu du gør, så er Anders Volander sej!"
+LANGUAGE.description_zombie_legs = "Du burde ikke kunne se det her… Men nu du gør, så er Anders Volander sej!"
+LANGUAGE.description_wraith = "En udød eller en skiggelse? \nIkke meget er kendt omkring den, udover det faktum at de bruger en \nunik skygge egenskab, for at gøre sig selv usynlig, og skarpe klør til at skære ting til konfetti."
+LANGUAGE.description_flesh_creeper = "*pending*"
+LANGUAGE.description_fast_zombie_legs = "Du burde ikke kunne se det her… Men nu du gør, så er Anders Volander sej!"
+LANGUAGE.description_chem_zombie = "Chem Zombies krop består af meget giftige kemikalier. \nDen har ingen mulighed for angreb, udover at håbe på at blive dræbt, og derved sprænge i luften, ved siden af en overlevende. \nEller måske en hel gruppe af dem?"
+LANGUAGE.description_shade = "Ved at lave et stærkt magnetisk område omkring sig selv, vil alle kugler og nærkampsangreb blive ligegyldige omkring den. \nMen af en eller anden grund kan den ikke lide skarpe lys."
+
+-- Class control schemes
+LANGUAGE.controls_zombie = "> PRIMARY: Claws\n> SECONDARY: Scream\n> RELOAD: Moan\n> SPRINT: Feign death\n> ON FATAL HIT IN LEGS: Revive / Transform"
+LANGUAGE.controls_poison_zombie = "> PRIMARY: Claws\n> SECONDARY: Flesh toss\n> RELOAD: Scream"
+LANGUAGE.controls_fast_zombie = "> PRIMARY: Claws\n> SECONDARY: Lunge / Climb (next to wall)\n> RELOAD: Scream"
+LANGUAGE.controls_bloated_zombie = "> PRIMARY: Claws\n> SECONDARY: Moan\n> SPRINT: Feign death\n> ON DEATH: Poison Gibs"
+LANGUAGE.controls_ghoul = "> PRIMARY: Poison claws\n> SECONDARY: Flesh toss\n> SPRINT: Feign death\n> RELOAD: Scream\n> ON HIT HUMAN: Slow\n> ON HIT BY HUMAN: Poison ejection"
+LANGUAGE.controls_headcrab = "> PRIMARY: Lunge attack\n> RELOAD: Burrow"
+LANGUAGE.controls_fast_headcrab = "> PRIMARY: Lunge attack"
+LANGUAGE.controls_poison_headcrab = "> PRIMARY: Lunge attack\n> SECONDARY: Spit poison\n> ON HIT HUMAN: Deadly poison\n> ON HIT POISON IN EYES: Blind\n> RELOAD: Scream"
+LANGUAGE.controls_the_tickle_monster = "> PRIMARY: Elastic claws\n> SECONDARY: Moan"
+LANGUAGE.controls_nightmare = "> PRIMARY: Death touch\n> SECONDARY: Moan"
+LANGUAGE.controls_pukepus = "> PRIMARY: Puke"
+LANGUAGE.controls_bonemesh = "> PRIMARY: Claws\n> SECONDARY: Toss blood bomb"
+LANGUAGE.controls_wraith = "> PRIMARY: Claws\n> SECONDARY: Scream\n> INVISIBILITY BASED ON MOVEMENT AND VIEW DISTANCE"
+LANGUAGE.controls_flesh_creeper = "> PRIMARY: Claws\n> SECONDARY: Head Butt"
+LANGUAGE.controls_chem_zombie = "> ON DEATH: Poison Bomb"
+LANGUAGE.controls_shade = "> PRIMARY: Lift\n> SECONDARY: Throw"
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/languages/dutch.lua b/gamemodes/zombiesurvival/gamemode/languages/dutch.lua
new file mode 100644
index 0000000..fb23871
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/languages/dutch.lua
@@ -0,0 +1,210 @@
+-- Translated by Shinyshark (http://www.noxiousnet.com/forums/index.php?action=profile;u=8372)
+
+translate.AddLanguage("nl", "Dutch")
+
+LANGUAGE.minute_points_added = "Geen schade gehad voor een hele minuut! %d punten gekregen."
+LANGUAGE.infliction_reached_class_unlocked = "%d%% toebrenging is behaald! %s vrijgespeeld!"
+LANGUAGE.infliction_reached = "%d%% van de mensen zijn gestorven!"
+LANGUAGE.x_unlocked = "%s vrijgespeeld!"
+LANGUAGE.disconnect_killed = "%s was gedisconnect, vermoord door %s."
+LANGUAGE.nail_removed_by = "%s verwijderde een spijker die van %s was."
+LANGUAGE.banned_for_life_warning = "Je bent verbannen voor het leven en kunt dus niks kopen!"
+LANGUAGE.need_to_be_near_arsenal_crate = "Je moet dicht bij een Arsenaal Krat zijn om spullen te kopen!"
+LANGUAGE.cant_purchase_right_now = "Je kunt op het moment niks kopen."
+LANGUAGE.dont_have_enough_points = "Je hebt niet genoeg punten."
+LANGUAGE.prepare_yourself = "Zet jezelf schrap..."
+LANGUAGE.purchased_x_for_y_points = "Kocht %s voor %d punten!"
+LANGUAGE.give_time_before_suicide = "Geef anderen de tijd om te spawnen voordat je zelfmoord pleegt."
+LANGUAGE.no_spare_ammo_to_give = "Geen extra ammunitie om te geven!"
+LANGUAGE.no_person_in_range = "Niemand in zicht!"
+LANGUAGE.that_life = "In dat leven..."
+LANGUAGE.x_damage_to_barricades = "%d schade toegericht aan barricades"
+LANGUAGE.x_damage_to_humans = "%d schade toegericht aan de mensen"
+LANGUAGE.x_brains_eaten = "%d hersenen gegeten"
+LANGUAGE.press_rmb_to_cycle_targets = "Klik RMK om tussen zombies te wisselen"
+LANGUAGE.press_lmb_to_spawn_on_them = "Klik LMK om op ze te spawnen"
+LANGUAGE.press_lmb_to_spawn = "Klik LMK om te spawnen"
+LANGUAGE.observing_x = "Je observeert %s (%d)"
+LANGUAGE.waiting_for_next_wave = "Wachten op de volgende aanvalsgolf om te beginnen"
+LANGUAGE.impossible = "Onmogelijk."
+LANGUAGE.trying_to_put_nails_in_glass = "Spijkers in glas slaan is een stom idee."
+LANGUAGE.boss_class_select = "Je zult %s zijn de volgende keer dat je een boss zombie bent."
+LANGUAGE.person_has_weapon = "Die persoon heeft dat wapen al."
+LANGUAGE.cant_do_that_in_classic_mode = "Je kunt dit niet doen in Classic Mode"
+LANGUAGE.cant_use_x_in_classic_mode = "Je kunt %s niet gebruiken in Classic Mode"
+LANGUAGE.cant_use_x_in_zombie_escape = "Je kunt %s niet gebruiken in Zombie Escape"
+LANGUAGE.no_class_switch_in_this_mode = "De huidige mode staat je niet toe om van klasse te veranderen."
+LANGUAGE.press_sprint_to_get_up = "Druk op SPRINT om op te staan"
+LANGUAGE.zombie_escape = "Zombie Escape!"
+LANGUAGE.nothing_for_this_ammo = "Je hebt niks wat dit type ammunitie gebruikt."
+LANGUAGE.you_decide_to_leave_some = "Je besloot om wat achter te laten voor je team."
+LANGUAGE.you_cant_purchase_now = "Je kunt op het moment geen spullen kopen."
+LANGUAGE.no_ammo_here = "Er is hier op het moment geen ammunitie."
+LANGUAGE.you_redeemed = "Je hebt jezelf verlost!"
+LANGUAGE.kill_the_last_human = "Vermoordt het laatste mens!"
+LANGUAGE.kick_the_last_human = "Schop het laatste mens!"
+LANGUAGE.you_are_the_last_human = "JE BENT HET LAATSTE MENS!"
+LANGUAGE.x_zombies_out_to_get_you = "%d ZOMBIES WILLEN JE HERSENEN!"
+LANGUAGE.x_pants_out_to_get_you = "%d BENEN WILLEN JE SCHOPPEN!"
+LANGUAGE.you_have_died = "Je bent gestorven."
+LANGUAGE.you_were_killed_by_x = "Je bent vermoordt door %s"
+LANGUAGE.you_were_kicked_by_x = "Je bent op je schenen geschopt door %s"
+LANGUAGE.arsenal_upgraded = "Arsenaal verbeterd"
+LANGUAGE.final_wave = "DE LAATSE AANVALSGOLF IS BEGONNEN!"
+LANGUAGE.final_wave_sub = "ALLE klasse vrijgespeeld en de kans ter verlossing is over!"
+LANGUAGE.wave_x_has_begun = "Aanvalsgolf %d is begonnen!"
+LANGUAGE.x_unlocked = "%s vrijgespeeld!"
+LANGUAGE.wave_x_is_over = "Aanvalsgolf %d is over!"
+LANGUAGE.wave_x_is_over_sub = "De levende doden zijn voor nu gestopt en de punten winkel is %d%% goedkoper."
+LANGUAGE.you_are_x = "Je bent %s"
+LANGUAGE.x_has_risen_as_y = "%s is ontwaakt als %s!!"
+LANGUAGE.x_has_risen = "%s is ontwaakt!"
+LANGUAGE.cant_use_worth_anymore = "Je kunt het waarde menu niet meer gebruiken!"
+LANGUAGE.class_not_unlocked_will_be_unlocked_x = "Deze klasse is nog niet vrijgespeeld. Hij zal vrijgespeeld zijn aan het begin van aanvalsgolf %d"
+LANGUAGE.you_are_already_a_x = "Je bent al een %s."
+LANGUAGE.you_will_spawn_as_a_x = "Je zult spawnen als een %s."
+LANGUAGE.crafting_successful = "Crafting succesvol!"
+LANGUAGE.x_crafted_y = "%s crafted %s."
+LANGUAGE.escape_from_the_zombies = "Ontsnap aan de zombies!"
+LANGUAGE.too_close_to_another_nail = "Te dicht bij een andere spijker."
+LANGUAGE.object_too_damaged_to_be_used = "Dat object is te beschadigd om nog gebruikt te worden."
+LANGUAGE.thanks_for_being_a_fan_of_zs = "Bedankt voor het wezen van een Zombie Survival fan!"
+LANGUAGE.cant_remove_nails_of_superior_player = "Je kunt de spijkers van een speler die het beter doet als jou niet verwijderen!"
+LANGUAGE.x_turned_on_noclip = "%s zette noclip aan."
+LANGUAGE.x_turned_off_noclip = "%s zette noclip uit."
+LANGUAGE.unlocked_on_wave_x = "Vrijgespeeld op aanvalsgolf %d"
+LANGUAGE.brains_eaten_x = "Hersenen gegeten: %s"
+LANGUAGE.points_x = "Punten: %s"
+LANGUAGE.next_wave_in_x = "Volgende aanvalsgolf in %s"
+LANGUAGE.wave_ends_in_x = "Aanvalsgolf eindigt in %s"
+LANGUAGE.wave_x_of_y = "Aanvalsgolf %d van de %d"
+LANGUAGE.zombie_invasion_in_x = "Zombie invasie begint in %s"
+LANGUAGE.intermission = "Tussen pauze"
+LANGUAGE.press_f2_for_the_points_shop = "Druk op F2 voor de punten winkel!"
+LANGUAGE.breath = "Zuurstof"
+LANGUAGE.zombie_volunteers = "Zombie vrijwilligers"
+LANGUAGE.x_discount_for_buying_between_waves = "%d%% korting voor het kopen tussen aanvalsgolfen!"
+LANGUAGE.number_of_initial_zombies_this_game = "Aantal aanvankelijke zombies dit spel (%d%%): %d"
+LANGUAGE.humans_closest_to_spawns_are_zombies = "Het mens dat het dichts bij de zombie spawn is zal starten als zombie."
+LANGUAGE.waiting_for_players = "Wachten op mensen..."
+LANGUAGE.requires_x_people = "Heeft %d mensen nodig"
+LANGUAGE.packing_others_object = "Oppakken van andermans object"
+LANGUAGE.packing = "Oppakken"
+LANGUAGE.ze_humans_are_frozen_until_x = "Mensen zijn bevroren tot $d seconden voordat de ronde begint."
+LANGUAGE.loading = "Laden..."
+LANGUAGE.next_round_in_x = "Volgende ronden in: %s"
+LANGUAGE.warning = "Opgepast!"
+LANGUAGE.ok_and_no_reminder = "OK en dit bericht niet meer laten zien"
+LANGUAGE.classic_mode_warning = "Deze server runt Zombie Survival in 'Classic Mode'\nClassic Mode is een setting die de gameplay aanpast. Dingen die aangepast zijn:\n* Geen zombie klasses kiezen. Iedereen gebruikt de klassieke zombie klasse\n* Geen barricaderings gereedschap zoals spijkers of turrets\n* Meer maar sneller aanvalsgolven\n\nDit is NIET de originele Zombie Survival!\n\n-- Servers die classic mode runnen weergeven dit links onderin het scherm --"
+LANGUAGE.classic_mode = "CLASSIC MODE"
+LANGUAGE.resist_x = "Weerstand: %d%%"
+LANGUAGE.right_click_to_hammer_nail = "Rechtermuisknop om een spijker erin te slaan."
+LANGUAGE.nails_x = "Spijkers: %d"
+LANGUAGE.resupply_box = "Voorraad Doos"
+LANGUAGE.purchase_now = "Koop nu!"
+LANGUAGE.integrity_x = "Integriteit: %d%%"
+LANGUAGE.empty = "LEEG"
+LANGUAGE.manual_control = "HANDMATIGE BESTURING"
+LANGUAGE.arsenal_crate = "Arsenaal Krat"
+
+-- Exit point objectives
+LANGUAGE.exit_destroyed = "De zombies hebben een uitgang vernietigd!"
+LANGUAGE.exit_destroyed_only_one_remain_h = "Nog een over! Als die ook kapot is, dan is het over voor ons!"
+LANGUAGE.exit_destroyed_only_one_remain_z = "Nog een over!"
+LANGUAGE.exit_destroyed_x_remain = "%d uitgangen over."
+LANGUAGE.last_exit_destroyed_all_is_lost = "De zombies hebben de laatste uitgang vernietigd."
+LANGUAGE.last_exit_destroyed_all_is_lost2 = "Er is geen onstappen meer..."
+
+-- Message beacon messages
+LANGUAGE.message_beacon_1 = "Verzamel je hier!"
+LANGUAGE.message_beacon_2 = "Hier verdedigen!"
+LANGUAGE.message_beacon_3 = "Turrets hier nodig!"
+LANGUAGE.message_beacon_4 = "Arsenaal kratten zijn hier nodig!"
+LANGUAGE.message_beacon_5 = "Doktoren zijn hier nodig!"
+LANGUAGE.message_beacon_6 = "Ammunitie doos hier nodig!"
+LANGUAGE.message_beacon_7 = "Arsenaal krat hier nodig!"
+LANGUAGE.message_beacon_8 = "Krachtveld hier nodig!"
+LANGUAGE.message_beacon_9 = "Explosieven hier nodig!"
+LANGUAGE.message_beacon_10 = "Zombies komen hier vandaan!"
+LANGUAGE.message_beacon_11 = "Niet binnentreden!"
+LANGUAGE.message_beacon_12 = "Niet hier buiten treden!"
+LANGUAGE.message_beacon_13 = "Verdedig dit gebied."
+LANGUAGE.message_beacon_14 = "Verdedig deze plek."
+LANGUAGE.message_beacon_15 = "Doktoren zijn hier!"
+LANGUAGE.message_beacon_16 = "Koop van mijn krat!"
+LANGUAGE.message_beacon_17 = "Barricadeer hier"
+LANGUAGE.message_beacon_18 = "Barricadeer hier niet"
+LANGUAGE.message_beacon_19 = "Laat de zombies hier niet binnen"
+LANGUAGE.message_beacon_20 = "Dit zal breken"
+LANGUAGE.message_beacon_21 = "Deze plek is gevaarlijk!"
+LANGUAGE.message_beacon_22 = "Pas op voor gif!"
+LANGUAGE.message_beacon_23 = "Zombies zijn hier door aan het breken!"
+LANGUAGE.message_beacon_24 = "Zombies komen eraan. Bouw een barricade!"
+LANGUAGE.message_beacon_25 = "Plan B hier"
+
+-- Class names
+LANGUAGE.class_zombie = "Zombie"
+LANGUAGE.class_poison_zombie = "Gif Zombie"
+LANGUAGE.class_fast_zombie = "Snelle Zombie"
+LANGUAGE.class_bloated_zombie = "Opgezwolle Zombie"
+LANGUAGE.class_classic_zombie = "Klassieke Zombie"
+LANGUAGE.class_super_zombie = "Super Zombie"
+LANGUAGE.class_fresh_dead = "Verse Dode"
+LANGUAGE.class_ghoul = "Ghoul"
+LANGUAGE.class_headcrab = "Headcrab"
+LANGUAGE.class_fast_headcrab = "Snelle Headcrab"
+LANGUAGE.class_poison_headcrab = "Gif Headcrab"
+LANGUAGE.class_the_tickle_monster = "The Tickle Monster"
+LANGUAGE.class_nightmare = "Nightmare"
+LANGUAGE.class_pukepus = "Pukepus"
+LANGUAGE.class_bonemesh = "Bonemesh"
+LANGUAGE.class_crow = "Kraai"
+LANGUAGE.class_wilowisp = "Wil O' Wisp"
+LANGUAGE.class_zombie_torso = "Zombie Torso"
+LANGUAGE.class_zombie_legs = "Zombie Benen"
+LANGUAGE.class_wraith = "Wraith"
+LANGUAGE.class_flesh_beast = "Flesh Beast"
+LANGUAGE.class_fast_zombie_legs = "Snelle Zombie Benen"
+LANGUAGE.class_chem_zombie = "Chem Zombie"
+LANGUAGE.class_shade = "Shade"
+
+-- Class descriptions
+LANGUAGE.description_zombie = "De basis zombie is erg duurzaam een heeft sterke klauwen.\nHet is moeilijk om hen dood te houden, zeker als je ze niet in hun hoofd schiet."
+LANGUAGE.description_poison_zombie = "Deze gemuteerde zombie is niet erg duurzaam, maar is abnormaal sterk.\nZijn lichaam is extreem giftig en hij gooit zelfs zijn eigen vlees als wat hij wil raken te ver weg is."
+LANGUAGE.description_fast_zombie = "Deze zak botten is veer snellen dan andere zombies.\nIn hun eentje stellen ze niet veel voor, maar ze kunnen bijna overal komen door met hun scherpe klauwen te klimmen\nOok kunnen ze gemakkelijk zwakke of gewonde mensen doden."
+LANGUAGE.description_bloated_zombie = "Hun lichaam zit vol met vluchtige, chemische stoffen.\nAlhoewel ze langzamer lopen, kunnen ze wat meer aan."
+LANGUAGE.description_ghoul = "Deze zombie heeft zeer chemisch vlees.\nHij is ietwat zwakker dan andere zombies, maar met zijn gif aanvallen maakt hij het weer goed.\nZijn klauwen kunnen mensen ietwat verzwakken en hij zal gif door zijn wonden schieten als hij genoeg schade oploopt."
+LANGUAGE.description_headcrab = "Headcrabs zijn wat de infectie starte.\nNiemand weet waar ze vandaan komen.\nHun manier van aanvallen is zich tegen iemand aangooien met hun scherpe tandjes op hun buikjes."
+LANGUAGE.description_fast_headcrab = "De mannelijk headcrab is sneller maar minder zwaar als de vrouwelijke headcrab.\nHoe je het ook ziet, hij is nog steeds even vervelend en dodelijk in een groep."
+LANGUAGE.description_poison_headcrab = "Deze headcrab zit vol met dodelijke nuerotoxins.\nEen bijt is normaal gezien genoeg om een volwassen mens te vermoorden.\nHij heeft ook de mogelijkheid om een minder sterk gif te schieten.\nZijn spuug is even dodelijk in het gezicht als ergens anders."
+LANGUAGE.description_the_tickle_monster = "Ze zeggen dat dit het monster is dat in je kast wacht tot je naar bed gaat.\nThe Tickle Monsters lange elastische armen maken het bijna onmogelijk om te ontsnappen, ook is hij een perfect barricade vernietiger."
+LANGUAGE.description_nightmare = "Een extreem rare mutatie geeft de Nightmare zijn abnormale mogelijkheden.\nSterker dan andere zombies op elke manier, de Nightmare is een vijand om bang voor te zijn.\nEen slag van zijn klauwen is genoeg om bijna elke persoon neer te leggen."
+LANGUAGE.description_pukepus = "Het rottende lichaam van de Puke Pus bestaat compleet uit organen die gebruikt zijn om gif te maken.\nHij is instaat om liters gif te kotsen, dit maakt hem erg gevaarlijk!"
+LANGUAGE.description_bonemesh = "Misvormde en verminkt, de Bonemesh is in staat om bloed bommen te gooien.\nElke bom bestaat uit botten en vlees dat mensen pijn doet, maar voor zombies een vijf sterren maaltijd is."
+LANGUAGE.description_crow = "Carrion Crows zijn nog erger dan dat ze al waren voor de infectie.\nZe voeden zich met geïnfecteerd vlees en ze worden 'carriers' voor de zombies.\nWaarom verberg je deze klasse niet, sufkop?\nWat is er mis met jou?"
+LANGUAGE.description_wilowisp = "Wordt soms ook wel de geest van de doden genoemd."
+LANGUAGE.description_zombie_torso = "Dit hoor je niet eens te zien!"
+LANGUAGE.description_zombie_legs = "Dit hoor je niet eens te zien!"
+LANGUAGE.description_wraith = "Een zombie of een verschijning?\nNiet veel is er te weten gekomen over hem behalve dan dat hij zijn\nunieke sluip verdediging en scherpe klauwen gebruikt om dingen in mootjes te snijden."
+LANGUAGE.description_flesh_beast = "*pending*"
+LANGUAGE.description_fast_zombie_legs = "Dit hoor je niet eens te zien!"
+LANGUAGE.description_chem_zombie = "The Chem Zombies lichaam bestaat uit vluchtige chemicaliën.\nHet kan niet aanvallen, echter zal het opblazen naast een mens en die schade toerichten."
+LANGUAGE.description_shade = "Door een sterk magnetisch veld omzich zelf heen te maken worden alle kogels en melee aanvallen nutteloos tegen hem.\nOm de een of andere reden kan de Shade niet tegen fel licht."
+
+-- Class control schemes
+LANGUAGE.controls_zombie = "> PRIMARY: Klauwen\n> SECONDARY: Schreeuw\n> RELOAD: Kreun\n> SPRINT: Dood spelen\n> FATAAL GERAAKT IN DE BENEN: Opstaan / Transformeren"
+LANGUAGE.controls_poison_zombie = "> PRIMARY: Klauwen\n> SECONDARY: Vlees gooien\n> RELOAD: Schreeuw"
+LANGUAGE.controls_fast_zombie = "> PRIMARY: Klauwen\n> SECONDARY: Springen / Klimmen (naast een muur)\n> RELOAD: Shreeuw"
+LANGUAGE.controls_bloated_zombie = "> PRIMARY: Klauwen\n> SECONDARY: Kreun\n> SPRINT: Dood spelen\n> ALS JE STERFT: Gif stukken"
+LANGUAGE.controls_ghoul = "> PRIMARY: Gif Klauwen\n> SECONDARY: Vlees gooien\n> SPRINT: Dood spelen\n> RELOAD: Schreeuw\n> ALS JE EEN MENS RAAKT: Sloom\n> ALS JE GERAAKT WORDT DOOR EEN MENS: Gif schieten"
+LANGUAGE.controls_headcrab = "> PRIMARY: Lunge aanval\n> RELOAD: In de grond kruipen"
+LANGUAGE.controls_fast_headcrab = "> PRIMARY: Lunge aanval"
+LANGUAGE.controls_poison_headcrab = "> PRIMARY: Lunge aanval\n> SECONDARY: Spuug gif\n> ALS JE EEN MENS RAAKT: Dodelijk gif\n> ALS JE GIF IN DE OGEN SCHIET: Verblinden\n> RELOAD: Schreeuw"
+LANGUAGE.controls_the_tickle_monster = "> PRIMARY: Elastiche Klauwen\n> SECONDARY: Kreun"
+LANGUAGE.controls_nightmare = "> PRIMARY: 'Death touch'\n> SECONDARY: Kreun"
+LANGUAGE.controls_pukepus = "> PRIMARY: Kotsen"
+LANGUAGE.controls_bonemesh = "> PRIMARY: Klauwen\n> SECONDARY: Gooi bloed bom"
+LANGUAGE.controls_wraith = "> PRIMARY: Klauwen\n> SECONDARY: Schreeuw\n> ONZICHTBAARHUID GEBASEERD OP BEWEGING EN AFSTAND"
+LANGUAGE.controls_flesh_beast = "> PRIMARY: Klauwen\n> SECONDARY: Hoofd stoot"
+LANGUAGE.controls_chem_zombie = "> ALS JE STERFT: Gif Bom"
+LANGUAGE.controls_shade = "> PRIMARY: Op pakken\n> SECONDARY: Gooien"
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/languages/english.lua b/gamemodes/zombiesurvival/gamemode/languages/english.lua
new file mode 100644
index 0000000..17a8007
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/languages/english.lua
@@ -0,0 +1,360 @@
+--[[
+English is the standard language that you should base your ID's off of.
+If something isn't found in your language file then it will fall back to English.
+
+Valid languages (from gmod's menu): bg cs da de el en en-PT es-ES et fi fr ga-IE he hr hu it ja ko lt nl no pl pt-BR pt-PT ru sk sv-SE th tr uk vi zh-CN zh-TW
+You MUST use one of the above when using translate.AddLanguage
+]]
+
+--[[
+RULES FOR TRANSLATORS!!
+* Only translate formally. Do not translate with slang, improper grammar, spelling, etc.
+* Do not translate proper things. For example, do not translate Zombie Survival (the name of the game). Do translate "survive the zombies".
+ For names of weapons, you would translate only the "Handgun" part of 'Peashooter' Handgun (and the quotes if your language doesn't use ' as quotes)
+ For names of classes, you would translate Bloated Zombie to whatever the word for Bloated and Zombie are. But you wouldn't translate Pukepus or Bonemesh.
+* Comment out things that you have not yet translated in your language file.
+ It will then fall back to this file instead of potentially using out of date wording in yours.
+]]
+
+translate.AddLanguage("en", "English")
+
+-- Various gamemode stuff
+LANGUAGE.minute_points_added = "No damage received for a whole minute! Added %d points."
+LANGUAGE.infliction_reached_class_unlocked = "%d%% infliction has been reached! %s unlocked!"
+LANGUAGE.infliction_reached = "%d%% of humans have died!"
+LANGUAGE.x_unlocked = "%s unlocked!"
+LANGUAGE.disconnect_killed = "%s was disconnect killed by %s."
+LANGUAGE.nail_removed_by = "%s removed a nail belonging to %s."
+LANGUAGE.banned_for_life_warning = "You're banned for life so you can't purchase anything!"
+LANGUAGE.need_to_be_near_arsenal_crate = "You need to be near an Arsenal Crate to purchase items!"
+LANGUAGE.cant_purchase_right_now = "You can't purchase anything right now."
+LANGUAGE.dont_have_enough_points = "You don't have enough points."
+LANGUAGE.prepare_yourself = "Prepare yourself..."
+LANGUAGE.purchased_x_for_y_points = "Purchased %s for %d points!"
+LANGUAGE.give_time_before_suicide = "Give others time to spawn before suiciding."
+LANGUAGE.no_spare_ammo_to_give = "No spare ammo to give!"
+LANGUAGE.no_person_in_range = "No person in range!"
+LANGUAGE.that_life = "That life..."
+LANGUAGE.x_damage_to_barricades = "%d damage to barricades"
+LANGUAGE.x_damage_to_humans = "%d damage to humans"
+LANGUAGE.x_brains_eaten = "%d brains eaten"
+LANGUAGE.press_jump_to_free_roam = "Press JUMP to free roam"
+LANGUAGE.press_rmb_to_cycle_targets = "Press RMB to cycle targets"
+LANGUAGE.press_lmb_to_spawn_on_them = "Press LMB to spawn on them"
+LANGUAGE.press_lmb_to_spawn = "Press LMB to spawn"
+LANGUAGE.press_reload_to_spawn_at_normal_point = "Press RELOAD to spawn at a normal spawn point"
+LANGUAGE.press_walk_to_spawn_as_x = "Press WALK to spawn as a %s"
+LANGUAGE.observing_x = "Observing %s (%d)"
+LANGUAGE.waiting_for_next_wave = "Waiting for the next wave to begin..."
+LANGUAGE.impossible = "Impossible."
+LANGUAGE.trying_to_put_nails_in_glass = "Trying to put nails in glass is a silly thing to do."
+LANGUAGE.boss_class_select = "You will be %s the next time you're a boss zombie."
+LANGUAGE.person_has_weapon = "They already have that weapon."
+LANGUAGE.cant_do_that_in_classic_mode = "You can't do that in Classic Mode."
+LANGUAGE.cant_use_x_in_classic_mode = "You can't use %s in Classic Mode."
+LANGUAGE.cant_use_x_in_zombie_escape = "You can't use %s in Zombie Escape."
+LANGUAGE.no_class_switch_in_this_mode = "The current mode doesn't allow you to switch classes."
+LANGUAGE.press_sprint_to_get_up = "Press SPRINT to get up"
+LANGUAGE.zombie_escape = "Zombie Escape!"
+LANGUAGE.nothing_for_this_ammo = "You don't have anything that uses this type of ammo."
+LANGUAGE.you_decide_to_leave_some = "You decide to leave some for your team."
+LANGUAGE.you_cant_purchase_now = "You can't purchase items right now."
+LANGUAGE.no_ammo_here = "There's no ammo here right now."
+LANGUAGE.you_redeemed = "You have redeemed!"
+LANGUAGE.kill_the_last_human = "Kill the last human!"
+LANGUAGE.kick_the_last_human = "Kick the last human!"
+LANGUAGE.you_are_the_last_human = "YOU ARE THE LAST HUMAN!"
+LANGUAGE.x_zombies_out_to_get_you = "%d ZOMBIES ARE OUT TO GET YOU!"
+LANGUAGE.x_pants_out_to_get_you = "%d PANTS ARE OUT TO GET YOU!"
+LANGUAGE.you_have_died = "You have died."
+LANGUAGE.you_were_killed_by_x = "You were killed by %s"
+LANGUAGE.you_were_kicked_by_x = "You were kicked in the shins by %s"
+LANGUAGE.arsenal_upgraded = "Arsenal Upgraded"
+LANGUAGE.final_wave = "THE FINAL WAVE HAS BEGUN!"
+LANGUAGE.final_wave_sub = "ALL classes unlocked and the chance for redemption has ended!"
+LANGUAGE.wave_x_has_begun = "Wave %d has begun!"
+LANGUAGE.x_unlocked = "%s unlocked!"
+LANGUAGE.wave_x_is_over = "Wave %d is over!"
+LANGUAGE.wave_x_is_over_sub = "The Undead have stopped rising and the Points Shop is %d%% off."
+LANGUAGE.you_are_x = "You are %s!"
+LANGUAGE.x_has_risen_as_y = "%s has risen as %s!!"
+LANGUAGE.x_has_risen = "%s has risen!"
+LANGUAGE.cant_use_worth_anymore = "You can't use the Worth menu any more!"
+LANGUAGE.class_not_unlocked_will_be_unlocked_x = "That class is not unlocked yet. It will be unlocked at the start of wave %d."
+LANGUAGE.you_are_already_a_x = "You are already a %s."
+LANGUAGE.you_will_spawn_as_a_x = "You will spawn as a %s."
+LANGUAGE.crafting_successful = "Crafting successful!"
+LANGUAGE.x_crafted_y = "%s crafted %s."
+LANGUAGE.escape_from_the_zombies = "Escape from the zombies!"
+LANGUAGE.too_close_to_another_nail = "Too close to another nail."
+LANGUAGE.object_too_damaged_to_be_used = "That object is too damaged to be used anymore."
+LANGUAGE.thanks_for_being_a_fan_of_zs = "Thanks for being a fan of Zombie Survival!"
+LANGUAGE.cant_remove_nails_of_superior_player = "You can't remove the nails of a player doing so much better than you."
+LANGUAGE.x_turned_on_noclip = "%s turned on noclip."
+LANGUAGE.x_turned_off_noclip = "%s turned off noclip."
+LANGUAGE.unlocked_on_wave_x = "Unlocked on wave %d"
+LANGUAGE.brains_eaten_x = "Brains eaten: %s"
+LANGUAGE.points_x = "Points: %s"
+LANGUAGE.next_wave_in_x = "Next wave in %s"
+LANGUAGE.wave_ends_in_x = "Wave ends in %s"
+LANGUAGE.wave_x_of_y = "Wave %d of %d"
+LANGUAGE.zombie_invasion_in_x = "Zombie invasion in %s"
+LANGUAGE.intermission = "Intermission"
+LANGUAGE.press_f2_for_the_points_shop = "Press F2 for the Points Shop!"
+LANGUAGE.breath = "Breath"
+LANGUAGE.zombie_volunteers = "Zombie Volunteers"
+LANGUAGE.x_discount_for_buying_between_waves = "%d%% discount for buying between waves!"
+LANGUAGE.number_of_initial_zombies_this_game = "Number of initial zombies this game (%d%%): %d"
+LANGUAGE.humans_closest_to_spawns_are_zombies = "The humans closest to the zombie spawns will start as zombies."
+LANGUAGE.waiting_for_players = "Waiting for players..."
+LANGUAGE.requires_x_people = "Requires %d people"
+LANGUAGE.packing_others_object = "Packing other person's object"
+LANGUAGE.packing = "Packing"
+LANGUAGE.ze_humans_are_frozen_until_x = "Humans are frozen until %d seconds before the round starts."
+LANGUAGE.loading = "Loading..."
+LANGUAGE.next_round_in_x = "Next round in: %s"
+LANGUAGE.warning = "Warning!"
+LANGUAGE.ok_and_no_reminder = "OK and don't pop this message up anymore"
+LANGUAGE.classic_mode_warning = "This server is running Zombie Survival in 'Classic Mode'\nClassic Mode is a setting which greatly alters gameplay. Things that are changed:\n* No selection of zombie classes. Everyone uses the Classic Zombie class\n* No barricading tools such as nailing or turrets\n* More but faster waves\n\nThis is NOT original Zombie Survival!\n\n-- Servers which run classic mode will display CLASSIC MODE in the bottom left of the screen --"
+LANGUAGE.classic_mode = "CLASSIC MODE"
+LANGUAGE.resist_x = "Resist: %d%%"
+LANGUAGE.right_click_to_hammer_nail = "Right click to hammer in a nail."
+LANGUAGE.nails_x = "Nails: %d"
+LANGUAGE.resupply_box = "Resupply Box"
+LANGUAGE.purchase_now = "Purchase now!"
+LANGUAGE.integrity_x = "Integrity: %d%%"
+LANGUAGE.empty = "EMPTY"
+LANGUAGE.manual_control = "MANUAL CONTROL"
+LANGUAGE.arsenal_crate = "Arsenal Crate"
+LANGUAGE.not_enough_room_for_a_nest = "Not enough room here for a nest!"
+LANGUAGE.too_close_to_another_nest = "Too close to another nest!"
+LANGUAGE.nest_created = "Nest created! Finish building to enable spawning here."
+LANGUAGE.nest_built_by_x = "A Flesh Creeper nest has been built by %s and is now a spawn point."
+LANGUAGE.nest_destroyed = "A Flesh Creeper nest has been destroyed."
+LANGUAGE.wait_x_seconds_before_making_a_new_nest = "You must wait %d more seconds before creating a new nest."
+LANGUAGE.too_close_to_a_human = "Too close to a human!"
+LANGUAGE.too_close_to_a_spawn = "Too close to a zombie spawn!"
+--LANGUAGE.nest_already_being_built = "This nest is already being built by someone else!"
+LANGUAGE.x_has_built_this_nest_and_is_still_around = "%s has built this nest and is still around, so you can't demolish it."
+LANGUAGE.no_other_nests = "You can't destroy a nest if only one remains."
+
+-- Sigils point objectives
+LANGUAGE.sigil_destroyed = "The Undead have destroyed a Sigil!"
+LANGUAGE.sigil_destroyed_only_one_remain_h = "Only one remains! If it falls then there is no hope of escape!"
+LANGUAGE.sigil_destroyed_only_one_remain_z = "Only one remains!"
+LANGUAGE.sigil_destroyed_x_remain = "%d Sigils remaining."
+LANGUAGE.last_sigil_destroyed_all_is_lost = "The Undead have destroyed the last Sigil."
+LANGUAGE.last_sigil_destroyed_all_is_lost2 = "There is no hope of escape."
+LANGUAGE.prop_obj_exit_h = "Escape!"
+LANGUAGE.prop_obj_exit_z = "Stop them!"
+
+-- Message beacon messages
+LANGUAGE.message_beacon_1 = "Meet up here"
+LANGUAGE.message_beacon_2 = "Need defense here"
+LANGUAGE.message_beacon_3 = "Need turrets here"
+LANGUAGE.message_beacon_4 = "Need arsenal crates here"
+LANGUAGE.message_beacon_5 = "Need medics here"
+LANGUAGE.message_beacon_6 = "Ammunition box here"
+LANGUAGE.message_beacon_7 = "Arsenal crate here"
+LANGUAGE.message_beacon_8 = "Need force fields here"
+LANGUAGE.message_beacon_9 = "Need explosives here"
+LANGUAGE.message_beacon_10 = "Zombies come from here"
+LANGUAGE.message_beacon_11 = "Do not enter!!"
+LANGUAGE.message_beacon_12 = "Don't go out"
+LANGUAGE.message_beacon_13 = "Defend this area"
+LANGUAGE.message_beacon_14 = "Defend this spot"
+LANGUAGE.message_beacon_15 = "Medics here"
+LANGUAGE.message_beacon_16 = "Buy from my crate"
+LANGUAGE.message_beacon_17 = "Barricade here"
+LANGUAGE.message_beacon_18 = "Don't barricade here"
+LANGUAGE.message_beacon_19 = "Don't let zombies in here"
+LANGUAGE.message_beacon_20 = "This will break"
+LANGUAGE.message_beacon_21 = "This place is dangerous!"
+LANGUAGE.message_beacon_22 = "Beware of poison!"
+LANGUAGE.message_beacon_23 = "Zombies are breaking through here!"
+LANGUAGE.message_beacon_24 = "Zombies are coming. Build a barricade!"
+LANGUAGE.message_beacon_25 = "Plan B here"
+
+-- Class names
+LANGUAGE.class_zombie = "Zombie"
+LANGUAGE.class_poison_zombie = "Poison Zombie"
+LANGUAGE.class_fast_zombie = "Fast Zombie"
+LANGUAGE.class_bloated_zombie = "Bloated Zombie"
+LANGUAGE.class_classic_zombie = "Classic Zombie"
+LANGUAGE.class_super_zombie = "Super Zombie"
+LANGUAGE.class_fresh_dead = "Fresh Dead"
+LANGUAGE.class_ghoul = "Ghoul"
+LANGUAGE.class_headcrab = "Headcrab"
+LANGUAGE.class_fast_headcrab = "Fast Headcrab"
+LANGUAGE.class_poison_headcrab = "Poison Headcrab"
+LANGUAGE.class_the_tickle_monster = "The Tickle Monster"
+LANGUAGE.class_nightmare = "Nightmare"
+LANGUAGE.class_pukepus = "Pukepus"
+LANGUAGE.class_bonemesh = "Bonemesh"
+LANGUAGE.class_crow = "Crow"
+LANGUAGE.class_wilowisp = "Wil O' Wisp"
+LANGUAGE.class_zombie_torso = "Zombie Torso"
+LANGUAGE.class_zombie_legs = "Zombie Legs"
+LANGUAGE.class_wraith = "Wraith"
+LANGUAGE.class_fast_zombie_legs = "Fast Zombie Legs"
+LANGUAGE.class_chem_zombie = "Chem Zombie"
+LANGUAGE.class_shade = "Shade"
+LANGUAGE.class_butcher = "The Butcher"
+LANGUAGE.class_flesh_creeper = "Flesh Creeper"
+LANGUAGE.class_gore_child = "Gore Child"
+LANGUAGE.class_giga_gore_child = "Giga Gore Child"
+
+-- Class descriptions
+LANGUAGE.description_zombie = "The basic zombie is very durable and has powerful claws.\nIt's hard to keep down, especially if not shot in the head."
+LANGUAGE.description_poison_zombie = "This mutated zombie is not only extremely durable but has abnormal strength.\nIts body is extremely toxic and will even tear out and toss its own flesh at things too far away to hit."
+LANGUAGE.description_fast_zombie = "This boney cadaver is much faster than other zombies.\nThey aren't much of a threat by themselves but can reach nearly any area by climbing with their razor sharp claws\nThey also have no problem hunting down weak or hurt humans."
+LANGUAGE.description_bloated_zombie = "Their body is comprised of volatile, toxic chemicals.\nAlthough they move slower, they can take slightly more of a beating."
+LANGUAGE.description_ghoul = "This zombie has highly toxic flesh.\nIt's slightly weaker than other zombies but makes up for it with its poison attacks.\nIts claws can debilitate a human for a short time and it will eject poison through its wounds if hit with enough damage."
+LANGUAGE.description_headcrab = "Headcrabs are what caused the initial infection.\nNo one knows where they truely came from.\nTheir method of attack is lunging with the sharp beaks on their belly."
+LANGUAGE.description_fast_headcrab = "The male headcrab is considerably faster but less beefy than the female.\nEither way, it's equally as annoying and deadly in groups."
+LANGUAGE.description_poison_headcrab = "This Headcrab is full of deadly nuerotoxins.\nOne bite is usually enough to kill an adult human.\nIt also has the ability to spit a less potent version of its poisons.\nThe spit is just as deadly if its victim is hit in the face."
+LANGUAGE.description_the_tickle_monster = "Said to be the monster that hides in your closet at night to drag you from your bed.\nThe Tickle Monster's almost elastic arms make it extremely hard to outrun and they also make it an ideal barricade destroyer."
+LANGUAGE.description_nightmare = "An extremely rare mutation gives the Nightmare its abnormal abilities.\nStronger than the every day zombie in almost every way, the Nightmare is a force to be reckoned with.\nOne swipe of its claws is enough to put down almost any person."
+LANGUAGE.description_pukepus = "The rotting body of the Puke Pus is comprised entirely of organs used for the generation of poison.\nIts capable of vomiting gallons of poison puke at a time making it extremely dangerous."
+LANGUAGE.description_bonemesh = "Disfigured and mangled, the Bonemesh is capable of tossing blood bombs.\nEach bomb is comprised of bones and flesh that damages humans while giving precious food to other zombies."
+LANGUAGE.description_crow = "Carrion Crows are more of a pest than they were before the infection.\nThey feed on infected flesh and become 'carriers' for the undead.\nWhy would you ever make this class not hidden?\nWhat is wrong with you?"
+LANGUAGE.description_wilowisp = "Sometimes referred to as spirits of the dead."
+LANGUAGE.description_zombie_torso = "You shouldn't even be seeing this."
+LANGUAGE.description_zombie_legs = "You shouldn't even be seeing this."
+LANGUAGE.description_wraith = "A zombie or an apparition?\nNot much is known about it besides the fact that it uses its\nunique stealth ability and sharp claws to cut things to ribbons."
+LANGUAGE.description_fast_zombie_legs = "You shouldn't even be seeing this."
+LANGUAGE.description_chem_zombie = "The Chem Zombie body is comprised of volatile, toxic chemicals.\nIt has no other means of attack besides being killed in hopes of blowing up next to any nearby humans."
+LANGUAGE.description_shade = "By creating a strong magnetic field around itself, all bullets and melee attacks are rendered useless against it.\nFor some reason the Shade is vulnerable to bright lights."
+LANGUAGE.description_butcher = "A crazed, undead butcher. It isn't very tough but anyone unlucky enough to be near it will most likely be torn to shreds."
+LANGUAGE.description_flesh_creeper = "Flesh Creepers possess the ability to create nests.\nFrom these nests, other zombified creatures emerge.\nThe way this works is unknown but it is imperitive to destroy any nests or creepers."
+LANGUAGE.description_gore_child = "Once zombified, an unborn child becomes infected as well.\nPossessing no special abilities, their strength comes from their numbers."
+LANGUAGE.description_giga_gore_child = "The result of a Gore Child which has been left unchecked for too long.\nA horror to behold, their massive body is the result of zombified stem cells.\nThey also become a host for Gore Children which can always be found in tow with it."
+
+-- Class control schemes
+LANGUAGE.controls_zombie = "> PRIMARY: Claws\n> SECONDARY: Scream\n> RELOAD: Moan\n> SPRINT: Feign death\n> ON FATAL HIT IN LEGS: Revive / Transform"
+LANGUAGE.controls_poison_zombie = "> PRIMARY: Claws\n> SECONDARY: Flesh toss\n> RELOAD: Scream"
+LANGUAGE.controls_fast_zombie = "> PRIMARY: Claws\n> SECONDARY: Lunge / Climb (next to wall)\n> RELOAD: Scream"
+LANGUAGE.controls_bloated_zombie = "> PRIMARY: Claws\n> SECONDARY: Moan\n> SPRINT: Feign death\n> ON DEATH: Poison Gibs"
+LANGUAGE.controls_ghoul = "> PRIMARY: Poison claws\n> SECONDARY: Flesh toss\n> SPRINT: Feign death\n> RELOAD: Scream\n> ON HIT HUMAN: Slow\n> ON HIT BY HUMAN: Poison ejection"
+LANGUAGE.controls_headcrab = "> PRIMARY: Lunge attack\n> RELOAD: Burrow"
+LANGUAGE.controls_fast_headcrab = "> PRIMARY: Lunge attack"
+LANGUAGE.controls_poison_headcrab = "> PRIMARY: Lunge attack\n> SECONDARY: Spit poison\n> ON HIT HUMAN: Deadly poison\n> ON HIT POISON IN EYES: Blind\n> RELOAD: Scream"
+LANGUAGE.controls_the_tickle_monster = "> PRIMARY: Elastic claws\n> SECONDARY: Moan"
+LANGUAGE.controls_nightmare = "> PRIMARY: Death touch\n> SECONDARY: Moan"
+LANGUAGE.controls_pukepus = "> PRIMARY: Puke"
+LANGUAGE.controls_bonemesh = "> PRIMARY: Claws\n> SECONDARY: Toss blood bomb"
+LANGUAGE.controls_wraith = "> PRIMARY: Claws\n> SECONDARY: Scream\n> INVISIBILITY BASED ON MOVEMENT AND VIEW DISTANCE"
+LANGUAGE.controls_chem_zombie = "> ON DEATH: Poison Bomb"
+LANGUAGE.controls_shade = "> PRIMARY: Lift\n> SECONDARY: Throw"
+LANGUAGE.controls_butcher = "> PRIMARY: Chop"
+LANGUAGE.controls_flesh_creeper = "> PRIMARY: Head Smash\n> SECONDARY: Nest"
+LANGUAGE.controls_gore_child = "> PRIMARY: Claws"
+LANGUAGE.controls_giga_gore_child = "> PRIMARY: Smash\n> SECONDARY: Throw Gore Child"
+
+-- The help file... Quite big! I wouldn't blame you if you didn't translate this part.
+LANGUAGE.help_cat_introduction = "Introduction"
+LANGUAGE.help_cat_survival = "Survival"
+LANGUAGE.help_cat_barricading = "Barricading"
+LANGUAGE.help_cat_upgrades = "Upgrades"
+LANGUAGE.help_cat_being_a_zombie = "Being a Zombie"
+LANGUAGE.help_cont_introduction = [[ Welcome to Zombie Survival, the (zombie) survival simulator. ZS allows you to fight zombie attacks, create barricades, and even be part of the undead horde.
+
+There are two teams: the survivors and the zombies. The humans win if they survive every wave. Some levels have special objectives to be completed, which may be optional or required to win.
+If a human is killed then they'll come back as a zombie, which makes it even more difficult for the remaining humans.
+
+The goal for the zombies is to kill all of the humans, making them all zombies and causing everyone to lose the round.
+Alternatively, a zombie can kill four humans to be redeemed. This allows them a second chance at survival and victory.
+Remember, the only way to win a round is to be a human when the round ends. Zombies can't technically win the game; zombies can only make everyone else lose!
+
+A certain amount of people are chosen (or volunteer) for being the starting zombies. This amount is displayed at the bottom of your screen before the round starts.
+
+Use the buttons up top to get help on more specific things.
+
+Tips for this section:
+
If you leave the game as a human then you'll rejoin as a zombie.
+After a certain amount of time has gone by, even new players will spawn as zombies.
+Use TEAM CHAT when needed. The default key is U and allows you to speak to only your team.
+
+]]
+LANGUAGE.help_cont_survival = [[Tips for this section:
+
Holding the ZOOM key (default: Z) allows you to move freely through barricades while walking extremely slow.
+You can only buy more items such as weapons and ammo during wave breaks but you can also loot ammunition, weapons, and tools from fallen comrades.
+If a human is directly killed by a zombie then they will rise again wherever they stand. Make sure you end their misery before they give you any.
+You're only given a certain amount of Worth to play with so think carefully what you should get!
+You can create, save, load, delete, and mark as default carts by pressing F2. This saves a ton of time which could be better spent setting up barricades or creating game plans.
+A spot that feels safe one moment may be a death trap with more or different types of zombies roaming around. Always allow extra space and a "Plan B" if things get ugly.
+You're useless to your team if you're not doing anything to help. You're even more useless to yourself since you're not getting any points or bigger weapons!
+By holding your SPRINT key for about ten seconds while looking at deployed objects that you own, you can pack them up for later use.
+Turrets without owners (a blue light) can be claimed by pressing USE on them. Ownerless turrets will not scan for targets!
+Props that aren't nailed to something don't make very good barricades unless they're really heavy.
+With enough punishment, doors can be thrown off their hinges.
+Most props will become red with more and more damage.
+Zombies can spawn on top of each other if no humans are around to witness it.
+Most melee weapons have a longer reach than zombie claws. Use this to your advantage if you insist on defending with a melee weapon.
+Players on the same team do not damage or collide with each other and can freely shoot and swing through each other.
+Make sure you use a barricade to your advantage and stay behind it a good distance away from the zombies. Guns have an infinite range, zombie claws do not.
+Poison damage will heal over time but enough of it can still kill you.
+Your team members aren't always right, don't be a sheep! Zombies like to kill sheep.
+Zombies can see your health, even through walls. Make sure to fall back when hurt as zombies will most likely try to pick you off.
+Don't hide, zombies can sense you through walls and in complete darkness.
+The Horde Meter at the bottom of the screen indicates how much of a damage and knockback resistance you have. Huddle up with other zombies for a big resistance when taking down strongholds!
+If you don't have enough zombies to take down a barricade, try hunting for new "team mates" elsewhere.
+Don't shoot zombies in the green gas! It quickly heals them and you're only wasting ammunition!
+Zombies are resistant to damage in the chest and even more so in the arms and legs. Make sure you're aiming for the head as some zombies have the ability to get up again if you don't!
+Although zombies take less damage in the legs, shooting them there will slow them down for a short time, enough to allow you or a team member to escape.
+
+]]
+LANGUAGE.help_cont_barricading = [[Barricading is an extremely important part of survival. It may seem like the undead aren't a threat early on but eventually they'll be powerful enough to kill your entire team in a few seconds.
+
+The only thing keeping the zombies out is a well-built and well-maintained barricade.
+
+There are a couple of tools that give you the ability to set this up. The one most useful tool is the hammer and nails. This allows you to nail down props which then must have the nails destroyed in order for the zombies to get to you.
+Position the prop you want to nail by pressing USE on it to pick it up. You can hold SPRINT while holding it to lock it in place. Then take your hammer and right click where you want the nail to go. It's a good idea to nail the prop to a sturdy object such as a wall instead of other props.
+Remember, when a prop is nailed it will forward the damage it takes to the nails themselves. You can repair nails by hitting them with the hammer but eventually they'll become too damaged to repair anymore. You can hold SHIFT with the hammer out to get a view of every single nail deployed on your screen as well as the owner.
+If you think a nail is in a bad place or you'd like to reposition a prop, you can remove nails by pointing at it and pressing RELOAD. Be warned, if you take a nail that doesn't belong to you then you will be given a point penalty.
+One more thing to remember: nails take less damage when they're nailed to bigger props. The bigger the size of the prop, the less damage its nails take and the other way around.
+
+One other tool is the 'Aegis' Barricade Kit. This quick-deploying tool allows you to place boards on any surface or deploy them between two walls. It doesn't even need props. To use it, you need to position a board in a spot that is legal. The ghost will turn from red to green to let you know.
+Deploy a board by pressing PRIMARY ATTACK. Rotate the board by using SECONDARY ATTACK and RELOAD. It uses boards for ammunition so boards you have from the Board Pack work as extra ammunition! You can pack up boards you've deployed by pressing SPRINT while pointing at it.
+
+Another tool worth noting is the Turret. This tosses bullets at any zombie that gets in the way of its laser. Its only downside is that it requires ammunition. You can refill ammunition by pressing USE on it. This will give you bonus points for helping the team.
+To deploy the turret, position it in a way so that the ghost is green. It must be on a solid surface (no props!). Rotate the turret with SECONDARY ATTACK and RELOAD. If you mess up, you can always pack the turret back up by pressing SPRINT while pointing at it. Remember, the turret will only fire at zombies that cross its tracking beam.
+
+Tips for this section:
+
+You get a 25% point bonus for killing zombies that are attacking a barricade!
+Use bigger props for barricades. The nails take less damage and the prop has room for more nails. In addition to that, it even acts as cover from projectiles.
+ ]]
+LANGUAGE.help_cont_upgrades = [[Points are obtained through killing zombies, healing team mates, and building defenses.
+You can then exchange points in the Points Shop which is available during wave breaks.
+Try to make your purchases at Arsenal Crates for a hefty discount!
+
+Tips for this section:
+
+Try planning ahead. Buy extra pistol ammunition in the Worth menu so you have plenty to spare once you get your first upgrade.
+You still get points for assists. The greater half of the points goes to the killer and the lesser half goes to the one who assisted in the kill.
+Worth and Points are separate. Make sure you spend all of your Worth!
+Arsenal Crates are extremely valuable and prime targets for zombie attacks.
+ ]]
+LANGUAGE.help_cont_being_a_zombie = [[Tips for this section:
+
+You have an unlimited amount of lives, the humans only have one each. Don't be afraid to attack, attack, attack!
+The regular Zombie class has the ability of durability. The only way to kill you for sure is to get shot in the head or be killed by a melee weapon. You don't need your legs.
+Zombies can spawn on top of each other if no humans are around to see it. Check the eyes of the skull on the bottom of your screen. If they're green then you are a valid spawn point!
+With enough practice, you can use props to slam them in to humans from a distance.
+Destroy deployables such as turrets and especially Arsenal Crates to cripple the humans.
+With enough punishment, doors can be thrown off their hinges.
+Most props will become red with more and more damage.
+The Wraith is completely invisible while standing still or at a distance.
+The Fast Zombie's lunge attack damage scales by how long you're in the air. The more air time you get, the larger the damage. Use your claw attack when in close range!
+In addition to being extremely tough, the Poison Zombie can rip out chunks of its own poison flesh and throw them at humans by pressing SECONDARY ATTACK.
+Most zombie claws have two chances to hit their target. If you "hit" your target when you click your mouse button then you're guaranteed a hit as long as they remain in range.
+The Poison Headcrab's spit projectile can confuse humans if it hits them in the head.
+Go for the humans with low health! Other zombies are also attracted to them so they should be the easiest targets.
+The Horde Meter at the bottom of the screen indicates how much of a damage and knockback resistance you have. Huddle up with other zombies for a big resistance when taking down strongholds!
+If you don't have enough zombies to take down a barricade, try hunting for new "team mates" elsewhere.
+If an area is too dark, try pressing your FLASHLIGHT button to toggle night vision.
+
+]]
+
+-- Place any custom stuff below here...
diff --git a/gamemodes/zombiesurvival/gamemode/languages/french.lua b/gamemodes/zombiesurvival/gamemode/languages/french.lua
new file mode 100644
index 0000000..bf9012a
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/languages/french.lua
@@ -0,0 +1,239 @@
+-- Translated by Shen (http://www.noxiousnet.com/forums/index.php?action=profile;u=3311)
+
+translate.AddLanguage("fr", "French")
+
+-- Various gamemode stuff
+LANGUAGE.minute_points_added = "Pas de dégâts reçus pendant une minute! %d points reçus."
+LANGUAGE.infliction_reached_class_unlocked = "%d%% de mortalité a été atteint! %s débloqué!"
+LANGUAGE.infliction_reached = "%d%% des humains sont morts!"
+LANGUAGE.x_unlocked = "%s débloqué!"
+LANGUAGE.disconnect_killed = "%s a été tué par deconnexion par %s."
+LANGUAGE.nail_removed_by = "%s a enlevé un clou appartenant à %s."
+LANGUAGE.banned_for_life_warning = "Vous ne pouvez rien acheter car vous êtes banni de tout achat!"
+LANGUAGE.need_to_be_near_arsenal_crate = "Vous devez être à proximité d'une Caisse d'armes pour pouvoir acheter!"
+LANGUAGE.cant_purchase_right_now = "Vous ne pouvez rien acheter pour l'instant."
+LANGUAGE.dont_have_enough_points = "Vous n'avez pas assez de points."
+LANGUAGE.prepare_yourself = "Préparez-vous.."
+LANGUAGE.purchased_x_for_y_points = "Vous avez acheté %s pour %d points!"
+LANGUAGE.give_time_before_suicide = "Attendez un instant avant de vous suicider."
+LANGUAGE.no_spare_ammo_to_give = "Pas davantage de munitions à donner!"
+LANGUAGE.no_person_in_range = "Pas de joueur à portée!"
+LANGUAGE.that_life = "Durant cette vie.."
+LANGUAGE.x_damage_to_barricades = "%d dégâts aux barricades"
+LANGUAGE.x_damage_to_humans = "%d dégâts aux humains"
+LANGUAGE.x_brains_eaten = "%d cerveaux dévorés"
+LANGUAGE.press_rmb_to_cycle_targets = "Clic-droit pour changer de cible"
+LANGUAGE.press_lmb_to_spawn_on_them = "Clic-gauche pour réapparaître sur cette cible"
+LANGUAGE.press_lmb_to_spawn = "Clic-gauche pour réapparaître"
+LANGUAGE.observing_x = "Cible observée: %s (%d)"
+LANGUAGE.waiting_for_next_wave = "En attente du début de la prochaine vague.."
+LANGUAGE.impossible = "Impossible."
+LANGUAGE.trying_to_put_nails_in_glass = "Il est impossible de clouer du verre."
+LANGUAGE.boss_class_select = "Vous serez %s la prochaine fois que vous serez un boss."
+LANGUAGE.person_has_weapon = "Ce joueur a déjà cette arme."
+LANGUAGE.cant_do_that_in_classic_mode = "Vous ne pouvez pas faire ça en Mode Classique."
+LANGUAGE.cant_use_x_in_classic_mode = "Vous ne pouvez pas utiliser %s en Mode Classique."
+LANGUAGE.cant_use_x_in_zombie_escape = "Vous ne pouvez pas utiliser %s en Zombie Escape."
+LANGUAGE.no_class_switch_in_this_mode = "Le Mode actuel ne vous permet pas de changer de classe."
+LANGUAGE.press_sprint_to_get_up = "Appuyez sur SPRINT pour vous relever"
+LANGUAGE.zombie_escape = "Zombie Escape!"
+LANGUAGE.nothing_for_this_ammo = "Vous n'avez aucun objet utilisant ce type de munitions."
+LANGUAGE.you_decide_to_leave_some = "Vous décidez d'en laisser un peu pour votre équipe."
+LANGUAGE.you_cant_purchase_now = "Vous ne pouvez pas faire d'achat pour l'instant."
+LANGUAGE.no_ammo_here = "Il n'y a pas de munitions là -dedans."
+LANGUAGE.you_redeemed = "Vous vous êtes racheté!"
+LANGUAGE.kill_the_last_human = "Tuez le Dernier Humain!"
+LANGUAGE.kick_the_last_human = "Bottez le Dernier Humain!"
+LANGUAGE.you_are_the_last_human = "VOUS ÊTES LE DERNIER HUMAIN!"
+LANGUAGE.x_zombies_out_to_get_you = "%d ZOMBIES SONT À VOS TROUSSES!"
+LANGUAGE.x_pants_out_to_get_you = "%d PANTALONS SONT À VOS TROUSSES!"
+LANGUAGE.you_have_died = "Vous êtes mort."
+LANGUAGE.you_were_killed_by_x = "Vous avez été tué par %s"
+LANGUAGE.you_were_kicked_by_x = "Vous vous êtes fait botter les fesses par %s"
+LANGUAGE.arsenal_upgraded = "Arsenal amélioré"
+LANGUAGE.final_wave = "LA VAGUE FINALE A DÉBUTÉ!"
+LANGUAGE.final_wave_sub = "TOUTES les classes ont été débloquées et vous ne pouvez plus vous racheter!"
+LANGUAGE.wave_x_has_begun = "La vague %d a débuté!"
+LANGUAGE.x_unlocked = "%s débloqué!"
+LANGUAGE.wave_x_is_over = "La vague %d est passée!"
+LANGUAGE.wave_x_is_over_sub = "Le nombre de zombies est en baisse ainsi qu'une réduction des prix de %d%%."
+LANGUAGE.you_are_x = "Vous êtes %s!"
+LANGUAGE.x_has_risen_as_y = "%s s'est réveillé en tant que %s!!"
+LANGUAGE.x_has_risen = "%s s'est révéillé!"
+LANGUAGE.cant_use_worth_anymore = "Vous ne pouvez plus utiliser le menu de Valeur!"
+LANGUAGE.class_not_unlocked_will_be_unlocked_x = "Cette classe n'est pas encore débloquée. Elle le sera au début de la vague %d."
+LANGUAGE.you_are_already_a_x = "Vous êtes déjà un %s."
+LANGUAGE.you_will_spawn_as_a_x = "Vous réapparaîtrez en tant qu'un %s."
+LANGUAGE.crafting_successful = "Artisanat réussi!"
+LANGUAGE.x_crafted_y = "%s a fabriqué %s."
+LANGUAGE.escape_from_the_zombies = "Échappez les zombies!"
+LANGUAGE.too_close_to_another_nail = "Trop près d'un autre clou."
+LANGUAGE.object_too_damaged_to_be_used = "Cet objet est bien trop endommagé pour toute utilisation."
+LANGUAGE.thanks_for_being_a_fan_of_zs = "Merci d'être un fan de Zombie Survival!"
+LANGUAGE.cant_remove_nails_of_superior_player = "Vous ne pouvez pas enlever le clou d'un joueur jouant mieux que vous."
+LANGUAGE.x_turned_on_noclip = "%s a activé le passe-murailles."
+LANGUAGE.x_turned_off_noclip = "%s a désactivé le passe-murailles."
+LANGUAGE.unlocked_on_wave_x = "Débloqué à la vague %d"
+LANGUAGE.brains_eaten_x = "Cerveaux dévorés: %s"
+LANGUAGE.points_x = "Points: %s"
+LANGUAGE.next_wave_in_x = "Début de la prochaine vague dans %s"
+LANGUAGE.wave_ends_in_x = "Fin de la vague dans %s"
+LANGUAGE.wave_x_of_y = "Vague %d sur %d"
+LANGUAGE.zombie_invasion_in_x = "Début de l'invasion dans %s"
+LANGUAGE.intermission = "Intermission"
+LANGUAGE.press_f2_for_the_points_shop = "Appuyez sur F2 pour ouvrir la Boutique!"
+LANGUAGE.breath = "Respiration"
+LANGUAGE.zombie_volunteers = "Volontaires pour être zombie"
+LANGUAGE.x_discount_for_buying_between_waves = "%d%% de réduction pour un achat entre deux vagues!"
+LANGUAGE.number_of_initial_zombies_this_game = "Nombre de zombies initiaux pour cette partie (%d%%): %d"
+LANGUAGE.humans_closest_to_spawns_are_zombies = "Les humains les plus proches aux points de réapparition des zombies deviendront les zombies initiaux."
+LANGUAGE.waiting_for_players = "En attente de joueurs.."
+LANGUAGE.requires_x_people = "Requiert %d joueurs"
+LANGUAGE.packing_others_object = "Emballage d'un objet appartenant à un autre joueur"
+LANGUAGE.packing = "Emballage"
+LANGUAGE.ze_humans_are_frozen_until_x = "Les Humains sont gelés pendant %d secondes avant le début de la partie."
+LANGUAGE.loading = "Chargement.."
+LANGUAGE.next_round_in_x = "Prochaine partie dans: %s"
+LANGUAGE.warning = "Attention!"
+LANGUAGE.ok_and_no_reminder = "OK et ne plus afficher ce message"
+LANGUAGE.classic_mode_warning = "Ce serveur héberge Zombie Survival en 'Mode Classique'\nLe Mode Classique est une option qui change entièrement la façon de jouer. Les modifications apportées sont:\n* Pas de classes de zombie. Tout le monde utilise le zombie standard.\n* Pas d'outils d'aide à la barricade tels que les tourelles ou les clous\n* Plus de vagues à moins longue durée\n\nCe n'est pas le Zombie Survival original!\n\n-- Les serveurs ayant le Mode Classique activé afficheront MODE CLASSIQUE en bas à gauche de l'écran --"
+LANGUAGE.classic_mode = "MODE CLASSIQUE"
+LANGUAGE.resist_x = "Résistance: %d%%"
+LANGUAGE.right_click_to_hammer_nail = "Clic-droit pour clouer."
+LANGUAGE.nails_x = "Clous: %d"
+LANGUAGE.resupply_box = "Caisse de réapprovisionnement"
+LANGUAGE.purchase_now = "Faites des achats!"
+LANGUAGE.integrity_x = "Intégrité: %d%%"
+LANGUAGE.empty = "VIDE"
+LANGUAGE.manual_control = "CONTRÔLE MANUEL"
+LANGUAGE.arsenal_crate = "Caisse d'armes"
+
+-- Exit point objectives
+LANGUAGE.exit_destroyed = "Les zombies ont détruit une sortie!"
+LANGUAGE.exit_destroyed_only_one_remain_h = "Il n'en reste plus qu'une! Si elle est détruite, il n'y a plus aucune chance de survie!"
+LANGUAGE.exit_destroyed_only_one_remain_z = "Il n'en reste plus qu'une!"
+LANGUAGE.exit_destroyed_x_remain = "%d sorties restantes."
+LANGUAGE.last_exit_destroyed_all_is_lost = "Les zombies ont détruit la dernière sortie."
+LANGUAGE.last_exit_destroyed_all_is_lost2 = "Il n'y a plus aucune chance de survie."
+
+-- Message beacon messages
+LANGUAGE.message_beacon_1 = "Regroupez-vous ici"
+LANGUAGE.message_beacon_2 = "Besoin de défense ici"
+LANGUAGE.message_beacon_3 = "Besoin de tourelles ici"
+LANGUAGE.message_beacon_4 = "Besoin de caisses d'armes ici"
+LANGUAGE.message_beacon_5 = "Besoin de soins ici"
+LANGUAGE.message_beacon_6 = "Caisse de réapprovisionnement ici"
+LANGUAGE.message_beacon_7 = "Caisse d'armes ici"
+LANGUAGE.message_beacon_8 = "Besoin d'un champ de force ici"
+LANGUAGE.message_beacon_9 = "Besoin d'explosifs ici"
+LANGUAGE.message_beacon_10 = "Les zombies entrent par là "
+LANGUAGE.message_beacon_11 = "N'entrez pas!!"
+LANGUAGE.message_beacon_12 = "Ne sortez pas"
+LANGUAGE.message_beacon_13 = "Défendez cet endroit"
+LANGUAGE.message_beacon_14 = "Défendez ce coin"
+LANGUAGE.message_beacon_15 = "Soins ici"
+LANGUAGE.message_beacon_16 = "Achetez de ma caisse"
+LANGUAGE.message_beacon_17 = "Barricadez ici"
+LANGUAGE.message_beacon_18 = "Ne barricadez pas ici"
+LANGUAGE.message_beacon_19 = "Ne laissez pas entrer les zombies entrer ici"
+LANGUAGE.message_beacon_20 = "Cela va tomber"
+LANGUAGE.message_beacon_21 = "Cet endroit est dangereux!"
+LANGUAGE.message_beacon_22 = "Attention au poison!"
+LANGUAGE.message_beacon_23 = "Les zombies arrivent!"
+LANGUAGE.message_beacon_24 = "Les zombies arivent bientôt. Commencez à barricader!"
+LANGUAGE.message_beacon_25 = "Plan B ici"
+
+-- Class names
+LANGUAGE.class_zombie = "Zombie"
+LANGUAGE.class_poison_zombie = "Zombie empoisonné"
+LANGUAGE.class_fast_zombie = "Zombie agile"
+LANGUAGE.class_bloated_zombie = "Zombie balloné"
+LANGUAGE.class_classic_zombie = "Zombie classique"
+LANGUAGE.class_super_zombie = "Super Zombie"
+LANGUAGE.class_fresh_dead = "Nouveau mort"
+LANGUAGE.class_ghoul = "Goule"
+LANGUAGE.class_headcrab = "Crabe de tête"
+LANGUAGE.class_fast_headcrab = "Crabe de tête agile"
+LANGUAGE.class_poison_headcrab = "Crabe de tête empoisonné"
+LANGUAGE.class_the_tickle_monster = "The Tickle Monster"
+LANGUAGE.class_nightmare = "Nightmare"
+LANGUAGE.class_pukepus = "Pukepus"
+LANGUAGE.class_bonemesh = "Bonemesh"
+LANGUAGE.class_crow = "Crow"
+LANGUAGE.class_wilowisp = "Wil O' Wisp"
+LANGUAGE.class_zombie_torso = "Torse d'un zombie"
+LANGUAGE.class_zombie_legs = "Jambes d'un zombie"
+LANGUAGE.class_wraith = "Spectre"
+LANGUAGE.class_flesh_beast = "Flesh Beast"
+LANGUAGE.class_fast_zombie_legs = "Jambes d'un zombie agile"
+LANGUAGE.class_chem_zombie = "Zombie chimique"
+LANGUAGE.class_shade = "Shade"
+
+-- Class descriptions
+LANGUAGE.description_zombie = "Le zombie de base est résistant et porte de puissants coups.\nDur à abattre, surtout si on ne lui tire pas en pleine tête."
+LANGUAGE.description_poison_zombie = "Ce zombie est non seulement très durable mais possède aussi une force anormale.\nSon corps est extrêment toxique et n'hésitera pas à en arracher une partie pour la lancer sur des cibles trop éloignées."
+LANGUAGE.description_fast_zombie = "Ce cadavre composé pratiquement que d'os est extrêment rapide et agile.\nIl ne représente pas de réel danger mais peut en revanche grimper pratiquement partout grâce à ses griffes tranchantes.\nIls ont aussi aucun problème pour ce qu'il est de s'en prendre aux humains affaiblis."
+LANGUAGE.description_bloated_zombie = "Son corps est gorgé de produits toxiques et chimiques.\nMalgré leur lenteur, ils peuvent encaisser plus de coups."
+LANGUAGE.description_ghoul = "Sa chair est hautement toxique.\nSon corps frêle fait qu'il peut encaisser moins de coups, mais cela est compensé par ses attaques toxiques.\nSes griffes peuvent hébéter un humain et le goule peut aussi éjecter du poison s'il prend suffisamment de dégâts."
+LANGUAGE.description_headcrab = "Les crabes de tête sont les causes initiales de l'infection.\nOn ignore à ce jour leur origine.\nLeur méthode d'attaque est de se jeter en avant avec ses griffes tranchantes."
+LANGUAGE.description_fast_headcrab = "Le crabe de tête masculin est bien plus agile mais aussi plus frêle que la femelle.\nEn tous les cas, il est plus contrariant et dangereux en groupe."
+LANGUAGE.description_poison_headcrab = "Ce crabe de tête est gorgé de neurotoxines.\nUne morsure est généralement assez pour tuer un adulte.\nIl peut aussi cracher une boule de poison moins toxique.\nLe crachat est néanmoins mortel si un humain le reçoit dans les yeux."
+LANGUAGE.description_the_tickle_monster = "On dit que c'est le monstre qui attend sous votre lit pour vous prendre avec lui.\nLes bras du Tickle Monster sont très élastiques ce qui fait de lui un adversaire difficile à semer, ils sont aussi très redoutables contre les barricades."
+LANGUAGE.description_nightmare = "Une mutation extrêmement rare est ce qui a rendu le Nightmare surpuissant.\nPlus fort qu'un zombie de toutes les manières, c'est une force qu'il ne faut pas sous-estimer.\nUn coup de ses griffes est suffisant pour abattre une personne."
+LANGUAGE.description_pukepus = "Le corps putréfié du Puke Pus ne conserve que les organes produisant du vomi gorgé de poison.\nIl est capable de vomir des litres de poison en un instant, ce qui fait de lui un redoutable adversaire."
+LANGUAGE.description_bonemesh = "Défiguré et mutilé, le Bonemesh est capable de lancer des bombes sanguines.\nSes bombes sont à base de chair est de sang, potentiellement dangereuses pour les humains, elles font office de nourriture pour les zombies."
+LANGUAGE.description_crow = "Les corbeaux sont moins problématiques que lors de l'infection.\nIls se nourrissent de chair pourrie et transportent l'infection."
+LANGUAGE.description_wilowisp = "Parfois appelé l'Esprit des morts."
+LANGUAGE.description_zombie_torso = "Rien à voir par ici, circulez."
+LANGUAGE.description_zombie_legs = "Rien à voir par ici, circulez."
+LANGUAGE.description_wraith = "Un zombie ou une apparition?\nOn n'en sait peu sur lui à part le fait qu'il puisse se mettre invisible et découper les humains."
+LANGUAGE.description_flesh_beast = "*en cours*"
+LANGUAGE.description_fast_zombie_legs = "Rien à voir par ici, circulez."
+LANGUAGE.description_chem_zombie = "Le corps de ce zombie est extrêment instable.\nIl n'a rien en particulier sauf l'espoir d'exploser près d'un humain."
+LANGUAGE.description_shade = "Grâce au champ de force magnétique autour de lui, les balles sont inutiles.\nIl est en revanche vulnérable aux lumières émises par les lampe-torches."
+
+-- Class control schemes
+LANGUAGE.controls_zombie = "> PRIMAIRE: Attaque\n> SECONDARY: Crier\n> RECHARGER: Crier\n> SPRINT: Feindre la mort\n> TIR FATAL DANS LES JAMBES: Résurrection / Transformation"
+LANGUAGE.controls_poison_zombie = "> PRIMAIRE: Attaque\n> SECONDARY: Lancer de la chair\n> RECHARGER: Crier"
+LANGUAGE.controls_fast_zombie = "> PRIMAIRE: Attaque\n> SECONDARY: Attaquer / Escalader (près d'un mur)\n> RECHARGER: Crier"
+LANGUAGE.controls_bloated_zombie = "> PRIMAIRE: Attaque\n> SECONDARY: Crier\n> SPRINT: Feindre la mort\n> MORT: Morceaux empoisonnés"
+LANGUAGE.controls_ghoul = "> PRIMAIRE: Attaque empoisonnée\n> SECONDARY: Lancer de la chair\n> SPRINT: Feindre la mort\n> RECHARGER: Crier\n> CONTACT D'UN HUMAIN: Ralentissement\n> ATTAQUÉ PAR UN HUMAIN: éjection de poison"
+LANGUAGE.controls_headcrab = "> PRIMAIRE: Attaque\n> RECHARGER: S'enterrer"
+LANGUAGE.controls_fast_headcrab = "> PRIMAIRE: Attaque"
+LANGUAGE.controls_poison_headcrab = "> PRIMAIRE: Attaque\n> SECONDARY: Cracher du poison\n> MORSURE: Poison mortel\n> CRACHAT SUR LES YEUX: Aveuglé\n> RECHARGER: Crier"
+LANGUAGE.controls_the_tickle_monster = "> PRIMAIRE: Attaque élastique\n> SECONDARY: Crier"
+LANGUAGE.controls_nightmare = "> PRIMAIRE: Attaque mortelle\n> SECONDARY: Crier"
+LANGUAGE.controls_pukepus = "> PRIMAIRE: Vomir"
+LANGUAGE.controls_bonemesh = "> PRIMAIRE: Attaque\n> SECONDARY: Lancer une bombe de sang"
+LANGUAGE.controls_wraith = "> PRIMAIRE: Attaque\n> SECONDARY: Crier\n> L'INVISIBILITÉ DÉPEND DU MOUVEMENT ET DE LA DISTANCE"
+LANGUAGE.controls_flesh_beast = "> PRIMAIRE: Attaque\n> SECONDARY: Coup de tête"
+LANGUAGE.controls_chem_zombie = "> ON DEATH: Bombe empoisonnée"
+LANGUAGE.controls_shade = "> PRIMAIRE: Souveler\n> SECONDARY: Lancer"
+
+-- The help file... Quite big! I wouldn't blame you if you didn't translate this part.
+LANGUAGE.help_cat_introduction = "Introduction"
+LANGUAGE.help_cat_survival = "Survie"
+LANGUAGE.help_cat_barricading = "Barricades"
+LANGUAGE.help_cat_upgrades = "Amélirations"
+LANGUAGE.help_cat_being_a_zombie = "Être un zombie"
+LANGUAGE.help_cont_introduction = [[ Bienvenue à Zombie Survival, le simulateur de survie (contre des zombies). ZS vous permet de combattre des invasions de zombies, créer des barricades, et même faire partie de la horde zombie.
+
+Il y a deux équipes: les humains et les zombies. Les humains gagnent s'ils survivent toutes les vagues. Certains niveaux ont des objectifs spéciaux à compléter, ces derniers pouvant être facultatifs ou nécessaires.
+Si un humain est tué, il devient un zombie, ce qui rend la tâche plus difficile pour les humains restants.
+
+Le but des zombies est de dévorer tous les humains, les transformant en zombies, causant la perte de tout les joueurs.
+Alternativement, un zombie peut dévorer quatre humains pour se racheter. Cela leur donne une seconde chance de survie.
+Le seul moyen de gagner, c'est de survivre toutes les vagues en tant qu'humain. Les zombies ne peuvent que perdre; ils peuvent en revanche entraîner la perte des autres joueurs!
+
+Un certain nombre de joueurs est calculé pour choisir les zombies initiaux. Ce nombre est affiché au centre de votre écran avant le début de la partie.
+
+Utilisez les boutons ci-dessus pour avoir de l'aide plus spécifique.
+
+Astuces pour cette section:
+
Si vous vous déconnectez en tant qu'humain, vous reviendrez en tant que zombie.
+Après un certain temps pendant la partie, les nouveaux joueurs rejoindront en tant que zombie.
+Utilisez le Tchat d'Équipe quand cela est nécessaire en appuyant sur U.
+
+]]
+
+-- Place any custom stuff below here...
diff --git a/gamemodes/zombiesurvival/gamemode/languages/german.lua b/gamemodes/zombiesurvival/gamemode/languages/german.lua
new file mode 100644
index 0000000..520cc4b
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/languages/german.lua
@@ -0,0 +1,218 @@
+-- Translated by Raptor (http://www.noxiousnet.com/forums/index.php?action=profile;u=5280)
+
+translate.AddLanguage("de", "German")
+
+-- Various gamemode stuff
+LANGUAGE.minute_points_added = "Kein Schaden für eine ganze Minute erhalten! %d Punkte hinzugefügt."
+LANGUAGE.infliction_reached_class_unlocked = "Der Schaden von %d%% wurde erreicht! %s freigeschaltet!"
+LANGUAGE.infliction_reached = "%d%% aller Menschen sind gestorben!"
+LANGUAGE.x_unlocked = "%s freigeschaltet!"
+LANGUAGE.disconnect_killed = "%s wurde getrennt getötet von %s."
+LANGUAGE.nail_removed_by = "%s hat einen Nagel von %s entfernt."
+LANGUAGE.banned_for_life_warning = "Du bist lebenslänglich verbannt, also kannst du nichts kaufen!"
+LANGUAGE.need_to_be_near_arsenal_crate = "Du musst in der Nähe eines Arsenal Crates sein um einen Artikel kaufen zu können!"
+LANGUAGE.cant_purchase_right_now = "Du kannst momentan nichts kaufen."
+LANGUAGE.dont_have_enough_points = "Du hast nicht genügend Punkte."
+LANGUAGE.prepare_yourself = "Bereite dich vor..."
+LANGUAGE.purchased_x_for_y_points = "%s für %d Punkte erworben!"
+LANGUAGE.give_time_before_suicide = "Gib anderen die Zeit zu spawnen bevor du Suizid begehst."
+LANGUAGE.no_spare_ammo_to_give = "Es gibt keine übrige Munition zum geben!"
+LANGUAGE.no_person_in_range = "Keine Person in Reichweite!"
+LANGUAGE.that_life = "Dieses Leben..."
+LANGUAGE.x_damage_to_barricades = "%d Schaden an Barrikaden"
+LANGUAGE.x_damage_to_humans = "%d Schaden an Menschen"
+LANGUAGE.x_brains_eaten = "%d Gehirne gefressen"
+LANGUAGE.press_rmb_to_cycle_targets = "Drücke RMT um das nächste Ziel zu wählen"
+LANGUAGE.press_lmb_to_spawn_on_them = "Drücke LMT um auf ihnen zu spawnen"
+LANGUAGE.press_lmb_to_spawn = "Drück die LMT um zu spawnen"
+LANGUAGE.observing_x = "%s beobachten (%d)"
+LANGUAGE.waiting_for_next_wave = "Es wird auf den Beginn der nächsten Welle gewartet..."
+LANGUAGE.impossible = "Unmöglich."
+LANGUAGE.trying_to_put_nails_in_glass = "Nägel in Glas zu schlagen ist keine gute Idee."
+LANGUAGE.boss_class_select = "Du wirst %s sein das nächste Mal wenn du ein Zombieboss bist."
+LANGUAGE.person_has_weapon = "Die haben schon diese Waffe."
+LANGUAGE.cant_do_that_in_classic_mode = "Du kannst das nich in Classic Mode machen."
+LANGUAGE.cant_use_x_in_classic_mode = "Du kannst %s in Classic Mode nicht verwenden."
+LANGUAGE.cant_use_x_in_zombie_escape = "Du kannst %s in Zombie Escape nicht verwenden."
+LANGUAGE.no_class_switch_in_this_mode = "Der jetzige Modus erlaubt dir nicht Klassen zu wechseln."
+LANGUAGE.press_sprint_to_get_up = "Drück SPRINTEN um hoch zu kommen"
+LANGUAGE.zombie_escape = "Zombie Escape!"
+LANGUAGE.nothing_for_this_ammo = "Du hast nichts das diesen Typ von Munition verwendet."
+LANGUAGE.you_decide_to_leave_some = "Du entscheidest dich welche aus deinem Team zu verlassen."
+LANGUAGE.you_cant_purchase_now = "Du kannst keine Artikel momentan erwerben."
+LANGUAGE.no_ammo_here = "Gerade jetzt gibt es keine Munition hier."
+LANGUAGE.you_redeemed = "Du bist zurückgekehrt!"
+LANGUAGE.kill_the_last_human = "Töte den letzten Menschen!"
+LANGUAGE.kick_the_last_human = "Trete den letzten Menschen!"
+LANGUAGE.you_are_the_last_human = "DU BIST DER LETZTE MENSCH!"
+LANGUAGE.x_zombies_out_to_get_you = "%d ZOMBIES SIND AUF DEM WEG DICH ZU SCHNAPPEN!"
+LANGUAGE.x_pants_out_to_get_you = "%d HOSEN SIND AUF DEM WEG DICH ZU SCHNAPPEN!"
+LANGUAGE.you_have_died = "Du bist gestorben."
+LANGUAGE.you_were_killed_by_x = "Du wurdest von %s getötet"
+LANGUAGE.you_were_kicked_by_x = "Du wurdest in die Schienbeine von %s getreten"
+LANGUAGE.arsenal_upgraded = "Arsenal verbessert"
+LANGUAGE.final_wave = "DIE LETZTE WELLE HAT BEGONNEN!"
+LANGUAGE.final_wave_sub = "ALLE Klassen freigeschaltet und die Chance zurückzukehren ist weg!"
+LANGUAGE.wave_x_has_begun = "Welle %d hat angefangen!"
+LANGUAGE.x_unlocked = "%s freigeschaltet!"
+LANGUAGE.wave_x_is_over = "Welle %d ist rum!"
+LANGUAGE.wave_x_is_over_sub = "Die Anzahl der Untoten steigt nicht mehr und der Points Shop ist %d%% aus."
+LANGUAGE.you_are_x = "Du bist %s!"
+LANGUAGE.x_has_risen_as_y = "%s ist auferstanden als %s!!"
+LANGUAGE.x_has_risen = "%s ist auferstanden!"
+LANGUAGE.cant_use_worth_anymore = "Du kannst den Worth Menu nicht mehr verwenden!"
+LANGUAGE.class_not_unlocked_will_be_unlocked_x = "Diese Klasse ist noch nicht freigeschaltet. Sie wird das erst beim Start von Welle %d sein."
+LANGUAGE.you_are_already_a_x = "Du bist schon tot %s."
+LANGUAGE.you_will_spawn_as_a_x = "Du wirst als %s spawnen."
+LANGUAGE.crafting_successful = "Fertigung erfolgreich!"
+LANGUAGE.x_crafted_y = "%s fertigte %s."
+LANGUAGE.escape_from_the_zombies = "Entkomme den Zombies!"
+LANGUAGE.too_close_to_another_nail = "Zu nah an einem anderen Nagel dran."
+LANGUAGE.object_too_damaged_to_be_used = "Dieses Objekt ist zu beschädigt um es weiter zu verwenden."
+LANGUAGE.thanks_for_being_a_fan_of_zs = "Danke, dass du ein Fan von Zombie Survival bist!"
+LANGUAGE.cant_remove_nails_of_superior_player = "Du kannst die Nägel eines anderen Spielers nicht entfernen, der es so viel besser macht als du."
+LANGUAGE.x_turned_on_noclip = "%s hat noclip angemacht."
+LANGUAGE.x_turned_off_noclip = "%s hat noclip ausgemacht."
+LANGUAGE.unlocked_on_wave_x = "Freigeschaltet bei Welle %d"
+LANGUAGE.brains_eaten_x = "Gehirne gegessen: %s"
+LANGUAGE.points_x = "Punkte: %s"
+LANGUAGE.next_wave_in_x = "Nächste Welle in %s"
+LANGUAGE.wave_ends_in_x = "Welle endet in %s"
+LANGUAGE.wave_x_of_y = "Welle %d von %d"
+LANGUAGE.zombie_invasion_in_x = "Zombieinvasion in %s"
+LANGUAGE.intermission = "Unterbrechung"
+LANGUAGE.press_f2_for_the_points_shop = "Drücke F2 für den Points Shop!"
+LANGUAGE.breath = "Atem"
+LANGUAGE.zombie_volunteers = "Freiwillige Zombies"
+LANGUAGE.x_discount_for_buying_between_waves = "%d%% Preisnachlass für das Kaufen zwischen Wellen!"
+LANGUAGE.number_of_initial_zombies_this_game = "Anzahl der ersten Zombies in diesem Spiel (%d%%): %d"
+LANGUAGE.humans_closest_to_spawns_are_zombies = "Die Menschen am nächsten vom Zombiespawn werden als Zombies spielen."
+LANGUAGE.waiting_for_players = "Auf Spieler warten..."
+LANGUAGE.requires_x_people = "Benötigt %d Leute"
+LANGUAGE.packing_others_object = "Packt Objekte einer anderen Person"
+LANGUAGE.packing = "Verpacken"
+LANGUAGE.ze_humans_are_frozen_until_x = "Menschen sind eingefroren für %d Sekunden bevor die Runde anfängt."
+LANGUAGE.loading = "Ladet..."
+LANGUAGE.next_round_in_x = "Nächste Runde in: %s"
+LANGUAGE.warning = "Warnung!"
+LANGUAGE.ok_and_no_reminder = "OK und zeig diese Nachricht nicht mehr an"
+LANGUAGE.classic_mode_warning = "Dieser Server läuft auf Zombie Survival in 'Classic Mode'\nClassic Mode ist eine Einstellund, welches das Gameplay stark verändert. Dinge, die anders sind:\n* Keine Auswahl der Zombieklassen. Jeder verwendet die klassische Zombie Klasse\n* Keine Werkzeuge zum Verbarrikadieren, wie Nägel oder automatische Geschütze \n* Mehr, aber schnellere Runden\n\nDas ist nicht das ürsprüngliche Zombie Survival!\n\n-- Server die auf Classic Mode laufen zeigen auch CLASSIC MODE in der unteren, linken Ecke des Bildschirms an --"
+LANGUAGE.classic_mode = "CLASSIC MODE"
+LANGUAGE.resist_x = "Leiste Widerstand: %d%%"
+LANGUAGE.right_click_to_hammer_nail = "Rechtsklick um einen Nagel mit einem Hammer reinzuschlagen."
+LANGUAGE.nails_x = "Nägel: %d"
+LANGUAGE.resupply_box = "Resupply Box"
+LANGUAGE.purchase_now = "Erwerbe jetzt!"
+LANGUAGE.integrity_x = "Unversehrtheit: %d%%"
+LANGUAGE.empty = "LEER"
+LANGUAGE.manual_control = "MANUELLE KONTROLLE"
+LANGUAGE.arsenal_crate = "Arsenal Crate"
+
+-- Exit point objectives
+LANGUAGE.exit_destroyed = "Die Untoten haben einen Ausgang zerstört!"
+LANGUAGE.exit_destroyed_only_one_remain_h = "Nur noch eins steht! Wenn es zerstört wird gibt es keine Hoffnung auf eine Flucht!"
+LANGUAGE.exit_destroyed_only_one_remain_z = "Nur noch eins steht!"
+LANGUAGE.exit_destroyed_x_remain = "%d vorhandene Ausgänge."
+LANGUAGE.last_exit_destroyed_all_is_lost = "Die Zombies haben den letzten Ausgang zerstört."
+LANGUAGE.last_exit_destroyed_all_is_lost2 = "Es gibt keine Hoffnung auf ein Entkommen."
+
+-- Message beacon messages
+LANGUAGE.message_beacon_1 = "Trefft euch hier"
+LANGUAGE.message_beacon_2 = "Brauchen Verteidigung hier"
+LANGUAGE.message_beacon_3 = "Brauchen Geschütze hier"
+LANGUAGE.message_beacon_4 = "Brauchen Arsenal Crates hier"
+LANGUAGE.message_beacon_5 = "Brauchen Sanitäter hier"
+LANGUAGE.message_beacon_6 = "Ammunition Box hier"
+LANGUAGE.message_beacon_7 = "Arsenal Crate hier"
+LANGUAGE.message_beacon_8 = "Brauchen Kraftfelder hier"
+LANGUAGE.message_beacon_9 = "Brauchen Sprengstoff hier"
+LANGUAGE.message_beacon_10 = "Zombies kommen von hier"
+LANGUAGE.message_beacon_11 = "Nicht betreten!!"
+LANGUAGE.message_beacon_12 = "Geh nicht raus"
+LANGUAGE.message_beacon_13 = "Verteidige dieses Gebiet"
+LANGUAGE.message_beacon_14 = "Verteidige diese Stelle"
+LANGUAGE.message_beacon_15 = "Sanitäter hier"
+LANGUAGE.message_beacon_16 = "Kauf von meiner Kiste"
+LANGUAGE.message_beacon_17 = "Verbarrikadiert hier"
+LANGUAGE.message_beacon_18 = "Nicht hier verbarrikadieren"
+LANGUAGE.message_beacon_19 = "Lasst Zombies nicht hier rein"
+LANGUAGE.message_beacon_20 = "Das wird kaputt gehen"
+LANGUAGE.message_beacon_21 = "Dieser Ort is gefährlich!"
+LANGUAGE.message_beacon_22 = "Sei auf Gift gefasst!"
+LANGUAGE.message_beacon_23 = "Zombies brechen hier durch!"
+LANGUAGE.message_beacon_24 = "Zombies kommen. Baut eine Barrikade!"
+LANGUAGE.message_beacon_25 = "Plan B hier"
+
+-- Class names
+LANGUAGE.class_zombie = "Zombie"
+LANGUAGE.class_poison_zombie = "Gift Zombie"
+LANGUAGE.class_fast_zombie = "Schneller Zombie"
+LANGUAGE.class_bloated_zombie = "Aufgeblähter Zombie"
+LANGUAGE.class_classic_zombie = "Klassischer Zombie"
+LANGUAGE.class_super_zombie = "Super Zombie"
+LANGUAGE.class_fresh_dead = "Fresh Dead"
+LANGUAGE.class_ghoul = "Ghoul"
+LANGUAGE.class_headcrab = "Headcrab"
+LANGUAGE.class_fast_headcrab = "Schnelles Headcrab"
+LANGUAGE.class_poison_headcrab = "Gift Headcrab"
+LANGUAGE.class_the_tickle_monster = "The Tickle Monster"
+LANGUAGE.class_nightmare = "Nightmare"
+LANGUAGE.class_pukepus = "Pukepus"
+LANGUAGE.class_bonemesh = "Bonemesh"
+LANGUAGE.class_crow = "Krähe"
+LANGUAGE.class_wilowisp = "Wil O' Wisp"
+LANGUAGE.class_zombie_torso = "Zombietorso"
+LANGUAGE.class_zombie_legs = "Zombiebeine"
+LANGUAGE.class_wraith = "Wraith"
+LANGUAGE.class_flesh_beast = "Flesh Beast"
+LANGUAGE.class_fast_zombie_legs = "Beine des schnellen Zombies"
+LANGUAGE.class_chem_zombie = "Chem Zombie"
+LANGUAGE.class_shade = "Shade"
+
+-- Class descriptions
+LANGUAGE.description_zombie = "Der normale Zombie ist sehr beständig und hat kraftvolle Klauen.\nEs ist schwer ihn unten zu halten, vor allem wenn er nicht in den Kopf geschossen wird."
+LANGUAGE.description_poison_zombie = "Dieser mutierte Zombie is nicht nur extrem langlebig, aber hat auch noch eine abnormale Kraft.\nSein Körper is extrem giftig. Er wird sogar sein eigenes Fleisch rausreissen und es auf Dinge werfen, die zu weit weg zum schlagen sind."
+LANGUAGE.description_fast_zombie = "Dieser knochige Kadaver ist viel schneller als andere Zombies.\nSie sind keine große Bedrohung alleine, aber können fast jedes Gebiet durchs Klettern mit ihren rasierscharfen Klauen erreichen.\nZudem haben sie keine Problem schwache oder verletzte Menschen zu jagen."
+LANGUAGE.description_bloated_zombie = "Ihre Körper beinhalten unberechenbare, giftige Chemikalien.\nObwohl sie sich langsamer bewegen, können sie etwas mehr einstecken."
+LANGUAGE.description_ghoul = "Dieser Zombie hat hoch giftiges Fleisch.\nEs is etwas schwächer als andere Zombies, gleicht das jedoch wieder aus mit seinen Giftattacken.\nSeine Klauen können einen Menschen für kurze Zeit entkräften und es wird Gift ausstoßen, wenn es mit genügend Kraft schlägt."
+LANGUAGE.description_headcrab = "Headcrabs sind was die Infektionen begonnen haben.\nNiemand weiss woher sie tatsächlich gekommen sind.\nIhre Angriffsmethode ist es sich auf ihr Opfer mit ihren scharfen Zähnen auf ihrem Bauch zu stürzen."
+LANGUAGE.description_fast_headcrab = "Das männliche Headcrab ist beträchtlich schneller, aber nicht so kräftig wie das weibliche.\nSo oder so sind sie beide gleich nervig und tödlich in Gruppen."
+LANGUAGE.description_poison_headcrab = "Diese Headcrab ist voller tödlichem Nervengift.\nEin Biss ist immer genug um einen erwachsenen Menschen zu töten.\nEs hat zudem die Fähigkeit eine wenige wirksame Version seines Giftes zu spucken.\nDer Speichel ist genau so tödlich, wenn ihr Opfer damit ins Gesicht getroffen wird."
+LANGUAGE.description_the_tickle_monster = "Bekannt als das Monster, dass sich nachts in deinem Schrank versteckt, um dich aus deinem Bett zu ziehen.\nDie beinahe elastischen Arme des Tickle Monsters machen es extrem schwer zu entkommen, zudem sind sie ideal zum zerstören von Barrikaden."
+LANGUAGE.description_nightmare = "Eine extrem seltene Mutation gibt dem Nightmare seine abnormalen Kräfte.\nStärker als der x-beliebige Zombie in soziemlich jeder Weise ist der Nightmare eine Einheit mit dar man rechnen muss.\nEin Schwung mit seinen Klauen ist genug um fast jede Person auszuschalten."
+LANGUAGE.description_pukepus = "Der verrottende Körper des Puke Pus ist komplett gefüllt mit Organen, die zur Produktion von Gift dienen.\nEs ist in der Lage Gallonen an giftiger Kotze auf ein Mal zu erbrechen, was es extrem gefährlich macht."
+LANGUAGE.description_bonemesh = "Entstellt und übel zugerichtet ist es dem Bonemesh möglich Blutbomben zu werfen.\nJede Bombe enthält Knochen und Fleisch, was Menschen schmerzen bereitet, aber anderen Zombies während dessen wertvolle Nahrung gibt."
+LANGUAGE.description_crow = "Aaskrähen sind eine größere Plage als bevor der Epidemie.\nSie nähren sich an infiziertem Fleich und werden zu 'Trägern' für die Untoten.\nWarum würdest du jemals diese Klasse nicht versteckt halten?\nWas stimmt mit dir nicht?"
+LANGUAGE.description_wilowisp = "Manchmal als Geister der Toten bezeichnet."
+LANGUAGE.description_zombie_torso = "Du solltest das noch nicht einmal sehen."
+LANGUAGE.description_zombie_legs = "Du solltest das noch nicht einmal sehen."
+LANGUAGE.description_wraith = "Ein Zombie oder ein Gespenst?\nNicht viel ist über es bekannt, außer der Tatsache dass es seine\nbesondere Unsichtbarkeit und scharfen Klauen verwendet um Dinge in Scheiben zu schneiden."
+LANGUAGE.description_flesh_beast = "*Noch nicht fertig*"
+LANGUAGE.description_fast_zombie_legs = "Du solltest das noch nicht einmal sehen."
+LANGUAGE.description_chem_zombie = "Der Chem Zombie beinhaltet etherische und giftige Chemikalien.\nEs hat keine anderen Absichten neben dem Angreifen, außer getötet zu werden, in Hoffnung in der Nähe von Menschen zu explodieren."
+LANGUAGE.description_shade = "In dem es ein starkes magnetisches Feld um sich herum aufbaut werden alle Angriffe mit Projektilen und Nahkampfwaffen nutzlos.\nAus irgendeinem Grund ist Shade verletzbar bei hellem Licht."
+
+-- Class control schemes
+LANGUAGE.controls_zombie = "> HAUPTWAFFE: Klauen\n> SEKUNDÄRWAFFE: Schrei\n> NACHLADEN: Stöhnen\n> SPRINTEN: Tod vortäuschen\n> BEI FATALEM ANGRIFF AUF DIE BEINE: Wiederbeleben / Transformieren"
+LANGUAGE.controls_poison_zombie = "> HAUPTWAFFE: Klauen\n> SEKUNDÄRWAFFE: Fleisch werfen\n> RELOAD: Schreien"
+LANGUAGE.controls_fast_zombie = "> HAUPTWAFFE: Klauen\n> SEKUNDÄRWAFFE: Sturzangriff / Klettern (nahe einer Wand)\n> RELOAD: Schreien"
+LANGUAGE.controls_bloated_zombie = "> HAUPTWAFFE: Klauen\n> SEKUNDÄRWAFFE: Stöhnen\n> SPRINT: Tod vortäuschen\n> BEIM TOD: Giftige Innereien"
+LANGUAGE.controls_ghoul = "> HAUPTWAFFE: Giftklauen\n> SEKUNDÄRWAFFE: Fleisch werfen\n> SPRINTEN: Tod vortäuschen\n> NACHLADEN: Schreien\n> BEIM SCHLAG AUF MENSCHEN: Verlangsamen\n> BEIM SCHLAG VON MENSCHEN: Auswurf von Gift"
+LANGUAGE.controls_headcrab = "> HAUPTWAFFE: Sturzangriff\n> NACHLADEN: Vergraben"
+LANGUAGE.controls_fast_headcrab = "> HAUPTWAFFE: Sturzangriff"
+LANGUAGE.controls_poison_headcrab = "> HAUPTWAFFE: Sturzangriff\n> SEKUNDÄRWAFFE: Gift spucken\n> BEIM SCHLAG AUF MENSCHEN: Tödliches Gift\n> WENN GIFT AUGEN TRIFFT: Blind machen\n> NACHLADEN: Schreien"
+LANGUAGE.controls_the_tickle_monster = "> HAUPTWAFFE: Elastische Klauen\n> SEKUNDÄRWAFFE: Stöhnen"
+LANGUAGE.controls_nightmare = "> HAUPTWAFFE: Todesberührung\n> SEKUNDÄRWAFFE: Stöhnen"
+LANGUAGE.controls_pukepus = "> HAUPTWAFFE: Erbrechen"
+LANGUAGE.controls_bonemesh = "> HAUPTWAFFE: Klauen\n> SEKUNDÄRWAFFE: Blutbombe werfen"
+LANGUAGE.controls_wraith = "> HAUPTWAFFE: Klauen\n> SEKUNDÄRWAFFE: Schreien\n> UNSICHTBARKEIT BASIEREND AUF BEWEGUNG UND SICHT"
+LANGUAGE.controls_flesh_beast = "> HAUPTWAFFE: Klauen\n> SEKUNDÄRWAFFE: Kopfnuss"
+LANGUAGE.controls_chem_zombie = "> BEIM TOD: Giftbombe"
+LANGUAGE.controls_shade = "> HAUPTWAFFE: Heben\n> SEKUNDÄRWAFFE: Werfen"
+
+-- The help file... Quite big! I wouldn't blame you if you didn't translate this part.
+LANGUAGE.help_cat_introduction = "Einführung"
+LANGUAGE.help_cat_survival = "Ãœberleben"
+LANGUAGE.help_cat_barricading = "Verbarrikadieren"
+LANGUAGE.help_cat_upgrades = "Verbesserungen"
+LANGUAGE.help_cat_being_a_zombie = "Zombie Dasein"
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/languages/italian.lua b/gamemodes/zombiesurvival/gamemode/languages/italian.lua
new file mode 100644
index 0000000..a1d09fb
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/languages/italian.lua
@@ -0,0 +1,213 @@
+-- Translated by Kradar (http://www.noxiousnet.com/forums/index.php?action=profile;u=6103)
+
+translate.AddLanguage("it", "Italian")
+
+ -- Various gamemode stuff
+
+ LANGUAGE.minute_points_added = "Non hai subito danni per un intero minuto! Aggiunti %d punti."
+ LANGUAGE.infliction_reached_class_unlocked = "Inflizione del %d%% raggiunta! %s sbloccato!"
+ LANGUAGE.infliction_reached = "Sono morti il %d%% degli umani!"
+ LANGUAGE.x_unlocked = "%s sbloccato!!"
+ LANGUAGE.disconnect_killed = "%s è stato ucciso da %s per aver lasciato il gioco."
+ LANGUAGE.nail_removed_by = "%s ha rimosso un chiodo di %s."
+ LANGUAGE.banned_for_life_warning = "Un tuo depotenziamento ti impedisce di comprare qualsiasi cosa!"
+ LANGUAGE.need_to_be_near_arsenal_crate = "Devi essere nelle vicinanze di una cassa dell'arsenale per fare acquisti!"
+ LANGUAGE.cant_purchase_right_now = "Non puoi acquistare niente al momento."
+ LANGUAGE.dont_have_enough_points = "Non hai abbastanza punti."
+ LANGUAGE.prepare_yourself = "Preparati..."
+ LANGUAGE.purchased_x_for_y_points = "Acquistato %s in cambio di %d punti!"
+ LANGUAGE.give_time_before_suicide = "Dai del tempo agli altri prima di suicidarti."
+ LANGUAGE.no_spare_ammo_to_give = "Non hai munizioni in più da dare!"
+ LANGUAGE.no_person_in_range = "Non c'è nessuna persona nelle vicinanze!"
+ LANGUAGE.that_life = "Che vita..."
+ LANGUAGE.x_damage_to_barricades = "%d di danno alle barricate"
+ LANGUAGE.x_damage_to_humans = "%d di danno agli umani"
+ LANGUAGE.x_brains_eaten = "%d cervelli divorati"
+ LANGUAGE.press_rmb_to_cycle_targets = "Premi il tasto destro per cambiare obbiettivo."
+ LANGUAGE.press_lmb_to_spawn_on_them = "Premi il tasto sinistro per rinascere su quest'obbiettivo."
+ LANGUAGE.press_lmb_to_spawn = "Premi il tasto destro per rinascere"
+ LANGUAGE.observing_x = "Osservando %s (%d)"
+ LANGUAGE.waiting_for_next_wave = "In attesa dell'inizio della prossima ondata.."
+ LANGUAGE.impossible = "Impossibile."
+ LANGUAGE.trying_to_put_nails_in_glass = "Cercare di piantare chiodi nel vetro è una cosa ridicola da fare."
+ LANGUAGE.boss_class_select = "Sarai %s la prossima volta che diventi capo zombie."
+ LANGUAGE.person_has_weapon = "Ha già quest'arma"
+ LANGUAGE.cant_do_that_in_classic_mode = "Non puoi farlo nella modalità Classic mode."
+ LANGUAGE.cant_use_x_in_classic_mode = "Non puoi usarlo %s nella modalità Classic mode."
+ LANGUAGE.cant_use_x_in_zombie_escape = "Non puoi usarlo %s nella modalità Zombie Escape."
+ LANGUAGE.no_class_switch_in_this_mode = "La modalità corrente non ti permette di cambiare classe."
+ LANGUAGE.press_sprint_to_get_up = "Premi SHIFT per alzarti."
+ LANGUAGE.zombie_escape = "Zombie Escape!"
+ LANGUAGE.nothing_for_this_ammo = "Non hai nulla che usi questo tipo di munizioni."
+ LANGUAGE.you_decide_to_leave_some = "Decidi di lasciarne un po per la tua squadra."
+ LANGUAGE.you_cant_purchase_now = "Non puoi acquistare oggetti al momento."
+ LANGUAGE.no_ammo_here = "Non ci sono munizioni qui al momento."
+ LANGUAGE.you_redeemed = "Ti sei redento!"
+ LANGUAGE.kill_the_last_human = "Uccidi l'ultimo umano rimasto!"
+ LANGUAGE.kick_the_last_human = "Caccia l'ultimo umano rimasto!"
+ LANGUAGE.you_are_the_last_human = "SEI L'ULTIMO UMANO RIMASTO!"
+ LANGUAGE.x_zombies_out_to_get_you = "%d ZOMBIE SONO FUORI PER PRENDERTI!"
+ LANGUAGE.x_pants_out_to_get_you = "%d PANTALONI SONO FUORI PER PRENDERTI!"
+ LANGUAGE.you_have_died = "Sei deceduto."
+ LANGUAGE.you_were_killed_by_x = "Sei stato ucciso da %s"
+ LANGUAGE.you_were_kicked_by_x = "%s ti ha preso a calci negli stinchi."
+ LANGUAGE.arsenal_upgraded = "Arsenale potenziato."
+ LANGUAGE.final_wave = "L'ONDATA FINALE E' COMINCIATA!"
+ LANGUAGE.final_wave_sub = "Tutte le classi sono state sbloccate e le possibilità per redimersi sono terminate!"
+ LANGUAGE.wave_x_has_begun = "L'ondata %d è cominciata!"
+ LANGUAGE.x_unlocked = "%s sbloccato!"
+ LANGUAGE.wave_x_is_over = "L'ondata %d è finita!"
+ LANGUAGE.wave_x_is_over_sub = "I non-morti hanno smesso di alzarsi e il Points shop ha uno sconto del %d%% ."
+ LANGUAGE.you_are_x = "Sei %s!"
+ LANGUAGE.x_has_risen_as_y = "%s si è alzato come %s!!"
+ LANGUAGE.x_has_risen = "%s si è alzato!"
+ LANGUAGE.cant_use_worth_anymore = "Non puoi più usare il Worth Menu!"
+ LANGUAGE.class_not_unlocked_will_be_unlocked_x = "Questa classe non è ancora stata sbloccata. Verrà sbloccata al termine dell'ondata %d."
+ LANGUAGE.you_are_already_a_x = "Sei già un %s."
+ LANGUAGE.you_will_spawn_as_a_x = "Rinascerai come %s."
+ LANGUAGE.crafting_successful = "Assemblaggio completato!"
+ LANGUAGE.x_crafted_y = "%s ha assemblato %s."
+ LANGUAGE.escape_from_the_zombies = "Fuggi dagli zombie!"
+ LANGUAGE.too_close_to_another_nail = "Troppo vicino ad un altro chiodo."
+ LANGUAGE.object_too_damaged_to_be_used = "Quest'oggetto è troppo danneggiato per essere sfruttato oltre."
+ LANGUAGE.thanks_for_being_a_fan_of_zs = "Appreziamo il vostro supporto per Zombie Survival!"
+ LANGUAGE.cant_remove_nails_of_superior_player = "Non puoi rimuovere i chiodi di un giocatore con un punteggio tanto maggiore del tuo."
+ LANGUAGE.x_turned_on_noclip = "%s è entrato in modalità noclip."
+ LANGUAGE.x_turned_off_noclip = "%s è uscito dalla modalità noclip."
+ LANGUAGE.unlocked_on_wave_x = "Sbloccato nell'ondata %d"
+ LANGUAGE.brains_eaten_x = "Cervelli divorati: %s"
+ LANGUAGE.points_x = "Punti: %s"
+ LANGUAGE.next_wave_in_x = "Prossima ondata tra %s"
+ LANGUAGE.wave_ends_in_x = "L'ondata corrente termina tra %s"
+ LANGUAGE.wave_x_of_y = "Ondata %d di %d"
+ LANGUAGE.zombie_invasion_in_x = "Invasione zombie tra %s"
+ LANGUAGE.intermission = "Intervallo"
+ LANGUAGE.press_f2_for_the_points_shop = "Premi F2 per visualizzare lo Points Shop!"
+ LANGUAGE.breath = "Respiro"
+ LANGUAGE.zombie_volunteers = "Zombie volontari"
+ LANGUAGE.x_discount_for_buying_between_waves = "%d%% di sconto su acquisti durante gli intervalli tra ondate!"
+ LANGUAGE.number_of_initial_zombies_this_game = "Numero di zombie iniziali questa partita (%d%%): %d"
+ LANGUAGE.humans_closest_to_spawns_are_zombies = "Gli umani più vicini alla base degli zombie inizieranno come zombie."
+ LANGUAGE.waiting_for_players = "In attesa di altri giocatori..."
+ LANGUAGE.requires_x_people = "Richiede %d giocatori"
+ LANGUAGE.packing_others_object = "Smantellando l'oggetto di un'altro giocatore"
+ LANGUAGE.packing = "Smantellando"
+ LANGUAGE.ze_humans_are_frozen_until_x = "Gli umani sono immobilizzati fino a quando mancano %d secondi all'inizio del round."
+ LANGUAGE.loading = "Caricamento..."
+ LANGUAGE.next_round_in_x = "Prossimo round tra: %s"
+ LANGUAGE.warning = "Attenzione!"
+ LANGUAGE.ok_and_no_reminder = "OK e non mostrare più questo messaggio"
+ LANGUAGE.classic_mode_warning = "Questo server ospita Zombie Survival in modalità 'Classic Mode'\nLa modalità 'Classic Mode' è un'impostazione che influenza molto il gameplay. Le differenze sono:/n* Non si possono scegliere le classi di zombie. Tutti usano lo zombie normale.\n* Non esistono barricate, chiodi o torrette\n*Ondate più numerose ma più veloci\n\nQuesto NON è il classico Zombie Survival!\n\n-- I server che ospitano la modalità Classic Mode indicheranno 'CLASSIC MODE' nella parte in basso a sinistra dello schermo --"
+ LANGUAGE.classic_mode = "CLASSIC MODE"
+ LANGUAGE.resist_x = "Resistenza: %d%%"
+ LANGUAGE.right_click_to_hammer_nail = "Premi tasto destro per martellare il chiodo."
+ LANGUAGE.nails_x = "Chiodi: %d"
+ LANGUAGE.resupply_box = "Cassa dei rifornimenti"
+ LANGUAGE.purchase_now = "Acquista ora!"
+ LANGUAGE.integrity_x = "Integrità : %d%%"
+ LANGUAGE.empty = "VUOTO"
+ LANGUAGE.manual_control = "CONTROLLO MANUALE"
+ LANGUAGE.arsenal_crate = "Cassa dell'arsenale"
+
+
+ -- Exit point objectives
+ LANGUAGE.exit_destroyed = "I non-morti hanno bloccato un'uscita!"
+ LANGUAGE.exit_destroyed_only_one_remain_h = "Ne rimane soltanto una! Se viene bloccata anche questa non ci saranno vie di fuga!"
+ LANGUAGE.exit_destroyed_only_one_remain_z = "Ne rimane soltanto una!"
+ LANGUAGE.exit_destroyed_x_remain = "%d vie di fuga rimanenti."
+ LANGUAGE.last_exit_destroyed_all_is_lost = "Gli zombie hanno bloccato l'ultima via di fuga."
+ LANGUAGE.last_exit_destroyed_all_is_lost2 = "Non ci sono più vie di fuga."
+
+ -- Message beacon messages
+ LANGUAGE.message_beacon_1 = "Incontrarsi qui"
+ LANGUAGE.message_beacon_2 = "Occorrono difese qui"
+ LANGUAGE.message_beacon_3 = "Bisogno di torrette qui"
+ LANGUAGE.message_beacon_4 = "Necessità di casse dell'Arsenale qui"
+ LANGUAGE.message_beacon_5 = "Servono medici qui"
+ LANGUAGE.message_beacon_6 = "Assemblare cassa di munizioni qui"
+ LANGUAGE.message_beacon_7 = "Installare cassa dell'Arsenale qui"
+ LANGUAGE.message_beacon_8 = "Servono campi di forza qui"
+ LANGUAGE.message_beacon_9 = "Servono esplosivi qui"
+ LANGUAGE.message_beacon_10 = "Gli zombie entrano da qui"
+ LANGUAGE.message_beacon_11 = "Non entrare qui!!"
+ LANGUAGE.message_beacon_12 = "Non uscire"
+ LANGUAGE.message_beacon_13 = "Difendi quest'area"
+ LANGUAGE.message_beacon_14 = "Difendi questo posto"
+ LANGUAGE.message_beacon_15 = "Medici qui"
+ LANGUAGE.message_beacon_16 = "Acquistate dalla mia cassa"
+ LANGUAGE.message_beacon_17 = "Barricata qui"
+ LANGUAGE.message_beacon_18 = "Non piazzare barricate qui"
+ LANGUAGE.message_beacon_19 = "Non lasciare che gli zombie entrino qui"
+ LANGUAGE.message_beacon_20 = "Questo si romperà "
+ LANGUAGE.message_beacon_21 = "Questo posto è pericoloso!"
+ LANGUAGE.message_beacon_22 = "Attenzione al veleno!"
+ LANGUAGE.message_beacon_23 = "Gli zombie stanno facendo irruzione qui!"
+ LANGUAGE.message_beacon_24 = "Gli zombie stanno arrivando, costruire una barricata qui!"
+ LANGUAGE.message_beacon_25 = "Piano B qui"
+
+ -- Class names
+ LANGUAGE.class_zombie = "Zombie"
+ LANGUAGE.class_poison_zombie = "Poison Zombie"
+ LANGUAGE.class_fast_zombie = "Fast Zombie"
+ LANGUAGE.class_bloated_zombie = "Bloated Zombie"
+ LANGUAGE.class_classic_zombie = "Classic Zombie"
+ LANGUAGE.class_super_zombie = "Super Zombie"
+ LANGUAGE.class_fresh_dead = "Fresh Dead"
+ LANGUAGE.class_ghoul = "Ghoul"
+ LANGUAGE.class_headcrab = "Headcrab"
+ LANGUAGE.class_fast_headcrab = "Fast Headcrab"
+ LANGUAGE.class_poison_headcrab = "Poison Headcrab"
+ LANGUAGE.class_the_tickle_monster = "The Tickle Monster"
+ LANGUAGE.class_nightmare = "Nightmare"
+ LANGUAGE.class_pukepus = "Pukepus"
+ LANGUAGE.class_bonemesh = "Bonemesh"
+ LANGUAGE.class_crow = "Crow"
+ LANGUAGE.class_wilowisp = "Wil O' Wisp"
+ LANGUAGE.class_zombie_torso = "Zombie Torso"
+ LANGUAGE.class_zombie_legs = "Zombie Legs"
+ LANGUAGE.class_wraith = "Wraith"
+ LANGUAGE.class_flesh_beast = "Flesh Beast"
+ LANGUAGE.class_fast_zombie_legs = "Fast Zombie Legs"
+ LANGUAGE.class_chem_zombie = "Chem Zombie"
+ LANGUAGE.class_shade = "Shade"
+
+ -- Class descriptions
+ LANGUAGE.description_zombie = "Lo zombie di base è molto resistente e ha dei potenti artigli.\nE' duro da uccidere, specie se non si spara alla testa."
+ LANGUAGE.description_poison_zombie = "Questo zombie mutante non solo è estremamente robusto ma è anche dotato di una forza fuori dal comune.\nIl suo corpo è altamente tossico ed è in grado di strapparsi da solo brani della propria carne per poi lanciarla lontano, ove le sue braccia non giungono."
+ LANGUAGE.description_fast_zombie = "Questo cadavere ossuto è molto più veloce degli altri zombie.\nNon sono una grande minaccia da soli ma sono in grado di raggiungere quasi qualsiasi posto arrampicandosi con i loro artigli affilati.\nInoltre possono facilmente uccidere umani feriti o deboli."
+ LANGUAGE.description_bloated_zombie = "Il loro corpo è ricco di sostanze chimiche tossiche e volatili.\nNonostante si muovano molto lentamente, occorre molto piu danno per buttarli giù."
+ LANGUAGE.description_ghoul = "Questo zombie, anch'esso tossico, è leggermente più debole di altri, ma compensa questo difetto con i suoi attacchi velenosi.\nI suoi artigli possono debilitare un umano per un breve periodo di tempo e può zombie has highly toxic flesh.\nIt's slightly weaker than other zombies but makes up for it with its poison attacks.\nIts claws can debilitate a human for a short time and it will eject poison through its wounds if hit with enough damage."
+ LANGUAGE.description_headcrab = "Gli Headcrabs sono ciò che hanno causato l'infezione iniziale.\nNessuno è a conoscenza della loro origine.\nIl loro modo di attaccare è quello di saltare, mettendo in mostra i loro denti affilati nella loro parte inferiore del corpo."
+ LANGUAGE.description_fast_headcrab = "L'headcrab maschio è decisamente più veloce della femmina, nonostante sia anche meno resistente.\nTuttavia, se sono in gruppo possono essere ugualmente pericolosi."
+ LANGUAGE.description_poison_headcrab = "Questo tipo di Headcrab ha a disposizione delle neurotossine letali.\nUn morso di solito è sufficiente a uccidere un uomo.\nHa anche la facoltà di emettere una versione meno potente del proprio veleno.\n Lo 'sputo' è ugualmente letale se la vittima viene colpita in testa."
+ LANGUAGE.description_the_tickle_monster = "Si dice che sia il mostro che si nasconde nel tuo armadio durante la notte per trascinarti a sè dal tuo letto.\nIl Tickle Monster è dotato di braccia quasi elastiche che gli permettono di rendere difficile la fuga a chiunque viene seguito da esso, e lo rendono anche un ideale distruttore di barricate."
+ LANGUAGE.description_nightmare = "Una mutazione estremamente rara dona al Nightmare le sue abilità paranormali.\nE' molto più forte di ogni altro zombie, tanto da essere la creatura più temibile che esista.\nUn suo attacco è sufficiente a uccidere quasi chiunque."
+ LANGUAGE.description_pukepus = "Il cadavere marcito del Puke Pus è composto interamente da organi adibiti alla produzione di veleno.\n E' capace di scagliare grandi quantità di vomito tossico alla volta, rendendolo estremamente pericoloso."
+ LANGUAGE.description_bonemesh = "Sfigurato e squartato, il Bonemesh è capace di scaraventare bombe di sangue.\nOgni bomba è composta da ossa e carne che ferisce gli umani e al tempo stesso ciba gli altri zombie."
+ LANGUAGE.description_crow = "I corvi corrieri sono più pestiferi rispetto a prima dell'infezione.\nSi cibano di carne infetta e diventano quindi corrieri per i non-morti.\nPerché ignorare questa classe?\nChe problemi hai?."
+ LANGUAGE.description_wilowisp = "Spesso riferito ai spiriti dei morti."
+ LANGUAGE.description_zombie_torso = "Non dovresti neanche vederlo."
+ LANGUAGE.description_zombie_legs = "Non dovresti neanche vederlo."
+ LANGUAGE.description_wraith = "Uno zombie o un'apparizione?\nNon si sa molto su di esso a parte il fatto che usi la sua\nUnica abilità di nascondersi e le sue unghie affilate per affettare ogni cosa."
+ LANGUAGE.description_flesh_beast = "*Lavori in corso*"
+ LANGUAGE.description_fast_zombie_legs = "Non dovresti neanche vederlo."
+ LANGUAGE.description_chem_zombie = "il Chem Zombie è formato da composti chimici tossici e volatili.\n Non ha altri modi per attaccare se non quello di farsi uccidere nelle vicinanze degli umani, per poi esplodere ferendoli."
+ LANGUAGE.description_shade = "Creando un forte campo magnetico attorno a se stesso, tutti i proiettili e attacchi ravvicinati vengono resi inutili contro di esso.\nTuttavia, per qualche strana ragione, lo Shade è vulnerabile alla luce chiara."
+
+ -- Class control schemes
+ LANGUAGE.controls_zombie = "> PRIMARIO: Artigli\n> SECONDARIO: Urlo\n> RICARICA: Lamento\n> SPRINT: Finta morte\n> Ucciso colpito alle gambe: Resurrezione / Trasformazione"
+ LANGUAGE.controls_poison_zombie = "> PRIMARIO: Artigli\n> SECONDARIO: Lancio di carne\n> RICARICA: Urlo"
+ LANGUAGE.controls_fast_zombie = "> PRIMARIO: Artigli\n> SECONDARIO: Slancio / Arrampicarsi (vicino ad un muro)\n> RICARICA: Urlo"
+ LANGUAGE.controls_bloated_zombie = "> PRIMARIO: Artigli\n> SECONDARIO: Lamento\n> SCATTO: Finta morte\n> ALLA MORTE: Budella velenose"
+ LANGUAGE.controls_ghoul = "> PRIMARIO: Artigli di veleno\n> SECONDARY: Lancio di carne\n> SCATTO: Finta morte\n> RICARICA: Urlo\n> COLPENDO UN UMANO: Rallentamento\n> COLPITO DA UN UMANO: Emissione di veleno"
+ LANGUAGE.controls_headcrab = "> PRIMARIO: Slancio\n> RICARICA: Seppellimento"
+ LANGUAGE.controls_fast_headcrab = "> PRIMARIO: Slancio"
+ LANGUAGE.controls_poison_headcrab = "> PRIMARIO: Slancio\n> SECONDARIO: Sputa veleno\n> COLPENDO UN UMANO: Veleno letale\n> COLPENDO AGLI OCCHI: Cecità \n> RICARICA: Urlo"
+ LANGUAGE.controls_the_tickle_monster = "> PRIMARIO: Unghie elastiche\n> SECONDARIO: Lamento"
+ LANGUAGE.controls_nightmare = "> PRIMARIO: Tocco della morte\n> SECONDARIO: Lamento"
+ LANGUAGE.controls_pukepus = "> PRIMARIO: Vomito"
+ LANGUAGE.controls_bonemesh = "> PRIMARIO: Artigli\n> SECONDARIO: Lancio bomba di sangue"
+ LANGUAGE.controls_wraith = "> PRIMARIO: Artigli\n> SECONDARIO: Urlo\n> INVISIBILITA' BASATA SULLA VISIBILITA' E SULLA DISTANZA"
+ LANGUAGE.controls_flesh_beast = "> PRIMARIO: Artigli\n> SECONDARIO: Testata"
+ LANGUAGE.controls_chem_zombie = "> ALLA MORTE: Bomba velenosa"
+ LANGUAGE.controls_shade = "> PRIMARIO: Solleva\n> SECONDARIO: Lancio"
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/languages/korean.lua b/gamemodes/zombiesurvival/gamemode/languages/korean.lua
new file mode 100644
index 0000000..4041273
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/languages/korean.lua
@@ -0,0 +1,318 @@
+-- Translated by honsal (http://www.noxiousnet.com/forums/index.php?action=profile;u=6435)
+
+translate.AddLanguage("ko", "Korean")
+
+LANGUAGE.minute_points_added = "1분 ë™ì•ˆ ë°ë¯¸ì§€ë¥¼ 받지 ì•Šì•„ %dí¬ì¸íŠ¸ë¥¼ 얻었다!"
+LANGUAGE.infliction_reached_class_unlocked = "%d%%ì˜ ì¸ê°„ì´ ê°ì—¼ë˜ì–´ %sì´(ê°€) í’€ë ¤ë‚¬ë‹¤!"
+LANGUAGE.infliction_reached = "ì¸ê°„ 중 %d%%ê°€ 먹혔다!"
+LANGUAGE.x_unlocked = "%sì´(ê°€) í’€ë ¤ë‚¬ë‹¤!"
+LANGUAGE.disconnect_killed = "%sì´(ê°€) %sì—게 살해당해 ë¹¡ì¢…í•´ë²„ë ¸ë‹¤."
+LANGUAGE.nail_removed_by = "%sì´(ê°€) %sì˜ ëª»ì„ ëºë‹¤."
+LANGUAGE.banned_for_life_warning = "현재 ìƒí™œì´ 금지당한 ìƒíƒœë¼ì„œ ì•„ë¬´ê²ƒë„ ì‚´ 수 없어!"
+LANGUAGE.need_to_be_near_arsenal_crate = "ì•„ì´í…œì„ êµ¬ë§¤í•˜ë ¤ë©´ ìƒì ìƒìžê°€ ê·¼ì²˜ì— ìžˆì–´ì•¼ 한다!"
+LANGUAGE.cant_purchase_right_now = "ì§€ê¸ˆì€ ì•„ë¬´ê²ƒë„ êµ¬ë§¤í• ìˆ˜ 없다."
+LANGUAGE.dont_have_enough_points = "í¬ì¸íŠ¸ê°€ 부족하다."
+LANGUAGE.prepare_yourself = "ìŠµê²©ì— ëŒ€ë¹„í•˜ìž..."
+LANGUAGE.purchased_x_for_y_points = "%sì„(를) %dí¬ì¸íŠ¸ì— 구매했다!"
+LANGUAGE.give_time_before_suicide = "ìžì‚´í•˜ê¸° ì „ì—, 팀ì›ì´ ëŒ€ë¹„í• ì‹œê°„ì„ ì¤˜ë¼."
+LANGUAGE.no_spare_ammo_to_give = "ì—¬ë¶„ì˜ íƒ„ì°½ì´ ì—†ë‹¤!"
+LANGUAGE.no_person_in_range = "범위 ì•ˆì— ì‚¬ëžŒì´ ì—†ë‹¤!"
+LANGUAGE.that_life = "ì¼ìƒë™ì•ˆ..."
+LANGUAGE.x_damage_to_barricades = "%d ë°ë¯¸ì§€ë¥¼ 바리케ì´ë“œì— 가함"
+LANGUAGE.x_damage_to_humans = "%d ë°ë¯¸ì§€ë¥¼ ì¸ê°„ì—게 가함"
+LANGUAGE.x_brains_eaten = "%dê°œì˜ ë‡Œë¥¼ 먹어치움"
+LANGUAGE.press_rmb_to_cycle_targets = "오른쪽 í´ë¦ìœ¼ë¡œ 타겟 변경"
+LANGUAGE.press_lmb_to_spawn_on_them = "왼쪽 í´ë¦ìœ¼ë¡œ ì´ ìœ„ì¹˜ì—ì„œ 부활"
+LANGUAGE.press_lmb_to_spawn = "왼쪽 í´ë¦ìœ¼ë¡œ 부활"
+LANGUAGE.observing_x = "ê´€ì¹ ì¤‘: %s (%d)"
+LANGUAGE.waiting_for_next_wave = "ë‹¤ìŒ ì›¨ì´ë¸Œê°€ 시작ë˜ê¸¸ 기다리는 중..."
+LANGUAGE.impossible = "불가능하다."
+LANGUAGE.trying_to_put_nails_in_glass = "맙소사! ë‚´ê°€ ìœ ë¦¬ì— ëª»ì„ ë°•ìœ¼ë ¤ 했어!"
+
+LANGUAGE.boss_class_select = "다ìŒë¶€í„°ëŠ” %s(으)ë¡œ 부활하게 ëœë‹¤."
+LANGUAGE.person_has_weapon = "ì´ë¯¸ ê·¸ 무기를 ê°€ì§€ê³ ìžˆë‹¤."
+LANGUAGE.cant_do_that_in_classic_mode = "í´ëž˜ì‹ 모드ì—ì„ ë¶ˆê°€ëŠ¥í•˜ë‹¤."
+LANGUAGE.cant_use_x_in_classic_mode = "í´ëž˜ì‹ 모드ì—ì„ %sì„(를) ì‚¬ìš©í• ìˆ˜ 없다."
+LANGUAGE.cant_use_x_in_zombie_escape = "좀비 탈출ì—서는 %sì„(를) ì‚¬ìš©í• ìˆ˜ 없다."
+LANGUAGE.no_class_switch_in_this_mode = "현재 모드는 í´ëž˜ìŠ¤ ë³€ê²½ì„ ì§€ì›í•˜ì§€ 않는다."
+LANGUAGE.press_sprint_to_get_up = "달리기 키를 눌러 ì¼ì–´ë‚¨"
+LANGUAGE.zombie_escape = "[좀비 탈출]"
+LANGUAGE.nothing_for_this_ammo = "ì´ íƒ„í™˜ì„ ì‚¬ìš©í• ìˆ˜ 있는 ì´ê¸°ê°€ 없다."
+LANGUAGE.you_decide_to_leave_some = "팀ì›ì„ 위해 남겨ë‘기로 ì •í–ˆë‹¤."
+LANGUAGE.you_cant_purchase_now = "ì§€ê¸ˆì€ ì•„ë¬´ê²ƒë„ êµ¬ë§¤í• ìˆ˜ 없다."
+LANGUAGE.no_ammo_here = "ì•„ì§ íƒ„ì•½ì´ ì¤€ë¹„ë˜ì§€ 않았다."
+LANGUAGE.you_redeemed = "성불!"
+LANGUAGE.kill_the_last_human = "마지막 ì¸ê°„ì„ ì£½ì—¬!"
+LANGUAGE.kick_the_last_human = "마지막 ì¸ê°„ì„ ì£½ì—¬ë²„ë ¤!"
+LANGUAGE.you_are_the_last_human = "네가 ì¸ê°„ì˜ ë§ˆì§€ë§‰ í¬ë§ì´ì•¼!"
+LANGUAGE.x_zombies_out_to_get_you = "%dë§ˆë¦¬ì˜ ì¢€ë¹„ê°€ ë„ ìž¡ê¸° 위해 ë‹¬ë ¤ì˜¨ë‹¤!"
+LANGUAGE.x_pants_out_to_get_you = "%dë§ˆë¦¬ì˜ ë§í• 시체가 너ì—게 다가온다!"
+LANGUAGE.you_have_died = "죽ìŒ."
+LANGUAGE.you_were_killed_by_x = "%sì—게 살해당함"
+LANGUAGE.you_were_kicked_by_x = "%sì´(ê°€) ì •ê°•ì´ë¥¼ ê±·ì–´ì°¸"
+LANGUAGE.arsenal_upgraded = "ë¬´ê¸°ê³ ì— ì¶”ê°€ë¨"
+LANGUAGE.final_wave = "마지막 웨ì´ë¸Œê°€ 시작ë˜ì—ˆë‹¤!"
+
+LANGUAGE.final_wave_sub = "ëª¨ë“ ì¢€ë¹„ê°€ í’€ë ¤ë‚¬ê³ , ì´ì œë¶€í„° ì„±ë¶ˆí• ìˆ˜ 없다!"
+LANGUAGE.wave_x_has_begun = "%d번째 웨ì´ë¸Œê°€ 시작ë다!"
+LANGUAGE.x_unlocked = "%sì´(ê°€) í’€ë ¤ë‚¬ë‹¤!"
+LANGUAGE.wave_x_is_over = "%d번째 웨ì´ë¸Œê°€ ë났다."
+
+LANGUAGE.wave_x_is_over_sub = "ì¢€ë¹„ë“¤ì˜ ìŠµê²©ì´ ì§€ì—°ëê³ , ìƒì ì—ì„œ %d%% í• ì¸ëœ 가격으로 ë¬¼í’ˆì„ íŒë§¤ì¤‘ì´ë‹¤."
+LANGUAGE.you_are_x = "%s(으)로 부활했다!"
+LANGUAGE.x_has_risen_as_y = "%sì´(ê°€) %s(으)ë¡œ 부활했다!!"
+LANGUAGE.x_has_risen = "%sì´(ê°€) 나타났다!"
+LANGUAGE.cant_use_worth_anymore = "ë”는 ìžê¸ˆì„ ì‚¬ìš©í• ìˆ˜ 없다!"
+LANGUAGE.class_not_unlocked_will_be_unlocked_x = "해당 좀비는 ì•„ì§ í’€ë ¤ë‚˜ì§€ 않았다. %d웨ì´ë¸Œ ì´í›„ì— í’€ë ¤ë‚œë‹¤."
+LANGUAGE.you_are_already_a_x = "ì´ë¯¸ %sì´ë‹¤."
+LANGUAGE.you_will_spawn_as_a_x = "ì´ì œ %s(으)ë¡œ 부활한다."
+LANGUAGE.crafting_successful = "조합 성공!"
+LANGUAGE.x_crafted_y = "%sì´(ê°€) %sì„(를) 조합했다."
+LANGUAGE.escape_from_the_zombies = "좀비로부터 탈출하ë¼!"
+LANGUAGE.too_close_to_another_nail = "다른 ëª»ì´ ë„ˆë¬´ ê°€ê¹Œì´ ìžˆë‹¤."
+LANGUAGE.object_too_damaged_to_be_used = "ê·¸ ë¬¼ê±´ì€ ë‹¤ì‹œ ì‚¬ìš©í•˜ê¸°ì— ë„ˆë¬´ 훼ì†ë다."
+LANGUAGE.thanks_for_being_a_fan_of_zs = "좀비 서바ì´ë²Œì˜ íŒ¬ì´ ë˜ì–´ì£¼ì…”ì„œ ê°ì‚¬í•œë‹¤!"
+LANGUAGE.cant_remove_nails_of_superior_player = "ë” ë›°ì–´ë‚œ í”Œë ˆì´ì–´ì˜ ëª»ì€ ì œê±°í• ìˆ˜ 없다."
+LANGUAGE.x_turned_on_noclip = "%s turned on noclip."
+LANGUAGE.x_turned_off_noclip = "%s turned off noclip."
+LANGUAGE.unlocked_on_wave_x = "%d웨ì´ë¸Œì— í’€ë ¤ë‚œë‹¤."
+LANGUAGE.brains_eaten_x = "먹어치운 뇌: %s개"
+LANGUAGE.points_x = "í¬ì¸íŠ¸: %sí¬ì¸íŠ¸"
+LANGUAGE.next_wave_in_x = "ë‹¤ìŒ ì›¨ì´ë¸Œê¹Œì§€: %sì´ˆ"
+LANGUAGE.wave_ends_in_x = "웨ì´ë¸Œê°€ ë나기까지: %sì´ˆ"
+LANGUAGE.wave_x_of_y = "%d웨ì´ë¸Œ 중 %d웨ì´ë¸Œ"
+LANGUAGE.zombie_invasion_in_x = "ì¢€ë¹„ë“¤ì˜ ìŠµê²©ê¹Œì§€: %sì´ˆ"
+LANGUAGE.intermission = "íœ´ì‹ ì‹œê°„"
+LANGUAGE.press_f2_for_the_points_shop = "F2를 눌러 ìƒì 사용!"
+LANGUAGE.breath = "O2"
+LANGUAGE.zombie_volunteers = "좀비 지ì›ìž 목ë¡"
+LANGUAGE.x_discount_for_buying_between_waves = "웨ì´ë¸Œ 사ì´ì—” %d í• ì¸ëœ 가격으로 íŒë§¤í•œë‹¤!"
+LANGUAGE.number_of_initial_zombies_this_game = "ì´ë²ˆ ë¼ìš´ë“œ 시작 ì‹œ ìŠµê²©í• ì¢€ë¹„ 수 (%d%%): %d마리"
+LANGUAGE.humans_closest_to_spawns_are_zombies = "좀비 ìŠ¤í° ì§€ì—ì— ê°€ê¹Œìš´ ì¸ê°„ì´ ì¢€ë¹„ê°€ ëœë‹¤."
+LANGUAGE.waiting_for_players = "í”Œë ˆì´ì–´ 기다리는 중..."
+LANGUAGE.requires_x_people = "%dëª…ì´ í•„ìš”í•¨"
+LANGUAGE.packing_others_object = "다른 ì‚¬ëžŒì˜ ë¬¼ê±´ 집는 중"
+LANGUAGE.packing = "집는 중"
+LANGUAGE.ze_humans_are_frozen_until_x = "ë¼ìš´ë“œ 시작 ì „ %d초까지 ì–¼ìŒ ìƒíƒœ."
+LANGUAGE.loading = "로딩 중..."
+LANGUAGE.next_round_in_x = "ë‹¤ìŒ ë¼ìš´ë“œê¹Œì§€: %s"
+LANGUAGE.warning = "ê²½ê³ !"
+LANGUAGE.ok_and_no_reminder = "ì‘, 다시 ë„우지 마"
+
+LANGUAGE.classic_mode_warning = "ì´ ì„œë²„ëŠ” 'í´ëž˜ì‹ 모드'ì—ì„œ ìž‘ë™ ì¤‘ì´ë‹¤.\ní´ëž˜ì‹ 모드ì—ì„ ê²Œìž„ ë°©ì‹ì— 커다란 변화가 ìƒê¹ë‹ˆë‹¤. 바뀌는 ì :\n* 좀비 종류를 ë³€ê²½í• ìˆ˜ 없다. ëª¨ë“ ì¢€ë¹„ëŠ” í´ëž˜ì‹ 좀비를 사용하게 ëœë‹¤.\n* 못, í„°ë ›ê³¼ ê°™ì€ ë°”ë¦¬ì¼€ì´ë”© íˆ´ì„ ì‚¬ìš©í• ìˆ˜ 없다.\n* 웨ì´ë¸Œê°€ ë” ë§Žì§€ë§Œ, ë” ë¹¨ë¦¬ 진행ëœë‹¤.\n\nê·¸ë ‡ë‹¤ê³ í•´ì„œ ì´ ëª¨ë“œê°€ ì˜¤ë¦¬ì§€ë„ ì¢€ë¹„ 서바ì´ë²Œ 모드는 아닙니다!\n\n-- í´ëž˜ì‹ 모드ì—ì„œ ìš´ì˜ ì¤‘ì¸ ì„œë²„ëŠ” 왼쪽 ì•„ëž˜ì— í´ëž˜ì‹ 모드 표시가 ë³´ì´ë‹¤ --"
+LANGUAGE.classic_mode = "í´ëž˜ì‹ 모드"
+LANGUAGE.resist_x = "ì €í•ë ¥: %d%%"
+LANGUAGE.right_click_to_hammer_nail = "오른쪽 í´ë¦ìœ¼ë¡œ 못 박기."
+LANGUAGE.nails_x = "못: %d"
+LANGUAGE.resupply_box = "보급 ìƒìž"
+LANGUAGE.purchase_now = "ì§€ë¦„ì‹ ê°•ë¦¼!"
+LANGUAGE.integrity_x = "내구ë„: %d%%"
+LANGUAGE.empty = "비어 있ìŒ"
+LANGUAGE.manual_control = "ìˆ˜ë™ ì¡°ìž‘"
+LANGUAGE.arsenal_crate = "ìƒì ìƒìž"
+
+-- Exit point objectives
+LANGUAGE.exit_destroyed = "ì¢€ë¹„ë“¤ì´ ì¶œêµ¬ë¥¼ 부쉈다!"
+LANGUAGE.exit_destroyed_only_one_remain_h = "마지막 í•˜ë‚˜ë§Œì´ ë‚¨ì•˜ë‹¤! 만약 ì´ë§ˆì € 부서진다면 ë” ì´ìƒì˜ í¬ë§ì€ 없다!"
+LANGUAGE.exit_destroyed_only_one_remain_z = "마지막 í•˜ë‚˜ë§Œì´ ë‚¨ì•˜ë‹¤!"
+LANGUAGE.exit_destroyed_x_remain = "%dê°œì˜ ì¶œêµ¬ê°€ 남아있ìŒ."
+LANGUAGE.last_exit_destroyed_all_is_lost = "ì¢€ë¹„ë“¤ì´ ë§ˆì§€ë§‰ 출구를 ë¶€ìˆ´ë²„ë ¸ë‹¤."
+LANGUAGE.last_exit_destroyed_all_is_lost2 = "ë” ì´ìƒì˜ 아무런 í¬ë§ì´ 없다."
+
+-- Message beacon messages
+LANGUAGE.message_beacon_1 = "여기서 만나ìž"
+LANGUAGE.message_beacon_2 = "여기를 방어해야 한다"
+LANGUAGE.message_beacon_3 = "ì—¬ê¸°ì— í„°ë ›ì„ ì„¤ì¹˜í•´ì•¼ 한다"
+LANGUAGE.message_beacon_4 = "ì—¬ê¸°ì— ìƒì ì´ í•„ìš”í•˜ë‹¤"
+LANGUAGE.message_beacon_5 = "ì—¬ê¸°ì— ì˜ë¬´ë³‘ì´ í•„ìš”í•˜ë‹¤"
+LANGUAGE.message_beacon_6 = "여기 탄약 박스가 있다"
+LANGUAGE.message_beacon_7 = "여기 ìƒì ì´ ìžˆë‹¤"
+LANGUAGE.message_beacon_8 = "여기 í¬ìŠ¤í•„드가 필요하다"
+LANGUAGE.message_beacon_9 = "여기 íë°œë¬¼ì´ í•„ìš”í•˜ë‹¤"
+LANGUAGE.message_beacon_10 = "ì¢€ë¹„ë“¤ì´ ì—¬ê¸¸ 통해 온다"
+LANGUAGE.message_beacon_11 = "들어가지 마!!"
+LANGUAGE.message_beacon_12 = "나가지 마ë¼"
+LANGUAGE.message_beacon_13 = "ì´ ì§€ì—ì„ ë°©ì–´í•˜ë¼"
+LANGUAGE.message_beacon_14 = "ì´ ì§€ì ì„ ë°©ì–´í•˜ë¼"
+LANGUAGE.message_beacon_15 = "ì˜ë¬´ë³‘ì´ ìžˆë‹¤"
+LANGUAGE.message_beacon_16 = "ë‚´ ìƒì ì—ì„œ 구매해 줘"
+LANGUAGE.message_beacon_17 = "바리케ì´ë“œê°€ 있다"
+LANGUAGE.message_beacon_18 = "ì´ê³³ì—” 바리케ì´ë“œë¥¼ 건설하지 마ë¼"
+LANGUAGE.message_beacon_19 = "좀비를 í•œ ë°œì§ë„ 들ì´ì§€ ë§ë¼"
+LANGUAGE.message_beacon_20 = "ì´ê±´ 곧 부서진다"
+LANGUAGE.message_beacon_21 = "ì´ ìž¥ì†ŒëŠ” 위험하다!"
+LANGUAGE.message_beacon_22 = "ë…ì„ ì¡°ì‹¬í•´!"
+LANGUAGE.message_beacon_23 = "ì¢€ë¹„ë“¤ì´ ì´ê³³ì„ 통해 나타난다!"
+LANGUAGE.message_beacon_24 = "ì¢€ë¹„ë“¤ì´ ë‹¤ê°€ì˜¨ë‹¤. 바리케ì´ë“œë¥¼ 건설해!"
+LANGUAGE.message_beacon_25 = "ìž‘ì „ B 지ì—"
+
+-- Class names
+LANGUAGE.class_zombie = "좀비"
+LANGUAGE.class_poison_zombie = "í¬ì´ì¦Œ 좀비"
+LANGUAGE.class_fast_zombie = "패스트 좀비"
+LANGUAGE.class_bloated_zombie = "부푼 좀비"
+LANGUAGE.class_classic_zombie = "í´ëž˜ì‹ 좀비"
+LANGUAGE.class_super_zombie = "ìŠˆí¼ ì¢€ë¹„"
+LANGUAGE.class_fresh_dead = "ì‹ ì„ í•œ 시체"
+LANGUAGE.class_ghoul = "구울"
+LANGUAGE.class_headcrab = "헤드í¬ëž©"
+LANGUAGE.class_fast_headcrab = "패스트 헤드í¬ëž©"
+LANGUAGE.class_poison_headcrab = "í¬ì´ì¦Œ 헤드í¬ëž©"
+LANGUAGE.class_the_tickle_monster = "í‹°í´ ëª¬ìŠ¤í„°"
+LANGUAGE.class_nightmare = "나ì´íŠ¸ë©”ì–´"
+LANGUAGE.class_pukepus = "푸í¬í¼ìŠ¤"
+LANGUAGE.class_bonemesh = "본매쉬"
+LANGUAGE.class_crow = "까마귀"
+LANGUAGE.class_wilowisp = "Wil O' Wisp"
+LANGUAGE.class_zombie_torso = "좀비 몸통"
+LANGUAGE.class_zombie_legs = "좀비 다리"
+LANGUAGE.class_wraith = "ë§ë ¹"
+LANGUAGE.class_flesh_beast = "ê°ì—¼ëœ 맹수"
+LANGUAGE.class_fast_zombie_legs = "패스트 좀비 다리"
+LANGUAGE.class_chem_zombie = "챔 좀비"
+LANGUAGE.class_shade = "ì…°ì´ë“œ"
+
+-- Class descriptions
+LANGUAGE.description_zombie = "ì²´ë ¥ë„ ì¢‹ê³ íž˜ë„ ì“¸ë§Œí•œ 좀비.\n머리를 맞지 않는다면 죽ì´ê¸°ê°€ ì–´ë µë‹¤."
+LANGUAGE.description_poison_zombie = "ì´ ëŒì—°ë³€ì´ 좀비는 ê°•ë ¥í• ë¿ ì•„ë‹ˆë¼ íŠ¹ìˆ˜í•œ ëŠ¥ë ¥ë„ ê°–ê³ ìžˆë‹¤.\nì´ ì¢€ë¹„ì˜ ëª¸ì€ êµ‰ìž¥í•œ ë…성으로 ì´ë¤„ì ¸ 있으며 ì‚´ì ì„ ëœ¯ì–´ 멀리 ë˜ì§ˆ 수 있다."
+LANGUAGE.description_fast_zombie = "ì´ ë¼ˆë°–ì— ì•ˆ ë‚¨ì€ ì¢€ë¹„ëŠ” 다른 좀비들보다 훨씬 ë¹ ë¥´ë‹¤.\në‚ ì¹´ë¡œìš´ ì†í†±ê³¼ ë°œí†±ì„ ì‚¬ìš©í•´ ë²½ì„ ê¸°ì–´ì˜¤ë¥¼ 수 있다.\në˜í•œ, 약해진 ì¸ê°„ì„ ìž¡ê¸°ì— ì „í˜€ 무리가 ì—†ì„ ì •ë„ë¡œ 충분히 위협ì ì´ë‹¤."
+LANGUAGE.description_bloated_zombie = "ì´ ì¢€ë¹„ì˜ ëª¸ì²´ëŠ” ìœ ë…í•œ 휘발성 물질로 êµ¬ì„±ë¼ ìžˆë‹¤.\nëŠë¦¬ê²Œ ì´ë™í•˜ì§€ë§Œ 충분히 위험하다."
+LANGUAGE.description_ghoul = "ì´ ì¢€ë¹„ëŠ” 강산성 피부를 ê°–ê³ ìžˆë‹¤.\n다른 좀비들보단 약간 약하지만, ë…ì„ ë˜ì§ˆ 수 있는 ëŠ¥ë ¥ì´ ìžˆë‹¤.\nì´ ì¢€ë¹„ì˜ ê³µê²©ì„ ì¸ê°„ì´ ë§žëŠ”ë‹¤ë©´ ê·¸ ì¸ê°„ì€ ëŠë ¤ì§€ê²Œ ë˜ê³ , ë…ì€ ëŠë ¤ì§€ê³ 약해진 ì¸ê°„ì„ ìž¡ê¸°ì— ì¶©ë¶„í•˜ë‹¤."
+LANGUAGE.description_headcrab = "헤드í¬ëž©ì€ 대규모 ê°ì—¼ì‚¬íƒœ ì´ˆê¸°ì— ë°œê²¬ëœ ì¢€ë¹„ì´ë‹¤.\n현재까지 ê·¸ ëˆ„êµ¬ë„ ì´ ì¢€ë¹„ê°€ 어디서 왔는지 모른다.\nì´ë“¤ì€ ë°°ì— ìžˆëŠ” ë‚ ì¹´ë¡œìš´ ì´ë¹¨ì„ 사용해 물어뜯는다."
+LANGUAGE.description_fast_headcrab = "수컷 헤드í¬ëž©ì€ 암컷보다 ë¹ ë¥´ì§€ë§Œ, 그보다는 약하다.\n그러나 만약 ì´ ì¢€ë¹„ê°€ ì¸ê°„들 집단 사ì´ì— 난입한다면, ìƒë‹¹ížˆ 위협ì ì¸ ì¡´ìž¬ê°€ ëœë‹¤."
+LANGUAGE.description_poison_headcrab = "ì´ í—¤ë“œí¬ëž©ì€ ë¸”ëž™ë§˜ë°”ì˜ ë…ì„ ê°–ê³ ìžˆë‹¤.\ní•œ 번 물면 ì„±ì¸ í•œ ëª…ì€ ê°€ë³ê²Œ 죽ì´ëŠ” ë…ì„±ì„ ì§€ë…”ë‹¤.\në…ì„ ë±‰ì„ ìˆ˜ 있는 ëŠ¥ë ¥ì´ ìžˆë‹¤.\n만약 ë…ì´ ì–¼êµ´ì— ë§žì•˜ë‹¤ë©´, ì¼ì‹œì 으로 ì‹¤ëª…ì„ í•˜ê²Œ ëœë‹¤."
+LANGUAGE.description_the_tickle_monster = "ë‹¹ì‹ ì´ ìž ë“ ë°¤, 장롱 ì†ì— 숨어있다가 침대로부터 ë‹¹ì‹ ì„ ëŒì–´ë‚´ì–´ 죽ì¸ë‹¤ëŠ” 괴물.\ní‹°í´ ëª¬ìŠ¤í„°ì˜ ìžìœ ìžìž¬ë¡œ 늘어나는 íŒ”ì€ ì¸ê°„ë“¤ì´ ë„ë§ê°ˆ 수 없게 í•˜ê³ ,\nì¸ê°„ë“¤ì˜ ì‚¬ê°ì§€ëŒ€ì—ì„œ 바리케ì´ë“œë¥¼ ë¶€ìˆ˜ëŠ”ë° ì•„ì£¼ ìœ ìš©í•˜ë‹¤."
+LANGUAGE.description_nightmare = "ì•Œ 수 없는 ëŒì—°ë³€ì´ë¥¼ 거친 나ì´íŠ¸ë©”어는 굉장히 비ìƒì‹ì ì¸ ëŠ¥ë ¥ì„ ì§€ë‹ˆê²Œ ë다.\nê±°ì˜ ëª¨ë“ ê²½ìš°ì—ì„œ, 존재하는 ì–´ë– í•œ 좀비보다 ê°•ë ¥í•œ íž˜ì„ ì§€ë…”ë‹¤.\n단 í•œ ë²ˆì˜ í• í„ë§Œìœ¼ë¡œë„ ì¸ê°„ì„ ë„‰ë‹¤ìš´ ì‹œí‚¤ê¸°ì— ì¶©ë¶„í•˜ë‹¤."
+LANGUAGE.description_pukepus = "ì´ ì¢€ë¹„ì˜ ìž¥ê¸°ëŠ” ë…ì„ ìƒì„±í•˜ëŠ” ë°ì— 특화ë다.\n푸í¬í¼ìŠ¤ì˜ ë…ì„ í† í•´ë‚´ëŠ” 공격 ë°©ì‹ì€, ê·¼ì ‘í•œ ì¸ê°„ì—게 있어 ê³µí¬ì˜ 대ìƒì´ë‹¤."
+LANGUAGE.description_bonemesh = "ì´ ì¢€ë¹„ëŠ” ê³ ê¹ƒë©ì–´ë¦¬ë¥¼ ë‰ì³ ë˜ì§„다.\nê°ê°ì˜ ê³ ê¹ƒë©ì´ëŠ” 공격하는 ë°ì—ë„ ì“°ì´ì§€ë§Œ, ì•„êµ° 좀비가 ê¸°ë ¥ì„ ë˜ì°¼ëŠ”ë° ì“°ì´ê¸°ë„ 한다."
+LANGUAGE.description_crow = "[ë°ì´í„° ë§ì†Œ]"
+LANGUAGE.description_wilowisp = "Sometimes referred to as spirits of the dead."
+LANGUAGE.description_zombie_torso = "You shouldn't even be seeing this."
+LANGUAGE.description_zombie_legs = "You shouldn't even be seeing this."
+
+LANGUAGE.description_wraith = "좀비, í˜¹ì€ ìœ ë ¹?\nì´ ê°œì²´ì— ëŒ€í•´ì„œëŠ” ì•Œë ¤ì§„ ê²ƒì´ ë§Žì§€ 않지만\në§ë ¹ë§Œì˜ 특별한 스텔스 기능과 ë‚ ì¹´ë¡œìš´ ì†í†±ì€ 세ìƒì˜ ì–´ë–¤ ìœ ë ¹ë³´ë‹¤ ê°•ë ¥í•˜ë‹¤."
+LANGUAGE.description_flesh_beast = "*pending*"
+LANGUAGE.description_fast_zombie_legs = "You shouldn't even be seeing this."
+
+
+LANGUAGE.description_chem_zombie = "ì±” ì¢€ë¹„ì˜ ëª¸ì€ ê°ì¢… ë…성 화학물질로 구성ë˜ì–´ 있다.\nì±” 좀비는 ê³µê²©í• ìˆ˜ 없지만,\nì£½ì„ ë•Œì— ê°•ë ¥í•œ íë°œì„ ì¼ìœ¼ì¼œ ì£¼ë³€ì˜ ëª¨ë“ ì¸ê°„ ë° ë°”ë¦¬ì¼€ì´ë“œì— ë°ë¯¸ì§€ë¥¼ 가한다."
+LANGUAGE.description_shade = "ìžì‹ ì˜ ì£¼ë³€ì— ê°•ë ¥í•œ ìžê¸°ìž¥ì„ 형성하므로ì¨, ëª¨ë“ ê³µê²©ì„ ë¬´íš¨í™”ì‹œí‚¨ë‹¤.\n그러나 ì–´ë–¤ ì´ìœ ì—ì„ ì§€ ê°•í•œ ë¹›ì— ì•½í•œ ëª¨ìŠµì„ ë³´ì¸ë‹¤."
+
+-- Class control schemes
+
+LANGUAGE.controls_zombie = "> 공격 1: í• í„\n> 공격 2: 울부짖ìŒ\n> ìž¬ìž¥ì „: ì‹ ìŒ\n> 달리기: 죽ì€ì²™ 함\n> ë‹¤ë¦¬ì— ì¹˜ëª…ì ê³µê²©ì„ ë°›ì•˜ì„ ì‹œ: 부활 / 변형"
+LANGUAGE.controls_poison_zombie = "> 공격 1: í• í„\n> 공격 2: ì‚´ì ë˜ì§€ê¸°\n> ìž¬ìž¥ì „: 울부짖ìŒ"
+LANGUAGE.controls_fast_zombie = "> 공격 1: í• í„\n> 공격 2: ë‹¬ë ¤ë“¦ / ë²½ 타기 (ë²½ ì•žì—ì„œ)\n> ìž¬ìž¥ì „: 울부짖ìŒ"
+LANGUAGE.controls_bloated_zombie = "> 공격 1: í• í„\n> 공격 2: ì‹ ìŒ\n> 달리기: 죽ì€ì²™ 함\n> ì£½ì„ ë•Œ: ë… ì기"
+
+LANGUAGE.controls_ghoul = "> 공격 1: ë… í• í„\n> 공격 2: ì‚´ì ë˜ì§€ê¸°\n> 달리기: 죽ì€ì²™ 함\n> ìž¬ìž¥ì „: 울부짖ìŒ\n> ì¸ê°„ì„ ë§žì·„ì„ ì‹œ: ëŒ€ìƒ ëŠë ¤ì§\n> ì¸ê°„ì—게 ê³µê²©ë°›ì„ ì‹œ: ë… ì£¼ìž…"
+LANGUAGE.controls_headcrab = "> 공격 1: ë‹¬ë ¤ë“¦ \n> ìž¬ìž¥ì „: 버로우"
+LANGUAGE.controls_fast_headcrab = "> 공격 1: ë‹¬ë ¤ë“¦ "
+
+LANGUAGE.controls_poison_headcrab = "> 공격 1: ë‹¬ë ¤ë“¦ \n> 공격 2: ë… ë°œì‚¬\n> ì¸ê°„ì„ ë§žì·„ì„ ì‹œ: ìƒíƒœì´ìƒ 'ë…'\n> ëˆˆì— ì 중 ì‹œ: ì¼ì‹œ 실명\n> ìž¬ìž¥ì „: 울부짖ìŒ"
+LANGUAGE.controls_the_tickle_monster = "> 공격 1: 늘어나며 í• í„\n> 공격 2: ì‹ ìŒ"
+LANGUAGE.controls_nightmare = "> 공격 1: í• í„\n> 공격 2: ì‹ ìŒ"
+LANGUAGE.controls_pukepus = "> 공격 1: í† í•¨"
+LANGUAGE.controls_bonemesh = "> 공격 1: í• í„\n> 공격 2: 피 í탄 ë˜ì§"
+
+LANGUAGE.controls_wraith = "> 공격 1: í• í„\n> 공격 2: 울부짖ìŒ\n> 패시브: ì´ë™ê³¼ ê±°ë¦¬ì— ë”°ë¥¸ íˆ¬ëª…ë„ ë³€í™”"
+LANGUAGE.controls_flesh_beast = "> 공격 1: í• í„\n> 공격 2: 박치기"
+LANGUAGE.controls_chem_zombie = "> ì£½ì„ ë•Œ: ë… í탄"
+LANGUAGE.controls_shade = "> 공격 1: 들기\n> 공격 2: ë˜ì§€ê¸°"
+
+-- The help file... Quite big! I wouldn't blame you if you didn't translate this part.
+LANGUAGE.help_cat_introduction = "좀비 서바ì´ë²Œ"
+LANGUAGE.help_cat_survival = "서바ì´ë²Œ"
+LANGUAGE.help_cat_barricading = "바리케ì´ë”©"
+LANGUAGE.help_cat_upgrades = "ì—…ê·¸ë ˆì´ë“œ"
+LANGUAGE.help_cat_being_a_zombie = "좀비"
+
+LANGUAGE.help_cont_introduction = [[ 좀비 ëŒ€ìž¬ì•™ì„ ê²½í—˜í• ìˆ˜ 있게 해주는 좀비 서바ì´ë²Œì— ì˜¤ì‹ ê²ƒì„ í™˜ì˜í•œë‹¤! ì—¬ëŸ¬ë¶„ì€ ì´ì œ 바리케ì´ë“œë¥¼ ì§“ê³ , 좀비를 ë°•ì‚´ ë‚´ë©°, ì–¸ë°ë“œë“¤ê³¼ ì „ìŸì„ ë²Œì¼ ìˆ˜ 있다.
+좀비 서바ì´ë²Œì—는 ìƒì¡´ìžì™€ 좀비ë¼ëŠ” ë‘ íŒ€ì´ ìžˆë‹¤. ìƒì¡´ìž, 즉 ì¸ê°„ì€ ëª¨ë“ ì›¨ì´ë¸Œë¥¼ 버티면 승리하게 ëœë‹¤. ì–´ë–¤ ë§µë“¤ì€ ìŠ¹ë¦¬í•˜ê¸° 위해 특별한 ë¯¸ì…˜ì„ ìˆ˜í–‰í•´ì•¼ 하는 ê²½ìš°ë„ ìžˆë‹¤.
+만약 ì¸ê°„ì´ ì£½ëŠ”ë‹¤ë©´, 좀비로 ë˜ì‚´ì•„나 ìƒì¡´ìžì˜ ìƒì¡´ì´ 훨씬 힘들어지게 ëœë‹¤. í˜‘ë ¥ì„ ìž˜í•´ì•¼ ìœ ë¦¬í•˜ë‹¤ëŠ” ë§ì´ì£ .
+ì¢€ë¹„ë“¤ì˜ ëª©í‘œëŠ” ëª¨ë“ ìƒì¡´ìžì„ 사냥하여 패배하게 하는 것ì´ë‹¤. ì´ë•Œ, 좀비 진ì˜ì—ì„œë„ '패배'ë¼ëŠ” 메세지를 보게 ëœë‹¤. 즉, ìŠ¹ë¦¬í•˜ë ¤ë©´ 반드시 ì¸ê°„ì¸ ìƒíƒœë¡œ ìƒì¡´í•´ì•¼ 한다는 ì–˜ê¸°ì£ .
+ê·¸ ëŒ€ì‹ , í•œ 좀비는 4ëª…ì˜ ì¸ê°„ì„ ì£½ì—¬ 성불(환ìƒ)í• ìˆ˜ 있다. ìƒì¡´í•˜ì—¬ ìŠ¹ë¦¬í• ìˆ˜ 있는 ë‘ ë²ˆì§¸ 기회를 잡게 ë˜ëŠ” ê²ë‹ˆë‹¤.
+하지만 기억하세요. ì•žì„œ ë§ì”€ë“œë ¸ë“¯, '승리'í• ìˆ˜ 있는 단 í•˜ë‚˜ì˜ ë°©ë²•ì€ ì¸ê°„ì¸ ìƒíƒœë¡œ ë까지 ìƒì¡´í•˜ëŠ” 것ë¿ì´ë‹¤. 좀비는 ìŠ¹ë¦¬í• ìˆ˜ 없다. 다만 모ë‘를 패배하게 í• ìˆ˜ ìžˆì„ ë¿ì´ì£ !
+ì¼ì • ìˆ˜ì˜ ì‚¬ëžŒì€ ì„ íƒë˜ê±°ë‚˜ 지ì›í•˜ì—¬ 숙주 좀비가 ëœë‹¤. 몇 ëª…ì´ ì„ íƒë 지는 ë¼ìš´ë“œ 시작 ì „ 화면 í•˜ë‹¨ì— í‘œì‹œëœë‹¤.
+ìƒë‹¨ì˜ 메뉴를 í´ë¦í•˜ì‹œë©´ 다른 ìœ ìš©í•œ ì •ë³´ë¥¼ 알아보실 수 있다.
+íŒ:
+
ì¸ê°„ì´ ìž¬ì ‘ì†í•˜ë©´ 좀비가 ëœë‹¤.
+ì–´ëŠ ì •ë„ ì‹œê°„ì´ í른 후ì—는 새로운 í”Œë ˆì´ì–´ë„ 좀비가 ëœë‹¤.
+팀 ì±„íŒ…ì´ í•„ìš”í•˜ì‹œë©´ 사용하세요. 기본 키는 Uì´ë‹¤.
+
+]]
+LANGUAGE.help_cont_survival = [[íŒ:
+
'gmod_undo'키(기본값: Z)를 눌러 아주 ëŠë¦¬ê²Œ 바리케ì´ë“œë¥¼ í†µê³¼í• ìˆ˜ 있다.
+웨ì´ë¸Œê°€ 진행 ì¤‘ì¼ ë•Œ, í¬ì¸íŠ¸ê°€ 충분하다면 ìƒì ìƒìžì—ì„œ ì›í•˜ëŠ” 무기와 ë„구, 탄창 ë“±ì„ ì‚´ 수 있다. 그러나 í¬ì¸íŠ¸ê°€ ì ë‹¤ê³ í•´ì„œ ê¼ ë‹µì´ ì—†ëŠ” ê²ƒì€ ì•„ë‹™ë‹ˆë‹¤. ë™ë£Œì˜ 잔해나 맵 구ì„êµ¬ì„ ë–¨ì–´ì ¸ 있는 무기, 탄창, ë„구 ë“±ì„ ì£¼ì›Œì„œ 사용하시면 ìƒì¡´ì— ë„ì›€ì´ ëœë‹¤.
+만약 ì¸ê°„ì´ ì¢€ë¹„ì˜ ì§ì ‘ì ì¸ ê³µê²©ìœ¼ë¡œ 죽는다면, ê·¸ ìžë¦¬ì—ì„œ 좀비로 ë˜ì‚´ì•„납니다. 즉시 처치하세요.
+ë¼ìš´ë“œ 시작 ì „ 주어지는 ìžê¸ˆì€ 매우 ì 다. ì‹ ì¤‘ížˆ 시작 무기를 ê³ ë¥´ì‹œê¸° ë°”ëžë‹ˆë‹¤.
+F2를 눌러 장바구니를 만들거나, ì €ìž¥í•˜ê±°ë‚˜, 불러오거나, ì‚ì œí•˜ê±°ë‚˜, 기본 장바구니로 ì„¤ì •í• ìˆ˜ 있다. ì´ë ‡ê²Œ 장바구니로 등ë¡í•œ 후 구매하면 ì—„ì²ë‚˜ê²Œ ë§Žì€ ì‹œê°„ì„ ì ˆì•½í•˜ì—¬ ì „ëžµì„ ì§¤ 수 있다.
+ì•ˆì „í•˜ë‹¤ê³ ëŠê»´ì§€ëŠ” 장소ì¼ìˆ˜ë¡ 조심하세요. 좀비가 íŒŒë†“ì€ í•¨ì •ì— ê±¸ë¦´ ìˆ˜ë„ ìžˆë‹¤.
+만약 íŒ€ì„ ìœ„í•´ ì•„ë¬´ê²ƒë„ í•˜ì§€ 않는다면, 팀ì—게 ë‹¹ì‹ ì€ ì•„ë¬´ëŸ° 쓸모없는 존재가 ëœë‹¤. í¬ì¸íŠ¸ë¥¼ 얻지 않거나, ë” ì¢‹ì€ ë¬´ê¸°ë¥¼ 구매하지 않는다면, íŒ€ì€ ë¬¼ë¡ ì´ê³ 여러분 ìžì‹ ì—ê²Œë„ í•„ìš” 없는 존재가 ë˜ì£ !
+'sprint'키(기본값: Shift)를 눌러 설치한 여러 ë¬¼ê±´ì„ íšŒìˆ˜í• ìˆ˜ 있다. 회수한 ë¬¼ê±´ë“¤ì€ ë‚˜ì¤‘ì— ë‹¤ì‹œ ì‚¬ìš©í• ìˆ˜ 있다.
+주ì¸ì´ 없는 í„°ë ›(파란 불빛)ì€ 'use'키(기본값: E)를 눌러 ìžì‹ ì˜ ê²ƒìœ¼ë¡œ 다시 ì‚¬ìš©í• ìˆ˜ 있다. 주ì¸ì´ 없는 í„°ë ›ì€ ì•„ë¬´ëŸ° í–‰ë™ë„ 하지 않으므로 최대한 빨리 사용하세요!
+ëª»ì´ ë°•í˜€ 있지 ì•Šì€ í”„ë¡ì€ 아무리 ë¬´ê±°ì›Œë„ ì“¸ëª¨ê°€ 없다. 반드시 ëª»ì„ ë°•ì•„ì„œ 바리케ì´ë“œë¥¼ 완성하세요.
+충분히 ë°ë¯¸ì§€ë¥¼ 가하면 ë¬¸ë„ ë¶€ì„œì§‘ë‹ˆë‹¤. 단, ì—´ë¦¬ê³ ë‹«ížˆëŠ” ë¬¸ì¼ ê²½ìš°ì—만 ì ìš©ëœë‹¤.
+ëŒ€ë¶€ë¶„ì˜ í”„ë¡ë“¤ì€ ë°ë¯¸ì§€ë¥¼ ë°›ì„ìˆ˜ë¡ ë¹¨ê°›ê²Œ 변한다.
+ì¢€ë¹„ë“¤ì€ ì£¼ë³€ì— ìžì‹ ë“¤ì„ ì³ë‹¤ë³´ëŠ” ì¸ê°„ì´ ì—†ìœ¼ë©´ ì„œë¡œì˜ ë¨¸ë¦¬ 위ì—ì„œ ë¶€í™œí• ìˆ˜ 있다.
+ëŒ€ë¶€ë¶„ì˜ ê·¼ì ‘ ë¬´ê¸°ë“¤ì€ ì¢€ë¹„ì˜ íŒ”ë³´ë‹¤ 긴 ì‚¬ì •ê±°ë¦¬ë¥¼ ê°–ê³ ìžˆë‹¤. 바리케ì´ë“œë¥¼ 지어 ë°©ì–´í• ë•Œ ì´ë¥¼ ê³ ë ¤í•´ 지으면 좋다.
+ê°™ì€ íŒ€ë¼ë¦¬ëŠ” 겹치지ë„, ë°ë¯¸ì§€ë¥¼ ì£¼ì§€ë„ ì•Šìœ¼ë©° ê³µê²©ì´ ê·¸ëŒ€ë¡œ 통과한다.
+바리케ì´ë“œë¥¼ ì•ˆì „í•œ 장소ì—, ê·¸ë¦¬ê³ ì¢€ë¹„ ìŠ¤í° ì§€ì ì—ì„œ 멀리 떨어진 ìž¥ì†Œì— ì§€ìœ¼ì„¸ìš”. ì¢€ë¹„ë“¤ì˜ íŒ”ì€ ì§§ì§€ë§Œ, ì´ì˜ ì‚¬ì •ê±°ë¦¬ëŠ” 매우 ê¹ë‹ˆë‹¤.
+ë… ë°ë¯¸ì§€ëŠ” 천천히 회복ë˜ì§€ë§Œ, ê·¸ë ‡ë‹¤ê³ í•´ì„œ 죽지 않는 ê±´ 아닙니다. 조심하세요.
+팀 멤버가 ì£½ì–´ê°„ë‹¤ê³ ê²ë¨¹ì§€ 마세요! ì¢€ë¹„ë“¤ì€ ê²ìŸì´ë¥¼ 아주 좋아한다!
+ì¢€ë¹„ë“¤ì€ ì¸ê°„ì´ ë²½ ë’¤ì— ìžˆì„지ë¼ë„ ê·¸ ì¸ê°„ì˜ ìƒíƒœë¥¼ ë³¼ 수 있다. ë§Žì´ ë‹¤ì¹œ ìƒíƒœë¼ë©´ 좀비가 ë‹¬ë ¤ë“¤ê¸° ì „ì— ì–¼ë¥¸ 후퇴하세요.
+숨지 ë§ê³ ë°©ì–´ì„ ì„ êµ¬ì¶•í•˜ì„¸ìš”. ì¢€ë¹„ë“¤ì€ ì¸ê°„ì´ ì–´ë””ì— ìžˆë“ ì§€ ë³¼ 수 있다.
+ì €í•ë ¥ 표시기는 현재 ë„‰ë°±ì— ëŒ€í•´ 얼마나 ì €í•ë ¥ì„ ê°–ê³ ìžˆëŠ”ì§€ 표시한다. ì¢€ë¹„ë“¤ì´ ë§Žìœ¼ë©´ 많ì„ìˆ˜ë¡ ì €í•ë ¥ì´ 강해집니다!
+바리케ì´ë“œë¥¼ ë¶€ìˆ ë§Œí¼ ì¢€ë¹„ê°€ 많지 않다면, 다른 장소ì—ì„œ '팀ì›'ì„ êµ¬í•´ë³´ì„¸ìš”.
+ì´ˆë¡ìƒ‰ ê°€ìŠ¤ì— ìžˆëŠ” 좀비를 ì˜ì§€ 마세요! 가스 안ì—ì„œ 좀비는 ë¹ ë¥´ê²Œ 회복하므로 아까운 ì´ì•Œë§Œ ë‚비하게 ëœë‹¤!
+좀비는 몸통, 팔, ë‹¤ë¦¬ì— ê°€í•´ì§€ëŠ” ê³µê²©ì— ë‚´ì„±ì´ ìžˆë‹¤. 머리를 ì •í™”í•˜ê²Œ ì˜ì„¸ìš”!
+ë¹„ë¡ ì¢€ë¹„ì˜ ë‹¤ë¦¬ì— ë°ë¯¸ì§€ê°€ ì 게 들어갈지ë¼ë„, ë‹¤ë¦¬ì— ê³µê²©ì„ ë°›ìœ¼ë©´ ëŠë ¤ì§€ëŠ” 효과가 있다. 위급한 ìƒí™©ì´ë¼ë©´, 다리를 집중 ì‚¬ê²©í•˜ê³ íŒ€ì›ê³¼ 함께 ë„ë§ì¹˜ì„¸ìš”.
+
+]]
+
+LANGUAGE.help_cont_barricading = [[바리케ì´ë”©ì€ ìƒì¡´ì— ì ˆëŒ€ë¡œ 없어서는 안 ë 행위ì´ë‹¤. ì¢€ë¹„ë“¤ì€ ì²˜ìŒì—” 약해 ë³´ì´ë‚˜ 후반으로 ê°ˆìˆ˜ë¡ ìˆœì‹ê°„ì— íŒ€ ì „ì²´ë¥¼ ì£½ì¼ ìˆ˜ ìžˆì„ ì •ë„ë¡œ ê°•ë ¥í•´ì§€ê¸° 때문ì´ë‹¤.
+좀비를 들어오지 못하게 하는 ìœ ì¼í•œ 방법ì€, 잘 지어진 바리케ì´ë“œì™€ 잘 ì§œì¸ ì „ìˆ ë¡œ 대ì‘하는 것ì´ë‹¤.
+좀비 서바ì´ë²Œì—” 바리케ì´ë“œë¥¼ 구성하기 위한 í•œ ì§ì˜ ë„구가 있다. 바로 'ëª©ìˆ˜ì˜ ë§ì¹˜'와 '못'ì´ë‹¤. ì´ë“¤ì€ 프ë¡ì„ 단단히 ê³ ì •í•´ 주며, ì¢€ë¹„ë“¤ì€ ì´ íŠ¼íŠ¼í•œ 바리케ì´ë“œë¥¼ 부수지 ì•Šê³ ëŠ” ë‹¹ì‹ ì—게 아무런 위해를 가하지 못한다.
+못 박기를 ì›í•˜ëŠ” 프ë¡ì„ ë³´ê³ 'USE'키(기본값: E)를 눌러 프ë¡ì„ 들어 올립니다. 'SPRINT'키(기본값: Shift)를 눌러 íŒìžë¥¼ ì›í•˜ëŠ” ìœ„ì¹˜ì— ë¶™ìž¡ê³ ìžˆì„ ìˆ˜ 있다. ê·¸ ìƒíƒœì—ì„œ ë§ì¹˜ë¥¼ ë“¤ê³ ì˜¤ë¥¸ìª½ í´ë¦í•˜ì—¬ ëª»ì„ ë°•ì•„ ê³ ì •í•˜ì‹œë©´ ëœë‹¤. 다른 프ë¡ë“¤ë³´ë‹¤ ë²½ì´ë‚˜ 쇼파 등 튼튼한 ë¬¼ê±´ì— ëª»ì„ ë°•ìœ¼ë©´ ë” ì•ˆì „í•˜ê²Œ ìƒì¡´í• 수 있다.
+단, 기억하세요! 못으로 ì—°ê²°ëœ í”„ë¡ë“¤ì€ ëª¨ë‘ ë™ì‹œì— ë°ë¯¸ì§€ë¥¼ 받다. 즉, í•œ 프ë¡ì´ ë°ë¯¸ì§€ë¥¼ 받으면 ê·¸ 프ë¡ê³¼ 못으로 ì—°ê²°ëœ ëª¨ë“ í”„ë¡ë“¤ì—게 ê°™ì€ ì–‘ì˜ ë°ë¯¸ì§€ê°€ 들어간다는 ê²ë‹ˆë‹¤. ì—¬ëŸ¬ë¶„ì€ ë§ì¹˜ë¡œ 프ë¡ì´ë‚˜ ëª»ì„ ìˆ˜ë¦¬í• ìˆ˜ 있다만, ê³„ì† ìˆ˜ë¦¬ë¥¼ 하다 ë³´ë©´ ê²°êµ ë„ˆë¬´ 너ëœë„ˆëœí•´ì ¸ ì‚¬ìš©í• ìˆ˜ 없게 ëœë‹¤. ë§ì¹˜ë¥¼ ë“¤ê³ 'SPRINT'키(기본값: Shift)를 눌러서 í™”ë©´ì— ë³´ì´ëŠ” ëª»ì˜ ì£¼ì¸ê³¼ ì²´ë ¥ì„ í™•ì¸í• 수 있다.
+만약 ëª»ì´ ì´ìƒí•œ ê³³ì— ë°•í˜”ë‹¤ê³ ìƒê°ë˜ê±°ë‚˜, 프ë¡ì˜ 위치를 ì˜®ê¸°ê³ ì‹¶ìœ¼ë©´ ëª»ì„ 'RELOAD'키(기본값: R)ì„ ëˆŒëŸ¬ 뺄 수 있다. 하지만 주ì˜í•˜ì„¸ìš”. 만약 ìžì‹ ì˜ ëª»ì´ ì•„ë‹Œ 다른 ì‚¬ëžŒì˜ ëª»ì„ ì œê±°í•œë‹¤ë©´ í¬ì¸íŠ¸ê°€ ê°ì†Œí•˜ê²Œ ëœë‹¤.
+ë˜ í•˜ë‚˜ 기억하셔야 í• ê²ƒì´ ìžˆë‹¤. ëª»ì˜ ì²´ë ¥ì€ í”„ë¡ì˜ 질량과 비례한다. 무ê²ê³ í° í”„ë¡ì¼ìˆ˜ë¡ ë°ë¯¸ì§€ë¥¼ ë” ë§Žì´ ë²„í…¨ë‚¼ 수 있다.
+'ì´ì§€ìŠ¤ 바리케ì´ë“œ 키트'ë¼ëŠ” ë˜ë‹¤ë¥¸ ë„구가 있다. ì´ ë°”ë¦¬ì¼€ì´ë“œ 키트는 ëª¨ë“ í‘œë©´, í˜¹ì€ ë‘ ê°œì˜ ë²½ 사ì´ì— ë¹ ë¥¸ ì†ë„ë¡œ 바리케ì´ë“œë¥¼ ì„¤ì¹˜í• ìˆ˜ 있게 해준다. 심지어 프ë¡ë„ í•„ìš” 없다. ì´ê²ƒì„ ì‚¬ìš©í•˜ì‹œë ¤ë©´ ì›í•˜ëŠ” ìœ„ì¹˜ì— ì ‘ê·¼í•˜ì…”ì„œ 빨간색 형체가 ì´ˆë¡ìƒ‰ì´ ë 때까지 ì ì ˆížˆ ì¡°ì •í•˜ì‹ í›„ í´ë¦í•˜ì—¬ 설치하시면 ëœë‹¤.
+'PRIMARY ATTACK'키(기본값: 마우스 왼쪽 í´ë¦)ì„ ëˆŒëŸ¬ ì„¤ì¹˜í• ìˆ˜ ìžˆê³ , 'RELOAD'(기본값: R)키나 'SECONDARY ATTACK'키(기본값: 마우스 오른쪽 í´ë¦)ì„ ëˆŒëŸ¬ íšŒì „ì‹œí‚¬ 수 있다. 보드팩과 ê°™ì´ 'ë³´ë“œ'를 사용하므로 ë³´ë“œíŒ©ì„ ì†Œì§€í•˜ê³ ìžˆë‹¤ë©´ ì‚¬ìš©í• ë•Œë§ˆë‹¤ 보드가 하나씩 사용ëœë‹¤! 'SPRINT'키(기본값: Shift)를 눌러 ì„¤ì¹˜ëœ íŒìžë¥¼ 회수하여 다시 쓸 수 있다.
+마지막으로, 'í„°ë ›'ì´ ìžˆë‹¤. í„°ë ›ì€ ë ˆì´ì ¸ì— ë‹¿ì€ ëª¨ë“ ì¢€ë¹„ì—게 ì´ì•Œì„ 발사한다. íƒ„ì•½ì´ ì—†ì„ ë•Œì—” ë ˆì´ì ¸ê°€ 빨간색으로 변하며 ê¸°ëŠ¥ì´ ì •ì§€ëœë‹¤. SMGíƒ„ì•½ì´ ìžˆë‹¤ë©´, í„°ë ›ì„ ë³´ê³ 'USE'키(기본값: E)를 눌러 ì¶©ì „ì‹œí‚¬ 수 있다. ì¶©ì „í• ê²½ìš°ì—는 í¬ì¸íŠ¸ë¥¼ 받다.
+í„°ë ›ì„ ë†“ìœ¼ì‹œë ¤ë©´ 빨간색 형체가 ì´ˆë¡ìƒ‰ì´ ë˜ëŠ” 위치로 ì´ë™í•˜ì‹ 후 í´ë¦í•˜ì‹œë©´ ëœë‹¤. 프ë¡ì´ ì—†ê³ , í‰ì§€ì—¬ì•¼ 한다. 'SECONDARY ATTACK'키(기본값: 마우스 오른쪽 í´ë¦) í˜¹ì€ 'RELOAD'키(기본값: R)ì„ ëˆŒëŸ¬ íšŒì „ì‹œí‚¬ 수 있다. 만약 ë¬¸ì œê°€ ë°œìƒí•œë‹¤ë©´, 'SPRINT'키(기본값: Shift)를 눌러 회수한 후 다른 ìœ„ì¹˜ì— ì„¤ì¹˜í• ìˆ˜ 있다. 기억하세요. í„°ë ›ì€ ë ˆì´ì ¸ì— ë‹¿ì€ ì¢€ë¹„ë§Œ 공격한다.
+íŒ:
+
+바리케ì´ë“œë¥¼ ê³µê²©ì¤‘ì¸ ì¢€ë¹„ë¥¼ 사살한다면 25%ì˜ í¬ì¸íŠ¸ 보너스를 받다!
+í¬ê³ 무거운 프ë¡ì„ 바리케ì´ë“œë¡œ 사용하세요. ëª»ì˜ ì²´ë ¥ì´ ë” ë§Žì•„ì§€ê³ , ëª»ì„ ë°•ì„ ìˆ˜ 있는 ìžë¦¬ë„ ë” ë§Žì•„ì§‘ë‹ˆë‹¤. ë˜í•œ, 바리케ì´ë“œëŠ” ë°œì‚¬ì²´ë„ ë§‰ë‹¤.(Ex: ë…)
+ ]]
+LANGUAGE.help_cont_upgrades = [[í¬ì¸íŠ¸ëŠ” 좀비를 죽ì´ê±°ë‚˜, íŒ€ì„ ì¹˜ë£Œí•˜ê±°ë‚˜, í„°ë ›ì˜ íƒ„í™˜ì„ ì¶©ì „í•˜ê±°ë‚˜, í¬ì¸íŠ¸ìƒµì„ ìš´ì˜í•˜ê±°ë‚˜, 보급ìƒìžë¥¼ 설치하거나 바리케ì´ë“œë¥¼ ìˆ˜ë¦¬í•¨ìœ¼ë¡œì¨ ì–»ì„ ìˆ˜ 있다.
+ê·¸ë ‡ê²Œ ì–»ì€ í¬ì¸íŠ¸ë“¤ì€ í¬ì¸íŠ¸ 샵ì—ì„œ ìƒì¡´ì— 필요한 무기, ë„구 등으로 êµí™˜í• 수 있다.
+웨ì´ë¸Œ 쉬는시간ì—는 í• ì¸ëœ 가격으로 íŒë§¤ë˜ë‹ˆ 기억하시기 ë°”ëžë‹ˆë‹¤!
+íŒ:
+
+계íšì„ 세우세요. ìžê¸ˆ 메뉴ì—ì„œ íƒ„ì•½ì„ ë‘둑히 챙겨 놓는다면 탄약 ê±±ì • ì—†ì´ ë” ë§Žì€ ì¢€ë¹„ë¥¼ ì‚¬ì‚´í•˜ê³ í¬ì¸íŠ¸ë¥¼ 얻어 장비를 ë”ìš± ë” ì‰½ê²Œ ì—…ê·¸ë ˆì´ë“œ 하실 수 있다.
+ì–´ì‹œìŠ¤íŠ¸ë§Œìœ¼ë¡œë„ í¬ì¸íŠ¸ë¥¼ ì–»ì„ ìˆ˜ 있다. ì§ì ‘ ì£½ì¸ ì‚¬ëžŒì—게 ë°˜ ì´ìƒì˜ í¬ì¸íŠ¸ê°€ 가지만, ì–´ì‹œìŠ¤í„°ë„ ì—¬ì „ížˆ í¬ì¸íŠ¸ë¥¼ 받으므로 최대한 í˜‘ë ¥í•˜ì„¸ìš”.
+ìžê¸ˆê³¼ í¬ì¸íŠ¸ëŠ” ê°™ì€ ê°œë…ì´ ì•„ë‹™ë‹ˆë‹¤. ë¼ìš´ë“œ 시작 ì „, ìžê¸ˆì„ ì „ë¶€ 쓰는 ê²ƒì´ ì¢‹ë‹¤!
+ìƒì ìƒìžëŠ” 공격, ë°©ì–´, ìƒì¡´ ëª¨ë“ ë©´ì— ìžˆì–´ 필수품ì´ë‹¤.
+ ]]
+LANGUAGE.help_cont_being_a_zombie = [[íŒ:
+
+좀비는 무한히 부활하지만, ì¸ê°„ì€ ë‹¨ í•˜ë‚˜ì˜ ìƒëª…ë°–ì— ì—†ë‹¤. ê³µê²©ì„ ë‘ë ¤ì›Œí•˜ì§€ 마세요! ëŠìž„ì—†ì´ ê³µê²©ë§Œ 하다 ë³´ë©´ ì–´ëŠìƒˆ ë”ìš± ê°•ë ¥í•´ì§„ 좀비 êµ°ë‹¨ì„ ë³¼ 수 ìžˆì„ ê²ë‹ˆë‹¤!
+좀비는 굉장히 ëˆì§ˆê¸´ ìƒëª…ë ¥ì„ ê°–ê³ ìžˆë‹¤. ì£½ì¼ ìˆ˜ 있는 단 í•˜ë‚˜ì˜ ë°©ë²•ì€ ë¨¸ë¦¬ë¥¼ ì´ì£½ì´ê±°ë‚˜, ê°•ë ¥í•œ ë°ë¯¸ì§€ë¥¼ 가하거나, ê·¼ì ‘ ê³µê²©ì„ í•˜ëŠ” 것 ë¿ì´ë‹¤. 좀비ì—게 다리는 í•„ìš” 없다.
+ê·¼ì²˜ì˜ ì•„ë¬´ëŸ° ì¸ê°„ë„ ì¢€ë¹„ë¥¼ ë³´ê³ ìžˆì§€ 않다면, ì¢€ë¹„ë“¤ì€ ì„œë¡œì˜ ë¨¸ë¦¬ 위ì—ì„œ ë¶€í™œí• ìˆ˜ 있다. 화면 ì•„ëž˜ì— ìžˆëŠ” í•´ê³¨ì˜ ëˆˆ ìƒ‰ê¹”ì„ ì£¼ì‹œí•˜ì„¸ìš”. ì´ˆë¡ìƒ‰ì´ë¼ë©´, 다른 좀비가 ë‹¹ì‹ ì˜ ìœ„ì—ì„œ ë¶€í™œí• ìˆ˜ 있다!
+ë§Žì´ ì‹œë„하다 ë³´ë©´ 프ë¡ì„ 강타해 ì¸ê°„ì—게 ë‚ ë ¤ë²„ë¦´ ìˆ˜ë„ ìžˆë‹¤.
+ìƒì ìƒìžë‚˜ í„°ë ›ê³¼ ê°™ì€ ì„¤ì¹˜ëœ ë¬¼ê±´ë“¤ì„ ë¶€ìˆ´ì„œ ì¸ê°„ì˜ ìƒì¡´ì„ 방해하세요.
+충분한 ë°ë¯¸ì§€ë¥¼ 받으면 ë¬¸ì˜ ê²½ì²©ì´ ë–¨ì–´ì§‘ë‹ˆë‹¤.
+ëŒ€ë¶€ë¶„ì˜ í”„ë¡ë“¤ì€ ë°ë¯¸ì§€ë¥¼ ë°›ì„ìˆ˜ë¡ ë¹¨ê°›ê²Œ 변한다.
+ë§ë ¹ì€ 가만히 ì„œ 있거나 ì¼ì • 거리보다 멀리 ìžˆì„ ë•Œ 완벽하게 투명해집니다.
+패스트 ì¢€ë¹„ì˜ ë‹¬ë ¤ë“œëŠ” ê³µê²©ì€ ì–¼ë§ˆë‚˜ 오래 ë‚ ì•˜ëŠ”ì§€ì— ë”°ë¼ ë°ë¯¸ì§€ê°€ 변한다. ê³µì¤‘ì— ì˜¤ëž˜ 있었ì„ìˆ˜ë¡ ë°ë¯¸ì§€ê°€ ê°•ë ¥í•´ì§‘ë‹ˆë‹¤. 만약 ì¸ê°„ì´ ê°€ê¹Œì´ì— 있다면, ê¸ì–´ë²„ë ¤ë„ ì¢‹ë‹¤!
+í¬ì´ì¦Œ 좀비는 í„°í”„í•˜ê²Œë„ ìžì‹ ì˜ ì‚´ì ì„ ëœ¯ì–´ ë˜ì ¸ë²„립니다. ì´ëŠ” 'SECONDARY ATTACK'키(기본값: 마우스 오른쪽 í´ë¦)ë¡œ ì‚¬ìš©í• ìˆ˜ 있다.
+대부분 ì¢€ë¹„ì˜ í• í€´ê¸° ê³µê²©ì€ 2ë²ˆì˜ ê¸°íšŒê°€ 있다. 만약 ì¸ê°„ì„ ì œëŒ€ë¡œ 친다면 공격 범위 안ì—ì„œ ê³„ì† ê³µê²©í• ìˆ˜ 있다.
+만약 í¬ì´ì¦Œ 헤드í¬ëž©ì˜ ë… ê³µê²©ì´ ì¸ê°€ì˜ ë¨¸ë¦¬ì— ë§žëŠ”ë‹¤ë©´ ë§žì€ ì¸ê°„ì€ ëª‡ ì´ˆ ë™ì•ˆ ì •ì‹ ì´ ì—†ê²Œ ëœë‹¤.
+ì²´ë ¥ì´ ë¶€ì¡±í•œ ì¸ê°„ì—게 가세요! 다른 좀비 ì—ì‹œ ì²´ë ¥ì´ ë¶€ì¡±í•œ ì¸ê°„ì„ ì„ í˜¸í•˜ë¯€ë¡œ ê·¸ë“¤ì€ ì•„ì£¼ ì†ì‰¬ìš´ 먹잇ê°ì´ ëœë‹¤.
+화면 í•˜ë‹¨ì— ìžˆëŠ” ì €í•ë ¥ 미터기는 ë‹¹ì‹ ì´ ë°ë¯¸ì§€ì™€ ë„‰ë°±ì— ì–¼ë§ˆë‚˜ ì €í•í• 수 있는지 나타냅니다. 좀비ë¼ë¦¬ 모ì´ê³ 모여 ê°•ë ¥í•œ êµ°ë‹¨ì„ ë§Œë“œì„¸ìš”!
+만약 바리케ì´ë“œë¥¼ ë¶€ìˆ ë§Œí¼ ì¢€ë¹„ê°€ 많지 않다면, 다른 ê³³ì—ì„œ 새로운 '팀ì›'ì„ êµ¬í•˜ì„¸ìš”.
+만약 너무 어둡다면, 'FLASHLIGHT'키(기본: F)를 눌러보세요.
+
+]]
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/languages/portuguese.lua b/gamemodes/zombiesurvival/gamemode/languages/portuguese.lua
new file mode 100644
index 0000000..c1faa9c
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/languages/portuguese.lua
@@ -0,0 +1,313 @@
+-- Translated by rui_troia (http://www.noxiousnet.com/forums/index.php?action=profile;u=6471)
+
+translate.AddLanguage("pt-PT", "Portuguese")
+
+-- Various gamemode stuff
+LANGUAGE.minute_points_added = "Não houve danos recebidos em um minuto! Adicionado %d pontos."
+LANGUAGE.infliction_reached_class_unlocked = "%d%% inflição foi alcançada! %s desbloqueiado!"
+LANGUAGE.infliction_reached = "%d%% dos humanos morreram!"
+LANGUAGE.x_unlocked = "%s desbloqueiado!"
+LANGUAGE.disconnect_killed = "%s foi desconectado morto por %s."
+LANGUAGE.nail_removed_by = "%s removeu um prego por %s."
+LANGUAGE.banned_for_life_warning = "Foste banido para a vida, não podes comprar!"
+LANGUAGE.need_to_be_near_arsenal_crate = "Tens que estar perto da Caixa de Arsenal para comprar!"
+LANGUAGE.cant_purchase_right_now = "Não podes comprar nada por enquanto."
+LANGUAGE.dont_have_enough_points = "Não tens pontos suficientes."
+LANGUAGE.prepare_yourself = "Prepara-te..."
+LANGUAGE.purchased_x_for_y_points = "Comprado %s por %d pontos!"
+LANGUAGE.give_time_before_suicide = "Dá outros tempo antes de suicidar."
+LANGUAGE.no_spare_ammo_to_give = "Não há munição para doar!"
+LANGUAGE.no_person_in_range = "Não há pessoa á tua volta!"
+LANGUAGE.that_life = "Nessa vida..."
+LANGUAGE.x_damage_to_barricades = "%d danos a barricadas"
+LANGUAGE.x_damage_to_humans = "%d danos aos humanos"
+LANGUAGE.x_brains_eaten = "%d cérebros comidos"
+LANGUAGE.press_rmb_to_cycle_targets = "Pressione RMB para rodar targetos"
+LANGUAGE.press_lmb_to_spawn_on_them = "Pressione LMB para fazer spawn nele"
+LANGUAGE.press_lmb_to_spawn = "Aperta LMB para fazer spawn"
+LANGUAGE.observing_x = "Observando %s (%d)"
+LANGUAGE.waiting_for_next_wave = "Esperando a próxima onda..."
+LANGUAGE.impossible = "Impossivel."
+LANGUAGE.trying_to_put_nails_in_glass = "Tentar pregando pregos em vidro é a coisa mais boba que podes fazer."
+LANGUAGE.boss_class_select = "Tu seras %s na proxima vez que seras o chefe."
+LANGUAGE.person_has_weapon = "Essa pessoa já tem essa arma."
+LANGUAGE.cant_do_that_in_classic_mode = "Não podes fazer isso no Classic Mode."
+LANGUAGE.cant_use_x_in_classic_mode = "Não podes usar %s no Classic Mode."
+LANGUAGE.cant_use_x_in_zombie_escape = "Não podes usar %s no Zombie Escape."
+LANGUAGE.no_class_switch_in_this_mode = "O modo actual não te deixa mudar de classes."
+LANGUAGE.press_sprint_to_get_up = "Pressione SPRINT para levantares"
+LANGUAGE.zombie_escape = "Zombie Escape!"
+LANGUAGE.nothing_for_this_ammo = "Não tens nada que usa esse tipo de munição."
+LANGUAGE.you_decide_to_leave_some = "Tu decides para deixares alguns para a tua equipa."
+LANGUAGE.you_cant_purchase_now = "Não podes comprar items neste momento."
+LANGUAGE.no_ammo_here = "Não ha munição nenhuma aqui neste momento."
+LANGUAGE.you_redeemed = "Tu ressucitaste!"
+LANGUAGE.kill_the_last_human = "Mata o ultimo humano!"
+LANGUAGE.kick_the_last_human = "Xuta o ultimo humano!"
+LANGUAGE.you_are_the_last_human = "TU ÉS O ULTIMO HUMANO!"
+LANGUAGE.x_zombies_out_to_get_you = "%d ZOMBIES ESTÃO Aà PARA TE APANHAREM!"
+LANGUAGE.x_pants_out_to_get_you = "%d CALÇAS ESTÃO Aà PARA TE APANHAREM!"
+LANGUAGE.you_have_died = "Tu morreste."
+LANGUAGE.you_were_killed_by_x = "Tu foste morto por %s"
+LANGUAGE.you_were_kicked_by_x = "As tuas canelas foram chutadas por %s"
+LANGUAGE.arsenal_upgraded = "Arsenal Modificado!"
+LANGUAGE.final_wave = "A ULTIMA ONDA COMEÇOU!"
+LANGUAGE.final_wave_sub = "TODAS as classes foram desbloqueiadas e a chance de redimir foi removida!"
+LANGUAGE.wave_x_has_begun = "Onda %d começou!"
+LANGUAGE.x_unlocked = "%s desbloqueiado!"
+LANGUAGE.wave_x_is_over = "Onda %d acabou!"
+LANGUAGE.wave_x_is_over_sub = "Os Mortos-Vivos pararam de vir e o saldo do Shopping dos Pontos está %d%% ."
+LANGUAGE.you_are_x = "Tu és %s!"
+LANGUAGE.x_has_risen_as_y = "%s foi ressucitado como %s!!"
+LANGUAGE.x_has_risen = "%s foi ressucitado!"
+LANGUAGE.cant_use_worth_anymore = "Tu não podes usar o Worth Menu agora!"
+LANGUAGE.class_not_unlocked_will_be_unlocked_x = "Essa classe não foi desbloqueiada ainda. Será desbloqueiada na onda %d."
+LANGUAGE.you_are_already_a_x = "Tu ja és %s."
+LANGUAGE.you_will_spawn_as_a_x = "Tu iras fazer spawn como %s."
+LANGUAGE.crafting_successful = "Construção sucedida!"
+LANGUAGE.x_crafted_y = "%s construiu %s."
+LANGUAGE.escape_from_the_zombies = "Escapa dos zombies!"
+LANGUAGE.too_close_to_another_nail = "Muito perto de um outro prego."
+LANGUAGE.object_too_damaged_to_be_used = "Esse objecto esta muito danificado para ser usado outra vez."
+LANGUAGE.thanks_for_being_a_fan_of_zs = "Obrigado por ser um fã de Zombie Survival!"
+LANGUAGE.cant_remove_nails_of_superior_player = "Não podes remover os pregos de um jogador melhor que voce."
+LANGUAGE.x_turned_on_noclip = "%s activou noclip."
+LANGUAGE.x_turned_off_noclip = "%s desactivou noclip."
+LANGUAGE.unlocked_on_wave_x = "Desbloqueiado na onda %d"
+LANGUAGE.brains_eaten_x = "Cérebros comidos: %s"
+LANGUAGE.points_x = "Pontos: %s"
+LANGUAGE.next_wave_in_x = "Proxima onda em %s"
+LANGUAGE.wave_ends_in_x = "Onda acaba em %s"
+LANGUAGE.wave_x_of_y = "Onda %d de %d"
+LANGUAGE.zombie_invasion_in_x = "Invasão de zombies em %s"
+LANGUAGE.intermission = "Intermissão"
+LANGUAGE.press_f2_for_the_points_shop = "Pressione F2 para o Shop dos Pontos!"
+LANGUAGE.breath = "Respire"
+LANGUAGE.zombie_volunteers = "Voluntários Zombies"
+LANGUAGE.x_discount_for_buying_between_waves = "%d%% desconto por comprar entre ondas!"
+LANGUAGE.number_of_initial_zombies_this_game = "Numero de zombies iniciais neste jogo (%d%%): %d"
+LANGUAGE.humans_closest_to_spawns_are_zombies = "Os Humanos mais pertos do spawn dos zombies irão ser selecionados."
+LANGUAGE.waiting_for_players = "Esperando por jogadores..."
+LANGUAGE.requires_x_people = "Requer %d pessoas"
+LANGUAGE.packing_others_object = "Empacotar objecto de outra pessoa"
+LANGUAGE.packing = "Paqueando"
+LANGUAGE.ze_humans_are_frozen_until_x = "Humanos estão parados até %d segundos antes da proxima ronda começar."
+LANGUAGE.loading = "Carregando..."
+LANGUAGE.next_round_in_x = "Proxima ronda em: %s"
+LANGUAGE.warning = "Aviso!"
+LANGUAGE.ok_and_no_reminder = "OK e esta mensagem não aparecerá."
+LANGUAGE.classic_mode_warning = "Este servidor esta correndo Zombie Survival em 'Classic Mode'\nClassic Mode é um modo que muda bastante o aspecto jogo. Coisas que mudaram:\n* Não há seleção de classes. Todos usam a classica Zombie Classe.\n* Não há ferramentas de barricar tal como pregos ou turrets\n* Mais ondas, mas mais rapidas.\n\nIsto NÃO É o original Zombie Survival!\n\n-- Servidores que corram este modo irão disponabilizar CLASSIC MODE no canto inferior esquerdo do ecrã --"
+LANGUAGE.classic_mode = "CLASSIC MODE"
+LANGUAGE.resist_x = "Resistencia: %d%%"
+LANGUAGE.right_click_to_hammer_nail = "Botão direito do mouse para pregar."
+LANGUAGE.nails_x = "Pregos: %d"
+LANGUAGE.resupply_box = "Caixa de resuplimentos"
+LANGUAGE.purchase_now = "Compre agora!"
+LANGUAGE.integrity_x = "Integridade: %d%%"
+LANGUAGE.empty = "VAZIO"
+LANGUAGE.manual_control = "CONTROLO MANUAL"
+LANGUAGE.arsenal_crate = "Caixa de Arsenal"
+
+-- Exit point objectives
+LANGUAGE.exit_destroyed = "Os Mortos-Vivos destruÃram uma saÃda!"
+LANGUAGE.exit_destroyed_only_one_remain_h = "Só resta uma! Se é derrubado não há esperança para uma saÃda!"
+LANGUAGE.exit_destroyed_only_one_remain_z = "Só resta uma!"
+LANGUAGE.exit_destroyed_x_remain = "%d saÃdas restantes."
+LANGUAGE.last_exit_destroyed_all_is_lost = "Os zombies destruÃram a ultima saÃda."
+LANGUAGE.last_exit_destroyed_all_is_lost2 = "Não há esperança para escapar."
+
+-- Message beacon messages
+LANGUAGE.message_beacon_1 = "Encontraremonos aqui"
+LANGUAGE.message_beacon_2 = "Precisamos de defesa aqui"
+LANGUAGE.message_beacon_3 = "Precisamos de turretas aqui"
+LANGUAGE.message_beacon_4 = "Precisamos de caixas de arsenal aqui"
+LANGUAGE.message_beacon_5 = "Precisamos de médicos aqui"
+LANGUAGE.message_beacon_7 = "Caixas de Arsenal aqui"
+LANGUAGE.message_beacon_8 = "Precisamos de campos-de-força aqui"
+LANGUAGE.message_beacon_9 = "Precisamos de explosivos aqui"
+LANGUAGE.message_beacon_10 = "Zombies vêm daqui"
+LANGUAGE.message_beacon_11 = "Não entrem!!"
+LANGUAGE.message_beacon_12 = "Não vá fora"
+LANGUAGE.message_beacon_13 = "Defendem esta area"
+LANGUAGE.message_beacon_14 = "Defendem este lugar"
+LANGUAGE.message_beacon_15 = "Médicos aqui"
+LANGUAGE.message_beacon_16 = "Compram da minha caixa"
+LANGUAGE.message_beacon_17 = "Barricada aqui"
+LANGUAGE.message_beacon_18 = "Não barricam aqui"
+LANGUAGE.message_beacon_19 = "Não deixam os zombies entrarem aqui"
+LANGUAGE.message_beacon_20 = "Isto vai quebrar"
+LANGUAGE.message_beacon_21 = "Este lugar é perigoso!"
+LANGUAGE.message_beacon_22 = "Cuidado com o veneno!"
+LANGUAGE.message_beacon_23 = "Zombies estão a partir a barricada aqui!"
+LANGUAGE.message_beacon_24 = "Zombies estão a vir, construa uma barricada!"
+LANGUAGE.message_beacon_25 = "Plano B aqui"
+
+-- Class names
+LANGUAGE.class_zombie = "Zombie"
+LANGUAGE.class_poison_zombie = "Zombie Venenoso"
+LANGUAGE.class_fast_zombie = "Zombie Rápido"
+LANGUAGE.class_bloated_zombie = "Zombie Inchado"
+LANGUAGE.class_classic_zombie = "Zombie Classico"
+LANGUAGE.class_super_zombie = "Super Zombie"
+LANGUAGE.class_fresh_dead = "Morto fresco"
+LANGUAGE.class_ghoul = "Ghoul"
+LANGUAGE.class_headcrab = "Headcrab"
+LANGUAGE.class_fast_headcrab = "Headcrab Rápido"
+LANGUAGE.class_poison_headcrab = "Headcrab Venenoso"
+LANGUAGE.class_the_tickle_monster = "The Tickle Monster"
+LANGUAGE.class_nightmare = "Nightmare"
+LANGUAGE.class_pukepus = "Pukepus"
+LANGUAGE.class_bonemesh = "Bonemesh"
+LANGUAGE.class_crow = "Corvo"
+LANGUAGE.class_wilowisp = "Wil O' Wisp"
+LANGUAGE.class_zombie_torso = "Torso Zombie"
+LANGUAGE.class_zombie_legs = "Zombie Pernas"
+LANGUAGE.class_wraith = "Wraith"
+LANGUAGE.class_flesh_beast = "Carne Besta"
+LANGUAGE.class_fast_zombie_legs = "Zombie Rápido pernas"
+LANGUAGE.class_chem_zombie = "Chem Zombie"
+LANGUAGE.class_shade = "Shade"
+
+-- Class descriptions
+LANGUAGE.description_zombie = "O Zombie básico que é muito duravel e tem garras potentes.\nÉ dificil de ser derrubado, especialmente se não é disparado na cabeça."
+LANGUAGE.description_poison_zombie = "Este zombie mutante não é so extremamente duravel mas tem uma força anormal.\nSeu corpo é extremamente tóxico e irá arrancar e atirar a sua própia carne para longe."
+LANGUAGE.description_fast_zombie = "Este cadáver ossoso é muito mais rápido comparado com os outros zombies.\nEles não são uma ameaça por eles própios, mas podem alcançar uma área perto deles, subindo com as suas garras.\nEles também não têm problema quando caçam humanos fracos com pouca vida."
+LANGUAGE.description_bloated_zombie = "O corpo é constituÃdo por voláteis, qúimicos tóxicos.\nMesmo que eles movem devagar, eles podem levar um pouco mais do que uma batida."
+LANGUAGE.description_ghoul = "Este zombie tem uma carne muito tóxica.\nÉ um pouco fraco comparado com os outros zombies, mas compensa com o seu ataque venenoso.\nSuas garras podem delibirar um humano por um curto periodo de tempo e irá ejectar veneno através dos seus ferimentos, se danificado com dano suficiente."
+LANGUAGE.description_headcrab = "Headcrabs foram a causa da infeção original\nNinguém sabe de onde eles verdadeiramente vieram.\nO seu método de ataque é morder com os seus dentes na sua barriga."
+LANGUAGE.description_fast_headcrab = "O headcrab macho é consideravelmente rápido mas menos carnudo que a fémea.\nDe qualquer maneira, é igualmente chato e mortÃfero em grupos."
+LANGUAGE.description_poison_headcrab = "Este headcrab está cheio de neurotóxinas.\nUma dentada é suficiente para matar um humano adulto.\nTambém tem a habilidade de guspir uma parte fraca do seu veneno.\nO guspo é mais mortÃfero se atinge a cabeça da vitima."
+LANGUAGE.description_the_tickle_monster = "Dito para ser o monstro que esconde no teu armário e te puxa da cama.\nOs braços do Tickle Monster são elásticos que o faz extremamente dificil de ser ultrapassado e também o fazem o ideal destruÃdor de barricadas."
+LANGUAGE.description_nightmare = "Uma extremamente rara mutação dá o Nightmare as suas habilidades.\nMais forte do que qualquer outro zombie em quase qualquer forma, o Nightmare é a força para ser contada.\nUma passada com as suas garras é o suficiente para derrubar a maioria das pessoas."
+LANGUAGE.description_pukepus = "O corpo apodrecÃdo de Puke Pus é compremetido inteiramente com orgãos que são usados para fazer a regeneração de veneno.\nÉ capáz de vomitar galões de vómito infectado que o torna extremamente perigoso."
+LANGUAGE.description_bonemesh = "Desfigurado e mutilado, o Bonemesh é capaz de atirar bombas de sangue.\nCada bomba é compremetida com ossos e carnes que é uma grande ameaça para os Humanos, no entanto é uma refeição deliciosa para os zombies."
+LANGUAGE.description_crow = "Corvos carnivoros são mais do que uma peste do que eles eram antes da infeção.\nEles alimentam-se da carne dos infectados e funcionam como ''carregadores'' para os Mortos-Vivos.\nPorque nunca querias fazer esta classe escondida?\nQual é o teu problema?"
+LANGUAGE.description_wilowisp = "Ãs vezes referidos como espÃritos dos mortos."
+LANGUAGE.description_zombie_torso = "Tu nem devias estar a ver isto."
+LANGUAGE.description_zombie_legs = "Tu nem devias estar a ver isto."
+LANGUAGE.description_wraith = "Um zombie ou uma aparição?\nNada se sabe muito sobre isso, tirando o facto que usa a sua\núnica habilidade desprevinida e garras afiádas para cortar coisas aos pedaços."
+LANGUAGE.description_flesh_beast = "*pending*"
+LANGUAGE.description_fast_zombie_legs = "Tu nem devias a estar a ver isto."
+LANGUAGE.description_chem_zombie = "O corpo do Chem Zombie é comprometido de volateis, produtos quÃmicos.\nNão tem nenhum meio para atacar, tirando o facto de morrer e com esperança matar o humano mais próximo da sua explosão."
+LANGUAGE.description_shade = "Criando um campo magnético á sua volta, todos os ataques a bala e melee são inúteis contra ele.\nPor alguma razão, Shade é vulneravel á luz brilhante."
+
+
+LANGUAGE.controls_zombie = "> PRIMARIO: Garras\n> SECUNDÃRIO: Gritar\n> RECARREGAR: Queixar\n> SPRINT: Fingir morte\n> DISPARO FATAL NAS PERNAS: Reviver / Transformar"
+LANGUAGE.controls_poison_zombie = "> PRIMARIO: Claws\n> SECUNDÃRIO: Atirar carne\n> RELOAD: Gritar"
+LANGUAGE.controls_fast_zombie = "> PRIMARIO: Claws\n> SECUNDÃRIO: Atirar-se / Trepar (próximo da parede)\n> RECARREGAR: Gritar"
+LANGUAGE.controls_bloated_zombie = "> PRIMARIO: Claws\n> SECUNDÃRIO: Queixar\n> SPRINT: Fingir morte\n> NA MORTE: Sangue venenoso"
+LANGUAGE.controls_ghoul = "> PRIMARIO: Garras venenósas\n> SECUNDÃRIO: Atirar carne\n> SPRINT: Fingir morte\n> RECARREGAR: Gritar\n> QUANDO ATINGE HUMANO: Lento\n> ATINGIDO POR HUMANO: Ejeção de veneno"
+LANGUAGE.controls_headcrab = "> PRIMARIO: Ataque estocado\n> RECARREGAR: Cavar"
+LANGUAGE.controls_fast_headcrab = "> PRIMARIO: Ataque estocado"
+LANGUAGE.controls_poison_headcrab = "> PRIMARIO: Ataque estocado\n> SECUNDÃRIO: Guspir Veneno\n> QUANDO ATINGE HUMANO: Veneno mortÃfero\n> QUANDO ATINGE NOS OLHOS: Cegueira\n> RECARREGAR: Gritar"
+LANGUAGE.controls_the_tickle_monster = "> PRIMARIO: Garras elásticas\n> SECUNDÃRIO: Queixar"
+LANGUAGE.controls_nightmare = "> PRIMARIO: Toque mortÃfero\n> SECONDARY: Queixar"
+LANGUAGE.controls_pukepus = "> PRIMARIO: Vómito"
+LANGUAGE.controls_bonemesh = "> PRIMARIO: Garras\n> SECUNDÃRIO: Atira bomba de sangue"
+LANGUAGE.controls_wraith = "> PRIMARIO: Garras\n> SECUNDÃRIO: Gritar\n> INVISIBILIDADE BASEADA NO MOVIMENTO E DISTANCIA"
+LANGUAGE.controls_flesh_beast = "> PRIMARIO: Garras\n> SECUNDÃRIO: Batida com cabeça"
+LANGUAGE.controls_chem_zombie = "> NA MORTE: Bomba Venenosa"
+LANGUAGE.controls_shade = "> PRIMARIO: Subir\n> SECUNDÃRIO: Atirar"
+
+LANGUAGE.help_cat_introduction = "Introdução"
+LANGUAGE.help_cat_survival = "Sobrevivência"
+LANGUAGE.help_cat_barricading = "Barricagem"
+LANGUAGE.help_cat_upgrades = "Upgrades"
+LANGUAGE.help_cat_being_a_zombie = "Sendo um Zombie"
+LANGUAGE.help_cont_introduction = [[ Bem vindo ao Zombie Survival, o simulador de sobrevivência (zombie). Zombie Survival te deixa lutar contra ataques zombies, criar barricadas, e até ser parte da horda dos zombies.
+
+Há duas equipas: Os Sobreviventes e os Zombies. Os Humanos ganham se sobrevivem todas as ondas. Alguns niveis têm objectivos a ser completados, que podem ser opcionais ou necessários para ganhar.
+Se um Humano é morto ele irá ser zombie, que faz mais dificil ter mais Humanos.
+
+O objectivo dos zombies é matar todos os Humanos, fazendo eles todos zombies e causar a toda gente a derrota da ronda.
+Alternativamente, um zombie pode matar quatro humanos para ser resgatado. Isto os deixa com uma segunda chance á sobrevivencia e victória.
+Lembra que, o único caminho para ganhar é ser humano quando a ronda acaba. Os Zombies não podem ganhar a ronda técnicamente; zombies só podem fazer todos os outros perderem!
+
+Uma certa quantidade de pessoas são escolhidas ao acaso (ou voluntareadas) para serem os zombies inÃciais. Esta quantidade está disponabilizada no fundo do teu ecrã, antes que uma ronda comece.
+
+Use os botões em cima para obter ajuda sobre coisas mais especÃficas.
+
+Dicas para esta seção:
+
Se tu saÃres do jogo como Humano, iras vir de volta como Zombie.
+Até ao inÃcio da onda 3 quem juntará ao jogo irá ser selecionado como zombie, mesmo os novos jogadores irão ser selecionados como zombies.
+Use o CHAT DE EQUIPA quando necessário. A tecla normal é U e te permite escrever SÓ para a tua equipa.
+
+]]
+LANGUAGE.help_cont_survival = [[Dicas para esta seção:
+
Carregando a tecla ZOOM (default: Z) deixa-te mover livremente nas barricadas, enquanto caminhas muito lentamente.
+Durante a Intermissão tu podes comprar mais items em uma Caixa de Arsenal porque irá aparecer um desconto, mas também podes descobrir items por comaradas mortos.
+Se um Humano for directamente morto por um Zombie, ele irá levantar-se. Acaba com a sua miséria antes que ele te ponha a miséria.
+É dado a ti algum worth para ser gastado no Worth Menu antes que a ronda comece, gasta tudo mas com cuidado!
+Tu podes criar, carregar eliminar e editar carregamentos no começo da ronda, apertando F2. Isto salva muito tempo que pode ser usado para pensar em planos e o que irás fazer na ronda.
+Um lugar que sente-se salvo em um momento pode tornar em uma morgue com um ou mais tipos diferentes de zombies á volta.Sempre pensa em um Plano B se as coisas ficarem feias.
+Tu és inutil á tua equipa se não estas a fazer alguma coisa que ajude. Tu estás sendo ainda mais inutil se não salvares pontos para comprar uma arma grande!
+Carregando a tua tecla SPRINT em objectos especiais, irás empacotar e podem ser utilizados em diversos sÃtios.
+Turretas sem donos (luz azul) podem ser tuas se apertares a tecla USE nelas. Turretas sem donos não irão disparar os zombies!
+Objectos que não estão pregados a alguma coisa são inuteis, a não se que sejam EXTREMAMENTE pesados.
+Com castigo suficiente, as portas podem ser arrancadas.
+Os objectos irão ficar mais e mais vermelhos com os danos que são dados, até expludirem.
+Zombies podem fazer spawn em cima deles, se não há um Humano a olhar.
+Algumas armas corpo-a-corpo têm um maior alcançe do que as garras dos zombies. Use isto como vantagem para defender-te a ti própio ou uma barricada com uma arma melee.
+Jogadores da mesma equipa não danificam-se a si própio, e não colidem-se entre si!.
+Tenha certeza de usar uma barricada para a tua proteção, as armas têm alcance infinito, mas as garras dos zombies não! (a não ser veneno).
+O dano de veneno pode ser curando com o tempo, mas muito veneno irá te fazer morto.
+Os membros da tua equipa nem sempre têm razão, tu não és um ovelha, pois não?! Zombies gostam de matar ovelhas.
+Zombies podem ver a tua vida, até através de paredes. Corre de volta para um sitio seguro, ou então vais ser caçado pelos zombies.
+Não escondas, os zombies podem te ver em qualquer lado, até na imensidão da escuridão.
+O Medidor de Horde que tens no fundo do ecrã deixa-te observar a resistencia e força que tens. Combina um ataque com zombies, assim podes acabar com barricadas gigantes!
+Se não tens zombies suficientes para acabar com uma barricada, encontra outros Humanos para caçares.
+Não dispares os zombies no gás verde!Só irá regenerar a vida dos zombies, assim só gastas a munição!
+Os Zombies são resistentes nas pernas, braços e corpo. Dispara para cabeça para mais danos e para prevenir alguns zombies de voltarem a levantar!
+Mesmo que os zombies sejam resistentes, se disparares irás o abrandar, isto pode ser util para salvar um colega com pouca vida.
+
+]]
+LANGUAGE.help_cont_barricading = [[Barricar é uma parte importantÃssima na sobrevivência. Pode parecer que os zombies não são uma ameaça no princÃpio mas eventualmente eles irão crescer e irão matar a tua equipa em uma questão de segundos.
+
+A melhor escolha para deixar os zombies de fora, é criar uma barricada.
+
+Há umas ferramentas que te ajudam a criar uma barricada. A mais poderosa e conhecida ferramenta é o Nailing Hammer, que é usado para pregar. Isto faz pregar objectos que tem que ser destruÃdos pelos zombies, antes que danifiquem o objecto.
+Posicione o objecto que queiras pregar apertando USE nele. Depois podes apanhar o teu Nailing Hammer e pregar-lo. É uma boa ideia para pregar o suporte a um objeto resistente, como uma parede, em vez de outros adereços.
+Lembra, quando um objecto esta pregado, o dano só irá para o prego, e depois para o objecto. Tu só o podes reparar batendo neles com o Hammer, mas vai chegar a altura em que os pregos estão danificados e não irão resistir mais. Tu podes carregar SHIFT para observar todos os pregos e os seus donos.
+.
+
+Uma outra ferramenta é a 'Aegis' Barricade Kit.Esta ferramenta é rapida e deixa-te colocar uma barreira de madeira em uma parede ou corredor. Não é necessário objectos. Para usar, tens que posicionar a uma posição valida (Fica vermelho para verde).
+Activa essa barreira carregando o botão do lado esquerdo. Roda usando ATAQUE SECUNDÃRIO e RECARREGA. Isso usa barricadas de madeira(boards) como munição! Tu podes apertar SHIFT para re-paquear essa barricada, que poderá ser reutilizada.
+
+Uma outra ferramenta util é a Turreta. Isto dispara balas nos zombies que se mete no seu caminho. Usa munição de SMG. Tu podes encher a turreta com munição apertando USE nela,isso te doará pontos.
+Para por uma turreta, posicione no chão até que fique VERDE. Tem que ser numa superfÃcie sólida (SEM OBJECTOS). Rode a turreta com ATAQUE SECUNDÃRIO e RECARREGA. Se não correr bem, paqueia-a apertando SHIFT nela. Lembra, a turreta só dispara zombies que está no seu alcance.
+
+Dicas para esta seção:
+
+Tu ganhas 25% bonus de pontos por matar zombies que atacam barricadas!
+Use objectos maior para a barricada. Os pregos ganham menos danos e há mais espaço para danificar os zombies.
+ ]]
+LANGUAGE.help_cont_upgrades = [[Pontos são obtidos por matando zombies, curando comaradas e construir barricadas.
+Tu podes trocar pontos no shop na intermissão por um preço mais barato.
+Faz as suas compras a Caixa de Arsenal para um desconto incrÃvel!
+
+Dicas para esta seção:
+
+Tenta planear. Compra munição extra no Worth Menu para que possas comprar uma pistola cheia de munição.
+Tu ainda ganhas pontos por assistências. A maior metade dos pontos vai para o matador, e a menor metade vai para o que danificou.
+Worth e Pontos são separados. Gasta toda a tua Worth!
+Caixas de Arsenal (Arsneal Crate) são extremamente valorizadas e são um grande alvo para os zombies.
+ ]]
+LANGUAGE.help_cont_being_a_zombie = [[Dicas para esta seção:
+
+Tu tens uma quantidade infinita de vidas, mas os Humanos não. Ataque sem piedade!
+O Zombie regular têm a capacidade de durabilidade. O unico caminho para ser morto com certeza é um ou mais disparos certeiros na cabeça. Tu não precisas das tuas pernas.
+Zombies podem fazer spawn nos seus colegas se não há Humanos por perto, vê a caveira, se tiver olhos verdes quer dizer que os teus colegas zombies podem fazer spawn em ti!
+Com muita prática, podes usar objectos para matar Humanos a uma GRANDE distancia.
+Destrua objectos especiais como turretas, Caixas de Arsenal e de resupplementos, isso irá por os Humanos em uma situação complicada.
+Com castigo suficiente, as portas podem ser arrancadas..
+Mais os objectos são atingidos, mais vermelhos irão ficar.
+O Wraith é completamente invisivel se não moveres.
+O ataque especial do Zombie Rápido depende quanto tempo estás no ar. O mais no ar estás, maior o dano. Usa as suas garras para combate corpo-a-corpo!
+Em adição de ser extremamente poderoso, o Zombie Venenoso pode arrancar carne de si mesmo e atirar ao seu alvo.
+O Headcrab Venenoso pode por os Humanos confusos se atingirem na cabeça.
+Vá para humanos com pouca vida! Os zombies também são atraÃdos, então tente ser o primeiro a matar a vitÃma!
+O Medidor de Horda no fundo do ecrã indica a quantidade de dano que podes resistir, mais zombies, mais resistencia!
+Se não tens zombies suficientes para acabar com uma barricada, tenta caçar..hehe.."coleguas de equipa" em outro sÃtio.
+Se uma área está muito escura, pressione o botão de LATERNA para VISÃO NOCTURNA.
+
+]]
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/languages/russian.lua b/gamemodes/zombiesurvival/gamemode/languages/russian.lua
new file mode 100644
index 0000000..97c5cbf
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/languages/russian.lua
@@ -0,0 +1,319 @@
+-- Translated by Mr. Darkness (http://www.noxiousnet.com/forums/index.php?action=profile;u=6296)
+
+translate.AddLanguage("ru", "Russian")
+
+-- Various gamemode stuff
+LANGUAGE.minute_points_added = "Ð’Ñ‹ не получили ранений за вÑÑŽ минуту! Вам было приÑвоено %d очков."
+LANGUAGE.infliction_reached_class_unlocked = "%d%% Ð·Ð°Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð±Ñ‹Ð»Ð¾ доÑтигнуто! %s разблокирован!"
+LANGUAGE.infliction_reached = "%d%% выживших погибло!"
+LANGUAGE.x_unlocked = "%s разблокирован!"
+LANGUAGE.disconnect_killed = "%s был отÑоединен, его убийца %s."
+LANGUAGE.nail_removed_by = "%s убрал гвоздь, ранее принадлежавший %s."
+LANGUAGE.banned_for_life_warning = "Ваша жизнь забанена, вы ничего не можете купить!"
+LANGUAGE.need_to_be_near_arsenal_crate = "Ð’Ñ‹ должны быть Ñ€Ñдом Ñ Arsenal crate чтобы делать покупки!"
+LANGUAGE.cant_purchase_right_now = "Вы, пока что, ничего не можете купить."
+LANGUAGE.dont_have_enough_points = "У Ð’Ð°Ñ Ð½ÐµÐ´Ð¾Ñтаточно очков."
+LANGUAGE.prepare_yourself = "ПриготовьтеÑÑŒ..."
+LANGUAGE.purchased_x_for_y_points = "Вами был куплен %s за %d очков!"
+LANGUAGE.give_time_before_suicide = "Дайте Ð²Ñ€ÐµÐ¼Ñ Ð¾Ñтальным, чтобы поÑвитьÑÑ Ð² игре, перед тем, как вы убьете ÑебÑ."
+LANGUAGE.no_spare_ammo_to_give = "Ðет запаÑов Ð´Ð»Ñ Ð¾Ñ‚Ð´Ð°Ñ‡Ð¸ другим!"
+LANGUAGE.no_person_in_range = "Ðет выжившего на виду!"
+LANGUAGE.that_life = "За Ñту жизнь..."
+LANGUAGE.x_damage_to_barricades = "%d вреда баррикадам"
+LANGUAGE.x_damage_to_humans = "%d вреда выжившим"
+LANGUAGE.x_brains_eaten = "%d мозгов Ñъедено"
+LANGUAGE.press_rmb_to_cycle_targets = "Ðажмите ПКМ Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾ чтобы Ñменить цель"
+LANGUAGE.press_lmb_to_spawn_on_them = "Ðажмите ЛКМ, чтобы поÑвитьÑÑ Ð½Ð° цели"
+LANGUAGE.press_lmb_to_spawn = "Ðажмите ЛКМ чтобы поÑвитьÑÑ"
+LANGUAGE.observing_x = "Ð’Ñ‹ Ñмотрите на %s (%d)"
+LANGUAGE.waiting_for_next_wave = "Ожидание начала Ñледующей волны..."
+LANGUAGE.impossible = "Ðто невозможно."
+LANGUAGE.trying_to_put_nails_in_glass = "Ðто очень умно ÑтаратьÑÑ Ð²Ð±Ð¸Ñ‚ÑŒ гвозди в Ñтекло."
+LANGUAGE.boss_class_select = "Ð’Ñ‹ поÑвитеÑÑŒ, как %s в Ñледующий раз как зараженный."
+LANGUAGE.person_has_weapon = "У него/ее уже еÑÑ‚ÑŒ Ñто оружие."
+LANGUAGE.cant_do_that_in_classic_mode = "Ð’Ñ‹ не можете так Ñделать в Classic Mode."
+LANGUAGE.cant_use_x_in_classic_mode = "Ð’Ñ‹ не можете иÑпользовать %s в Classic Mode."
+LANGUAGE.cant_use_x_in_zombie_escape = "Ð’Ñ‹ не можете иÑпользовать %s в Zombie Escape."
+LANGUAGE.no_class_switch_in_this_mode = "Данный мод не позволÑет вам менÑÑ‚ÑŒ клаÑÑÑ‹."
+LANGUAGE.press_sprint_to_get_up = "Ðажмите кнопку БЕГÐТЬ чтобы поднÑÑ‚ÑŒÑÑ"
+LANGUAGE.zombie_escape = "Zombie Escape!"
+LANGUAGE.nothing_for_this_ammo = "У Ð’Ð°Ñ Ð½ÐµÑ‚ ничего, что иÑпользует Ñтот тип амуниции."
+LANGUAGE.you_decide_to_leave_some = "Ð’Ñ‹ решили оÑтавить некоторое количеÑтво Ð´Ð»Ñ Ð’Ð°ÑˆÐµÐ¹ команды."
+LANGUAGE.you_cant_purchase_now = "Вы не можете покупать предметы на данный момент."
+LANGUAGE.no_ammo_here = "ЗдеÑÑŒ нет запаÑов на данный момент."
+LANGUAGE.you_redeemed = "Ð’Ñ‹ были воÑкрешены!"
+LANGUAGE.kill_the_last_human = "Убейте поÑледнего выжившего!"
+LANGUAGE.kick_the_last_human = "Кикните поÑледнего выжившего!"
+LANGUAGE.you_are_the_last_human = "ВЫ ПОСЛЕДÐИЙ ВЫЖИВШИЙ!"
+LANGUAGE.x_zombies_out_to_get_you = "%d ЗÐÐ ÐЖЕÐÐЫЕ ИДУТ ЗРВÐМИ!"
+LANGUAGE.x_pants_out_to_get_you = "%d ÐОГИ ИДУТ ЗРВÐМИ!"
+LANGUAGE.you_have_died = "Вы умерли."
+LANGUAGE.you_were_killed_by_x = "Вы били убиты игроком %s"
+LANGUAGE.you_were_kicked_by_x = "Ð’Ð°Ñ Ñ€Ð°Ð·Ð±Ð¸Ð»Ð¸ в ÐºÐ»Ð¾Ñ‡ÑŒÑ Ð¸Ð³Ñ€Ð¾ÐºÐ¾Ð¼ %s"
+LANGUAGE.arsenal_upgraded = "ÐÑ€Ñенал был обновлен"
+LANGUAGE.final_wave = "ПОСЛЕДÐЯЯ ВОЛÐÐ ÐÐЧÐЛÐСЬ!"
+LANGUAGE.final_wave_sub = "Ð’Ñе клаÑÑÑ‹ разблокированы, а возможноÑÑ‚ÑŒ на возрождение иÑÑÑкло!"
+LANGUAGE.wave_x_has_begun = "Волна номер %d началаÑÑŒ!"
+LANGUAGE.x_unlocked = "%s разблокирован!"
+LANGUAGE.wave_x_is_over = "Волна номер %d завершилаÑÑŒ!"
+LANGUAGE.wave_x_is_over_sub = "Зараженные оÑтановили Ñвое возрождение а товары в Points Shop теперь Ñо Ñкидкой %d%%."
+LANGUAGE.you_are_x = "Ð’Ñ‹ %s!"
+LANGUAGE.x_has_risen_as_y = "%s поÑвилÑÑ ÐºÐ°Ðº %s!!"
+LANGUAGE.x_has_risen = "%s поÑвилÑÑ!"
+LANGUAGE.cant_use_worth_anymore = "Ð’Ñ‹ больше не можете иÑпользовать worth меню!"
+LANGUAGE.class_not_unlocked_will_be_unlocked_x = "Ðтот клаÑÑ ÐµÑ‰Ñ‘ не разблокирован. Он будет разблокирован на Ñледующей волне %d."
+LANGUAGE.you_are_already_a_x = "Вы уже %s."
+LANGUAGE.you_will_spawn_as_a_x = "Ð’Ñ‹ поÑвитеÑÑŒ, как %s."
+LANGUAGE.crafting_successful = "СлиÑние прошло удачно!"
+LANGUAGE.x_crafted_y = "%s Ñоздал %s."
+LANGUAGE.escape_from_the_zombies = "Убегайте от зараженных!"
+LANGUAGE.too_close_to_another_nail = "Слишком близко к другому гвоздю."
+LANGUAGE.object_too_damaged_to_be_used = "Ðтот объект Ñлишком поврежден Ð´Ð»Ñ Ð´Ð°Ð»ÑŒÐ½ÐµÐ¹ÑˆÐµÐ³Ð¾ иÑпользованиÑ."
+LANGUAGE.thanks_for_being_a_fan_of_zs = "СпаÑибо за то, что бы наш игрок мода Zombie Survival!"
+LANGUAGE.cant_remove_nails_of_superior_player = "Ð’Ñ‹ не можете Ñнимать гвозди игрока, который играет гораздо лучше ВаÑ."
+LANGUAGE.x_turned_on_noclip = "%s включил noclip."
+LANGUAGE.x_turned_off_noclip = "%s выключил noclip."
+LANGUAGE.unlocked_on_wave_x = "РазблокируетÑÑ Ð½Ð° волне %d"
+LANGUAGE.brains_eaten_x = "Мозгов Ñъедено: %s"
+LANGUAGE.points_x = "Очков: %s"
+LANGUAGE.next_wave_in_x = "Ð¡Ð»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ Ð²Ð¾Ð»Ð½Ð° через %s"
+LANGUAGE.wave_ends_in_x = "Волна заканчиваетÑÑ Ñ‡ÐµÑ€ÐµÐ· %s"
+LANGUAGE.wave_x_of_y = "Волна %d из %d"
+LANGUAGE.zombie_invasion_in_x = "Зараженные наÑтупают через %s"
+LANGUAGE.intermission = "Пауза"
+LANGUAGE.press_f2_for_the_points_shop = "Ðажмите F2 чтобы открыть Points Shop!"
+LANGUAGE.breath = "Дыхание"
+LANGUAGE.zombie_volunteers = "Зараженными Ñтанут"
+LANGUAGE.x_discount_for_buying_between_waves = "Скидка в %d%% Ð´Ð»Ñ Ð¿Ð¾ÐºÑƒÐ¿Ð¾Ðº в конце каждой волны!"
+LANGUAGE.number_of_initial_zombies_this_game = "КоличеÑтво зараженных в Ñтой игре (%d%%): %d"
+LANGUAGE.humans_closest_to_spawns_are_zombies = "Самые близко ÑтоÑщие к Ñпауну зараженних Ñтанут зараженными."
+LANGUAGE.waiting_for_players = "Ожидание игроков..."
+LANGUAGE.requires_x_people = "ТребуетÑÑ %d игроков"
+LANGUAGE.packing_others_object = "Складываем объект другого игрока"
+LANGUAGE.packing = "Складываем"
+LANGUAGE.ze_humans_are_frozen_until_x = "Выжившие заморожены на %d Ñекунд до конца раунда."
+LANGUAGE.loading = "Загрузка..."
+LANGUAGE.next_round_in_x = "Следующий раунд через: %s"
+LANGUAGE.warning = "Внимание!"
+LANGUAGE.ok_and_no_reminder = "Хорошо, пожалуйÑта, больше не показывайте Ñто Ñообщение"
+LANGUAGE.classic_mode_warning = "Ðа Ñтом Ñервере ведетÑÑ Zombie Survival в режиме 'Classic Mode'\nClassic Mode Ñто мод, который ведет альтернативную игру. То, что было изменено:\n* ÐевозможноÑÑ‚ÑŒ выбора клаÑÑа зараженного. Ð’Ñе играют за Classic Zombie class\n* ИнÑтрументы баррикады и турели отключены\n* Больше волн, но они заканчиваютÑÑ Ð±Ñ‹Ñтрее\n\nÐто не оригинальный Zombie Survival!\n\n-- Серверы, которые ведут режим КлаÑÑичеÑкого режима будут показывать CLASSIC MODE в нижнем лемом углу Ñкрана --"
+LANGUAGE.classic_mode = "CLASSIC MODE"
+LANGUAGE.resist_x = "СтойкоÑÑ‚ÑŒ: %d%%"
+LANGUAGE.right_click_to_hammer_nail = "ПКМ чтобы вбить гвоздь."
+LANGUAGE.nails_x = "Гвозди: %d"
+LANGUAGE.resupply_box = "Ящик аммуниции"
+LANGUAGE.purchase_now = "Покупайте ÑейчаÑ!"
+LANGUAGE.integrity_x = "ЦелоÑтноÑÑ‚ÑŒ: %d%%"
+LANGUAGE.empty = "ПУСТО"
+LANGUAGE.manual_control = "ИÐÐУÐЛЬÐОЕ УПРÐВЛЕÐИЕ"
+LANGUAGE.arsenal_crate = "ÐÑ€Ñенальный Ñщик"
+
+-- Exit point objectives
+LANGUAGE.exit_destroyed = "Зараженные уничтожили какой-то выход!"
+LANGUAGE.exit_destroyed_only_one_remain_h = "ПоÑледный оÑталÑÑ! ЕÑли он будет уничтожен, у Ð’Ð°Ñ Ð½Ðµ оÑтанетÑÑ ÑˆÐ°Ð½Ñа на побег!"
+LANGUAGE.exit_destroyed_only_one_remain_z = "ОÑтаетÑÑ Ð¿Ð¾Ñледний!"
+LANGUAGE.exit_destroyed_x_remain = "%d выходов оÑталоÑÑŒ."
+LANGUAGE.last_exit_destroyed_all_is_lost = "Зараженные уничтожили поÑледний выход."
+LANGUAGE.last_exit_destroyed_all_is_lost2 = "У Ð’Ð°Ñ Ð½Ðµ оÑталоÑÑŒ шанÑов на побег."
+
+-- Message beacon messages
+LANGUAGE.message_beacon_1 = "Ð’ÑтречаемÑÑ Ð·Ð´ÐµÑÑŒ"
+LANGUAGE.message_beacon_2 = "ЗдеÑÑŒ нужна защита"
+LANGUAGE.message_beacon_3 = "ЗдеÑÑŒ нужны турели"
+LANGUAGE.message_beacon_4 = "Ðужны арÑенальные Ñщики здеÑÑŒ"
+LANGUAGE.message_beacon_5 = "Ðужны медики здеÑÑŒ"
+LANGUAGE.message_beacon_6 = "Ящик аммуниции здеÑÑŒ"
+LANGUAGE.message_beacon_7 = "ÐÑ€Ñенальный Ñщик здеÑÑŒ"
+LANGUAGE.message_beacon_8 = "Ðужны force fields здеÑÑŒ"
+LANGUAGE.message_beacon_9 = "Ðужны взрывоопаÑные объекты здеÑÑŒ"
+LANGUAGE.message_beacon_10 = "Зараженные могут пройти здеÑÑŒ"
+LANGUAGE.message_beacon_11 = "Ðе входить!!"
+LANGUAGE.message_beacon_12 = "Ðе выходите наружу"
+LANGUAGE.message_beacon_13 = "Защищайте Ñтот район"
+LANGUAGE.message_beacon_14 = "Защищайте Ñто меÑто"
+LANGUAGE.message_beacon_15 = "Медики здеÑÑŒ"
+LANGUAGE.message_beacon_16 = "Покупайте из моего Ñщика"
+LANGUAGE.message_beacon_17 = "БаррикадироватьÑÑ Ð·Ð´ÐµÑÑŒ"
+LANGUAGE.message_beacon_18 = "Ðе баррикадируйтеÑÑŒ здеÑÑŒ"
+LANGUAGE.message_beacon_19 = "Ðе давайте зараженным пройти Ñюда"
+LANGUAGE.message_beacon_20 = "Ðто ÑломаетÑÑ"
+LANGUAGE.message_beacon_21 = "Ðто меÑто опаÑно!"
+LANGUAGE.message_beacon_22 = "Избегайте Ñд!"
+LANGUAGE.message_beacon_23 = "Зараженные проламываютÑÑ Ð·Ð´ÐµÑÑŒ!"
+LANGUAGE.message_beacon_24 = "Зараженные подходÑÑ‚. БаррикадируйтеÑÑŒ здеÑÑŒ!"
+LANGUAGE.message_beacon_25 = "План Б здеÑÑŒ"
+
+-- Class names
+LANGUAGE.class_zombie = "Зомби"
+LANGUAGE.class_poison_zombie = "Ядовитый Зомби"
+LANGUAGE.class_fast_zombie = "БыÑтрый зомби"
+LANGUAGE.class_bloated_zombie = "Жирный зомби"
+LANGUAGE.class_classic_zombie = "КлаÑÑичеÑкий зомби"
+LANGUAGE.class_super_zombie = "Супер зомби"
+LANGUAGE.class_fresh_dead = "Свежий зараженный"
+LANGUAGE.class_ghoul = "Вурдалак"
+LANGUAGE.class_headcrab = "Ð¥Ñдкраб"
+LANGUAGE.class_fast_headcrab = "БыÑтрый Ñ…Ñдкраб"
+LANGUAGE.class_poison_headcrab = "Ядовитый Ñ…Ñдкраб"
+LANGUAGE.class_the_tickle_monster = "The Tickle Monster"
+LANGUAGE.class_nightmare = "Nightmare"
+LANGUAGE.class_pukepus = "Pukepus"
+LANGUAGE.class_bonemesh = "Bonemesh"
+LANGUAGE.class_crow = "Ворон"
+LANGUAGE.class_wilowisp = "Wil O' Wisp"
+LANGUAGE.class_zombie_torso = "Ð¢Ð¾Ñ€Ñ Ð·Ð¾Ð¼Ð±Ð¸"
+LANGUAGE.class_zombie_legs = "Ðоги зомби"
+LANGUAGE.class_wraith = "Дух"
+LANGUAGE.class_flesh_beast = "Flesh Beast"
+LANGUAGE.class_fast_zombie_legs = "Ðоги быÑтрого зомби"
+LANGUAGE.class_chem_zombie = "ХимичеÑкий зомби"
+LANGUAGE.class_shade = "Shade"
+
+-- Class descriptions
+LANGUAGE.description_zombie = "Обычный зомби очень Ñтойкий и довольно Ñилен.\nЕго Ñложно положить, оÑобенно еÑли не ÑтрелÑÑ‚ÑŒ в голову."
+LANGUAGE.description_poison_zombie = "Ðтот мутированный зараженный не только Ñерьезно Ñтойкий у него также выÑÐ¾ÐºÐ°Ñ Ñила удара.\nЕго тело очень токÑично И рвёт его ÑобÑтвенное мÑÑо и кожу что позволÑет ему кидать вÑе Ñто в выживших."
+LANGUAGE.description_fast_zombie = "Ðтот кадавр гораздо быÑтрее, чем оÑтальные зараженные.\nОни не такие опаÑные одиночками, Ðо могут доÑтигнуть люього района, Ð¿Ð¾Ð»Ð·Ð°Ñ Ð¿Ð¾ Ñтенам Ñвоими оÑтрыми когтÑми.\nОни также могут без проблем охотитьÑÑ Ð½Ð° Ñлабых, еле живых выживших."
+LANGUAGE.description_bloated_zombie = "Их тело ÑоÑтоит из токÑичных вещеÑтв.\nХоть они и двигаютÑÑ Ð¼ÐµÐ´Ð»ÐµÐ½Ð½Ð¾, они могут нанеÑти большой ущерб."
+LANGUAGE.description_ghoul = "У Ñтого замби выÑоко токÑÐ¸Ñ‡Ð½Ð°Ñ Ð¿Ð»Ð¾Ñ‚ÑŒ.\nÐтот зомби немного Ñлабее других, но наноÑит большой ущерб Ñвоими токÑичеÑкими атаками.\nЕго когти могут оÑлабить выжившего на короткий Ñрок, а также он выпуÑкает Ñд из Ñвоих ран, еÑли ущерб, нанеÑенный ему будет довольно выÑоким."
+LANGUAGE.description_headcrab = "Ð¥Ñдкрабы - Ð¿ÐµÑ€Ð²Ð°Ñ Ð¿Ñ€Ð¸Ñ‡Ð¸Ð½Ð° заражениÑ.\nÐикто не знает, откуда они на Ñамом деле пришли.\nИх метод атаки заключаетÑÑ Ð² прыгании на жертву Ñвоими когтÑми на животе."
+LANGUAGE.description_fast_headcrab = "Самец Ñ…Ñдкраба гораздо быÑтрее, но Ñлабее, чем Ñамка.\nÐо как бы ни так, они вÑе же надоедливее и опаÑнее в группах."
+LANGUAGE.description_poison_headcrab = "Ðтот Ñ…Ñдкраб полон неуротокÑинов.\nОдного укуÑа обычно доÑтаточно, чтобы убить взроÑлого человека.\nОн также может плеватьÑÑ Ð¼ÐµÐ½ÐµÐµ опаÑным Ñдом.\nПлевок, однако также Ñмертельно опаÑен, еÑли попадает в лицо Ñвоей жертвы."
+LANGUAGE.description_the_tickle_monster = "ИзвеÑтен, как \"монÑÑ‚Ñ€, прÑчущийÑÑ Ñƒ Ñ‚ÐµÐ±Ñ Ð² шкафу\" чтобы ночью утащить Ñ‚ÐµÐ±Ñ Ð¸Ð· твоей кравати.\nУ Ñтого Tickle Monster почти ÑлаÑтичные руки, что делают его неизбегаемым как и почти что идеальным уничтожителем баррикад."
+LANGUAGE.description_nightmare = "Ðтой очень редкой мутации дает необычные ÑпоÑобноÑти Nightmare.\nОн Ñильнее, чем любой обычный зараженный в почти что любом направлении, у Nightmare ужаÑÐ°ÑŽÑ‰Ð°Ñ Ñила.\nОдного взмаха когтÑми обычно доÑтаточно чтобы убить выжившего."
+LANGUAGE.description_pukepus = "Гниющее тело Puke Pus иÑпользует внутренние органы Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñда.\nОн ÑпоÑобен извергать маÑÑÑ‹ рвоты Ñда, который очень опаÑен."
+LANGUAGE.description_bonemesh = "Без фигуры и изуродованный Bonemesh ÑпоÑобен делать бомбы из крови.\nÐšÐ°Ð¶Ð´Ð°Ñ Ð±Ð¾Ð¼Ð±Ð° ÑоÑтоит из коÑтей и плоти, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð²Ñ€ÐµÐ´Ð¸Ñ‚ выжившим, одновременно ÑвлÑÑÑÑŒ отличной едой Ð´Ð»Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… зараженных."
+LANGUAGE.description_crow = "Отвратительные вороны ÑÐµÐ¹Ñ‡Ð°Ñ Ð±Ð¾Ð»ÐµÐµ чем паразиты поÑле инфекции.\nОни питаютÑÑ Ð¿Ð»Ð¾Ñ‚ÑŒÑŽ зараженных и ÑтановÑÑ‚ÑÑ \"ноÑителÑми\" зараженным.\nПочему вы вообще не Ñкрыли Ñтот клаÑÑ?\nЧто Ñ Ð’Ð°Ð¼Ð¸ не так?"
+LANGUAGE.description_wilowisp = "Иногда извеÑтный, как \"дух зараженных\"."
+LANGUAGE.description_zombie_torso = "Вам даже не Ñледует видеть ÐТО."
+LANGUAGE.description_zombie_legs = "Ðто не Ð´Ð»Ñ Ð’Ð°ÑˆÐ¸Ñ… глаз."
+LANGUAGE.description_wraith = "Зомби или иллюзиÑ?\nÐе многое извеÑтно о нем,кроме факта, что его\nÐ½ÐµÐ¾Ð±Ñ‹Ñ‡Ð½Ð°Ñ ÑпоÑобноÑÑ‚ÑŒ невидимоÑти и оÑтрые когти могут разрезать вÑе по куÑочкам."
+LANGUAGE.description_flesh_beast = "*на подходе*"
+LANGUAGE.description_fast_zombie_legs = "Ðе Ð´Ð»Ñ Ð’Ð°ÑˆÐ¸Ñ… глаз."
+LANGUAGE.description_chem_zombie = "Тело ХимичеÑкого Зараженного ÑоÑтоит из реактивных, токÑичных химикатов.\nУ Ñтого зараженного нет Ð¿Ð¾Ð²Ð¾Ð´Ð°Ð´Ð»Ñ Ð°Ñ‚Ñ‚Ð°ÐºÐ¸, кроме как ÑамоубийÑтво, Ñ Ð½Ð°Ð´ÐµÐ¶Ð´Ð¾Ð¹ подорвать Ñ€Ñдом ÑтоÑщих выживших."
+LANGUAGE.description_shade = "Ð¡Ð¾Ð·Ð´Ð°Ð²Ð°Ñ Ñильное магнитичеÑкое поле вокруг ÑебÑ, вÑе пули и рукопашне аттаки беÑполезны против него.\nОднако, по какой-то причине Shade раним Ñрким Ñветом."
+
+-- Class control schemes
+LANGUAGE.controls_zombie = "> ПЕРВИЧÐЫЙ: Когти\n> ВТОРИЧÐЫЙ: Крик\n> ПЕРЕЗÐРЯДКÐ: Плач\n> БЕГ: ПритворитьÑÑ Ð¼ÐµÑ€Ñ‚Ð²Ñ‹Ð¼\n> УБИЙСТВО Ð’ ÐОГИ: Ð¨Ð°Ð½Ñ Ð½Ð° реанимацию / транÑформациÑ"
+LANGUAGE.controls_poison_zombie = "> ПЕРВИЧÐЫЙ: Когти\n> ВТОРИЧÐЫЙ: Кинуть плотью\n> ПЕРЕЗÐРЯДКÐ: Крик"
+LANGUAGE.controls_fast_zombie = "> ПЕРВИЧÐЫЙ: Когти\n> ВТОРИЧÐЫЙ: Пригнуть выÑоко / Лазить (по Ñтене)\n> ПЕРЕЗÐРЯДКÐ: Крик"
+LANGUAGE.controls_bloated_zombie = "> ПЕРВИЧÐЫЙ: Когти\n> ВТОРИЧÐЫЙ: Плач\n> БЕГ: ПритворитьÑÑ Ð¼ÐµÑ€Ñ‚Ð²Ñ‹Ð¼\n> СМЕРТЬ: Ядовитые куÑки плоти"
+LANGUAGE.controls_ghoul = "> ПЕРВИЧÐЫЙ: Ядовитые когти\n> ВТОРИЧÐЫЙ: Кинуть плотью\n> БЕГ: ПритворитьÑÑ Ð¼ÐµÑ€Ñ‚Ð²Ñ‹Ð¼\n> ПЕРЕЗÐРЯДКÐ: Крик\n> УДÐРИВ ВЫЖИВШЕГО: Замедление\n> ПРИ ПОЛУЧЕÐИИ Ð ÐÐЕÐИЯ: ВыпуÑк Ñда из ран"
+LANGUAGE.controls_headcrab = "> ПЕРВИЧÐЫЙ: Ð£ÐºÑƒÑ Ð² прыжке\n> ПЕРЕЗÐРЯДКÐ: ЗарытьÑÑ Ð¿Ð¾Ð´ землю"
+LANGUAGE.controls_fast_headcrab = "> ПЕРВИЧÐЫЙ: Ð£ÐºÑƒÑ Ð² прыжке"
+LANGUAGE.controls_poison_headcrab = "> ПЕРВИЧÐЫЙ: Ð£ÐºÑƒÑ Ð² прыжке\n> ВТОРИЧÐЫЙ: Плевок Ñдом\n> УДÐРИВ ВЫЖИВШЕГО: Смертельный Ñд\n> ПОПÐДÐÐИЕ ЯДОМ Ð’ ГЛÐЗÐ: ОÑлерление\n> ПЕРЕЗÐРЯДКÐ: Крик"
+LANGUAGE.controls_the_tickle_monster = "> ПЕРВИЧÐЫЙ: ÐлаÑтичные когти\n> ВТОРИЧÐЫЙ: Плач"
+LANGUAGE.controls_nightmare = "> ПЕРВИЧÐЫЙ: ПрикоÑновение Ñмерти\n> ВТОРИЧÐЫЙ: Плач"
+LANGUAGE.controls_pukepus = "> ПЕРВИЧÐЫЙ: Рвота"
+LANGUAGE.controls_bonemesh = "> ПЕРВИЧÐЫЙ: Когти\n> ВТОРИЧÐЫЙ: Кинуть кровавой бомбой"
+LANGUAGE.controls_wraith = "> ПЕРВИЧÐЫЙ: Когти\n> ВТОРИЧÐЫЙ: Крик\n> ÐЕВИДИМОСТЬ ЗÐВИСИТ ОТ ДВИЖЕÐИЯ И Ð ÐССТОЯÐИЯ ВИДИМОСТИ"
+LANGUAGE.controls_flesh_beast = "> ПЕРВИЧÐЫЙ: Когти\n> ВТОРИЧÐЫЙ: Ð¥Ñд Батт"
+LANGUAGE.controls_chem_zombie = "> СМЕРТЬ: Ядовитый взрыв"
+LANGUAGE.controls_shade = "> ПЕРВИЧÐЫЙ: ЛевитациÑ\n> ВТОРИЧÐЫЙ: Кинуть"
+
+-- The help file... Quite big! I wouldn't blame you if you didn't translate this part.
+LANGUAGE.help_cat_introduction = "Ð’Ñтупление"
+LANGUAGE.help_cat_survival = "Выживание"
+LANGUAGE.help_cat_barricading = "Баррикадирование"
+LANGUAGE.help_cat_upgrades = "ÐŸÐ¾Ð²Ñ‹ÑˆÐµÐ½Ð¸Ñ Ð¸ апгрейды"
+LANGUAGE.help_cat_being_a_zombie = "Когда Ñ Ð·Ð°Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ‹Ð¹"
+LANGUAGE.help_cont_introduction = [[ Добро пожаловать в Zombie Survival, ÑимулÑтор на (зомби) выживание. ZS позволÑет Вам играть против аттаки зомби, Ñоздавать баррикады, и даже ÑтановитьÑÑ Ñ‡Ð°Ñтью армии зараженных. (Перевод: Mr. Darkness)
+
+У Ð’Ð°Ñ ÐµÑÑ‚ÑŒ две комманды: выжившие и зараженные. Выжившие выигрывают, еÑли выживают вÑе волны. Ðекоторые карты имеют оÑобенные заданиÑ, выполнÑÑ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ðµ можно выиграть (пример: zs_obj_outland, zs_obj_pharmancy).
+ЕÑли выживший умирает, то он ÑтановитÑÑ Ñ‡Ð°Ñтью армии зомби, что дает меньше шанÑов на выигрыш выживших.
+
+Цель зараженных - убить вÑех выживших, Ð´ÐµÐ»Ð°Ñ Ð¸Ñ… чаÑтью Ñвоей армии, и заÑтавлÑÑ Ñ‚Ð°ÐºÐ¸Ð¼ образом Ñделать гейм овер.
+Однако, зараженный может убить четверо выживших, чтобы возродитьÑÑ. Ðто дает ему второй ÑˆÐ°Ð½Ñ Ð½Ð° выживание и победу.
+Помните, единÑтвенный ÑпоÑоб выиграть раунд - оÑтатьÑÑ Ð²Ñ‹Ð¶Ð¸Ð²ÑˆÐ¸Ð¼ до конца раунда. Зараженные техничеÑки не выигрывают, а наоборот - заÑтавлÑÑŽÑ‚ оÑтальных проиграть!
+
+ÐеÑколько человек будет выбрано (Или желающие) Чтобы Ñтать зараженным в начале раунда. Их кол-во будет изображено внизу Вашего Ñкрана до начала раунда.
+
+ИÑпользуйте кнопки "вверх" и "вниз" чтобы узнать более ÑпецефичеÑкие вещи.
+
+Советы Ð´Ð»Ñ Ñтой Ñекции:
+
ЕÑли вы выходите из игры, как выживший, при переподключении вы ÑтановитеÑÑŒ зобми.
+ПоÑле того, как некоторое Ð²Ñ€ÐµÐ¼Ñ Ñ€Ð°ÑƒÐ½Ð´Ð° прошло, подключающиеÑÑ Ðº Ñерверу игроки поÑвÑÑ‚ÑÑ, как зомби.
+ИÑпользуйте КОМÐÐДÐЫЙ ЧÐТ, когда Ñто нужно. Ð¡Ñ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð°Ñ ÐºÐ»Ð°Ð²Ð¸ÑˆÐ° - U, позволÑет обращатьÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ к Ñвоей команде.
+
+]]
+LANGUAGE.help_cont_survival = [[Tips for this section:
+
Зажмите калвижу ZOOM (Ñтандартно: Z) чтобы проходить Ñквозь баррикады Ñ Ð¼ÐµÐ´Ð»ÐµÐ½Ð½Ð¾Ð¹ ÑкороÑтью.
+Ð’Ñ‹ можете покупать предметы, такие как Ð¾Ñ€ÑƒÐ¶Ð¸Ñ Ð¸ аммуницию во Ð²Ñ€ÐµÐ¼Ñ Ð¿ÐµÑ€ÐµÑ€Ñ‹Ð²Ð¾Ð² между волнами, но вы также можете Ñобирать оружиÑ, инÑтрументы Ñ ÑƒÐ¼ÐµÑ€ÑˆÐ¸Ñ… выживших.
+ЕÑли выживший был убит именно зараженным, то они будут реанемированы, как зомби. Убейте их до того, как они убили ВаÑ!
+Вам дано только некоторое количеÑтво Worth которыми вы можете купить начальные предметы, обдумайте Ñвои покупки внимательно!
+Мы можете Ñоздавать, ÑохранÑÑ‚ÑŒ, загружать, удалÑÑ‚ÑŒ и помечать, как Ñтандартные покупки, Ð½Ð°Ð¶Ð¸Ð¼Ð°Ñ F2. Таким образом вы можете Ñохранить тонны времени на баррикадирование или обдумывание планов на игру.
+Какое-либо безопаÑное меÑтно может какатьÑÑ Ñ‚Ð°ÐºÐ¸Ð¼ поначалу, но может Ñтать Ñмертельной ловушкой Ñ Ð·Ð¾Ð¼Ð±Ð¸ вокруг. Ð’Ñегда ищите дополнительное проÑтранÑтво и "План Б" еÑли вÑе идет не так.
+Ð’Ñ‹ беÑполезны Ð´Ð»Ñ Ñвоей команды, еÑли вы ничего не делаете, чтобы помочь. Ð’Ñ‹ даже более беÑполезны Ð´Ð»Ñ Ñамого ÑебÑ, поÑкольку Ð’Ñ‹ не зарабатываете очков и не получаете крутые оружиÑ!
+Зажмите клавишу БЕГ, в то времÑ, как Ñмотрите на любой Вами поÑтавленный объект, чтобы убрать их Ð´Ð»Ñ Ð´Ð°Ð»ÑŒÐ½ÐµÐ¹ÑˆÐµÐ³Ð¾ иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾Ð·Ð¶Ðµ.
+Ðе принадлежащие никому турели (Ñиний Ñвет) могут Ñтать Вашими, нажав кнопку ИСПОЛЬЗОВÐТЬ. Ðичейные турели не будут ÑтрелÑÑ‚ÑŒ!
+Вокруг валÑющиеÑÑ Ð¿Ñ€ÐµÐ´Ð¼ÐµÑ‚Ñ‹ Ñтоит иÑпользовать, как баррикаду и Ñтоит их пригвоздить, но не еÑли они Ñлишком Ñ‚Ñжелые.
+ÐанеÑÑ Ð´Ð¾Ñтаточно урона дверÑм, их можно ÑнеÑти.
+БольшинÑтво пребметов ÑтановитÑÑ ÐºÑ€Ð°Ñного цвета, в завиÑимоÑти от нанеÑенного им урона.
+Зомби могут поÑвлÑÑ‚ÑŒÑ Ð½Ð°Ð´ друг другом, еÑли выжившие не видÑÑ‚ Ñтого.
+БольшинÑтво орудий ближнего Ð±Ð¾Ñ Ð´Ð¾Ñтают дальше, чем когти зараженных. ИÑпользуйте Ñто, как привелегию в защите оружиÑми ближнего боÑ.
+Игроки одной и той же комманды могут ÑтрелÑÑ‚ÑŒ, проходить, бить Ñквозь друг друга.
+Ð’Ñегда оÑтавайтеÑÑŒ за Ñвоей баррикадой и отойдите на доÑтаточно далекое раÑÑтоÑние от зараженных. У оружий дальнего Ð±Ð¾Ñ Ð±ÐµÑконечное раÑÑтоÑние выÑтрела, у когтей зараженных - нет.
+Жизнь воÑÑтанавливаетÑÑ Ð¿Ð¾Ñле нанеÑÐµÐ½Ð¸Ñ Ð’Ð°Ð¼ урона, но его доÑтаточно, чтобы убить любого выжившего.
+Ваша команда не вÑегда права, не Ñледуйте приказам, как овечка! Зомби любÑÑ‚ овечек.
+Зомби визÑÑ‚ Ваше ÑоÑтоÑние здоровьÑ, даже Ñквозь Ñтены. Отходите, еÑли Ð²Ð°Ñ Ñ€Ð°Ð½Ð¸Ð»Ð¸, так как зомби будут охотитьÑÑ Ð¸Ð¼ÐµÐ½Ð½Ð¾ за раненными.
+Ðе прÑчьтеÑÑŒ, зараженные могут видеть Ð²Ð°Ñ Ñквозь Ñтены и даже в темноте.
+Horde Meter (измеритель толпы зомби) внизу Ñкрана говорит о том, Ñколько вы можете нанеÑти вреда и вынеÑти его от выживших, выноÑливоÑÑ‚ÑŒ толчков от пуль. СгруппируйтеÑÑŒ Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼Ð¸ зомби, чтобы получить большую выноÑливоÑÑ‚ÑŒ, ÑƒÐ½Ð¸Ñ‡Ñ‚Ð¾Ð¶Ð°Ñ Ð±Ð°Ñ€Ñ€Ð¸ÐºÐ°Ð´Ñ‹ выживших!
+ЕÑли у Ð²Ð°Ñ Ð½ÐµÐ´Ð¾Ñтаточно зомби, чтобы уничтожить баррикады, попробуйте найти Ñебе других игроков команды.
+Ðе ÑтрелÑйте в зараженных, которые находÑÑ‚ÑÑ Ð² зеленом газе! Он их быÑтро иÑцелÑет, а вы только тратите патроны!
+Зомби выноÑливы к урону в грудь, даже больше к конечноÑÑ‚Ñм. СтарайтеÑÑŒ ÑтрелÑÑ‚ÑŒ в голову, поÑкольку зомби могут реанимировать и доÑтать ВаÑ!
+Although zombies take less damage in the legs, shooting them there will slow them down for a short time, enough to allow you or a team member to escape.
+
+]]
+LANGUAGE.help_cont_barricading = [[Баррикадирование - Ñто очень Ð²Ð°Ð¶Ð½Ð°Ñ Ñ‡Ð°ÑÑ‚ÑŒ выживаниÑ. Может показатьÑÑ Ñ‚Ð°Ðº, что зомби не такин опаÑные в начале игры, но позже они Ñтанут доÑтаточно Ñилными, чтобы убить Вашу команду за неÑколько Ñекунд.
+
+ЕдинÑтвенный ÑпоÑоб держать диÑтанцию от зомби - Ñто поÑтроить хорошую барикаду.
+
+ЕÑÑ‚ÑŒ неÑколько инÑтрументов, которые дают Вам возможноÑÑ‚ÑŒ Ñделать Ñто. Самый извеÑтный - молоток и гвоздь. Ðто позволÑет прибить предметы к Ñтене/полу, в то времÑ, как гвозди должны быть Ñломаны, чтобы зомби могли доÑтать ваÑ.
+РаÑтавьте предметы, которые вы хотите прибить гвоздем, нажав кнопку ИСПОЛЬЗОВÐТЬ на Ñтот предмет, чтобы поднÑÑ‚ÑŒ его. Ð’Ñ‹ можете задержать кнопу БЕГ, чтобы крутить его. Потом доÑтаньте молоток, чтобы прибить его гвоздем правой кнопкой мыши. Лучше вÑего прибивать предметы к Ñтене, чем к другим объектам.
+Помните, когда прежмет прибит, он будет вноÑить полученный урон в гвозди, прибитые к нему. Ð’Ñ‹ можете ремонтировать гвозди, ударÑÑ Ð¿Ñ€ÐµÐ´Ð¼ÐµÑ‚Ñ‹ молотком, но Ñто приведет их к тому, что их уже Ð½ÐµÐ»ÑŒÐ·Ñ Ð±ÑƒÐ´ÐµÑ‚ отремонтировать. Задержите SHIFT, держа молоток в руках, чтобы увидеть вÑе гвозди, прибитые к предметам.
+ЕÑли вам кажетÑÑ, что гвоздь прибит неправильно, или вы хотели бы изменить позицию предмета, вы можете убрать гвозди, Ð½Ð°Ð¶Ð¸Ð¼Ð°Ñ Ð½Ð° клавишу ПЕРЕЗÐРЯДКÐ, в то времÑ, как Ð’Ñ‹ Ñмотрите на Ñтот гвоздь. ОÑторожно, еÑли вы убираете гвоздь, не принадлежащий Вам, вам будет штраф в одно очко.
+Запомните еще вот что: гвоздÑм наноÑитÑÑ Ð¼ÐµÐ½ÑŒÑˆÐµ урона, еÑли они прибиты к более крупным предметам. Чем больше размер предмета, тем меньше урона наноÑитÑÑ Ð³Ð²Ð¾Ð·Ð´Ñм.
+
+Ещё один инÑтрумент называетÑÑ 'Aegis' Barricade Kit. Он позволÑет вам раÑÑтавлÑÑ‚ÑŒ деревÑнные доÑки на любой меÑтноÑти, или раÑÑтавлÑÑ‚ÑŒ доÑки между Ð´Ð²ÑƒÐ¼Ñ Ñтенами. Он даже не требует поÑторонних предметов. Чтобы иÑпользовать его, Ñтавьте доÑку в доÑтупном меÑте. Его Ñпектр превратитÑÑ Ð¸Ð· краÑного в зеленый, Ð³Ð¾Ð²Ð¾Ñ€Ñ Ð¾ его доÑтупноÑти.
+Ставьте доÑку, Ð½Ð°Ð¶Ð¸Ð¼Ð°Ñ Ð½Ð° кнопку выÑтрела. Крутите доÑку Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ кнопки второÑтепенной атаки (Ñтандарт - ПКМ) и кнопкой ПЕРЕЗÐРЯДКÐ. Он иÑпользует доÑки, как аммуницию, так что доÑки, которые у Ð²Ð°Ñ ÐµÑÑ‚ÑŒ в Board Pack могут быть иÑпользованы, как Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð°Ð¼ÑƒÐ½Ð¸Ñ†Ð¸Ñ! Ð’Ñ‹ можете также Ñобирать доÑки, которые вы раÑÑтавили, Ð½Ð°Ð´Ð¸Ð¼Ð°Ñ Ð½Ð° них кнопку БЕГ, в то времÑ, как Ð’Ñ‹ Ñмотрите на нее.
+
+Ещё один инÑтрумент - Turret (турель). Она ÑтрелÑет во вÑех зараженных которые попадаютÑÑ Ð¿Ð¾Ð´ ее обзор. ЕдинÑтвенное, что турель требует - Ñто аммунициÑ. Ð’Ñ‹ можете перезарÑжать ее нажав клавишой ИСПОЛЬЗОВÐТЬ на неё. Она вам даÑÑ‚ дополнительные очки за помощь команде.
+Чтобы поÑтавить турель, поÑтавьте ее так, чтобы ее Ñпектр окраÑилÑÑ Ð² зеленый цвет. Ставьте на землю, но не на предметы. Крутите турель при помощи кнопки второÑтепенной атаки и кнопкой ПЕРЕЗÐРЯДКÐ. ЕÑли что-то не так, вы можете запаковать турель обратно, зажав кнопку БЕГ. Помните, турель ÑтрелÑет лишь в зараженных, переÑекших ее лазер.
+
+Советы:
+
+Ð’Ñ‹ получаете Ð±Ð¾Ð½ÑƒÑ Ð² 25% очков за убийÑтво зомби, атакующих баррикаду!
+ИÑпользуйте большие предметы Ð´Ð»Ñ Ð±Ð°Ñ€Ñ€Ð¸ÐºÐ°Ð´Ñ‹. Гвозди получают меньше урона а предметы имеют больше объема Ð´Ð»Ñ Ð¸Ñ… раÑÑтавлениÑ. Ртакже они Ñлужат, как прикрытие от дальних атак.
+ ]]
+LANGUAGE.help_cont_upgrades = [[Очки можно заработать, ÑƒÐ±Ð¸Ð²Ð°Ñ Ð·Ð¾Ð¼Ð±Ð¸, Ð²Ñ‹Ð»ÐµÑ‡Ð¸Ð²Ð°Ñ Ñ€Ð°Ð½ÐµÐ½Ð½Ñ‹Ñ…, и ÑÑ‚Ñ€Ð¾Ñ Ð·Ð°Ñ‰Ð¸Ñ‚Ñƒ.
+Ð’Ñ‹ также можете оплачивать очками в Points Shop что можно Ñделать во Ð²Ñ€ÐµÐ¼Ñ Ð¿ÐµÑ€ÐµÑ€Ñ‹Ð²Ð¾Ð² между волнами.
+СтарайтеÑÑŒ покупать в Arsenal Crates почаще!
+
+Советы:
+
+Планируйте на неÑколько шагов вреред. Покупайте аммуницию Ð´Ð»Ñ Ð¿Ð¸Ñтолетов в Worth menu, чтобы у Ð²Ð°Ñ Ð±Ñ‹Ð»Ð¾ доÑтаточно аммуниции, как только вы получаете Ñвой первый апгрейд.
+Ð’Ñ‹ получаете очки за помощь в убийÑтвах. Ð‘Ð¾Ð»ÑŒÑˆÐ°Ñ Ñ‡Ð°ÑÑ‚ÑŒ очков идет убийце а Ð¼ÐµÐ½ÑŒÑˆÐ°Ñ Ñ‡Ð°ÑÑ‚ÑŒ помощнику.
+Worth и Points - раздельные понÑтиÑ. Тратьте вÑе Ñвои Worth!
+Arsenal Crates очень ранимы и их легко Ñломать атаками зомби.
+ ]]
+LANGUAGE.help_cont_being_a_zombie = [[Советы:
+
+У Ð’Ð°Ñ Ð±ÐµÑконечное кол-во жизней, у выживших лишь только одна. Ðе бойтеÑÑŒ атаковать, атакуйте, и ещё раз атакуйте!
+Обычный кдаÑÑ Ð—Ð¾Ð¼Ð±Ð¸ очень выноÑлив. ЕдинÑтвенный ÑпоÑоб убить Ð’Ð°Ñ - ÑтрелÑÑ‚ÑŒ в голову, или быть убитым орудиÑми ближнего боÑ. Вам не нужны ноги.
+Зомби могут поÑвлÑÑ‚ÑŒÑÑ Ð´Ñ€ÑƒÐ³ над другом, еÑли выжившие не могут Ñто увидеть. Следите за глазами черепа внизу Вашего Ñкрана. ЕÑли они зеленые, вы можете поÑвитьÑÑ Ð½Ð° зараженном!
+С доÑтаточной практикой вы можете иÑпользовать предметы, чтобы вмазать их в рожу выживших Ñ Ñ€Ð°ÑÑтоÑниÑ.
+Уничтожайте раÑÑтавленные предметы, такие как турели и, тем более, арÑенальные Ñщики, чтобы оÑлабить выживших.
+ÐанеÑÑ Ð´Ð¾Ñтаточно урона, вы можете ÑнеÑти двери.
+БольшинÑтво предметов ÑтановÑÑ‚ÑÑ ÐºÑ€Ð°Ñного цвета, в завиÑимоÑти от нанеÑенного им урона.
+Wraith абÑолютно невидимо, когда Ñтоит Ñмирно или находитÑÑ Ð½Ð° раÑÑтоÑнии.
+Ðтака прыжком Fast Zombie наноÑит урон, в завиÑимоÑти от того, Ñколько Ð’Ñ‹ продержалиÑÑŒ в воздухе при прыжке. Чем больше времени - тем больше урона. Бейте когтÑми в боликом раÑÑтоÑнии!
+Помимо огромной ÑтойкоÑти и Ñилы, Poison Zombie Ñрывает куÑки Ñвоей Ñдовитой плоти и швырÑет ее в выживших, Ð½Ð°Ð¶Ð¸Ð¼Ð°Ñ Ð½Ð° кнопку второÑтепенной атаки (ÑÑ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð°Ñ ÐºÐ»Ð°Ð²Ð¸ÑˆÐ° - ПКМ).
+БольшинÑтво когтей зомби дает два шанÑа ударить выжившего. ЕÑли вы "ударÑете" Вашу цель, в то времÑ, как вы атакуете, вы бьете по цели, еÑли цель на доÑтупном раÑÑтоÑнии.
+Плевок Poison Headcrab может запутать выживших, бьет ли он в голову.
+ОхотьтеÑÑŒ за Ñлабыми выжившими! Другие зараженные также будут охотитьÑÑ Ð·Ð° ними, поÑтому они ÑтановÑÑ‚ÑÑ Ð»ÐµÐ³Ñ‡Ð°Ð¹ÑˆÐ¸Ð¼Ð¸ целÑми.
+Horde Meter вниху Ñкрана измерÑет кол-во Вашей выноÑливоÑти и вреда, который вы можете нанеÑти. ГруппируйтеÑÑŒ Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼Ð¸ зомби Ð´Ð»Ñ Ð±Ð¾Ð»ÑŒÑˆÐµÐ¹ выноÑливоÑти!
+ЕÑли у Ð²Ð°Ñ Ð½ÐµÐ´Ð¾Ñтаточно зомби, чтобы уничтожить баррикады, попробуйте позвать к Ñебе других игроков команды.
+ЕÑли в меÑтноÑти Ñлишком темно, нажмите на клавишу ФОÐÐРИК Ð´Ð»Ñ Ñ€ÐµÐ¶Ð¸Ð¼Ð° ночного видениÑ.
+
+]]
+
+-- Place any custom stuff below here...
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/languages/spanish.lua b/gamemodes/zombiesurvival/gamemode/languages/spanish.lua
new file mode 100644
index 0000000..c5ab7f4
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/languages/spanish.lua
@@ -0,0 +1,212 @@
+-- Translated by Box, ptown, and dr broly
+
+translate.AddLanguage("es-ES", "Spanish")
+
+-- Various gamemode stuff
+LANGUAGE.minute_points_added = "No hubo daño recibido en un minuto! Añadido %d puntos."
+LANGUAGE.infliction_reached_class_unlocked = "%d%% inflicción se ha alcanzado! %S desbloqueado!"
+LANGUAGE.infliction_reached = "%d%% de los seres humanos han muerto!"
+LANGUAGE.x_unlocked = "%s desbloqueado!"
+LANGUAGE.disconnect_killed = "%s se desconecte asesinado por %s."
+LANGUAGE.nail_removed_by = "%s sacó un clavo perteneciente a %s."
+LANGUAGE.banned_for_life_warning = "Está suspendido de por vida por lo que no se puede comprar nada!"
+LANGUAGE.need_to_be_near_arsenal_crate = "Usted debe estar cerca del Caja de Arsenal para comprar!"
+LANGUAGE.cant_purchase_right_now = "No se puede comprar nada en este momento"
+LANGUAGE.dont_have_enough_points = "Usted no tiene suficientes puntos"
+LANGUAGE.prepare_yourself = "Prepárate ..."
+LANGUAGE.purchased_x_for_y_points = "Comprados %s por %d puntos!"
+LANGUAGE.give_time_before_suicide = "Dar a los demás tiempo para desovar antes suicidando"
+LANGUAGE.no_spare_ammo_to_give = "No hay munición de repuesto para dar!"
+LANGUAGE.no_person_in_range = "No hay persona en rango!"
+LANGUAGE.that_life = "En que vida..."
+LANGUAGE.x_damage_to_barricades = "%d daño a las barricadas"
+LANGUAGE.x_damage_to_humans = "%d daño a las humanos"
+LANGUAGE.x_brains_eaten = "%d cerebro comido"
+LANGUAGE.press_rmb_to_cycle_targets = "Pulsa RMB para rotar blancos"
+LANGUAGE.press_lmb_to_spawn_on_them = "Pulsa LMB para que desovar aqui"
+LANGUAGE.press_lmb_to_spawn = "Pulsa LMB para que desovar"
+LANGUAGE.observing_x = "Observando %s (%d)"
+LANGUAGE.waiting_for_next_wave = "Espera por la próxima onda para comenzar ..."
+LANGUAGE.impossible = "Imposible"
+LANGUAGE.trying_to_put_nails_in_glass = "Tratar de poner clavos en vidrio es una tonterÃa"
+LANGUAGE.boss_class_select = "Usted será %s la próxima vez que usted es un jefe de zombie"
+LANGUAGE.person_has_weapon = "Ellos ya tienen esa arma"
+LANGUAGE.cant_do_that_in_classic_mode = "Usted no puede hacer eso en Classic Mode"
+LANGUAGE.cant_use_x_in_classic_mode = "No se puede usar %s en Classic Mode"
+LANGUAGE.cant_use_x_in_zombie_escape = "No se puede usar %s en Zombie Escape."
+LANGUAGE.no_class_switch_in_this_mode = "El modo actual no le permite cambiar las clases"
+LANGUAGE.zombie_escape = "Zombie Escapa!"
+LANGUAGE.nothing_for_this_ammo = "No tiene nadie que utiliza este tipo de munición."
+LANGUAGE.you_decide_to_leave_some = "Usted decidir dejar algo para su equipo"
+LANGUAGE.you_cant_purchase_now = "No se puede comprar artÃculos en esto momento"
+LANGUAGE.no_ammo_here = "No hay munición aquà ahora mismo."
+LANGUAGE.you_redeemed = "Usted resucitaste!"
+LANGUAGE.kill_the_last_human = "Mata la último humano!"
+LANGUAGE.kick_the_last_human = "Patada el último humano!"
+LANGUAGE.you_are_the_last_human = "Tu eres la último humano!"
+LANGUAGE.x_zombies_out_to_get_you = "%d ZOMBIES SON TRATANDO DE HACERTE DAÑO!"
+LANGUAGE.x_pants_out_to_get_you = "%d PANTALONES SON TRATANDO DE HACERTE DAÑO!"
+LANGUAGE.you_have_died = "Tu estas murió"
+LANGUAGE.you_were_killed_by_x = "Usted fue asesinado por %s"
+LANGUAGE.you_were_kicked_by_x = "Usted fue una patada en la espinilla por %s"
+LANGUAGE.arsenal_upgraded = "Arsenal es mejorada"
+LANGUAGE.final_wave = "LA ONDA FINAL HA COMENZANDO!"
+LANGUAGE.final_wave_sub = "Todas las clases desbloquea y la oportunidad de redención ha terminado!"
+LANGUAGE.wave_x_has_begun = "Onda %d has empezar!"
+LANGUAGE.x_unlocked = " %s desbloqueado!"
+LANGUAGE.wave_x_is_over = "Onda %d se ha acabado!"
+LANGUAGE.wave_x_is_over_sub = "Los muertos vivientes han dejado de subir y el saldo de Puntos de Compra es %d%%"
+LANGUAGE.you_are_x = "Tu eres %s!"
+LANGUAGE.x_has_risen_as_y = "%s ha sido resucitado como %s!!"
+LANGUAGE.x_has_risen = "%s ha sido resucitado!"
+LANGUAGE.cant_use_worth_anymore = "No se puede utilizar el Worth Menu nunca más!"
+LANGUAGE.class_not_unlocked_will_be_unlocked_x = "Esa clase no se desbloquea todavÃa. Será desbloqueado en el inicio de la onda d%."
+LANGUAGE.you_are_already_a_x = "Usted ya eres una %s."
+LANGUAGE.you_will_spawn_as_a_x = "Usted desovarán como un zombie"
+LANGUAGE.crafting_successful = "Construcción exitosa"
+LANGUAGE.x_crafted_y = "%s construido %s."
+LANGUAGE.escape_from_the_zombies = "Escapa de los zombies!"
+LANGUAGE.too_close_to_another_nail = "Demasiado cerca de otro clavo."
+LANGUAGE.object_too_damaged_to_be_used = "Este objeto está demasiado dañada para ser utilizadas."
+LANGUAGE.thanks_for_being_a_fan_of_zs = "Gracias por ser un fan de Zombie Survival!"
+LANGUAGE.cant_remove_nails_of_superior_player = "No se puede quitar las clavos de un jugador haciendo mucho mejor que tú."
+LANGUAGE.x_turned_on_noclip = "%s activado noclip."
+LANGUAGE.x_turned_off_noclip = "%s desactivado noclip."
+LANGUAGE.unlocked_on_wave_x = "desbloqueado en onda %d"
+LANGUAGE.brains_eaten_x = "Cerebros comido: %s"
+LANGUAGE.points_x = "Puntas: %s"
+LANGUAGE.next_wave_in_x = "Próxima ola en %s"
+LANGUAGE.wave_ends_in_x = "Ola termina en %s"
+LANGUAGE.wave_x_of_y = "Ola %d de %d"
+LANGUAGE.zombie_invasion_in_x = "Invasión de zombies en %s"
+LANGUAGE.intermission = "Intermisión"
+LANGUAGE.press_f2_for_the_points_shop = "Pulsa F2 para la Tienda de Puntos!"
+LANGUAGE.breath = "Respirar"
+LANGUAGE.zombie_volunteers = "Voluntarios de Zombies"
+LANGUAGE.x_discount_for_buying_between_waves = "%d%% descuento compra entre olas!"
+LANGUAGE.number_of_initial_zombies_this_game = "Número de zombies inicial en este juego (%d%%): %d"
+LANGUAGE.humans_closest_to_spawns_are_zombies = "Los seres humanos más cercanos al engendro de zombies serán seleccionados."
+LANGUAGE.waiting_for_players = "Esperando por los jugadores ..."
+LANGUAGE.requires_x_people = "Requiere %d personas"
+LANGUAGE.packing_others_object = "Embalaje objeto de otra persona"
+LANGUAGE.packing = "Embalaje"
+LANGUAGE.ze_humans_are_frozen_until_x = "Los seres humanos se congelan hasta %d segundos antes de la ronda comienza."
+LANGUAGE.loading = "Cargando ..."
+LANGUAGE.next_round_in_x = "Proxima ronda en:% s"
+LANGUAGE.warning = "Aviso!"
+LANGUAGE.ok_and_no_reminder = "OK y este mensaje no aparecerá."
+LANGUAGE.classic_mode_warning = "Este servidor se está ejecutando en Zombie Survival 'Classic Mode'/nClassic Mode es un modo que altera enormemente la jugabilidad. Las cosas que han cambiado:/n* No hay la selección de clases de zombies. Todos utilizan la clase Zombie clásico./n* No se necesitan herramientas barricadas como clavar o torretas\n* Más olas, pero más rápido\n\nEsta NO ES la Supervivencia Zombie original!\n\n-- Los servidores que ejecutan este modo divulgaremos CLASSIC MODE en la parte inferior izquierda de la pantalla --"
+LANGUAGE.classic_mode = "CLASSIC MODE"
+LANGUAGE.resist_x = "Resistir: %d%%"
+LANGUAGE.right_click_to_hammer_nail = "Haga lic Derecho para clavar un clavo"
+LANGUAGE.nails_x = "Clavos: %d"
+LANGUAGE.resupply_box = "Caja de reabastecimiento"
+LANGUAGE.purchase_now = "Comprar ahora!"
+LANGUAGE.integrity_x = "Integridad: %d%%"
+LANGUAGE.empty = "VACÃO"
+LANGUAGE.manual_control = "CONTROL MANUAL"
+LANGUAGE.arsenal_crate = "Cajón de Arsenal"
+
+-- Exit point objectives
+LANGUAGE.exit_destroyed = "Los muertos vivientes han destruido una salida!"
+LANGUAGE.exit_destroyed_only_one_remain_h = "Sólo queda uno! Si se cae, entonces no hay esperanza de escapar!"
+LANGUAGE.exit_destroyed_only_one_remain_z = "Sólo queda uno!"
+LANGUAGE.exit_destroyed_x_remain = "%d resto de salidas."
+LANGUAGE.last_exit_destroyed_all_is_lost = "The zombies have destroyed the last exit."
+LANGUAGE.last_exit_destroyed_all_is_lost2 = "No hay esperanza para escapar."
+
+-- Message beacon messages
+LANGUAGE.message_beacon_1 = "Reunirse aquÃ"
+LANGUAGE.message_beacon_2 = "Necesitamos defensa aquÃ"
+LANGUAGE.message_beacon_3 = "Necesitamos las torretas aquÃ"
+LANGUAGE.message_beacon_4 = "Necesitamos las Cajas de Arsenal aquÃ"
+LANGUAGE.message_beacon_5 = "Necesitamos las medicos aqui"
+LANGUAGE.message_beacon_6 = "Caja de Municiones aquÃ"
+LANGUAGE.message_beacon_7 = "Caja de Arsenal aquÃ"
+LANGUAGE.message_beacon_8 = "Necesitamos la campos de fuerza aquÃ"
+LANGUAGE.message_beacon_9 = "Necesitamos explosivos aquÃ"
+LANGUAGE.message_beacon_10 = "Zombies vienen de aquÃ"
+LANGUAGE.message_beacon_11 = "No entre!"
+LANGUAGE.message_beacon_12 = "No salgas"
+LANGUAGE.message_beacon_13 = "Defender esta zona"
+LANGUAGE.message_beacon_14 = "Defender este lugar"
+LANGUAGE.message_beacon_15 = "Médicos aquÃ"
+LANGUAGE.message_beacon_16 = "Comprar a mi caja"
+LANGUAGE.message_beacon_17 = "Barricada aquÃ"
+LANGUAGE.message_beacon_18 = "No barricada aquÃ"
+LANGUAGE.message_beacon_19 = "No dejes que los zombis entra aquÃ"
+LANGUAGE.message_beacon_20 = "Esto va a romper"
+LANGUAGE.message_beacon_21 = "Este lugar es peligroso!"
+LANGUAGE.message_beacon_22 = "Cuidado con veneno!"
+LANGUAGE.message_beacon_23 = "Los zombis se abren paso aquÃ!"
+LANGUAGE.message_beacon_24 = "Zombies están llegando. Construir una barricada!"
+LANGUAGE.message_beacon_25 = "Plan B aquÃ"
+
+
+-- Class names
+LANGUAGE.class_zombie = "Zombie"
+LANGUAGE.class_poison_zombie = "Zombie Venenoso"
+LANGUAGE.class_fast_zombie = "Zombie Veloz"
+LANGUAGE.class_bloated_zombie = "Zombie Hinchado"
+LANGUAGE.class_classic_zombie = "Zombie Clásico"
+LANGUAGE.class_super_zombie = "Super Zombie"
+LANGUAGE.class_fresh_dead = "Recién Muerto"
+LANGUAGE.class_ghoul = "Demonio Necrófago"
+LANGUAGE.class_headcrab = "Headcrab"
+LANGUAGE.class_fast_headcrab = "Headcrab Veloz"
+LANGUAGE.class_poison_headcrab = "Headcrab Venenoso"
+LANGUAGE.class_the_tickle_monster = "El Monstruo Cosquilloso"
+LANGUAGE.class_nightmare = "Pesadilla"
+LANGUAGE.class_pukepus = "Pukepus"
+LANGUAGE.class_bonemesh = "Bonemesh"
+LANGUAGE.class_crow = "Cuervo"
+LANGUAGE.class_wilowisp = "Wil O' Wisp"
+LANGUAGE.class_zombie_torso = "Torso"
+LANGUAGE.class_zombie_legs = "Piernas"
+LANGUAGE.class_wraith = "Fantasma"
+LANGUAGE.class_flesh_beast = "Bestia de Carne"
+LANGUAGE.class_fast_zombie_legs = "Piernas Rápidas"
+LANGUAGE.class_chem_zombie = "Zombie QuÃmico"
+LANGUAGE.class_shade = "Sombra"
+
+
+-- Class descriptions
+LANGUAGE.description_zombie = "El zombie básico es muy resistente y tiene poderosas garras.\nEs difÃcil mantener bajos, especialmente si no disparó en la cabeza."
+LANGUAGE.description_poison_zombie = "Este zombie mutado no sólo es extremadamente duradera, pero tiene una fuerza anormal.\nSu cuerpo es extremadamente tóxico y se iniciará y arrojar carne a usted"
+LANGUAGE.description_fast_zombie = "Este zombie es mucho más rápido en comparación con los otros zombies.\nSon débiles solo, pero pueden subir por las paredes con sus garras."
+LANGUAGE.description_bloated_zombie = "El cuerpo consta de compuestos volátiles, quÃmicos tóxicos.\nAunque son lentos, se puede recibir una paliza."
+LANGUAGE.description_ghoul = "Este zombie tiene una carne muy tóxico.\nEs un poco débil en comparación con los otros zombies, pero lo compensa con su ataque venenoso.\nSus garras pueden retrasar un humano y se expulsar veneno a través de sus lesiones, se puede doler mucho"
+LANGUAGE.description_headcrab = "Headcrabs eran la causa de la infección original.\nNadie sabe de dónde vino.\nSu método de ataque es morder con sus dientes en su estómago."
+LANGUAGE.description_fast_headcrab = "El macho headcrab es considerablemente más rápido pero menos carnosa que la hembra.\nIrrelevante porque es igualmente molesto y mortal en grupos."
+LANGUAGE.description_poison_headcrab = "Esta headcrab está lleno de neurotoxinas.\nUna mordedura es suficiente para matar a un humano adulto.\nSe puede tambien escupir veneno.\nLa veneno es más mortal que llega a la cabeza de la vÃctima."
+LANGUAGE.description_the_tickle_monster = "Se dice que es el monstruo que se esconde en su armario y saca usted de la cama.\nLos brazos del Monstruo Cosquilloso son muy largos y difÃciles de huir de. También es bueno para destruir las barricadas"
+LANGUAGE.description_nightmare = "Una mutación muy rara da Pesadilla sus habilidades.\nMás fuerte que cualquier otro zombie, Pesadilla es una fuerza a tener en cuenta.\nUn pegar con sus garras es suficiente para debilitar cualquier ser humano."
+LANGUAGE.description_pukepus = "El cuerpo putrefacto de Puke Pus está totalmente consistir de los órganos que se usan para realizar la regeneración de veneno.\nEs capaz de escupir litros de vómito infectados por lo que es extremadamente peligroso."
+LANGUAGE.description_bonemesh = "Desfigurado y mutilado, el Bonemesh puede disparar bombas de sangre.\nCada bomba está hecha de huesos y carne que es una gran amenaza para el humano, pero es una deliciosa comida para los zombies."
+LANGUAGE.description_crow = "Cuervos carnÃvoros son más que una plaga de lo que eran antes de la infección.\nSe alimentan de la carne de aves infectadas y actúan como 'portadores' para los zombies.\n¿Por qué iba yo a ocultar esta clase?\n¿Cuál es su problema?"
+LANGUAGE.description_wilowisp = "Algunas veces conocido como espÃritus de los muertos."
+LANGUAGE.description_zombie_torso = "No se supone que ver esto ..."
+LANGUAGE.description_zombie_legs = "No se supone que ver esto ..."
+LANGUAGE.description_wraith = "¿Un zombi o una aparición?\nNo mucho se sabe sobre él, olvidar el hecho de que utiliza su\ncapacidad de sigilo único y garras afiladas para cortar las cosas en pedazos."
+LANGUAGE.description_flesh_beast = "*Pending*"
+LANGUAGE.description_fast_zombie_legs = "No se supone que ver esto ..."
+LANGUAGE.description_chem_zombie = "El cuerpo de Chem Zombie está totalmente consistir de volátil, productos quÃmicos.\nNo tiene medios para atacar pero explota cuando murieron, con la esperanza de matar a los humanos cercanos."
+LANGUAGE.description_shade = "Creación de un campo magnético a su alrededor, todos los ataques cuerpo a cuerpo de bala y son inútiles contra él.\nPero, por alguna razón, la sombra es vulnerable a la luz brillante."
+
+-- Class control schemes
+LANGUAGE.controls_zombie = "> PRIMARIO: Garras\n> SECUNDARIO: Gritar\n> RECARGA: Gemido\n> SPRINT: Fingir muerte\n> MUERTE A TIROS EN LAS PIERNAS: Resucitar / Transformar"
+LANGUAGE.controls_poison_zombie = "> PRIMARIO: Garras\n> SECUNDARIO: Tirar Carne\n> RECARGAR: Gritar"
+LANGUAGE.controls_fast_zombie = "> PRIMARIO: Garras\n> SECUNDARIO: Saltar / Trepar (Al lado de una pared)\n> RECARGAR: Gritar"
+LANGUAGE.controls_bloated_zombie = "> PRIMARIO: Garras\n> SECUNDARIO: Gemido\n> SPRINT: Fingir muerte\n> EN MUERTE: Sangre Veneno"
+LANGUAGE.controls_ghoul = "> PRIMARIO: Garras\n> SECUNDARIO: Tirar carne\n> SPRINT: Fingir muerte\n> RECARGAR: Gritar\n> CUANDO ALCANZA HUMANO: Lento\n> ALCANZADO POR HUMANOS: Liberación veneno"
+LANGUAGE.controls_headcrab ="> PRIMARIO: Saltar ataque\n> RECARGAR: Cavar"
+LANGUAGE.controls_fast_headcrab ="> PRIMARIO: Saltar ataque"
+LANGUAGE.controls_poison_headcrab = ">PRIMARIO: Saltar ataque\n> SECUNDARIO: Escupir veneno\n> CUANDO ALCANZA HUMANO: Veneno mortÃfero\n> CUANDO ALCANZA LOS OJOS: Ceguera\n> RECARGAR: Gritar"
+LANGUAGE.controls_the_tickle_monster = ">PRIMARIO: Garras elástica\n SECUNDARIO: Gemido"
+LANGUAGE.controls_nightmare = ">PRIMARIO: Toque mortal\n> SECUNDARIO: Gemido"
+LANGUAGE.controls_pukepus = ">PRIMARIO: Vómito"
+LANGUAGE.controls_bonemesh = "> PRIMARIO: Garras\n> SECUNDARIO: Tirar bomba de sangre"
+LANGUAGE.controls_wraith = "> PRIMARIO: Garras\n> SECUNDARIO: Gritar"
+LANGUAGE.controls_flesh_beast = "> PRIMARIO: Garras\n> SECUNDARIO: Batir con la cabeza"
+LANGUAGE.controls_chem_zombie = "> EN MUERTE: Bomba veneno"
+LANGUAGE.controls_shade = "> PRIMARIO: Subir\n SEGUNDARIO: Tirar"
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/mapeditor.lua b/gamemodes/zombiesurvival/gamemode/mapeditor.lua
new file mode 100644
index 0000000..0e12ef3
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/mapeditor.lua
@@ -0,0 +1,338 @@
+GM.MapEditorPrefix = "zs"
+
+file.CreateDir(GM.MapEditorPrefix.."maps")
+
+concommand.Add("mapeditor_add", function(sender, command, arguments)
+ if not sender:IsSuperAdmin() then return end
+
+ if not arguments[1] then return end
+
+ local tr = sender:GetEyeTrace()
+ if tr.Hit then
+ local ent = ents.Create(string.lower(arguments[1]))
+ if ent:IsValid() then
+ ent:SetPos(tr.HitPos)
+ ent:Spawn()
+ table.insert(GAMEMODE.MapEditorEntities, ent)
+ GAMEMODE:SaveMapEditorFile()
+ end
+ end
+end)
+
+concommand.Add("mapeditor_addonme", function(sender, command, arguments)
+ if not sender:IsSuperAdmin() then return end
+
+ if not arguments[1] then return end
+
+ local ent = ents.Create(string.lower(arguments[1]))
+ if ent:IsValid() then
+ ent:SetPos(sender:EyePos())
+ ent:SetAngles(sender:GetAngles())
+ ent:Spawn()
+ table.insert(GAMEMODE.MapEditorEntities, ent)
+ GAMEMODE:SaveMapEditorFile()
+ end
+end)
+
+concommand.Add("mapeditor_remove", function(sender, command, arguments)
+ if not sender:IsSuperAdmin() then return end
+
+ local tr = sender:GetEyeTrace()
+ if tr.Entity and tr.Entity:IsValid() then
+ for i, ent in ipairs(GAMEMODE.MapEditorEntities) do
+ if ent == tr.Entity then
+ table.remove(GAMEMODE.MapEditorEntities, i)
+ ent:Remove()
+ end
+ end
+ GAMEMODE:SaveMapEditorFile()
+ end
+end)
+
+local function ME_Pickup(pl, ent, uid)
+ if pl:IsValid() and ent:IsValid() then
+ ent:SetPos(util.TraceLine({start=pl:GetShootPos(),endpos=pl:GetShootPos() + pl:GetAimVector() * 3000, filter={pl, ent}}).HitPos)
+ return
+ end
+ timer.Destroy(uid.."mapeditorpickup")
+ GAMEMODE:SaveMapEditorFile()
+end
+
+concommand.Add("mapeditor_pickup", function(sender, command, arguments)
+ if not sender:IsSuperAdmin() then return end
+
+ local tr = sender:GetEyeTrace()
+ if tr.Entity and tr.Entity:IsValid() then
+ for i, ent in ipairs(GAMEMODE.MapEditorEntities) do
+ if ent == tr.Entity then
+ timer.CreateEx(sender:UniqueID().."mapeditorpickup", 0.25, 0, ME_Pickup, sender, ent, sender:UniqueID())
+ end
+ end
+ end
+end)
+
+concommand.Add("mapeditor_nudgeup", function(sender, command, arguments)
+ if not sender:IsSuperAdmin() then return end
+
+ local tr = sender:GetEyeTrace()
+ if tr.Entity and tr.Entity:IsValid() then
+ for i, ent in ipairs(GAMEMODE.MapEditorEntities) do
+ if ent == tr.Entity then
+ local amount = tonumber(arguments[1]) or 1
+ ent:SetPos(ent:GetPos() + Vector(0,0,amount))
+ GAMEMODE:SaveMapEditorFile()
+ return true
+ end
+ end
+ end
+end)
+
+concommand.Add("mapeditor_nudgeforward", function(sender, command, arguments)
+ if not sender:IsSuperAdmin() then return end
+
+ local tr = sender:GetEyeTrace()
+ if tr.Entity and tr.Entity:IsValid() then
+ for i, ent in ipairs(GAMEMODE.MapEditorEntities) do
+ if ent == tr.Entity then
+ local amount = tonumber(arguments[1]) or 1
+ ent:SetPos(ent:GetPos() + ent:GetForward() * amount)
+ GAMEMODE:SaveMapEditorFile()
+ return true
+ end
+ end
+ end
+end)
+
+concommand.Add("mapeditor_nudgeright", function(sender, command, arguments)
+ if not sender:IsSuperAdmin() then return end
+
+ local tr = sender:GetEyeTrace()
+ if tr.Entity and tr.Entity:IsValid() then
+ for i, ent in ipairs(GAMEMODE.MapEditorEntities) do
+ if ent == tr.Entity then
+ local amount = tonumber(arguments[1]) or 1
+ ent:SetPos(ent:GetPos() + ent:GetRight() * amount)
+ GAMEMODE:SaveMapEditorFile()
+ return true
+ end
+ end
+ end
+end)
+
+concommand.Add("mapeditor_rotateup", function(sender, command, arguments)
+ if not sender:IsSuperAdmin() then return end
+
+ local tr = sender:GetEyeTrace()
+ if tr.Entity and tr.Entity:IsValid() then
+ for i, ent in ipairs(GAMEMODE.MapEditorEntities) do
+ if ent == tr.Entity then
+ local amount = tonumber(arguments[1]) or 1
+ local ang = ent:GetAngles()
+ ang:RotateAroundAxis(ang:Up(), amount)
+ ent:SetAngles(ang)
+ GAMEMODE:SaveMapEditorFile()
+ return true
+ end
+ end
+ end
+end)
+
+concommand.Add("mapeditor_rotateforward", function(sender, command, arguments)
+ if not sender:IsSuperAdmin() then return end
+
+ local tr = sender:GetEyeTrace()
+ if tr.Entity and tr.Entity:IsValid() then
+ for i, ent in ipairs(GAMEMODE.MapEditorEntities) do
+ if ent == tr.Entity then
+ local amount = tonumber(arguments[1]) or 1
+ local ang = ent:GetAngles()
+ ang:RotateAroundAxis(ang:Forward(), amount)
+ ent:SetAngles(ang)
+ GAMEMODE:SaveMapEditorFile()
+ return true
+ end
+ end
+ end
+end)
+
+concommand.Add("mapeditor_rotateright", function(sender, command, arguments)
+ if not sender:IsSuperAdmin() then return end
+
+ local tr = sender:GetEyeTrace()
+ if tr.Entity and tr.Entity:IsValid() then
+ for i, ent in ipairs(GAMEMODE.MapEditorEntities) do
+ if ent == tr.Entity then
+ local amount = tonumber(arguments[1]) or 1
+ local ang = ent:GetAngles()
+ ang:RotateAroundAxis(ang:Right(), amount)
+ ent:SetAngles(ang)
+ GAMEMODE:SaveMapEditorFile()
+ return true
+ end
+ end
+ end
+end)
+
+concommand.Add("mapeditor_drop", function(sender, command, arguments)
+ if not sender:IsSuperAdmin() then return end
+
+ timer.Destroy(sender:UniqueID().."mapeditorpickup")
+ GAMEMODE:SaveMapEditorFile()
+end)
+
+function GM:LoadMapEditorFile()
+ local mapname = game.GetMap()
+
+ self.MapEditorEntities = {}
+
+ local red
+
+ if file.Exists(self.FolderName.."/gamemode/prepackagedmapprofiles/"..mapname..".lua", "LUA") then
+ red = file.Read(self.FolderName.."/gamemode/prepackagedmapprofiles/"..mapname..".lua", "LUA")
+ elseif file.Exists(self.MapEditorPrefix.."maps/"..mapname..".txt", "DATA") then
+ red = file.Read(self.MapEditorPrefix.."maps/"..mapname..".txt", "DATA")
+ end
+
+ if red then
+ if string.sub(red, 1, 3) == "SRL" then
+ for _, enttab in pairs(Deserialize(red)) do
+ local ent = ents.Create(string.lower(enttab.Class))
+ if ent:IsValid() then
+ ent:SetPos(enttab.Position)
+ ent:SetAngles(enttab.Angles)
+ if enttab.KeyValues then
+ ent.KeyValues = ent.KeyValues or {}
+ for key, value in pairs(enttab.KeyValues) do
+ ent.KeyValues[key] = value
+ end
+ end
+ ent:Spawn()
+ table.insert(self.MapEditorEntities, ent)
+ end
+ end
+ else
+ for _, stuff in pairs(string.Explode(",", red)) do
+ local expstuff = string.Explode(" ", stuff)
+ local ent = ents.Create(string.lower(expstuff[1]))
+ if ent:IsValid() then
+ ent:SetPos(Vector(tonumber(expstuff[2]), tonumber(expstuff[3]), tonumber(expstuff[4])))
+ for i=5, #expstuff do
+ local kv = string.Explode("§", expstuff[i])
+ ent:SetKeyValue(kv[1], kv[2])
+ end
+ ent:Spawn()
+ table.insert(self.MapEditorEntities, ent)
+ end
+ end
+ end
+ end
+end
+
+function GM:SaveMapEditorFile()
+ local sav = {}
+ for _, ent in pairs(self.MapEditorEntities) do
+ if ent:IsValid() then
+ local enttab = {}
+ enttab.Class = ent:GetClass()
+ enttab.Position = ent:GetPos()
+ enttab.Angles = ent:GetAngles()
+ if ent.KeyValues then
+ local keyvalues = {}
+ for i, key in ipairs(ent.KeyValues) do
+ keyvalues[key] = ent[key]
+ end
+ enttab.KeyValues = keyvalues
+ end
+ table.insert(sav, enttab)
+ end
+ end
+ file.Write(self.MapEditorPrefix.."maps/"..game.GetMap()..".txt", Serialize(sav))
+end
+
+function Deserialize(sIn)
+ SRL = nil
+
+ if #sIn == 0 then return {} end
+
+ if string.sub(sIn, 1, 4) ~= "SRL=" then sIn = "SRL="..sIn end RunString(sIn)
+
+ return SRL
+end
+
+local allowedtypes = {}
+allowedtypes["string"] = true
+allowedtypes["number"] = true
+allowedtypes["table"] = true
+allowedtypes["Vector"] = true
+allowedtypes["Angle"] = true
+allowedtypes["boolean"] = true
+local function MakeTable(tab, done)
+ local str = ""
+ local done = done or {}
+
+ local sequential = table.IsSequential(tab)
+
+ for key, value in pairs(tab) do
+ local keytype = type(key)
+ local valuetype = type(value)
+
+ if allowedtypes[keytype] and allowedtypes[valuetype] then
+ if sequential then
+ key = ""
+ else
+ if keytype == "number" or keytype == "boolean" then
+ key ="["..tostring(key).."]="
+ else
+ key = "["..string.format("%q", tostring(key)).."]="
+ end
+ end
+
+ if valuetype == "table" and not done[value] then
+ done[value] = true
+ if type(value._serialize) == "function" then
+ str = str..key..value:_serialize()..","
+ else
+ str = str..key.."{"..MakeTable(value, done).."},"
+ end
+ else
+ if valuetype == "string" then
+ value = string.format("%q", value)
+ elseif valuetype == "Vector" then
+ value = "Vector("..value.x..","..value.y..","..value.z..")"
+ elseif valuetype == "Angle" then
+ value = "Angle("..value.pitch..","..value.yaw..","..value.roll..")"
+ else
+ value = tostring(value)
+ end
+
+ str = str .. key .. value .. ","
+ end
+ end
+ end
+
+ if string.sub(str, -1) == "," then
+ return string.sub(str, 1, #str - 1)
+ else
+ return str
+ end
+end
+
+function Serialize(tIn, bRaw)
+ if #tIn == 0 then
+ local empty = true
+ for k in pairs(tIn) do
+ empty = false
+ break
+ end
+ if empty then
+ return ""
+ end
+ end
+
+ if bRaw then
+ return "{"..MakeTable(tIn).."}"
+ end
+
+ return "SRL={"..MakeTable(tIn).."}"
+end
+
diff --git a/gamemodes/zombiesurvival/gamemode/maps/Abandonned_Building.lua b/gamemodes/zombiesurvival/gamemode/maps/Abandonned_Building.lua
new file mode 100644
index 0000000..33c5a2d
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/Abandonned_Building.lua
@@ -0,0 +1,42 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("func_button")) do ent:Remove() end
+
+ local tsp = {}
+ local ctsp = {}
+
+ for _, ent in pairs(ents.FindByClass("info_player_terrorist")) do
+ table.insert(tsp, ent)
+ end
+
+ for _, ent in pairs(ents.FindByClass("info_player_counterterrorist")) do
+ table.insert(ctsp, ent)
+ end
+
+ for _, ent in pairs(tsp) do
+ local newent = ents.Create("info_player_counterterrorist")
+ if newent:IsValid() then
+ newent:SetPos(ent:GetPos())
+ newent:SetAngles(ent:GetAngles())
+ newent:Spawn()
+ end
+ end
+
+ for _, ent in pairs(ctsp) do
+ local newent = ents.Create("info_player_terrorist")
+ if newent:IsValid() then
+ newent:SetPos(ent:GetPos())
+ newent:SetAngles(ent:GetAngles())
+ newent:Spawn()
+ end
+ end
+
+ for _, ent in pairs(tsp) do
+ ent:Remove()
+ end
+
+ for _, ent in pairs(ctsp) do
+ ent:Remove()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/Zm_Toxa_West_v2.lua b/gamemodes/zombiesurvival/gamemode/maps/Zm_Toxa_West_v2.lua
new file mode 100644
index 0000000..a2c9d95
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/Zm_Toxa_West_v2.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("trigger_teleport")) do
+ ent:Remove()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/cf_haunted_b1.lua b/gamemodes/zombiesurvival/gamemode/maps/cf_haunted_b1.lua
new file mode 100644
index 0000000..f733bf9
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/cf_haunted_b1.lua
@@ -0,0 +1,28 @@
+-- This profile gets rid of exploitable doors and opens the area portals they control.
+-- It also creates zombie spawns in the graveyard and human spawns in the front yard.
+
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(258, 130, 248))
+ ent:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent:SetKeyValue("solid", "6")
+ ent:Spawn()
+ end
+
+ for _, spawn in pairs(ents.FindByClass("info_player*")) do
+ spawn:Fire("kill", "", 0)
+ end
+
+ for _, door in pairs(ents.FindByClass("func_door_rotating")) do
+ door:Fire("open", "", 0)
+ door:Fire("kill", "", 1)
+ end
+
+ timer.Simple(2, function()
+ team.SetSpawnPoint(TEAM_UNDEAD, ents.FindByClass("info_player_undead"))
+ team.SetSpawnPoint(TEAM_HUMAN, ents.FindByClass("info_player_human"))
+ end)
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/cs_business_b2.lua b/gamemodes/zombiesurvival/gamemode/maps/cs_business_b2.lua
new file mode 100644
index 0000000..5c8991c
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/cs_business_b2.lua
@@ -0,0 +1,52 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-413.3240, 2016.3511, 247.6189))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ ent2:SetColor(Color(0, 0, 0, 0))
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-413.3240, 2016.3511, 354.1814))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ ent2:SetColor(Color(0, 0, 0, 0))
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(1141.4768, 2121.8750, 128.0313))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ ent2:SetColor(Color(0, 0, 0, 0))
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-502.0918, 2096.4048, 128.0313))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ ent2:SetColor(Color(0, 0, 0, 0))
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-332.6040, 2233.0410, 128.0313))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ ent2:SetColor(Color(0, 0, 0, 0))
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/cs_crackhousenightbeta4.lua b/gamemodes/zombiesurvival/gamemode/maps/cs_crackhousenightbeta4.lua
new file mode 100644
index 0000000..53d11f1
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/cs_crackhousenightbeta4.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("prop_physics*")) do
+ ent:GetPhysicsObject():EnableMotion(true)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/cs_deadhouse.lua b/gamemodes/zombiesurvival/gamemode/maps/cs_deadhouse.lua
new file mode 100644
index 0000000..aa96e24
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/cs_deadhouse.lua
@@ -0,0 +1,10 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(-905, 99, 128))
+ ent:SetAngles(Angle(0,90,90))
+ ent:SetKeyValue("solid", "6")
+ ent:SetModel(Model("models/props_junk/sawblade001a.mdl"))
+ ent:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/de_4thstreet_opt.lua b/gamemodes/zombiesurvival/gamemode/maps/de_4thstreet_opt.lua
new file mode 100644
index 0000000..52943d5
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/de_4thstreet_opt.lua
@@ -0,0 +1,21 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(292.1930, 516.1370, -153.9688))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(297.9688, 488.5906, -410.4203))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/de_cemetery.lua b/gamemodes/zombiesurvival/gamemode/maps/de_cemetery.lua
new file mode 100644
index 0000000..61e5735
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/de_cemetery.lua
@@ -0,0 +1,18 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(286.3725, 1232.6808, -491.9688))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ end
+
+ for _, ent in pairs(ents.FindInSphere(Vector(280.2706, 1271.7953, 0), 400)) do
+ if string.find(ent:GetClass(), "info_player") then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/de_hangcastle_s.lua b/gamemodes/zombiesurvival/gamemode/maps/de_hangcastle_s.lua
new file mode 100644
index 0000000..44586b0
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/de_hangcastle_s.lua
@@ -0,0 +1,11 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ -- Dumb secret room crap.
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(800.1951, 1992.9767, -27.9688))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/de_nightquarters_v1.lua b/gamemodes/zombiesurvival/gamemode/maps/de_nightquarters_v1.lua
new file mode 100644
index 0000000..eb28d01
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/de_nightquarters_v1.lua
@@ -0,0 +1,13 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("env_fire")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-341.7814, -380.7280, 345.9983))
+ ent2:SetKeyValue("damagescale", 30)
+ ent2:SetKeyValue("firesize", 200)
+ ent2:Spawn()
+ ent2:Fire("Enable", "", 0)
+ ent2:Fire("StartFire", "", 0.1)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/de_nipperhouse_v2.lua b/gamemodes/zombiesurvival/gamemode/maps/de_nipperhouse_v2.lua
new file mode 100644
index 0000000..3e1807f
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/de_nipperhouse_v2.lua
@@ -0,0 +1,5 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("func_door*")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/de_residentevil2_final.lua b/gamemodes/zombiesurvival/gamemode/maps/de_residentevil2_final.lua
new file mode 100644
index 0000000..3ccfe18
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/de_residentevil2_final.lua
@@ -0,0 +1,15 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, class in pairs(GAMEMODE.ZombieClasses) do
+ class.Unlocked = true
+ end
+
+ hook.Add("PlayerInitialSpawn", "GiveAllClasses", function(pl)
+ pl:SendLua("for _,class in pairs(GAMEMODE.ZombieClasses) do class.Unlocked=true end")
+ end)
+
+ for _, ent in pairs(ents.FindByClass("prop_physics*")) do
+ ent:GetPhysicsObject():EnableMotion(true)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/de_zentech_office.lua b/gamemodes/zombiesurvival/gamemode/maps/de_zentech_office.lua
new file mode 100644
index 0000000..c5f84f4
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/de_zentech_office.lua
@@ -0,0 +1,5 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ for _, ent in pairs(ents.FindByClass("prop_physics*")) do ent:SetCollisionGroup(COLLISION_GROUP_NONE) end
+
+ for _, ent in pairs(ents.FindByClass("func_button")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/gm_highstreet.lua b/gamemodes/zombiesurvival/gamemode/maps/gm_highstreet.lua
new file mode 100644
index 0000000..24344d4
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/gm_highstreet.lua
@@ -0,0 +1,6 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ -- Removes a bunch of lag.
+ for _, ent in pairs(ents.FindByClass("func_smokevolume")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/ka_soccer_2006_v1.lua b/gamemodes/zombiesurvival/gamemode/maps/ka_soccer_2006_v1.lua
new file mode 100644
index 0000000..71a6559
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/ka_soccer_2006_v1.lua
@@ -0,0 +1,5 @@
+hook.Add("InitPostEntityMap", "DestroyTHurts", function()
+ for _, ent in pairs(ents.FindByClass("trigger_hurt")) do
+ ent:Remove()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_FireWaLL_aftershock_v1b.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_FireWaLL_aftershock_v1b.lua
new file mode 100644
index 0000000..b64c15a
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_FireWaLL_aftershock_v1b.lua
@@ -0,0 +1,19 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("trigger_teleport")) do
+ ent:Remove()
+ end
+
+ for _, ent in pairs(ents.FindByClass("func_button")) do
+ ent:Remove()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-93.9688, 666.7913, 256.0313))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel("models/props_lab/blastdoor001c.mdl")
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_airport_panic_bobpoblo2.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_airport_panic_bobpoblo2.lua
new file mode 100644
index 0000000..50412c9
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_airport_panic_bobpoblo2.lua
@@ -0,0 +1,14 @@
+-- This profile gets rid of exploitable doors and teleporters.
+
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, door in pairs(ents.FindByClass("func_door_rotating")) do
+ door:Fire("open", "", 0)
+ door:Fire("kill", "", 1)
+ end
+
+ for _, ent in pairs(ents.FindByClass("trigger_teleport")) do
+ ent:Remove()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_an_kapras.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_an_kapras.lua
new file mode 100644
index 0000000..c6609bb
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_an_kapras.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("trigger_teleport")) do ent:Remove() end
+ for _, ent in pairs(ents.FindByClass("func_door")) do ent:Remove() end
+ for _, ent in pairs(ents.FindByClass("func_door_rotating")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_atix_helicopter.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_atix_helicopter.lua
new file mode 100644
index 0000000..7e4479b
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_atix_helicopter.lua
@@ -0,0 +1 @@
+ZOMBIEGASSES = false
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_bowling_madness_v3_fixed.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_bowling_madness_v3_fixed.lua
new file mode 100644
index 0000000..c6609bb
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_bowling_madness_v3_fixed.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("trigger_teleport")) do ent:Remove() end
+ for _, ent in pairs(ents.FindByClass("func_door")) do ent:Remove() end
+ for _, ent in pairs(ents.FindByClass("func_door_rotating")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_canyon.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_canyon.lua
new file mode 100644
index 0000000..21c33d3
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_canyon.lua
@@ -0,0 +1,23 @@
+-- Plugs up two semi-secrets.
+
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(-169.4831, 177.5246, -746.0686))
+ ent:SetAngles(Angle(90, 0, 0))
+ ent:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent:SetKeyValue("solid", "6")
+ ent:Spawn()
+ end
+
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(-926.7128, -478.6960, -687.9688))
+ ent:SetAngles(Angle(0, 90, 0))
+ ent:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent:SetKeyValue("solid", "6")
+ ent:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_countrytrain_b4.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_countrytrain_b4.lua
new file mode 100644
index 0000000..b811e44
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_countrytrain_b4.lua
@@ -0,0 +1,7 @@
+-- This profile removes the suitcases in the map to break the objectives from Zombie Master. Not doing this ruins the map.
+
+hook.Add("InitPostEntityMap", "Adding", function()
+ for _, ent in pairs(ents.FindByModel("models/props_c17/suitcase001a.mdl")) do
+ ent:Remove()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_crazycity.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_crazycity.lua
new file mode 100644
index 0000000..5ee5579
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_crazycity.lua
@@ -0,0 +1,17 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetModel("models/props_vehicles/car005b_physics.mdl")
+ ent:SetPos(Vector(1121, 862, 80))
+ ent:SetAngles(Angle(0, 180, 0))
+ ent:SetKeyValue("solid", SOLID_VPHYSICS)
+ ent:Spawn()
+ end
+
+ for _, ent in pairs(ents.FindByClass("func_door_rotating")) do
+ ent:Fire("open", "", 0)
+ ent:Fire("kill", "", 0.5)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_darkhouse_ocxv3.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_darkhouse_ocxv3.lua
new file mode 100644
index 0000000..492e741
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_darkhouse_ocxv3.lua
@@ -0,0 +1,18 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ -- Block off impossible camping spot.
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-1019.9873, 1049.5773, 76.0313))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ end
+
+ -- Remove virtually impossible barricade in basement.
+ for _, ent in pairs(ents.FindByClass("prop_physics*")) do
+ if ent:GetPos().z < 100 then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_distant.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_distant.lua
new file mode 100644
index 0000000..c20a33f
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_distant.lua
@@ -0,0 +1,65 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("trigger_teleport")) do
+ ent:Remove()
+ end
+
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(-867.2750, -749.3450, -340.1626))
+ ent:SetKeyValue("solid", "6")
+ ent:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent:Spawn()
+ ent:SetColor(Color(0, 0, 0, 255))
+ end
+
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(-497.7150, -1303.8472, 0))
+ ent:SetAngles(Angle(90, 90, 0))
+ ent:SetKeyValue("solid", "6")
+ ent:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent:Spawn()
+ ent:SetColor(Color(0, 0, 0, 255))
+ end
+
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(1394.0304, 1602.6035, 0.0313))
+ ent:SetAngles(Angle(0, 90, 0))
+ ent:SetKeyValue("solid", "6")
+ ent:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent:Spawn()
+ ent:SetColor(Color(0, 0, 0, 255))
+ end
+
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(448.1150, 217.9688, 247.7707))
+ ent:SetAngles(Angle(90, 0, 90))
+ ent:SetKeyValue("solid", "6")
+ ent:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent:Spawn()
+ ent:SetColor(Color(0, 0, 0, 255))
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(250, 826, 568))
+ ent2:SetAngles(Angle(0, 196, 90))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:SetColor(Color(0, 0, 0, 0))
+ ent2:Spawn()
+ end
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(250, 826, 568))
+ ent2:SetAngles(Angle(0, 165, 90))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:SetColor(Color(0, 0, 0, 0))
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_evacuated_city.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_evacuated_city.lua
new file mode 100644
index 0000000..c6609bb
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_evacuated_city.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("trigger_teleport")) do ent:Remove() end
+ for _, ent in pairs(ents.FindByClass("func_door")) do ent:Remove() end
+ for _, ent in pairs(ents.FindByClass("func_door_rotating")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_fury_v2.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_fury_v2.lua
new file mode 100644
index 0000000..7834af0
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_fury_v2.lua
@@ -0,0 +1,11 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(-48.8903, 1088.3591, -407.9688))
+ ent:SetKeyValue("solid", 6)
+ ent:SetModel("models/props_lab/blastdoor001a.mdl")
+ ent:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_ghs_abdandon_mall.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_ghs_abdandon_mall.lua
new file mode 100644
index 0000000..e2e520c
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_ghs_abdandon_mall.lua
@@ -0,0 +1,14 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(707, 1355, 16))
+ ent2:SetKeyValue("solid", SOLID_VPHYSICS)
+ ent2:SetModel(Model("models/props_lab/blastdoor001b.mdl"))
+ ent2:SetColor(Color(0, 0, 0, 0))
+ ent2:Spawn()
+ end
+
+ for _, ent in pairs(ents.FindByClass("trigger_teleport")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_gilman_v2.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_gilman_v2.lua
new file mode 100644
index 0000000..179e3fb
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_gilman_v2.lua
@@ -0,0 +1,13 @@
+-- This profile removes the ZM objectives from the map.
+
+hook.Add("InitPostEntityMap", "MapProfile", function()
+ for _, ent in pairs(ents.FindByClass("prop_dynamic*")) do
+ if ent:GetModel() == "models/alyx.mdl" then
+ ent:Remove()
+ end
+ end
+
+ for _, ent in pairs(ents.FindByModel("models/items/car_battery01.mdl")) do
+ ent:Remove()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_gorodok_v1.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_gorodok_v1.lua
new file mode 100644
index 0000000..f9adc40
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_gorodok_v1.lua
@@ -0,0 +1,9 @@
+-- This profile gets rid of laggy func_dustcloud's
+
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("func_dustcloud")) do
+ ent:Remove()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_hauntedmanor_v1.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_hauntedmanor_v1.lua
new file mode 100644
index 0000000..ee89d6e
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_hauntedmanor_v1.lua
@@ -0,0 +1,18 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local SRL={Vector(-254.19750976563,-685.88067626953,-22.953275680542),Vector(-108.41053771973,-690.50183105469,-23.968748092651),Vector(-438.01739501953,-704.39770507813,-23.968748092651),Vector(-437.08544921875,-582.66363525391,-23.968748092651),Vector(-435.97445678711,-437.54248046875,-23.968748092651),Vector(-433.01181030273,-50.553520202637,-23.968748092651),Vector(-431.85144042969,101.01706695557,-23.968748092651),Vector(-430.04916381836,336.43515014648,-23.968748092651),Vector(-429.06161499023,465.43173217773,-23.968748092651),Vector(-427.67904663086,646.02691650391,-23.968748092651),Vector(-200.09281921387,646.37353515625,-23.968748092651),Vector(180.42523193359,651.29577636719,-23.968748092651),Vector(439.93426513672,638.70758056641,-23.968748092651),Vector(436.01934814453,429.54156494141,-23.968748092651),Vector(27.078559875488,-795.63104248047,-23.96875),Vector(54.141960144043,-779.68212890625,296.03125),Vector(48.307918548584,-693.26184082031,296.03125),Vector(387.14245605469,539.59765625,-23.968751907349),Vector(394.55435180664,431.81665039063,-23.968751907349),Vector(468.0383605957,431.17691040039,-23.968751907349),Vector(486.22283935547,471.17419433594,-23.968751907349),Vector(485.62991333008,516.32147216797,-23.968751907349),Vector(516.96435546875,615.88751220703,-23.968751907349),Vector(365.65390014648,650.21929931641,-23.968751907349),Vector(379.04675292969,488.705078125,-23.968751907349),Vector(456.77871704102,496.63772583008,-23.968751907349),Vector(31.537395477295,-787.37066650391,-23.968751907349),Vector(40.981872558594,-705.79577636719,-23.968751907349),Vector(67.53955078125,-656.24426269531,-23.968751907349),Vector(-304.89349365234,-708.57000732422,-23.968751907349),Vector(-177.1509552002,-733.75140380859,-23.968751907349),Vector(-135.64286804199,-668.65576171875,-23.968751907349)}
+
+ -- Removes secret teleport to skybox.
+ for _, ent in pairs(ents.FindByClass("trigger_teleport")) do
+ ent:Remove()
+ end
+
+ local alt
+ for i, ent in ipairs(ents.FindByClass("info_player_terrorist")) do
+ alt = not alt
+ if alt then
+ ent:SetPos(SRL[i])
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_hotline_miami_v2_0.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_hotline_miami_v2_0.lua
new file mode 100644
index 0000000..1203e99
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_hotline_miami_v2_0.lua
@@ -0,0 +1,3 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ util.RemoveAll("trigger_teleport")
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_infected.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_infected.lua
new file mode 100644
index 0000000..6214734
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_infected.lua
@@ -0,0 +1,5 @@
+ROUNDTIME = 1500
+
+hook.Add("PlayerInitialSpawn", "SendAlteredTime", function(pl)
+ pl:SendLua("ROUNDTIME=1500")
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_krusty_krab_a3.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_krusty_krab_a3.lua
new file mode 100644
index 0000000..08ea1cb
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_krusty_krab_a3.lua
@@ -0,0 +1,6 @@
+-- Removes teleports and other annoying ZM garbage.
+
+hook.Add("InitPostEntityMap", "Adding", function()
+ for _, ent in pairs(ents.FindByClass("trigger_push")) do ent:Remove() end
+ for _, ent in pairs(ents.FindByClass("trigger_teleport")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_london_v1_0.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_london_v1_0.lua
new file mode 100644
index 0000000..68bbadf
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_london_v1_0.lua
@@ -0,0 +1,10 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ local ent = ents.FindByClass("trigger_teleport")
+
+ ent[1]:Remove()
+ ent[3]:Remove()
+ ent[7]:Remove()
+ ent[11]:Remove()
+ ent[13]:Remove()
+ ent[14]:Remove()
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_lv426.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_lv426.lua
new file mode 100644
index 0000000..f28f8c2
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_lv426.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindInSphere(Vector(-3069.6348, -1300.0313, -159.9688), 24)) do
+ if ent:GetClass() == "func_button" then ent:Remove() end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_macd_island17.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_macd_island17.lua
new file mode 100644
index 0000000..46f726a
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_macd_island17.lua
@@ -0,0 +1,13 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(236, 1427, 660.5))
+ ent:SetAngles(Angle(90, 0, 0))
+ ent:SetKeyValue("solid", "6")
+ ent:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent:Spawn()
+ ent:SetColor(Color(0, 0, 0, 0))
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_mall_beta_b1.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_mall_beta_b1.lua
new file mode 100644
index 0000000..4240592
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_mall_beta_b1.lua
@@ -0,0 +1,23 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(-1028.6432, -3061.5071, 812.0313))
+ ent:SetModel("models/props_lab/blastdoor001a.mdl")
+ ent:SetKeyValue("solid", "6")
+ ent:Spawn()
+ end
+
+ ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(-1028.39, -3062.3708, 918.0627))
+ ent:SetModel("models/props_lab/blastdoor001a.mdl")
+ ent:SetKeyValue("solid", "6")
+ ent:Spawn()
+ end
+
+ for _, ent in pairs(ents.FindByClass("prop_physics*")) do
+ if ent:GetModel() == "models/props_wasteland/kitchen_shelf001a.mdl"then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_mini_petrols_v6.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_mini_petrols_v6.lua
new file mode 100644
index 0000000..06076a6
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_mini_petrols_v6.lua
@@ -0,0 +1,39 @@
+-- Blocks off some secrets and long hallways. Removes excess vending machines sitting everywhere.
+
+hook.Add("InitPostEntityMap", "Adding", function()
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(1144.9447, -4209.1284, 39.0313))
+ ent:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent:SetKeyValue("solid", "6")
+ ent:Spawn()
+ end
+
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(2445.5959, -3636.7520, 13.0313))
+ ent:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent:SetKeyValue("solid", "6")
+ ent:Spawn()
+ end
+
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(3250.6699, -4818.5039, 22.0313))
+ ent:SetAngles(Angle(0, 90, 0))
+ ent:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent:SetKeyValue("solid", "6")
+ ent:Spawn()
+ end
+
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(3310.6541, -2534.7319, 19.0865))
+ ent:SetAngles(Angle(0, 90, 0))
+ ent:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent:SetKeyValue("solid", "6")
+ ent:Spawn()
+ end
+
+ for _, ent in pairs(ents.FindByModel("models/props/cs_office/vending_machine.mdl")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_neko_dark_v2_fix2.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_neko_dark_v2_fix2.lua
new file mode 100644
index 0000000..a045355
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_neko_dark_v2_fix2.lua
@@ -0,0 +1,8 @@
+-- This profile gets rid of exploitable doors.
+
+hook.Add("InitPostEntityMap", "MapProfile", function()
+ for _, door in pairs(ents.FindByClass("func_door_rotating")) do
+ door:Fire("open", "", 0)
+ door:Fire("kill", "", 0.5)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_nomercy_hospital2.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_nomercy_hospital2.lua
new file mode 100644
index 0000000..4f9e815
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_nomercy_hospital2.lua
@@ -0,0 +1,22 @@
+-- Removes invulnerable rotating doors that seem to be so popular in CS:S
+
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, door in pairs(ents.FindByClass("func_door_rotating")) do
+ door:Fire("open", "", 0)
+ door:Fire("kill", "", 1)
+ end
+
+ local ent = ents.Create("zombiegasses")
+ if ent:IsValid() then
+ ent:SetPos(Vector(1915, 414, -3170))
+ ent:Spawn()
+ end
+
+ local ent = ents.Create("info_player_terrorist")
+ if ent:IsValid() then
+ ent:SetPos(Vector(1972, 422, -3179))
+ ent:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_onadega_v2a.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_onadega_v2a.lua
new file mode 100644
index 0000000..585a5cf
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_onadega_v2a.lua
@@ -0,0 +1,25 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("func_door*")) do ent:Remove() end
+ for _, ent in pairs(ents.FindByClass("trigger_teleport")) do ent:Remove() end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-0.7995, -28.3111, 0))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001b.mdl"))
+ ent2:Spawn()
+ ent2:SetColor(Color(0, 0, 0, 0))
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(563.9561, -531.1329, -119.9688))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001b.mdl"))
+ ent2:Spawn()
+ ent2:SetColor(Color(0, 0, 0, 255))
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_papys_secret_project.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_papys_secret_project.lua
new file mode 100644
index 0000000..f044228
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_papys_secret_project.lua
@@ -0,0 +1,10 @@
+-- This profile gets rid of exploitable doors.
+
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, door in pairs(ents.FindByClass("func_door_rotating")) do
+ door:Fire("open", "", 0)
+ door:Fire("kill", "", 1)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_portal.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_portal.lua
new file mode 100644
index 0000000..f044228
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_portal.lua
@@ -0,0 +1,10 @@
+-- This profile gets rid of exploitable doors.
+
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, door in pairs(ents.FindByClass("func_door_rotating")) do
+ door:Fire("open", "", 0)
+ door:Fire("kill", "", 1)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_siberia_v2.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_siberia_v2.lua
new file mode 100644
index 0000000..03a7c2e
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_siberia_v2.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("func_door_rotating")) do
+ ent:Remove()
+ end
+end)
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_tag_sealed.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_tag_sealed.lua
new file mode 100644
index 0000000..4b15268
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_tag_sealed.lua
@@ -0,0 +1,5 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("func_door")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_tx_highschoolbeta7.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_tx_highschoolbeta7.lua
new file mode 100644
index 0000000..979b9f9
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_tx_highschoolbeta7.lua
@@ -0,0 +1,23 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent = ents.Create("env_fire")
+ if ent:IsValid() then
+ ent:SetPos(Vector(4023.4456, 3151.3376, 0.0313))
+ ent:SetKeyValue("damagescale", 60)
+ ent:SetKeyValue("firesize", 200)
+ ent:Spawn()
+ ent:Fire("Enable", "", 0)
+ ent:Fire("StartFire", "", 0)
+ end
+
+ local ent = ents.Create("env_fire")
+ if ent:IsValid() then
+ ent:SetPos(Vector(4120.3535, 2121.4338, 0.0313))
+ ent:SetKeyValue("damagescale", 60)
+ ent:SetKeyValue("firesize", 200)
+ ent:Spawn()
+ ent:Fire("Enable", "", 0)
+ ent:Fire("StartFire", "", 0)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zm_westwood_final.lua b/gamemodes/zombiesurvival/gamemode/maps/zm_westwood_final.lua
new file mode 100644
index 0000000..6e57dcf
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zm_westwood_final.lua
@@ -0,0 +1,39 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-263, -566, -116))
+ ent2:SetAngles(Angle(90, 0, 0))
+ ent2:SetKeyValue("solid", SOLID_VPHYSICS)
+ ent2:SetModel(Model("models/props_lab/blastdoor001b.mdl"))
+ ent2:Spawn()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(400, -792, -116))
+ ent2:SetAngles(Angle(90, 0, 0))
+ ent2:SetKeyValue("solid", SOLID_VPHYSICS)
+ ent2:SetModel(Model("models/props_lab/blastdoor001b.mdl"))
+ ent2:Spawn()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(400, -858, -116))
+ ent2:SetAngles(Angle(90, 0, 0))
+ ent2:SetKeyValue("solid", SOLID_VPHYSICS)
+ ent2:SetModel(Model("models/props_lab/blastdoor001b.mdl"))
+ ent2:Spawn()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(576, -851, -116))
+ ent2:SetAngles(Angle(90, 0, 0))
+ ent2:SetKeyValue("solid", SOLID_VPHYSICS)
+ ent2:SetModel(Model("models/props_lab/blastdoor001b.mdl"))
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_abandoned_mall_v5b.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_abandoned_mall_v5b.lua
new file mode 100644
index 0000000..337a31b
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_abandoned_mall_v5b.lua
@@ -0,0 +1,3 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ for _, ent in pairs(ents.FindByClass("func_button")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_ambush_v3.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_ambush_v3.lua
new file mode 100644
index 0000000..d52ebca
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_ambush_v3.lua
@@ -0,0 +1,22 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-746, -122, 704))
+ ent2:SetAngles(Angle(0, 90, -90))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001b.mdl"))
+ ent2:Spawn()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-710, -116, 704))
+ ent2:SetAngles(Angle(0, 0, -90))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001b.mdl"))
+ ent2:Spawn()
+ end
+
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_asylum_v6.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_asylum_v6.lua
new file mode 100644
index 0000000..ceab26d
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_asylum_v6.lua
@@ -0,0 +1,9 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindInSphere(Vector(968.1165, 953.7861, 16.0313), 100)) do
+ if ent:GetClass() == "info_player_human" then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_barren.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_barren.lua
new file mode 100644
index 0000000..0923449
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_barren.lua
@@ -0,0 +1,8 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ -- I think its about time that this map be purged of blue shelves.
+ for _, ent in pairs(ents.FindByClass("prop_physics")) do
+ if ent:GetModel() == "models/props_wasteland/kitchen_shelf001a.mdl"then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_blastdoors_fixed.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_blastdoors_fixed.lua
new file mode 100644
index 0000000..c2c427f
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_blastdoors_fixed.lua
@@ -0,0 +1,51 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-255, 1215+53, 448))
+ ent2:SetAngles(Angle(90, 270, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:SetColor(Color(0, 0, 0, 0))
+ ent2:Spawn()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(0, 1215+53, 448))
+ ent2:SetAngles(Angle(90, 270, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:SetColor(Color(0, 0, 0, 0))
+ ent2:Spawn()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-512-53, 575, 448))
+ ent2:SetAngles(Angle(90, 0, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:SetColor(Color(0, 0, 0, 0))
+ ent2:Spawn()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-512-53, 830, 448))
+ ent2:SetAngles(Angle(90, 0, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:SetColor(Color(0, 0, 0, 0))
+ ent2:Spawn()
+ end
+
+ for _, ent in pairs(ents.FindByClass("func_breakable")) do
+ ent:Fire("Break", "", 0)
+ end
+
+ for _, ent in pairs(ents.FindByName("blastdoor2")) do
+ ent:Fire("Break", "", 0)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_block13.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_block13.lua
new file mode 100644
index 0000000..7c84513
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_block13.lua
@@ -0,0 +1,11 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(-320.409821, -502.737671, 139.487274))
+ ent:SetAngles(Angle(0, 90, 0))
+ ent:SetKeyValue("solid", "6")
+ ent:SetModel("models/props_lab/blastdoor001c.mdl")
+ ent:Spawn()
+ ent:SetNoDraw(true)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_bog_pubremakev1.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_bog_pubremakev1.lua
new file mode 100644
index 0000000..e92e37d
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_bog_pubremakev1.lua
@@ -0,0 +1,11 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("trigger_teleport")) do
+ ent:Remove()
+ end
+
+ for _, ent in pairs(ents.FindByClass("trigger_hurt")) do
+ ent:Remove()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_boohouse.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_boohouse.lua
new file mode 100644
index 0000000..48b15e3
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_boohouse.lua
@@ -0,0 +1,5 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("item_ammo_crate")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_bunker.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_bunker.lua
new file mode 100644
index 0000000..9b722f9
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_bunker.lua
@@ -0,0 +1,12 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(953.7239, -1549.8622, 128.0313))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel("models/props_lab/blastdoor001c.mdl")
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_chaste_part1.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_chaste_part1.lua
new file mode 100644
index 0000000..e615811
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_chaste_part1.lua
@@ -0,0 +1,8 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ -- The map has a super long hallway one way cade just like all subersive maps. This gets rid of human's favorite prop, but I think it would be best to remove the map from the server.
+ for _, ent in pairs(ents.FindByClass("prop_physics")) do
+ if ent:GetModel() == "models/props_wasteland/kitchen_shelf001a.mdl"then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_checkpoint_b6.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_checkpoint_b6.lua
new file mode 100644
index 0000000..082f246
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_checkpoint_b6.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ for _, ent in pairs(ents.FindByClass("prop_physics*")) do
+ if ent:GetModel() == "models/props_wasteland/kitchen_shelf001a.mdl"then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_coasthouse.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_coasthouse.lua
new file mode 100644
index 0000000..cd2c6a5
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_coasthouse.lua
@@ -0,0 +1,21 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-541.4225, 15.8781, 512.0313))
+ ent2:SetAngles(Angle(-60, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001a.mdl"))
+ ent2:Spawn()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-541.4225, -76.1219, 564.0313))
+ ent2:SetAngles(Angle(-60, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001a.mdl"))
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_crucifix_hill.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_crucifix_hill.lua
new file mode 100644
index 0000000..3f88ca5
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_crucifix_hill.lua
@@ -0,0 +1,8 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ local ent = ents.Create("logic_classunlock")
+ if ent:IsValid() then
+ ent:Spawn()
+ ent:Fire("lockclass", "all", 0)
+ ent:Fire("defaultclass", "classic zombie", 0)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_darkvilla.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_darkvilla.lua
new file mode 100644
index 0000000..1eef1ef
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_darkvilla.lua
@@ -0,0 +1,32 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("trigger_teleport")) do
+ ent:Remove()
+ end
+
+ for _, ent in pairs(ents.FindByClass("func_button")) do
+ ent:Remove()
+ end
+
+ for _, ent in pairs(ents.FindByClass("prop_dynamic")) do
+ local pro = ents.Create("prop_physics")
+ if pro:IsValid() then
+ pro:SetModel(ent:GetModel())
+ pro:SetPos(ent:GetPos())
+ pro:SetAngles(ent:GetAngles())
+ pro:Spawn()
+ ent:Remove()
+ end
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(900, -228, -151))
+ ent2:SetAngles(Angle(0, 180, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001b.mdl"))
+ ent2:SetColor(Color(0, 0, 0, 0))
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_deadblock_v2.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_deadblock_v2.lua
new file mode 100644
index 0000000..0923449
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_deadblock_v2.lua
@@ -0,0 +1,8 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ -- I think its about time that this map be purged of blue shelves.
+ for _, ent in pairs(ents.FindByClass("prop_physics")) do
+ if ent:GetModel() == "models/props_wasteland/kitchen_shelf001a.mdl"then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_deathhouse.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_deathhouse.lua
new file mode 100644
index 0000000..9c68e78
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_deathhouse.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ -- Gameplay is revolving around camping the 2nd floor which has the health charger. This isn't how I wanted the map to play so the health chargers need to go.
+ for _, ent in pairs(ents.FindByClass("item_healthcharger")) do
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_equilibre_v4.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_equilibre_v4.lua
new file mode 100644
index 0000000..d0d5bf0
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_equilibre_v4.lua
@@ -0,0 +1,3 @@
+hook.Add("InitPostEntityMap", "MapProfile", function()
+ for _, ent in pairs(ents.FindByClass("func_physbox")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_farmhouse_v2.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_farmhouse_v2.lua
new file mode 100644
index 0000000..0a77397
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_farmhouse_v2.lua
@@ -0,0 +1,9 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("item_ammo_crate")) do ent:Remove() end
+
+ for _, ent in pairs(ents.FindByClass("trigger_hurt")) do ent:Remove() end
+
+ for _, ent in pairs(ents.FindInSphere(Vector(447.7879, -630.0, 0), 32)) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_fireforest_zeta.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_fireforest_zeta.lua
new file mode 100644
index 0000000..3c162ea
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_fireforest_zeta.lua
@@ -0,0 +1,9 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindInSphere(Vector(-360.8554, -766.1578, 35.3844))) do
+ if ent:GetClass() == "info_player_human" then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_forbidden_bureau.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_forbidden_bureau.lua
new file mode 100644
index 0000000..0923449
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_forbidden_bureau.lua
@@ -0,0 +1,8 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ -- I think its about time that this map be purged of blue shelves.
+ for _, ent in pairs(ents.FindByClass("prop_physics")) do
+ if ent:GetModel() == "models/props_wasteland/kitchen_shelf001a.mdl"then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_forestofthedamned_v2.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_forestofthedamned_v2.lua
new file mode 100644
index 0000000..f9a8c43
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_forestofthedamned_v2.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("func_door")) do
+ ent:Remove()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_forgotten_city_enclosed.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_forgotten_city_enclosed.lua
new file mode 100644
index 0000000..f8cd866
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_forgotten_city_enclosed.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("info_player_counterterrorist")) do
+ ent:Remove()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_hauntedbayou.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_hauntedbayou.lua
new file mode 100644
index 0000000..48b15e3
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_hauntedbayou.lua
@@ -0,0 +1,5 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("item_ammo_crate")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_house_outbreak_b2.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_house_outbreak_b2.lua
new file mode 100644
index 0000000..bf2b7c2
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_house_outbreak_b2.lua
@@ -0,0 +1,9 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("prop_physics")) do
+ if ent:GetModel() == "models/props_c17/furniturecouch001a.mdl" and ent:GetPos().z > 160 then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_infected_city_b1.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_infected_city_b1.lua
new file mode 100644
index 0000000..95e6c0b
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_infected_city_b1.lua
@@ -0,0 +1,12 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(1948, 1232, 746))
+ ent2:SetAngles(Angle(0, 0, -90))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_infected_square_v1.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_infected_square_v1.lua
new file mode 100644
index 0000000..3298eb2
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_infected_square_v1.lua
@@ -0,0 +1,5 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("func_button")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_inn_b2.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_inn_b2.lua
new file mode 100644
index 0000000..2d02a67
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_inn_b2.lua
@@ -0,0 +1,12 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(2702, 377, 47))
+ ent2:SetAngles(Angle(0, 0, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_wasteland/controlroom_filecabinet001a.mdl"))
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_jail_v1.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_jail_v1.lua
new file mode 100644
index 0000000..0923449
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_jail_v1.lua
@@ -0,0 +1,8 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ -- I think its about time that this map be purged of blue shelves.
+ for _, ent in pairs(ents.FindByClass("prop_physics")) do
+ if ent:GetModel() == "models/props_wasteland/kitchen_shelf001a.mdl"then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_lighthouse.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_lighthouse.lua
new file mode 100644
index 0000000..b34abb9
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_lighthouse.lua
@@ -0,0 +1,12 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-41.6038, -342.7579, 120.0313))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_livehouse.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_livehouse.lua
new file mode 100644
index 0000000..48b15e3
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_livehouse.lua
@@ -0,0 +1,5 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("item_ammo_crate")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_livehouse_final.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_livehouse_final.lua
new file mode 100644
index 0000000..74a7142
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_livehouse_final.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ for _, ent in pairs(ents.FindByClass("prop_physics")) do
+ if ent:GetModel() == "models/props_wasteland/kitchen_shelf001a.mdl"then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_lost_b1.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_lost_b1.lua
new file mode 100644
index 0000000..e615811
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_lost_b1.lua
@@ -0,0 +1,8 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ -- The map has a super long hallway one way cade just like all subersive maps. This gets rid of human's favorite prop, but I think it would be best to remove the map from the server.
+ for _, ent in pairs(ents.FindByClass("prop_physics")) do
+ if ent:GetModel() == "models/props_wasteland/kitchen_shelf001a.mdl"then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_lost_coast_house_v2.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_lost_coast_house_v2.lua
new file mode 100644
index 0000000..48b15e3
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_lost_coast_house_v2.lua
@@ -0,0 +1,5 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("item_ammo_crate")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_mall_v2.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_mall_v2.lua
new file mode 100644
index 0000000..07ba16d
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_mall_v2.lua
@@ -0,0 +1,5 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("prop_physics")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_mines_b3.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_mines_b3.lua
new file mode 100644
index 0000000..60acd59
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_mines_b3.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "MPInitPostEntity", function()
+ for _, ent in pairs(ents.FindByClass("func_button")) do
+ ent:Remove()
+ end
+
+ ents.FindByClass("func_rot_button")[3]:Remove()
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_mystery3.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_mystery3.lua
new file mode 100644
index 0000000..3cae15b
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_mystery3.lua
@@ -0,0 +1,11 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(1432.0452, 2344.0313, -352.4774))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_noir.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_noir.lua
new file mode 100644
index 0000000..f9a8c43
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_noir.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("func_door")) do
+ ent:Remove()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_obj_crestsofwaves_b1.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_obj_crestsofwaves_b1.lua
new file mode 100644
index 0000000..0c60e88
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_obj_crestsofwaves_b1.lua
@@ -0,0 +1,3 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ GAMEMODE.ZombieDamageMultiplier = 2.5
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_placid.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_placid.lua
new file mode 100644
index 0000000..3a1dac7
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_placid.lua
@@ -0,0 +1,23 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("env_fire")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-3577.2402, -2450.1162, -398.9688))
+ ent2:SetKeyValue("damagescale", 60)
+ ent2:SetKeyValue("firesize", 200)
+ ent2:Spawn()
+ ent2:Fire("Enable", "", 0)
+ ent2:Fire("StartFire", "", 0)
+ end
+
+ local ent3 = ents.Create("env_fire")
+ if ent3:IsValid() then
+ ent3:SetPos(Vector(-3696.8652, 2621.0576, -239.1022))
+ ent3:SetKeyValue("damagescale", 60)
+ ent3:SetKeyValue("firesize", 200)
+ ent3:Spawn()
+ ent3:Fire("Enable", "", 0)
+ ent3:Fire("StartFire", "", 0)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_plaza_opt.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_plaza_opt.lua
new file mode 100644
index 0000000..e5d9676
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_plaza_opt.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByName("Gunstoredoor")) do ent:Remove() end
+ for _, ent in pairs(ents.FindByName("Store3F2")) do ent:Remove() end
+ for _, ent in pairs(ents.FindByName("Store1F2")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_raunchyhouse.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_raunchyhouse.lua
new file mode 100644
index 0000000..919ef3a
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_raunchyhouse.lua
@@ -0,0 +1,40 @@
+hook.Add("InitPostEntityMap", "DestroyDoor", function()
+ DESTROY_PROP_DOORS = false
+ DESTROY_DOORS = false
+ local doors = ents.FindByClass("prop_door_rotating")
+ if doors[2] then
+ doors[2]:Remove()
+ end
+
+ for _, ent in pairs(ents.FindByClass("gmod_player_start")) do
+ if ent:GetPos().z > -440 then
+ ent:Remove()
+ end
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(2946.4270, -2783.7803, -439.9688))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_wasteland/kitchen_shelf001a.mdl"))
+ ent2:Spawn()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(2946.7278, -2781.4426, -407.3824 + 6))
+ ent2:SetAngles(Angle(0, 50, 90))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_junk/CinderBlock01a.mdl"))
+ ent2:Spawn()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(2946.5017, -2783.1523, -343.4822 + 6))
+ ent2:SetAngles(Angle(0, 90, 90))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_junk/CinderBlock01a.mdl"))
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_ravenholm_final.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_ravenholm_final.lua
new file mode 100644
index 0000000..52bc521
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_ravenholm_final.lua
@@ -0,0 +1,8 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ -- The map has many viable spots, but one of them is vastly more viable than the rest due to a blue shelf. guess what this map profile does?
+ for _, ent in pairs(ents.FindByClass("prop_physics")) do
+ if ent:GetModel() == "models/props_wasteland/kitchen_shelf001a.mdl"then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_ravenholm_v3.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_ravenholm_v3.lua
new file mode 100644
index 0000000..9abcbac
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_ravenholm_v3.lua
@@ -0,0 +1,31 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(802, -260, -563))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ ent2:SetColor(Color(0, 0, 0, 0))
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(900, -169, -565))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ ent2:SetColor(Color(0, 0, 0, 0))
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(899, -332, -536))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ ent2:SetColor(Color(0, 0, 0, 0))
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_residentevil_v2.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_residentevil_v2.lua
new file mode 100644
index 0000000..c25bf35
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_residentevil_v2.lua
@@ -0,0 +1,5 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("prop_physics*")) do ent:GetPhysicsObject():EnableMotion(true) end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_sandtraps_v2.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_sandtraps_v2.lua
new file mode 100644
index 0000000..abbb77a
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_sandtraps_v2.lua
@@ -0,0 +1,13 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(2360, -2724, 218))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ ent2:SetColor(Color(0, 0, 0, 0))
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_seclusion.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_seclusion.lua
new file mode 100644
index 0000000..0fa909c
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_seclusion.lua
@@ -0,0 +1,16 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ local Placements = {
+ Vector(-2025, 1110, -770),
+ Vector(-2370, 1100, -855)
+ }
+
+ for _, pos in pairs(Placements) do
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(pos)
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel("models/props_lab/blastdoor001c.mdl")
+ ent2:Spawn()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_stadium.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_stadium.lua
new file mode 100644
index 0000000..f064f74
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_stadium.lua
@@ -0,0 +1,19 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(1431.674316, 759.331238, -171.968750))
+ ent:SetKeyValue("solid", "6")
+ ent:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent:Spawn()
+ ent:SetNoDraw(true)
+ end
+
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(1431.674316, 759.331238, -116))
+ ent:SetKeyValue("solid", "6")
+ ent:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent:Spawn()
+ ent:SetNoDraw(true)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_storm_v1.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_storm_v1.lua
new file mode 100644
index 0000000..a2c9d95
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_storm_v1.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("trigger_teleport")) do
+ ent:Remove()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_stormier_b1.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_stormier_b1.lua
new file mode 100644
index 0000000..a2c9d95
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_stormier_b1.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("trigger_teleport")) do
+ ent:Remove()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_stormiest_b1.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_stormiest_b1.lua
new file mode 100644
index 0000000..e376eed
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_stormiest_b1.lua
@@ -0,0 +1,25 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("weapon_zs_boomstick")) do ent:Remove() end
+ for _, ent in pairs(ents.FindByClass("weapon_zs_medicalkit")) do ent:Remove() end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-2146, 1663, -625))
+ ent2:SetAngles(Angle(0, 66, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:SetColor(Color(0, 0, 0, 0))
+ ent2:Spawn()
+ end
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-2226, 1781, -625))
+ ent2:SetAngles(Angle(0, 0, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:SetColor(Color(0, 0, 0, 0))
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_subversive_1.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_subversive_1.lua
new file mode 100644
index 0000000..e615811
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_subversive_1.lua
@@ -0,0 +1,8 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ -- The map has a super long hallway one way cade just like all subersive maps. This gets rid of human's favorite prop, but I think it would be best to remove the map from the server.
+ for _, ent in pairs(ents.FindByClass("prop_physics")) do
+ if ent:GetModel() == "models/props_wasteland/kitchen_shelf001a.mdl"then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_swimming_pool_v2.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_swimming_pool_v2.lua
new file mode 100644
index 0000000..e8ac7c4
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_swimming_pool_v2.lua
@@ -0,0 +1,20 @@
+-- Removes stupid ammo crates in the only room anyone would ever want to hold out in.
+-- Unlocks doors of secret rooms.
+
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("item_ammo_crate")) do
+ ent:Remove()
+ end
+
+ for _, ent in pairs(ents.FindByModel("models/props_c17/door01_left.mdl")) do
+ ent:Fire("unlock", "", 0)
+ end
+
+ local ent = ents.Create("info_player_zombie")
+ if ent:IsValid() then
+ ent:SetPos(Vector(-1641, -61, 7))
+ ent:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_termites_v2.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_termites_v2.lua
new file mode 100644
index 0000000..eb61551
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_termites_v2.lua
@@ -0,0 +1,12 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(179.0722, -540.1974, -190.9688))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_the_pub_final7.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_the_pub_final7.lua
new file mode 100644
index 0000000..4068bdd
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_the_pub_final7.lua
@@ -0,0 +1,5 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("point_worldhint")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_thevillage_final_opt.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_thevillage_final_opt.lua
new file mode 100644
index 0000000..323d815
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_thevillage_final_opt.lua
@@ -0,0 +1,41 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-579, 220, 83))
+ ent2:SetAngles(Angle(0, 0, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_c17/oildrum001.mdl"))
+ ent2:Spawn()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-557, 216, 91))
+ ent2:SetAngles(Angle(20.5, 180, -180))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_junk/CinderBlock01a.mdl"))
+ ent2:Spawn()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-582, 230, 133))
+ ent2:SetAngles(Angle(90, 24.5, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_junk/CinderBlock01a.mdl"))
+ ent2:Spawn()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-587, 234, 144))
+ ent2:SetAngles(Angle(0, 90, 90))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_junk/CinderBlock01a.mdl"))
+ ent2:Spawn()
+ end
+
+ for _, ent in pairs(ents.FindByName("lift")) do
+ ent:SetKeyValue("blockdamage", 0)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_tigcrik.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_tigcrik.lua
new file mode 100644
index 0000000..d755b9d
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_tigcrik.lua
@@ -0,0 +1,13 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(-969, 1039, 438))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ ent2:SetColor(Color(0, 0, 0, 0))
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_town_b1_7.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_town_b1_7.lua
new file mode 100644
index 0000000..82c7380
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_town_b1_7.lua
@@ -0,0 +1,18 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ for _, ent in pairs(ents.FindInSphere(Vector(1736.2645, -1860.0313, -525.5502), 32)) do
+ if ent:GetClass() == "func_door_rotating" then ent:Remove() end
+ end
+
+ for _, ent in pairs(ents.FindByClass("func_movelinear")) do
+ ent:Remove()
+ end
+
+ local ent2 = ents.Create("prop_dynamic_override")
+ if ent2:IsValid() then
+ ent2:SetPos(Vector(1120.2247, -2566.5984, -263.9688))
+ ent2:SetAngles(Angle(0, 90, 0))
+ ent2:SetKeyValue("solid", "6")
+ ent2:SetModel(Model("models/props_lab/blastdoor001c.mdl"))
+ ent2:Spawn()
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_trainstation.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_trainstation.lua
new file mode 100644
index 0000000..74a7142
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_trainstation.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ for _, ent in pairs(ents.FindByClass("prop_physics")) do
+ if ent:GetModel() == "models/props_wasteland/kitchen_shelf001a.mdl"then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_tug_hut.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_tug_hut.lua
new file mode 100644
index 0000000..e96f0e2
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_tug_hut.lua
@@ -0,0 +1,23 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(-890.3486, 71.1159, 140.0313))
+ ent:SetAngles(Angle(0, 90, 0))
+ ent:SetModel("models/props_lab/blastdoor001a.mdl")
+ ent:SetKeyValue("solid", "6")
+ ent:Spawn()
+ end
+
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetPos(Vector(-1083.4521, -107.9099, 140.0313))
+ ent:SetModel("models/props_lab/blastdoor001a.mdl")
+ ent:SetKeyValue("solid", "6")
+ ent:Spawn()
+ end
+
+ for _, ent in pairs(ents.FindByClass("item_healthcharger")) do
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_urbandecay_final.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_urbandecay_final.lua
new file mode 100644
index 0000000..48b15e3
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_urbandecay_final.lua
@@ -0,0 +1,5 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("item_ammo_crate")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_vault_106_v5.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_vault_106_v5.lua
new file mode 100644
index 0000000..74a7142
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_vault_106_v5.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ for _, ent in pairs(ents.FindByClass("prop_physics")) do
+ if ent:GetModel() == "models/props_wasteland/kitchen_shelf001a.mdl"then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_woodhouse_rain.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_woodhouse_rain.lua
new file mode 100644
index 0000000..53d11f1
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_woodhouse_rain.lua
@@ -0,0 +1,7 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("prop_physics*")) do
+ ent:GetPhysicsObject():EnableMotion(true)
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_xccr_lite.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_xccr_lite.lua
new file mode 100644
index 0000000..93a69f4
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_xccr_lite.lua
@@ -0,0 +1,5 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("item_suitcharger")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_xmas_lodge.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_xmas_lodge.lua
new file mode 100644
index 0000000..715db94
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_xmas_lodge.lua
@@ -0,0 +1,11 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+
+
+ for _, ent in pairs(ents.FindByClass("item_ammo_crate")) do ent:Remove() end
+
+ for _, ent in pairs(ents.FindByClass("prop_physics*")) do
+ if ent:GetPos().z < -300 then
+ ent:Remove()
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/maps/zs_zincoshine_v2.lua b/gamemodes/zombiesurvival/gamemode/maps/zs_zincoshine_v2.lua
new file mode 100644
index 0000000..746b816
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/maps/zs_zincoshine_v2.lua
@@ -0,0 +1,3 @@
+hook.Add("InitPostEntityMap", "Adding", function()
+ for _, ent in pairs(ents.FindByClass("item_ammo_crate")) do ent:Remove() end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/nixthelag.lua b/gamemodes/zombiesurvival/gamemode/nixthelag.lua
new file mode 100644
index 0000000..ff70fb7
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/nixthelag.lua
@@ -0,0 +1,49 @@
+AddCSLuaFile("nixthelag.lua")
+
+-- Let's remove a bunch of expensive stuff that is never used.
+
+hook.Add("Initialize", "NixTheLag", function()
+ -- Horrible amount of cycle usage, especially on the server.
+ hook.Remove("PlayerTick", "TickWidgets")
+
+ if SERVER then
+ -- Forget what this is but probably retarded.
+ if timer.Exists("CheckHookTimes") then
+ timer.Remove("CheckHookTimes")
+ end
+ end
+
+ if CLIENT then
+ -- These call on bloated convar getting methods and aren't ever used anyway outside of sandbox.
+ hook.Remove("RenderScreenspaceEffects", "RenderColorModify")
+ hook.Remove("RenderScreenspaceEffects", "RenderBloom")
+ hook.Remove("RenderScreenspaceEffects", "RenderToyTown")
+ hook.Remove("RenderScreenspaceEffects", "RenderTexturize")
+ hook.Remove("RenderScreenspaceEffects", "RenderSunbeams")
+ hook.Remove("RenderScreenspaceEffects", "RenderSobel")
+ hook.Remove("RenderScreenspaceEffects", "RenderSharpen")
+ hook.Remove("RenderScreenspaceEffects", "RenderMaterialOverlay")
+ hook.Remove("RenderScreenspaceEffects", "RenderMotionBlur")
+ hook.Remove("RenderScene", "RenderStereoscopy")
+ hook.Remove("RenderScene", "RenderSuperDoF")
+ hook.Remove("GUIMousePressed", "SuperDOFMouseDown")
+ hook.Remove("GUIMouseReleased", "SuperDOFMouseUp")
+ hook.Remove("PreventScreenClicks", "SuperDOFPreventClicks")
+ hook.Remove("PostRender", "RenderFrameBlend")
+ hook.Remove("PreRender", "PreRenderFrameBlend")
+ hook.Remove("Think", "DOFThink")
+ hook.Remove("RenderScreenspaceEffects", "RenderBokeh")
+ hook.Remove("NeedsDepthPass", "NeedsDepthPass_Bokeh")
+
+ -- Useless since we disabled widgets above.
+ hook.Remove("PostDrawEffects", "RenderWidgets")
+
+ -- Could screw with people's point shops but whatever.
+ hook.Remove("PostDrawEffects", "RenderHalos")
+ end
+end)
+
+-- This probably chops off a few FPS (1 to 5) but stops many problems with frame spikes.
+--[[hook.Add("Think", "ManualGC", function()
+ collectgarbage("step", 192)
+end)]]
diff --git a/gamemodes/zombiesurvival/gamemode/noxapi/client.lua b/gamemodes/zombiesurvival/gamemode/noxapi/client.lua
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/noxapi/client.lua
@@ -0,0 +1 @@
+
diff --git a/gamemodes/zombiesurvival/gamemode/noxapi/noxapi.lua b/gamemodes/zombiesurvival/gamemode/noxapi/noxapi.lua
new file mode 100644
index 0000000..c6dc243
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/noxapi/noxapi.lua
@@ -0,0 +1,18 @@
+-- This allows communication to the noxapi. Mostly for checking if people are supporters.
+-- Supporters don't get any gameplay advantages.
+-- A supporter is someone who has gold or diamond member on noxiousnet.
+-- Ripping this out or modifying it is silly. Also, I do not need to go on your server to see if you are doing so.
+
+include("shared.lua")
+
+if SERVER then
+ AddCSLuaFile("noxapi.lua")
+ AddCSLuaFile("shared.lua")
+ AddCSLuaFile("client.lua")
+
+ include("server.lua")
+end
+
+if CLIENT then
+ include("client.lua")
+end
diff --git a/gamemodes/zombiesurvival/gamemode/noxapi/server.lua b/gamemodes/zombiesurvival/gamemode/noxapi/server.lua
new file mode 100644
index 0000000..0b9534b
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/noxapi/server.lua
@@ -0,0 +1,17 @@
+local function PlayerInitialSpawn(pl)
+ http.Fetch("http://www.noxiousnet.com/api/player/memberlevel?steamid="..pl:SteamID(), function(body, len, headers, code)
+ local level = tonumber(body)
+ if level == 1 or level == 2 then
+ pl._SUPPORTER_ = true
+ pl:PrintMessage(HUD_PRINTCONSOLE, "GREETINGS FROM NOX, FELLOW SUPPORTER!")
+ end
+ end)
+end
+
+--if not NDB then
+ --hook.Add("PlayerInitialSpawn", "noxapi", PlayerInitialSpawn)
+--end
+
+hook.Add("Initialize", "noxapi", function()
+ resource.AddFile("materials/noxiousnet/noxicon.png")
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/noxapi/shared.lua b/gamemodes/zombiesurvival/gamemode/noxapi/shared.lua
new file mode 100644
index 0000000..271700c
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/noxapi/shared.lua
@@ -0,0 +1,11 @@
+local meta = FindMetaTable("Player")
+if not meta then return end
+
+function meta:IsNoxSupporter()
+ if NDB then
+ local memberlevel = self:GetMemberLevel()
+ return memberlevel == MEMBER_GOLD or memberlevel == MEMBER_DIAMOND
+ end
+
+ return self._SUPPORTER_
+end
diff --git a/gamemodes/zombiesurvival/gamemode/obj_entity_extend.lua b/gamemodes/zombiesurvival/gamemode/obj_entity_extend.lua
new file mode 100644
index 0000000..6404e58
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/obj_entity_extend.lua
@@ -0,0 +1,331 @@
+local meta = FindMetaTable("Entity")
+if not meta then return end
+
+function meta:ApplyPlayerProperties(ply)
+ self.GetPlayerColor = function() return ply:GetPlayerColor() end
+ self:SetBodygroup( ply:GetBodygroup(1), 1 )
+ self:SetMaterial( ply:GetMaterial() )
+ self:SetSkin( ply:GetSkin() or 1 )
+end
+
+function meta:GetVolume()
+ local mins, maxs = self:OBBMins(), self:OBBMaxs()
+ return (maxs.x - mins.x) + (maxs.y - mins.y) + (maxs.z - mins.z)
+end
+
+function meta:TakeSpecialDamage(damage, damagetype, attacker, inflictor, hitpos)
+ attacker = attacker or self
+ if not attacker:IsValid() then attacker = self end
+ inflictor = inflictor or attacker
+ if not inflictor:IsValid() then inflictor = attacker end
+
+ local dmginfo = DamageInfo()
+ dmginfo:SetDamage(damage)
+ dmginfo:SetAttacker(attacker)
+ dmginfo:SetInflictor(inflictor)
+ dmginfo:SetDamagePosition(hitpos or self:NearestPoint(inflictor:NearestPoint(self:LocalToWorld(self:OBBCenter()))))
+ dmginfo:SetDamageType(damagetype)
+ self:TakeDamageInfo(dmginfo)
+
+ return dmginfo
+end
+
+function meta:NearestBone(pos)
+ local count = self:GetBoneCount()
+ if count == 0 then return end
+
+ local nearest
+ local nearestdist
+
+ for boneid = 1, count - 1 do
+ local bonepos, boneang = self:GetBonePositionMatrixed(boneid)
+ local dist = bonepos:Distance(pos)
+
+ if not nearest or dist < nearestdist then
+ nearest = boneid
+ nearestdist = dist
+ end
+ end
+
+ return nearest
+end
+
+function meta:IsProjectile()
+ return self:GetCollisionGroup() == COLLISION_GROUP_PROJECTILE or self.m_IsProjectile
+end
+
+function meta:ResetBones(onlyscale)
+ local v = Vector(1, 1, 1)
+ if onlyscale then
+ for i=0, self:GetBoneCount() - 1 do
+ self:ManipulateBoneScale(i, v)
+ end
+ else
+ local a = Angle(0, 0, 0)
+ for i=0, self:GetBoneCount() - 1 do
+ self:ManipulateBoneScale(i, v)
+ self:ManipulateBoneAngles(i, a)
+ self:ManipulateBonePosition(i, vector_origin)
+ end
+ end
+end
+
+function meta:SetTeamID(teamid)
+ self.TeamID = teamid
+end
+
+function meta:GetTeamID()
+ return self.Team and self:Team() or self.TeamID or 0
+end
+
+function meta:SetBarricadeHealth(m)
+ self:SetDTFloat(1, m)
+end
+
+function meta:GetBarricadeHealth()
+ return self:GetDTFloat(1)
+end
+
+function meta:SetMaxBarricadeHealth(m)
+ self:SetDTFloat(2, m)
+end
+
+function meta:GetMaxBarricadeHealth()
+ return self:GetDTFloat(2)
+end
+
+function meta:SetBarricadeRepairs(m)
+ self:SetDTFloat(3, m)
+end
+
+function meta:GetBarricadeRepairs()
+ return self:GetDTFloat(3)
+end
+
+function meta:GetMaxBarricadeRepairs()
+ return self:GetMaxBarricadeHealth() * 1.5
+end
+
+function meta:GetBonePositionMatrixed(index)
+ local matrix = self:GetBoneMatrix(index)
+ if matrix then
+ return matrix:GetTranslation(), matrix:GetAngles()
+ end
+
+ return self:GetPos(), self:GetAngles()
+end
+
+-- This needs to be done otherwise the physics might crash.
+function meta:CollisionRulesChanged()
+ if not self.m_OldCollisionGroup then self.m_OldCollisionGroup = self:GetCollisionGroup() end
+ self:SetCollisionGroup(self.m_OldCollisionGroup == COLLISION_GROUP_DEBRIS and COLLISION_GROUP_WORLD or COLLISION_GROUP_DEBRIS)
+ self:SetCollisionGroup(self.m_OldCollisionGroup)
+ self.m_OldCollisionGroup = nil
+end
+
+function meta:IsNailed()
+ if self:IsValid() then -- In case we're the world.
+ for _, nail in pairs(ents.FindByClass("prop_nail")) do
+ if nail:IsValid() and (nail.GetAttachEntity and nail:GetAttachEntity() == self or nail.GetBaseEntity and nail:GetBaseEntity() == self) then
+ return true
+ end
+ end
+ end
+
+ return false
+end
+
+function meta:GetAlpha()
+ return self:GetColor().a
+end
+
+function meta:SetAlpha(a)
+ local col = self:GetColor()
+ col.a = a
+ self:SetColor(col)
+end
+
+local function barricadetimer(self, timername)
+ if self:IsValid() then
+ for _, e in pairs(ents.FindInBox(self:WorldSpaceAABB())) do
+ if e:IsPlayer() and e:Alive() then
+ return
+ end
+ end
+
+ self.IsBarricadeObject = nil
+ self:CollisionRulesChanged()
+ end
+
+ timer.Destroy(timername)
+end
+
+function meta:TemporaryBarricadeObject()
+ if self.IsBarricadeObject then return end
+
+ for _, e in pairs(ents.FindInBox(self:WorldSpaceAABB())) do
+ if e:IsPlayer() and e:Alive() then
+ self.IsBarricadeObject = true
+ self:CollisionRulesChanged()
+
+ local timername = "TemporaryBarricadeObject"..self:GetCreationID()
+ timer.CreateEx(timername, 0, 0, barricadetimer, self, timername)
+
+ return
+ end
+ end
+end
+
+function meta:IsBarricadeProp()
+ return self.IsBarricadeObject or self:IsNailed()
+end
+
+function meta:GetHolder()
+ for _, ent in pairs(ents.FindByClass("status_human_holding")) do
+ if ent:GetObject() == self then
+ local owner = ent:GetOwner()
+ if owner:IsPlayer() and owner:Alive() then return owner, ent end
+ end
+ end
+end
+
+function meta:RemoveNextFrame(time)
+ self.Removing = true
+ self:Fire("kill", "", time or 0.01)
+end
+
+function meta:ThrowFromPosition(pos, force, noknockdown)
+ if force == 0 or self:IsProjectile() or self.NoThrowFromPosition then return false end
+
+ if self:IsPlayer() and self:ActiveBarricadeGhosting() then return false end
+
+ if self:GetMoveType() == MOVETYPE_VPHYSICS then
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() and phys:IsMoveable() then
+ local nearest = self:NearestPoint(pos)
+ phys:ApplyForceOffset(force * 50 * (nearest - pos):GetNormalized(), nearest)
+ end
+
+ return true
+ elseif self:GetMoveType() >= MOVETYPE_WALK and self:GetMoveType() < MOVETYPE_PUSH then
+ self:SetGroundEntity(NULL)
+ if SERVER and not noknockdown and self:IsPlayer() then
+ local absforce = math.abs(force)
+ if absforce >= 512 or self.Clumsy and self:Team() ~= TEAM_UNDEAD and absforce >= 32 then
+ self:KnockDown()
+ end
+ end
+ self:SetVelocity(force * (self:LocalToWorld(self:OBBCenter()) - pos):GetNormalized())
+
+ return true
+ end
+end
+
+function meta:ThrowFromPositionSetZ(pos, force, zmul, noknockdown)
+ if force == 0 or self:IsProjectile() or self.NoThrowFromPosition then return false end
+ zmul = zmul or 0.7
+
+ if self:IsPlayer() and self:ActiveBarricadeGhosting() then return false end
+
+ if self:GetMoveType() == MOVETYPE_VPHYSICS then
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() and phys:IsMoveable() then
+ local nearest = self:NearestPoint(pos)
+ local dir = nearest - pos
+ dir.z = 0
+ dir:Normalize()
+ dir.z = zmul
+ phys:ApplyForceOffset(force * 50 * dir, nearest)
+ end
+
+ return true
+ elseif self:GetMoveType() >= MOVETYPE_WALK and self:GetMoveType() < MOVETYPE_PUSH then
+ self:SetGroundEntity(NULL)
+ if SERVER and not noknockdown and self:IsPlayer() then
+ local absforce = math.max(math.abs(force) * math.abs(zmul), math.abs(force))
+ if absforce >= 512 or self.Clumsy and self:Team() ~= TEAM_UNDEAD and absforce >= 32 then
+ self:KnockDown()
+ end
+ end
+
+ local dir = self:LocalToWorld(self:OBBCenter()) - pos
+ dir.z = 0
+ dir:Normalize()
+ dir.z = zmul
+ self:SetVelocity(force * dir)
+
+ return true
+ end
+end
+
+util.PrecacheSound("player/pl_pain5.wav")
+util.PrecacheSound("player/pl_pain6.wav")
+util.PrecacheSound("player/pl_pain7.wav")
+function meta:PoisonDamage(damage, attacker, inflictor, hitpos, noreduction)
+ damage = damage or 1
+
+ local dmginfo = DamageInfo()
+
+ if self:IsPlayer() then
+ if self:Team() == TEAM_UNDEAD then return end
+
+ if self.BuffResistant then
+ damage = damage / 2
+ end
+
+ self:ViewPunch(Angle(math.random(-10, 10), math.random(-10, 10), math.random(-20, 20)))
+ self:EmitSound("player/pl_pain"..math.random(5, 7)..".wav")
+
+ if SERVER then
+ self:GiveStatus("poisonrecovery"):AddDamage(math.floor(damage * 0.75))
+ end
+
+ dmginfo:SetDamageType(DMG_ACID)
+ else
+ if not noreduction then
+ damage = damage / 3
+ end
+ dmginfo:SetDamageType(DMG_SLASH) -- Fixes not doing damage to props.
+ end
+
+ attacker = attacker or self
+ inflictor = inflictor or attacker
+
+ dmginfo:SetDamagePosition(hitpos or self:NearestPoint(inflictor:NearestPoint(self:LocalToWorld(self:OBBCenter()))))
+ dmginfo:SetDamage(damage)
+ dmginfo:SetAttacker(attacker)
+ dmginfo:SetInflictor(inflictor)
+ self:TakeDamageInfo(dmginfo)
+end
+
+if CLIENT then
+ function meta:SetModelScaleVector(vec)
+ local bonecount = self:GetBoneCount()
+ if bonecount and bonecount > 1 then
+ local scale
+ if type(vec) == "number" then
+ scale = vec
+ else
+ scale = math.min(vec.x, vec.y, vec.z)
+ end
+ self._ModelScale = Vector(scale, scale, scale)
+ self:SetModelScale(scale, 0)
+ else
+ if type(vec) == "number" then
+ vec = Vector(vec, vec, vec)
+ end
+
+ self._ModelScale = vec
+ local m = Matrix()
+ m:Scale(vec)
+ self:EnableMatrix("RenderMultiply", m)
+ end
+ end
+
+ if not meta.TakeDamageInfo then
+ meta.TakeDamageInfo = function() end
+ end
+ if not meta.SetPhysicsAttacker then
+ meta.SetPhysicsAttacker = function() end
+ end
+end
diff --git a/gamemodes/zombiesurvival/gamemode/obj_entity_extend_sv.lua b/gamemodes/zombiesurvival/gamemode/obj_entity_extend_sv.lua
new file mode 100644
index 0000000..248d5ae
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/obj_entity_extend_sv.lua
@@ -0,0 +1,434 @@
+local meta = FindMetaTable("Entity")
+if not meta then return end
+
+function meta:GetDefaultBarricadeHealth()
+ local mass = 2
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ mass = phys:GetMass()
+ end
+
+ return math.Clamp(mass * GAMEMODE.BarricadeHealthMassFactor + self:GetVolume() * GAMEMODE.BarricadeHealthVolumeFactor, GAMEMODE.BarricadeHealthMin, GAMEMODE.BarricadeHealthMax)
+end
+
+function meta:HitFence(data, phys)
+ local pos = phys:GetPos()
+ local vel = data.OurOldVelocity
+ local endpos = data.HitPos + vel:GetNormalized()
+ if util.TraceLine({start = pos, endpos = endpos, mask = MASK_SOLID, filter = self}).Hit and not util.TraceLine({start = pos, endpos = endpos, mask = MASK_SHOT, filter = self}).Hit then -- Essentially hit a fence or passable object.
+ self:SetPos(data.HitPos)
+ phys:SetPos(data.HitPos)
+ phys:SetVelocityInstantaneous(vel)
+
+ return true
+ end
+
+ return false
+end
+
+function meta:GhostAllPlayersInMe(timeout, allowrepeat)
+ if not allowrepeat then
+ if self.GhostedBefore then return end
+ self.GhostedBefore = true
+ end
+
+ local ent = ents.Create("point_propnocollide")
+ if ent:IsValid() then
+ ent:SetPos(self:GetPos())
+ ent:Spawn()
+ if timeout then
+ ent:SetTimeOut(CurTime() + timeout)
+ end
+ ent:SetTeam(TEAM_HUMAN)
+
+ ent:SetProp(self)
+ end
+end
+
+local function SortItems(a, b)
+ if a.CleanupPriority == b.CleanupPriority then
+ return a.Created < b.Created
+ end
+
+ return a.CleanupPriority < b.CleanupPriority
+end
+local function CheckItemCreated(self)
+ if not self:IsValid() or self.PlacedInMap then return end
+
+ local tab = {}
+ for _, ent in pairs(ents.FindByClass("prop_ammo")) do
+ if not ent.PlacedInMap then
+ table.insert(tab, ent)
+ end
+ end
+ for _, ent in pairs(ents.FindByClass("prop_flashlightbattery")) do
+ if not ent.PlacedInMap then
+ table.insert(tab, ent)
+ end
+ end
+ for _, ent in pairs(ents.FindByClass("prop_weapon")) do
+ if not ent.PlacedInMap then
+ table.insert(tab, ent)
+ end
+ end
+
+ if #tab > GAMEMODE.MaxDroppedItems then
+ table.sort(tab, SortItems)
+ for i = 1, GAMEMODE.MaxDroppedItems do
+ tab[i]:Remove()
+ end
+ end
+end
+function meta:ItemCreated()
+ self.Created = self.Created or CurTime()
+ timer.Simple(0, function() CheckItemCreated(self) end)
+end
+
+function meta:FireOutput(outpt, activator, caller, args)
+ local intab = self[outpt]
+ if intab then
+ for key, tab in pairs(intab) do
+ for __, subent in pairs(self:FindByNameHammer(tab.entityname, activator, caller)) do
+ local delay = tonumber(tab.delay)
+ if delay == nil or delay <= 0 then
+ subent:Input(tab.input, activator, caller, tab.args)
+ else
+ local inp = tab.input
+ local args = tab.args
+ timer.Simple(delay, function() if subent:IsValid() then subent:Input(inp, activator, caller, args) end end)
+ end
+ end
+ end
+ end
+end
+
+function meta:AddOnOutput(key, value)
+ self[key] = self[key] or {}
+ local tab = string.Explode(",", value)
+ table.insert(self[key], {entityname=tab[1], input=tab[2], args=tab[3], delay=tab[4], reps=tab[5]})
+end
+
+function meta:FindByNameHammer(name, activator, caller)
+ if name == "!self" then return {self} end
+ if name == "!activator" then return {activator} end
+ if name == "!caller" then return {caller} end
+ return ents.FindByName(name)
+end
+
+function meta:IsNailed()
+ if self:IsValid() and self.Nails then -- In case we're the world.
+ for _, nail in pairs(self.Nails) do
+ if nail and nail:IsValid() and (nail:GetAttachEntity() == self or nail:GetBaseEntity() == self) then
+ return true
+ end
+ end
+ end
+
+ return false
+end
+
+function meta:IsNailedToWorld(hierarchy)
+ if self:IsNailed() then
+ for _, nail in pairs(self.Nails) do
+ if nail:GetAttachEntity():IsWorld() then
+ return true
+ end
+ end
+ end
+
+ if hierarchy then
+ for _, ent in pairs(self:GetAllConstrainedEntities()) do
+ if ent ~= self and ent:IsValid() and ent:IsNailedToWorld() then return true end
+ end
+ end
+
+ return false
+end
+
+function meta:IsNailedToWorldHierarchy()
+ return self:IsNailedToWorld(true)
+end
+
+function meta:GetNailFrozen()
+ return self.m_NailFrozen
+end
+meta.IsNailFrozen = meta.GetNailFrozen
+
+function meta:SetNailFrozen(frozen)
+ if frozen then
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() and phys:IsMoveable() then
+ self.m_NailFrozen = true
+ phys:EnableMotion(false)
+ end
+ elseif self:IsNailFrozen() then
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ self.m_NailFrozen = false
+ phys:EnableMotion(true)
+ phys:Wake()
+ end
+ end
+end
+
+function constraint.GetAllConstrainedEntitiesOrdered(ent)
+ local allcons = constraint.GetAllConstrainedEntities(ent)
+
+ local tab = {}
+
+ if allcons then
+ for k, v in pairs(allcons) do
+ table.insert(tab, v)
+ end
+ end
+
+ return tab
+end
+
+function meta:GetAllConstrainedEntities()
+ local allcons = constraint.GetAllConstrainedEntitiesOrdered(self)
+ if not allcons or #allcons == 0 then
+ return {self}
+ end
+
+ return allcons
+end
+
+function meta:PackUp(pl)
+ if not self.CanPackUp then return end
+
+ local cur = pl:GetStatus("packup")
+ if cur and cur:IsValid() then return end
+
+ local status = pl:GiveStatus("packup")
+ if status:IsValid() then
+ status:SetPackUpEntity(self)
+ status:SetEndTime(CurTime() + (self.PackUpTime or 4))
+
+ if self.GetObjectOwner then
+ local owner = self:GetObjectOwner()
+ if owner:IsValid() and owner:Team() == TEAM_HUMAN and owner ~= pl and not gamemode.Call("PlayerIsAdmin", pl) then
+ status:SetNotOwner(true)
+ end
+ end
+ end
+end
+
+function meta:GetPropsInContraption()
+ local allcons = constraint.GetAllConstrainedEntities(self)
+ if not allcons or #allcons == 0 then
+ return 1
+ end
+
+ return #allcons
+end
+
+function meta:HumanNearby()
+ for _, pl in pairs(team.GetPlayers(TEAM_HUMAN)) do
+ local plpos = pl:GetPos()
+ if pl:Alive() and self:NearestPoint(plpos):Distance(plpos) <= 512 then
+ return true
+ end
+ end
+end
+
+function meta:ResetLastBarricadeAttacker(attacker, dmginfo)
+ if attacker:IsPlayer() and attacker:Team() == TEAM_UNDEAD then
+ self.m_LastDamagedByZombie = CurTime()
+
+ if self:HumanNearby() then
+ local dmg = math.ceil(dmginfo:GetDamage())
+ attacker.BarricadeDamage = attacker.BarricadeDamage + dmg
+ if attacker.LifeBarricadeDamage ~= nil then
+ attacker:AddLifeBarricadeDamage(dmg)
+ end
+ if attacker:GetZombieClassTable().Name == "Crow" then
+ attacker.CrowBarricadeDamage = attacker.CrowBarricadeDamage + dmg
+ end
+ end
+ end
+end
+
+meta.OldSetPhysicsAttacker = meta.SetPhysicsAttacker
+function meta:SetPhysicsAttacker(ent)
+ if self:GetClass() == "func_physbox" and ent:IsValid() then
+ self.PBAttacker = ent
+ self.NPBAttacker = CurTime() + 1
+ end
+ self:OldSetPhysicsAttacker(ent)
+end
+
+local function randomsort(a, b)
+ return a.rand < b.rand
+end
+local function randomize(t)
+ for k, v in pairs(t) do v.rand = math.Rand(0, 1) end
+ table.sort(t, randomsort)
+end
+
+-- Return true to override default behavior.
+function meta:DamageNails(attacker, inflictor, damage, dmginfo)
+ if not self:IsNailed() or self.m_NailsDontAbsorb then return end
+
+ if self:GetBarricadeHealth() <= 0 then return end
+
+ if not gamemode.Call("CanDamageNail", self, attacker, inflictor, damage, dmginfo) then
+ if dmginfo then
+ dmginfo:SetDamage(0)
+ dmginfo:SetDamageType(DMG_BULLET)
+ end
+
+ return true
+ end
+
+ if damage < 0 then
+ if dmginfo then
+ dmginfo:SetDamage(0)
+ end
+
+ return true
+ end
+
+ self:ResetLastBarricadeAttacker(attacker, dmginfo)
+
+ local nails = self:GetLivingNails()
+ if #nails <= 0 then return end
+
+ self:SetBarricadeHealth(self:GetBarricadeHealth() - damage)
+ for i, nail in ipairs(nails) do
+ nail:OnDamaged(damage, attacker, inflictor, dmginfo)
+ end
+
+ if attacker:IsPlayer() then
+ GAMEMODE:DamageFloater(attacker, self, dmginfo)
+ end
+
+ if dmginfo then dmginfo:SetDamage(0) end
+
+ if self:GetBarricadeHealth() <= 0 then
+ if self:GetModel() ~= "" and self:GetModel() ~= "models/error.mdl" then
+ if self:GetName() == "" and self:GetVolume() < 100 then
+ self:Fire("break", "", 0.01)
+ self:Fire("kill", "", 0.05)
+ else
+ local ent = ents.Create("env_propbroken")
+ if ent:IsValid() then
+ ent:Spawn()
+ ent:AttachTo(self)
+ end
+ end
+ end
+
+ for _, nail in pairs(nails) do
+ self:RemoveNail(nail)
+ end
+ end
+
+ return true
+end
+
+function meta:GetNails()
+ local tab = {}
+
+ if self.Nails then
+ for _, nail in pairs(self.Nails) do
+ if nail and nail:IsValid() then
+ table.insert(tab, nail)
+ end
+ end
+ end
+
+ return tab
+end
+
+function meta:GetLivingNails()
+ local tab = {}
+
+ if self.Nails then
+ for _, nail in pairs(self.Nails) do
+ if nail and nail:IsValid() and nail:GetNailHealth() > 0 then
+ table.insert(tab, nail)
+ end
+ end
+ end
+
+ return tab
+end
+
+function meta:GetFirstNail()
+ if self.Nails then
+ for i, nail in ipairs(self.Nails) do
+ if nail and nail:IsValid() and not nail:GetAttachEntity():IsValid() then return nail end
+ end
+ for i, nail in ipairs(self.Nails) do
+ if nail and nail:IsValid() then return nail end
+ end
+ end
+end
+
+local function GetNailOwner(nail, filter)
+ for _, ent in pairs(ents.GetAll()) do
+ if ent ~= filter and ent.Nails then
+ for __, n in pairs(ent.Nails) do
+ if n == nail then
+ return ent
+ end
+ end
+ end
+ end
+
+ return game.GetWorld()
+end
+
+function meta:RemoveNail(nail, dontremoveentity, removedby)
+ if not self:IsNailed() then return end
+
+ if not nail then
+ nail = self:GetFirstNail()
+ end
+
+ if not nail or not nail:IsValid() then return end
+
+ local cons = nail:GetNailConstraint()
+ local othernails = 0
+ for _, othernail in pairs(ents.FindByClass("prop_nail")) do
+ if othernail ~= nail and othernail:GetNailConstraint():IsValid() and othernail:GetNailConstraint() == cons then
+ othernails = othernails + 1
+ end
+ end
+
+ -- Only remove the constraint if it's the last nail.
+ if othernails == 0 and cons:IsValid() then
+ cons:Remove()
+ end
+
+ local ent2 = GetNailOwner(nail, self)
+
+ for i, n in ipairs(self.Nails) do
+ if n == nail then
+ table.remove(self.Nails, i)
+ break
+ end
+ end
+
+ if ent2 and ent2.Nails then
+ for i, n in ipairs(ent2.Nails) do
+ if n == nail then
+ table.remove(ent2.Nails, i)
+ ent2:TemporaryBarricadeObject()
+ break
+ end
+ end
+ end
+
+ self:TemporaryBarricadeObject()
+
+ gamemode.Call("OnNailRemoved", nail, self, ent2, removedby)
+
+ if not dontremoveentity then
+ nail:Remove()
+ nail.m_IsRemoving = true
+ end
+
+ return true
+end
diff --git a/gamemodes/zombiesurvival/gamemode/obj_player_extend.lua b/gamemodes/zombiesurvival/gamemode/obj_player_extend.lua
new file mode 100644
index 0000000..aeae9fa
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/obj_player_extend.lua
@@ -0,0 +1,866 @@
+local meta = FindMetaTable("Player")
+if not meta then return end
+
+meta.GetTeamID = meta.Team
+
+function meta:GetMaxHealthEx()
+ if self:Team() == TEAM_UNDEAD then
+ return self:GetMaxZombieHealth()
+ end
+
+ return self:GetMaxHealth()
+end
+
+function meta:Dismember(dismembermenttype)
+ local effectdata = EffectData()
+ effectdata:SetOrigin(self:EyePos())
+ effectdata:SetEntity(self)
+ effectdata:SetScale(dismembermenttype)
+ util.Effect("dismemberment", effectdata, true, true)
+end
+
+function meta:HasWon()
+ if self:Team() == TEAM_HUMAN and self:GetObserverMode() == OBS_MODE_ROAMING then
+ if SERVER then
+ local target = self:GetObserverTarget()
+ return target and target:IsValid() and target:GetClass() == "prop_obj_exit"
+ end
+
+ return true
+ end
+
+ return false
+end
+
+function meta:GetBossZombieIndex()
+ local bossclasses = {}
+ for _, classtable in pairs(GAMEMODE.ZombieClasses) do
+ if classtable.Boss then
+ table.insert(bossclasses, classtable.Index)
+ end
+ end
+
+ if #bossclasses == 0 then return -1 end
+
+ local desired = self:GetInfo("zs_bossclass") or ""
+ if GAMEMODE:IsBabyMode() then
+ desired = "Giga Gore Child"
+ elseif desired == "[RANDOM]" or desired == "" then
+ desired = "Nightmare"
+ end
+
+ local bossindex
+ for _, classindex in pairs(bossclasses) do
+ local classtable = GAMEMODE.ZombieClasses[classindex]
+ if string.lower(classtable.Name) == string.lower(desired) then
+ bossindex = classindex
+ break
+ end
+ end
+
+ return bossindex or bossclasses[math.random(#bossclasses)]
+end
+
+function meta:GetAuraRange()
+ local wep = self:GetActiveWeapon()
+ return wep:IsValid() and wep.GetAuraRange and wep:GetAuraRange() or 2048
+end
+
+function meta:GetCoupledHeadcrab()
+ local status = self.m_Couple
+ return status and status:IsValid() and status:GetPartner() or NULL
+end
+
+function meta:GetPoisonDamage()
+ return self.PoisonRecovery and self.PoisonRecovery:IsValid() and self.PoisonRecovery:GetDamage() or 0
+end
+
+function meta:GetBleedDamage()
+ return self.Bleed and self.Bleed:IsValid() and self.Bleed:GetDamage() or 0
+end
+
+function meta:CallWeaponFunction(funcname, ...)
+ local wep = self:GetActiveWeapon()
+ if wep:IsValid() and wep[funcname] then
+ return wep[funcname](wep, self, ...)
+ end
+end
+
+function meta:ClippedName()
+ local name = self:Name()
+ if #name > 16 then
+ name = string.sub(name, 1, 14)..".."
+ end
+
+ return name
+end
+
+function meta:DispatchAltUse()
+ local tr = self:TraceLine(64, MASK_SOLID, self:GetMeleeFilter())
+ local ent = tr.Entity
+ if ent and ent:IsValid() then
+ if ent.AltUse then
+ return ent:AltUse(self, tr)
+ end
+ end
+end
+
+function meta:MeleeViewPunch(damage)
+ local maxpunch = (damage + 25) * 0.5
+ local minpunch = -maxpunch
+ self:ViewPunch(Angle(math.Rand(minpunch, maxpunch), math.Rand(minpunch, maxpunch), math.Rand(minpunch, maxpunch)))
+end
+
+function meta:NearArsenalCrate()
+ local pos = self:EyePos()
+
+ for _, ent in pairs(ents.FindByClass("prop_arsenalcrate")) do
+ local nearest = ent:NearestPoint(pos)
+ if pos:Distance(nearest) <= 80 and (WorldVisible(pos, nearest) or self:TraceLine(80).Entity == ent) then
+ return true
+ end
+ end
+
+ return false
+end
+meta.IsNearArsenalCrate = meta.NearArsenalCrate
+
+function meta:NearestArsenalCrateOwnedByOther()
+ local pos = self:EyePos()
+
+ for _, ent in pairs(ents.FindByClass("prop_arsenalcrate")) do
+ local nearest = ent:NearestPoint(pos)
+ local owner = ent:GetObjectOwner()
+ if owner ~= self and owner:IsValid() and owner:IsPlayer() and owner:Team() == TEAM_HUMAN and pos:Distance(nearest) <= 80 and (WorldVisible(pos, nearest) or self:TraceLine(80).Entity == ent) then
+ return ent
+ end
+ end
+end
+
+function meta:SetZombieClassName(classname)
+ if GAMEMODE.ZombieClasses[classname] then
+ self:SetZombieClass(GAMEMODE.ZombieClasses[classname].Index)
+ end
+end
+
+function meta:AddLegDamage(damage)
+ self:SetLegDamage(self:GetLegDamage() + damage)
+end
+
+function meta:SetPoints(points)
+ self:SetDTInt(1, points)
+end
+
+function meta:GetPoints()
+ return self:GetDTInt(1)
+end
+
+function meta:SetPalsy(onoff, nosend)
+ self.m_Palsy = onoff
+ if SERVER and not nosend then
+ self:SendLua("LocalPlayer():SetPalsy("..tostring(onoff)..")")
+ end
+end
+
+function meta:GetPalsy()
+ return self.m_Palsy
+end
+
+function meta:SetHemophilia(onoff, nosend)
+ self.m_Hemophilia = onoff
+ if SERVER and not nosend then
+ self:SendLua("LocalPlayer():SetHemophilia("..tostring(onoff)..")")
+ end
+end
+
+function meta:GetHemophilia()
+ return self.m_Hemophilia
+end
+
+function meta:SetUnlucky(onoff)
+ self.m_Unlucky = onoff
+end
+
+function meta:GetUnlucky()
+ return self.m_Unlucky
+end
+
+function meta:SetLegDamage(damage)
+ self.LegDamage = CurTime() + math.min(GAMEMODE.MaxLegDamage, damage * 0.125)
+ if SERVER then
+ self:UpdateLegDamage()
+ end
+end
+
+function meta:RawSetLegDamage(time)
+ self.LegDamage = math.min(CurTime() + GAMEMODE.MaxLegDamage, time)
+ if SERVER then
+ self:UpdateLegDamage()
+ end
+end
+
+function meta:RawCapLegDamage(time)
+ self:RawSetLegDamage(math.max(self.LegDamage or 0, time))
+end
+
+function meta:GetLegDamage()
+ local base = self.LegDamage or 0
+ return math.max(0, base - CurTime())
+end
+
+function meta:ProcessDamage(dmginfo)
+ local attacker, inflictor = dmginfo:GetAttacker(), dmginfo:GetInflictor()
+
+ if self.DamageVulnerability then
+ dmginfo:SetDamage(dmginfo:GetDamage() * self.DamageVulnerability)
+ end
+
+ if self:Team() == TEAM_UNDEAD then
+ if self ~= attacker then
+ dmginfo:SetDamage(dmginfo:GetDamage() * GAMEMODE:GetZombieDamageScale(dmginfo:GetDamagePosition(), pl))
+ end
+
+ return self:CallZombieFunction("ProcessDamage", dmginfo)
+ elseif attacker:IsValid() and attacker:IsPlayer() and attacker:Team() == TEAM_UNDEAD and inflictor:IsValid() and inflictor == attacker:GetActiveWeapon() then
+ local damage = dmginfo:GetDamage()
+
+ local scale = inflictor.SlowDownScale or 1
+ if damage >= 40 or scale > 1 then
+ local dolegdamage = true
+ if inflictor.SlowDownImmunityTime then
+ if CurTime() < (self.SlowDownImmunityTime or 0) then
+ dolegdamage = false
+ else
+ self.SlowDownImmunityTime = CurTime() + inflictor.SlowDownImmunityTime
+ end
+ end
+ if dolegdamage then
+ self:RawCapLegDamage(self:GetLegDamage() + CurTime() + damage * 0.04 * (inflictor.SlowDownScale or 1))
+ end
+ end
+
+ if self:GetHemophilia() and damage >= 5 then
+ local dmgtype = dmginfo:GetDamageType()
+ if dmgtype == 0
+ or bit.band(dmgtype, DMG_SLASH) ~= 0
+ or bit.band(dmgtype, DMG_CLUB) ~= 0
+ or bit.band(dmgtype, DMG_BULLET) ~= 0
+ or bit.band(dmgtype, DMG_BUCKSHOT) ~= 0
+ or bit.band(dmgtype, DMG_CRUSH) ~= 0 then
+ local bleed = self:GiveStatus("bleed")
+ if bleed and bleed:IsValid() then
+ bleed:AddDamage(damage * 0.2)
+ if attacker:IsValid() and attacker:IsPlayer() then
+ bleed.Damager = attacker
+ end
+ end
+ end
+ end
+ end
+end
+
+function meta:KnockDown(time)
+ if self:Team() ~= TEAM_UNDEAD then
+ self:GiveStatus("knockdown", time or 3)
+ end
+end
+
+function meta:GetZombieClass()
+ return self.Class or GAMEMODE.DefaultZombieClass
+end
+
+local ZombieClasses = GM.ZombieClasses
+function meta:GetZombieClassTable()
+ return ZombieClasses[self:GetZombieClass()]
+end
+
+function meta:CallZombieFunction(funcname, ...)
+ if self:Team() == TEAM_UNDEAD then
+ local tab = self:GetZombieClassTable()
+ if tab[funcname] then
+ return tab[funcname](tab, self, ...)
+ end
+ end
+end
+
+function meta:TraceLine(distance, mask, filter, start)
+ start = start or self:GetShootPos()
+ return util.TraceLine({start = start, endpos = start + self:GetAimVector() * distance, filter = filter or self, mask = mask})
+end
+
+function meta:TraceHull(distance, mask, size, filter, start)
+ start = start or self:GetShootPos()
+ return util.TraceHull({start = start, endpos = start + self:GetAimVector() * distance, filter = filter or self, mask = mask, mins = Vector(-size, -size, -size), maxs = Vector(size, size, size)})
+end
+
+function meta:DoubleTrace(distance, mask, size, mask2, filter)
+ local tr1 = self:TraceLine(distance, mask, filter)
+ if tr1.Hit then return tr1 end
+ if mask2 then
+ local tr2 = self:TraceLine(distance, mask2, filter)
+ if tr2.Hit then return tr2 end
+ end
+
+ local tr3 = self:TraceHull(distance, mask, size, filter)
+ if tr3.Hit then return tr3 end
+ if mask2 then
+ local tr4 = self:TraceHull(distance, mask2, size, filter)
+ if tr4.Hit then return tr4 end
+ end
+
+ return tr1
+end
+
+function meta:SetSpeed(speed)
+ if not speed then speed = 200 end
+
+ self:SetWalkSpeed(speed)
+ self:SetRunSpeed(speed)
+ self:SetMaxSpeed(speed)
+end
+
+function meta:SetHumanSpeed(speed)
+ if self:Team() == TEAM_HUMAN then self:SetSpeed(speed) end
+end
+
+function meta:ResetSpeed(noset, health)
+ if not self:IsValid() then return end
+
+ if self:Team() == TEAM_UNDEAD then
+ local speed = self:GetZombieClassTable().Speed * GAMEMODE.ZombieSpeedMultiplier
+ self:SetSpeed(speed)
+ return speed
+ end
+
+ local wep = self:GetActiveWeapon()
+ local speed
+
+ if wep:IsValid() and wep.GetWalkSpeed then
+ speed = wep:GetWalkSpeed()
+ end
+
+ if not speed then
+ speed = wep.WalkSpeed or SPEED_NORMAL
+ end
+
+ if self.HumanSpeedAdder and self:Team() == TEAM_HUMAN and 32 < speed then
+ speed = speed + self.HumanSpeedAdder
+ end
+
+ --[[if self:IsHolding() then
+ local status = self.status_human_holding
+ if status and status:IsValid() and status:GetObject():IsValid() and status:GetObject():GetPhysicsObject():IsValid() then
+ speed = math.min(speed, math.max(CARRY_SPEEDLOSS_MINSPEED, speed - status:GetObject():GetPhysicsObject():GetMass() * CARRY_SPEEDLOSS_PERKG))
+ end
+ end]]
+
+ if 32 < speed and not GAMEMODE.ZombieEscape then
+ if not health then health = self:Health() end
+ if health < 60 then
+ speed = math.max(88, speed - speed * 0.4 * (1 - health / 60))
+ end
+ end
+
+ if not noset then
+ self:SetSpeed(speed)
+ end
+
+ return speed
+end
+
+function meta:ResetJumpPower(noset)
+ local power = DEFAULT_JUMP_POWER
+
+ if self:Team() == TEAM_UNDEAD then
+ power = self:CallZombieFunction("GetJumpPower") or power
+
+ local classtab = self:GetZombieClassTable()
+ if classtab and classtab.JumpPower then
+ power = classtab.JumpPower
+ end
+ else
+ if self:GetBarricadeGhosting() then
+ power = power * 0.25
+ if not noset then
+ self:SetJumpPower(power)
+ end
+
+ return power
+ end
+ end
+
+ local wep = self:GetActiveWeapon()
+ if wep and wep.ResetJumpPower then
+ power = wep:ResetJumpPower(power) or power
+ end
+
+ if not noset then
+ self:SetJumpPower(power)
+ end
+
+ return power
+end
+
+function meta:SetBarricadeGhosting(b)
+ if b and self.NoGhosting then return end
+
+ self:SetDTBool(0, b)
+ self:CollisionRulesChanged()
+
+ self:ResetJumpPower()
+end
+
+function meta:GetBarricadeGhosting()
+ return self:GetDTBool(0)
+end
+meta.IsBarricadeGhosting = meta.GetBarricadeGhosting
+
+function meta:ShouldBarricadeGhostWith(ent)
+ return ent:IsBarricadeProp()
+end
+
+function meta:BarricadeGhostingThink()
+ if self:KeyDown(IN_ZOOM) or self:ActiveBarricadeGhosting() then return end
+
+ self:SetBarricadeGhosting(false)
+end
+
+function meta:ShouldNotCollide(ent)
+ if ent:IsPlayer() then
+ return self:Team() == ent:Team() or self.NoCollideAll or ent.NoCollideAll
+ end
+
+ return self:GetBarricadeGhosting() and ent:IsBarricadeProp() or self:Team() == TEAM_HUMAN and ent:GetPhysicsObject():IsValid() and ent:GetPhysicsObject():HasGameFlag(FVPHYSICS_PLAYER_HELD)
+end
+
+local function nocollidetimer(self, timername)
+ if self:IsValid() then
+ for _, e in pairs(ents.FindInBox(self:WorldSpaceAABB())) do
+ if e:IsPlayer() and e ~= self and GAMEMODE:ShouldCollide(self, e) then
+ return
+ end
+ end
+
+ self:SetCollisionGroup(COLLISION_GROUP_PLAYER)
+ end
+
+ timer.Destroy(timername)
+end
+
+function meta:TemporaryNoCollide(force)
+ if self:GetCollisionGroup() ~= COLLISION_GROUP_PLAYER and not force then return end
+
+ for _, e in pairs(ents.FindInBox(self:WorldSpaceAABB())) do
+ if e:IsPlayer() and e ~= self and GAMEMODE:ShouldCollide(self, e) then
+ self:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
+
+ local timername = "TemporaryNoCollide"..self:UniqueID()
+ timer.CreateEx(timername, 0, 0, nocollidetimer, self, timername)
+
+ return
+ end
+ end
+
+ self:SetCollisionGroup(COLLISION_GROUP_PLAYER)
+end
+
+meta.OldSetHealth = FindMetaTable("Entity").SetHealth
+function meta:SetHealth(health)
+ self:OldSetHealth(health)
+ if self:Team() == TEAM_HUMAN and 1 <= health then
+ self:ResetSpeed(nil, health)
+ end
+end
+
+function meta:IsHeadcrab()
+ return self:Team() == TEAM_UNDEAD and GAMEMODE.ZombieClasses[self:GetZombieClass()].IsHeadcrab
+end
+
+function meta:AirBrake()
+ local vel = self:GetVelocity()
+
+ vel.x = vel.x * 0.15
+ vel.y = vel.y * 0.15
+ if vel.z > 0 then
+ vel.z = vel.z * 0.15
+ end
+
+ self:SetLocalVelocity(vel)
+end
+
+function meta:GetMeleeFilter()
+ return GAMEMODE.RoundEnded and {self} or team.GetPlayers(self:Team())
+end
+meta.GetTraceFilter = meta.GetMeleeFilter
+
+function meta:MeleeTrace(distance, size, filter, start)
+ return self:TraceHull(distance, MASK_SOLID, size, filter, start)
+end
+
+function meta:PenetratingMeleeTrace(distance, size, prehit, start)
+ start = start or self:GetShootPos()
+
+ local t = {}
+ local trace = {start = start, endpos = start + self:GetAimVector() * distance, filter = self:GetMeleeFilter(), mask = MASK_SOLID, mins = Vector(-size, -size, -size), maxs = Vector(size, size, size)}
+ local onlyhitworld
+ for i=1, 50 do
+ local tr = util.TraceHull(trace)
+
+ if not tr.Hit then break end
+
+ if tr.HitWorld then
+ table.insert(t, tr)
+ break
+ end
+
+ if onlyhitworld then break end
+
+ local ent = tr.Entity
+ if ent and ent:IsValid() then
+ if not ent:IsPlayer() then
+ trace.mask = MASK_SOLID_BRUSHONLY
+ onlyhitworld = true
+ end
+
+ table.insert(t, tr)
+ table.insert(trace.filter, ent)
+ end
+ end
+
+ if prehit and (#t == 1 and not t[1].HitNonWorld and prehit.HitNonWorld or #t == 0 and prehit.HitNonWorld) then
+ t[1] = prehit
+ end
+
+ return t
+end
+
+function meta:ActiveBarricadeGhosting(override)
+ if self:Team() ~= TEAM_HUMAN and not override or not self:GetBarricadeGhosting() then return false end
+
+ for _, ent in pairs(ents.FindInBox(self:WorldSpaceAABB())) do
+ if self:ShouldBarricadeGhostWith(ent) then return true end
+ end
+
+ return false
+end
+
+function meta:IsHolding()
+ return self:GetHolding():IsValid()
+end
+meta.IsCarrying = meta.IsHolding
+
+function meta:GetHolding()
+ local status = self.status_human_holding
+ if status and status:IsValid() then
+ local obj = status:GetObject()
+ if obj:IsValid() then return obj end
+ end
+
+ return NULL
+end
+
+function meta:GetMaxZombieHealth()
+ return self:GetZombieClassTable().Health
+end
+
+local oldmaxhealth = FindMetaTable("Entity").GetMaxHealth
+function meta:GetMaxHealth()
+ if self:Team() == TEAM_UNDEAD then
+ return self:GetMaxZombieHealth()
+ end
+
+ return oldmaxhealth(self)
+end
+
+if not meta.OldAlive then
+ meta.OldAlive = meta.Alive
+ function meta:Alive()
+ return self:GetObserverMode() == OBS_MODE_NONE and not self.NeverAlive and self:OldAlive()
+ end
+end
+
+local VoiceSets = {}
+
+VoiceSets["male"] = {
+ ["GiveAmmoSounds"] = {
+ Sound("vo/npc/male01/ammo03.wav"),
+ Sound("vo/npc/male01/ammo04.wav"),
+ Sound("vo/npc/male01/ammo05.wav")
+ },
+ ["PainSoundsLight"] = {
+ Sound("vo/npc/male01/ow01.wav"),
+ Sound("vo/npc/male01/ow02.wav"),
+ Sound("vo/npc/male01/pain01.wav"),
+ Sound("vo/npc/male01/pain02.wav"),
+ Sound("vo/npc/male01/pain03.wav")
+ },
+ ["PainSoundsMed"] = {
+ Sound("vo/npc/male01/pain04.wav"),
+ Sound("vo/npc/male01/pain05.wav"),
+ Sound("vo/npc/male01/pain06.wav")
+ },
+ ["PainSoundsHeavy"] = {
+ Sound("vo/npc/male01/pain07.wav"),
+ Sound("vo/npc/male01/pain08.wav"),
+ Sound("vo/npc/male01/pain09.wav")
+ },
+ ["DeathSounds"] = {
+ Sound("vo/npc/male01/no02.wav"),
+ Sound("ambient/voices/citizen_beaten1.wav"),
+ Sound("ambient/voices/citizen_beaten3.wav"),
+ Sound("ambient/voices/citizen_beaten4.wav"),
+ Sound("ambient/voices/citizen_beaten5.wav"),
+ Sound("vo/npc/male01/pain07.wav"),
+ Sound("vo/npc/male01/pain08.wav")
+ },
+ ["EyePoisonedSounds"] = {
+ Sound("ambient/voices/m_scream1.wav")
+ }
+}
+
+VoiceSets["barney"] = {
+ ["GiveAmmoSounds"] = {
+ Sound("items/ammo_pickup.wav")
+ },
+ ["PainSoundsLight"] = {
+ Sound("vo/npc/Barney/ba_pain02.wav"),
+ Sound("vo/npc/Barney/ba_pain07.wav"),
+ Sound("vo/npc/Barney/ba_pain04.wav")
+ },
+ ["PainSoundsMed"] = {
+ Sound("vo/npc/Barney/ba_pain01.wav"),
+ Sound("vo/npc/Barney/ba_pain08.wav"),
+ Sound("vo/npc/Barney/ba_pain10.wav")
+ },
+ ["PainSoundsHeavy"] = {
+ Sound("vo/npc/Barney/ba_pain05.wav"),
+ Sound("vo/npc/Barney/ba_pain06.wav"),
+ Sound("vo/npc/Barney/ba_pain09.wav")
+ },
+ ["DeathSounds"] = {
+ Sound("vo/npc/Barney/ba_ohshit03.wav"),
+ Sound("vo/npc/Barney/ba_no01.wav"),
+ Sound("vo/npc/Barney/ba_no02.wav"),
+ Sound("vo/npc/Barney/ba_pain03.wav")
+ },
+ ["EyePoisonedSounds"] = {
+ Sound("vo/k_lab/ba_thingaway02.wav")
+ }
+}
+
+VoiceSets["female"] = {
+ ["GiveAmmoSounds"] = {
+ Sound("vo/npc/female01/ammo03.wav"),
+ Sound("vo/npc/female01/ammo04.wav"),
+ Sound("vo/npc/female01/ammo05.wav")
+ },
+ ["PainSoundsLight"] = {
+ Sound("vo/npc/female01/pain01.wav"),
+ Sound("vo/npc/female01/pain02.wav"),
+ Sound("vo/npc/female01/pain03.wav")
+ },
+ ["PainSoundsMed"] = {
+ Sound("vo/npc/female01/pain04.wav"),
+ Sound("vo/npc/female01/pain05.wav"),
+ Sound("vo/npc/female01/pain06.wav")
+ },
+ ["PainSoundsHeavy"] = {
+ Sound("vo/npc/female01/pain07.wav"),
+ Sound("vo/npc/female01/pain08.wav"),
+ Sound("vo/npc/female01/pain09.wav")
+ },
+ ["DeathSounds"] = {
+ Sound("vo/npc/female01/no01.wav"),
+ Sound("vo/npc/female01/ow01.wav"),
+ Sound("vo/npc/female01/ow02.wav"),
+ Sound("vo/npc/female01/goodgod.wav"),
+ Sound("ambient/voices/citizen_beaten2.wav")
+ },
+ ["EyePoisonedSounds"] = {
+ Sound("ambient/voices/f_scream1.wav")
+ }
+}
+
+VoiceSets["alyx"] = {
+ ["GiveAmmoSounds"] = {
+ Sound("vo/npc/female01/ammo03.wav"),
+ Sound("vo/npc/female01/ammo04.wav"),
+ Sound("vo/npc/female01/ammo05.wav")
+ },
+ ["PainSoundsLight"] = {
+ Sound("vo/npc/Alyx/gasp03.wav"),
+ Sound("vo/npc/Alyx/hurt08.wav")
+ },
+ ["PainSoundsMed"] = {
+ Sound("vo/npc/Alyx/hurt04.wav"),
+ Sound("vo/npc/Alyx/hurt06.wav"),
+ Sound("vo/Citadel/al_struggle07.wav"),
+ Sound("vo/Citadel/al_struggle08.wav")
+ },
+ ["PainSoundsHeavy"] = {
+ Sound("vo/npc/Alyx/hurt05.wav"),
+ Sound("vo/npc/Alyx/hurt06.wav")
+ },
+ ["DeathSounds"] = {
+ Sound("vo/npc/Alyx/no01.wav"),
+ Sound("vo/npc/Alyx/no02.wav"),
+ Sound("vo/npc/Alyx/no03.wav"),
+ Sound("vo/Citadel/al_dadgordonno_c.wav"),
+ Sound("vo/Streetwar/Alyx_gate/al_no.wav")
+ },
+ ["EyePoisonedSounds"] = {
+ Sound("vo/npc/Alyx/uggh01.wav"),
+ Sound("vo/npc/Alyx/uggh02.wav")
+ }
+}
+
+VoiceSets["combine"] = {
+ ["GiveAmmoSounds"] = {
+ Sound("npc/combine_soldier/vo/hardenthatposition.wav"),
+ Sound("npc/combine_soldier/vo/readyweapons.wav"),
+ Sound("npc/combine_soldier/vo/weareinaninfestationzone.wav"),
+ Sound("npc/metropolice/vo/dismountinghardpoint.wav")
+ },
+ ["PainSoundsLight"] = {
+ Sound("npc/combine_soldier/pain1.wav"),
+ Sound("npc/combine_soldier/pain2.wav"),
+ Sound("npc/combine_soldier/pain3.wav")
+ },
+ ["PainSoundsMed"] = {
+ Sound("npc/metropolice/pain1.wav"),
+ Sound("npc/metropolice/pain2.wav")
+ },
+ ["PainSoundsHeavy"] = {
+ Sound("npc/metropolice/pain3.wav"),
+ Sound("npc/metropolice/pain4.wav")
+ },
+ ["DeathSounds"] = {
+ Sound("npc/combine_soldier/die1.wav"),
+ Sound("npc/combine_soldier/die2.wav"),
+ Sound("npc/combine_soldier/die3.wav")
+ },
+ ["EyePoisonSounds"] = {
+ Sound("npc/combine_soldier/die1.wav"),
+ Sound("npc/combine_soldier/die2.wav"),
+ Sound("npc/metropolice/vo/shit.wav")
+ }
+}
+
+VoiceSets["monk"] = {
+ ["GiveAmmoSounds"] = {
+ Sound("vo/ravenholm/monk_giveammo01.wav")
+ },
+ ["PainSoundsLight"] = {
+ Sound("vo/ravenholm/monk_pain01.wav"),
+ Sound("vo/ravenholm/monk_pain02.wav"),
+ Sound("vo/ravenholm/monk_pain03.wav"),
+ Sound("vo/ravenholm/monk_pain05.wav")
+ },
+ ["PainSoundsMed"] = {
+ Sound("vo/ravenholm/monk_pain04.wav"),
+ Sound("vo/ravenholm/monk_pain06.wav"),
+ Sound("vo/ravenholm/monk_pain07.wav"),
+ Sound("vo/ravenholm/monk_pain08.wav")
+ },
+ ["PainSoundsHeavy"] = {
+ Sound("vo/ravenholm/monk_pain09.wav"),
+ Sound("vo/ravenholm/monk_pain10.wav"),
+ Sound("vo/ravenholm/monk_pain12.wav")
+ },
+ ["DeathSounds"] = {
+ Sound("vo/ravenholm/monk_death07.wav")
+ },
+ ["EyePoisonSounds"] = {
+ Sound("vo/ravenholm/monk_death07.wav")
+ }
+}
+
+function meta:PlayEyePoisonedSound()
+ local snds = VoiceSets[self.VoiceSet].EyePoisonSounds
+ if snds then
+ self:EmitSound(snds[math.random(1, #snds)])
+ end
+end
+
+function meta:PlayGiveAmmoSound()
+ local snds = VoiceSets[self.VoiceSet].GiveAmmoSounds
+ if snds then
+ self:EmitSound(snds[math.random(1, #snds)])
+ end
+end
+
+function meta:PlayDeathSound()
+ local snds = VoiceSets[self.VoiceSet].DeathSounds
+ if snds then
+ self:EmitSound(snds[math.random(1, #snds)])
+ end
+end
+
+function meta:PlayZombieDeathSound()
+ if not self:CallZombieFunction("PlayDeathSound") then
+ local snds = self:GetZombieClassTable().DeathSounds
+ if snds then
+ self:EmitSound(snds[math.random(#snds)])
+ end
+ end
+end
+
+function meta:PlayPainSound()
+ if CurTime() < self.NextPainSound then return end
+
+ local snds
+
+ if self:Team() == TEAM_UNDEAD then
+ if self:CallZombieFunction("PlayPainSound") then return end
+ snds = self:GetZombieClassTable().PainSounds
+ else
+ local set = VoiceSets[self.VoiceSet]
+ if set then
+ local health = self:Health()
+ if 70 <= health then
+ snds = set.PainSoundsLight
+ elseif 35 <= health then
+ snds = set.PainSoundsMed
+ else
+ snds = set.PainSoundsHeavy
+ end
+ end
+ end
+
+ if snds then
+ local snd = snds[math.random(#snds)]
+ if snd then
+ self:EmitSound(snd)
+ self.NextPainSound = CurTime() + SoundDuration(snd) - 0.1
+ end
+ end
+end
+
+local ViewHullMins = Vector(-8, -8, -8)
+local ViewHullMaxs = Vector(8, 8, 8)
+function meta:GetThirdPersonCameraPos(origin, angles)
+ local allplayers = player.GetAll()
+ local tr = util.TraceHull({start = origin, endpos = origin + angles:Forward() * -math.max(36, self:Team() == TEAM_UNDEAD and self:GetZombieClassTable().CameraDistance or self:BoundingRadius()), mask = MASK_SHOT, filter = allplayers, mins = ViewHullMins, maxs = ViewHullMaxs})
+ return tr.HitPos + tr.HitNormal * 3
+end
+
+-- Override these because they're different in 1st person and on the server.
+function meta:SyncAngles()
+ local ang = self:EyeAngles()
+ ang.pitch = 0
+ ang.roll = 0
+ return ang
+end
+meta.GetAngles = meta.SyncAngles
+
+function meta:GetForward()
+ return self:SyncAngles():Forward()
+end
+
+function meta:GetUp()
+ return self:SyncAngles():Up()
+end
+
+function meta:GetRight()
+ return self:SyncAngles():Right()
+end
diff --git a/gamemodes/zombiesurvival/gamemode/obj_player_extend_cl.lua b/gamemodes/zombiesurvival/gamemode/obj_player_extend_cl.lua
new file mode 100644
index 0000000..544e27b
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/obj_player_extend_cl.lua
@@ -0,0 +1,209 @@
+local meta = FindMetaTable("Player")
+if not meta then return end
+
+function meta:FloatingScore(victim, effectname, frags, flags)
+ if MySelf == self then
+ gamemode.Call("FloatingScore", victim, effectname, frags, flags)
+ end
+end
+
+function meta:FixModelAngles(velocity)
+ local eye = self:EyeAngles()
+ self:SetLocalAngles(eye)
+ self:SetRenderAngles(eye)
+ self:SetPoseParameter("move_yaw", math.NormalizeAngle(velocity:Angle().yaw - eye.y))
+end
+
+function meta:RemoveAllStatus(bSilent, bInstant)
+end
+
+function meta:RemoveStatus(sType, bSilent, bInstant, sExclude)
+end
+
+function meta:GetStatus(sType)
+ local ent = self["status_"..sType]
+ if ent and ent.Owner == self then return ent end
+end
+
+function meta:GiveStatus(sType, fDie)
+end
+
+function meta:IsFriend()
+ return self.m_IsFriend
+end
+
+timer.Create("checkfriend", 5, 0, function()
+ -- This probably isn't the fastest function in the world so I cache it.
+ for _, pl in pairs(player.GetAll()) do
+ pl.m_IsFriend = pl:GetFriendStatus() == "friend"
+ end
+end)
+
+if not meta.SetGroundEntity then
+ function meta:SetGroundEntity(ent) end
+end
+
+if not meta.Kill then
+ function meta:Kill() end
+end
+
+if not meta.HasWeapon then
+ function meta:HasWeapon(class)
+ for _, wep in pairs(self:GetWeapons()) do
+ if wep:GetClass() == class then return true end
+ end
+
+ return false
+ end
+end
+
+function meta:SetMaxHealth(num)
+ self:SetDTInt(0, math.ceil(num))
+end
+
+meta.OldGetMaxHealth = FindMetaTable("Entity").GetMaxHealth
+function meta:GetMaxHealth()
+ return self:GetDTInt(0)
+end
+
+function meta:DoHulls(classid, teamid)
+ teamid = teamid or self:Team()
+ classid = classid or self:GetZombieClass()
+
+ if teamid == TEAM_UNDEAD then
+ self:SetIK(false)
+
+ local classtab = GAMEMODE.ZombieClasses[classid]
+ if classtab then
+ if classtab.ModelScale then
+ self:SetModelScale(classtab.ModelScale, 0)
+ elseif self:GetModelScale() ~= DEFAULT_MODELSCALE then
+ self:SetModelScale(DEFAULT_MODELSCALE, 0)
+ end
+
+ if not classtab.Hull or not classtab.HullDuck then
+ self:ResetHull()
+ end
+ if classtab.ViewOffset then
+ self:SetViewOffset(classtab.ViewOffset)
+ elseif self:GetViewOffset() ~= DEFAULT_VIEW_OFFSET then
+ self:SetViewOffset(DEFAULT_VIEW_OFFSET)
+ end
+ if classtab.ViewOffsetDucked then
+ self:SetViewOffsetDucked(classtab.ViewOffsetDucked)
+ elseif self:GetViewOffsetDucked() ~= DEFAULT_VIEW_OFFSET_DUCKED then
+ self:SetViewOffsetDucked(DEFAULT_VIEW_OFFSET_DUCKED)
+ end
+ if classtab.HullDuck then
+ self:SetHullDuck(classtab.HullDuck[1], classtab.HullDuck[2])
+ end
+ if classtab.Hull then
+ self:SetHull(classtab.Hull[1], classtab.Hull[2])
+ end
+ if classtab.StepSize then
+ self:SetStepSize(classtab.StepSize)
+ elseif self:GetStepSize() ~= DEFAULT_STEP_SIZE then
+ self:SetStepSize(DEFAULT_STEP_SIZE)
+ end
+ if classtab.JumpPower then
+ self:SetJumpPower(classtab.JumpPower)
+ elseif self:GetJumpPower() ~= DEFAULT_JUMP_POWER then
+ self:SetJumpPower(DEFAULT_JUMP_POWER)
+ end
+
+ if classtab.ClientsideModelScale then
+ self.ClientsideModelScale = Vector(1, 1, 1) * classtab.ClientsideModelScale
+ local m = Matrix()
+ m:Scale(self.ClientsideModelScale)
+ self:EnableMatrix("RenderMultiply", m)
+ end
+ self.NoCollideAll = classtab.NoCollideAll
+ self.AllowTeamDamage = classtab.AllowTeamDamage
+ self.NeverAlive = classtab.NeverAlive
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMass(classtab.Mass or DEFAULT_MASS)
+ end
+ end
+ else
+ self:SetIK(true)
+
+ self:SetModelScale(DEFAULT_MODELSCALE, 0)
+ self:ResetHull()
+ self:SetViewOffset(DEFAULT_VIEW_OFFSET)
+ self:SetViewOffsetDucked(DEFAULT_VIEW_OFFSET_DUCKED)
+ self:SetStepSize(DEFAULT_STEP_SIZE)
+ self:SetJumpPower(DEFAULT_JUMP_POWER)
+
+ if self.ClientsideModelScale then
+ self.ClientsideModelScale = nil
+ self:DisableMatrix("RenderMultiply")
+ end
+ self.NoCollideAll = nil
+ self.AllowTeamDamage = nil
+ self.NeverAlive = nil
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMass(DEFAULT_MASS)
+ end
+ end
+end
+
+function meta:GivePenalty(amount)
+ surface.PlaySound("ambient/alarms/klaxon1.wav")
+end
+
+function meta:SetZombieClass(cl)
+ self:CallZombieFunction("SwitchedAway")
+
+ local classtab = GAMEMODE.ZombieClasses[cl]
+ if classtab then
+ self.Class = classtab.Index or cl
+ self:CallZombieFunction("SwitchedTo")
+ end
+end
+
+net.Receive("zs_penalty", function(length)
+ local penalty = net.ReadUInt(16)
+
+ MySelf:GivePenalty(penalty)
+end)
+
+net.Receive("zs_dohulls", function(length)
+ local ent = net.ReadEntity()
+ local classid = net.ReadUInt(16)
+ local teamid = net.ReadUInt(16)
+
+ if ent:IsValid() then
+ ent:DoHulls(classid, teamid)
+ end
+end)
+
+net.Receive("zs_zclass", function(length)
+ local ent = net.ReadEntity()
+ local id = net.ReadUInt(8)
+
+ if ent:IsValid() and ent:IsPlayer() then
+ ent:SetZombieClass(id)
+ end
+end)
+
+net.Receive("zs_floatscore", function(length)
+ local victim = net.ReadEntity()
+ local effectname = net.ReadString()
+ local frags = net.ReadInt(24)
+ local flags = net.ReadUInt(8)
+
+ if victim and victim:IsValid() then
+ MySelf:FloatingScore(victim, effectname, frags, flags)
+ end
+end)
+
+net.Receive("zs_floatscore_vec", function(length)
+ local pos = net.ReadVector()
+ local effectname = net.ReadString()
+ local frags = net.ReadInt(24)
+ local flags = net.ReadUInt(8)
+
+ MySelf:FloatingScore(pos, effectname, frags, flags)
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/obj_player_extend_sv.lua b/gamemodes/zombiesurvival/gamemode/obj_player_extend_sv.lua
new file mode 100644
index 0000000..ad6d85f
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/obj_player_extend_sv.lua
@@ -0,0 +1,906 @@
+local meta = FindMetaTable("Player")
+if not meta then return end
+
+function meta:FakeDeath(sequenceid, modelscale, length)
+ for _, ent in pairs(ents.FindByClass("fakedeath")) do
+ if ent:GetOwner() == self then
+ ent:Remove()
+ end
+ end
+
+ local ent = ents.Create("fakedeath")
+ if ent:IsValid() then
+ ent:SetOwner(self)
+ ent:SetModel(self:GetModel())
+ ent:SetSkin(self:GetSkin())
+ ent:SetColor(self:GetColor())
+ ent:SetMaterial(self:GetMaterial())
+ ent:SetPos(self:GetPos() + Vector(0, 0, 64))
+ ent:Spawn()
+ ent:SetModelScale(modelscale or self:GetModelScale(), 0)
+
+ ent:SetDeathSequence(sequenceid or 0)
+ ent:SetDeathAngles(self:GetAngles())
+ ent:SetDeathSequenceLength(length or 1)
+
+ self:DeleteOnRemove(ent)
+ end
+
+ return ent
+end
+
+local MuscularBones = {
+ ["ValveBiped.Bip01_R_Upperarm"] = Vector(1, 2, 2),
+ ["ValveBiped.Bip01_R_Forearm"] = Vector(1, 2, 2),
+ ["ValveBiped.Bip01_L_Upperarm"] = Vector(1, 2, 2),
+ ["ValveBiped.Bip01_L_Forearm"] = Vector(1, 2, 2)
+}
+function meta:DoMuscularBones()
+ if self.BuffMuscular and self:Team() == TEAM_HUMAN then
+ self.MuscularBones = {}
+
+ for bonename, newscale in pairs(MuscularBones) do
+ local boneid = self:LookupBone(bonename)
+ if boneid and boneid > 0 then
+ table.insert(self.MuscularBones, boneid)
+ self:ManipulateBoneScale(boneid, newscale)
+ end
+ end
+ elseif self.MuscularBones then
+ for _, boneid in pairs(self.MuscularBones) do
+ self:ManipulateBoneScale(boneid, Vector(1, 1, 1))
+ end
+ self.MuscularBones = nil
+ end
+end
+
+local NoodleArmBones = {
+ ["ValveBiped.Bip01_R_Upperarm"] = Vector(1, 0.4, 0.4),
+ ["ValveBiped.Bip01_R_Forearm"] = Vector(1, 0.4, 0.4),
+ ["ValveBiped.Bip01_L_Upperarm"] = Vector(1, 0.4, 0.4),
+ ["ValveBiped.Bip01_L_Forearm"] = Vector(1, 0.4, 0.4)
+}
+function meta:DoNoodleArmBones()
+ if self.NoObjectPickup and self:Team() == TEAM_HUMAN then
+ self.NoodleArmBones = {}
+
+ for bonename, newscale in pairs(NoodleArmBones) do
+ local boneid = self:LookupBone(bonename)
+ if boneid and boneid > 0 then
+ table.insert(self.NoodleArmBones, boneid)
+ self:ManipulateBoneScale(boneid, newscale)
+ end
+ end
+ elseif self.NoodleArmBones then
+ for _, boneid in pairs(self.NoodleArmBones) do
+ self:ManipulateBoneScale(boneid, Vector(1, 1, 1))
+ end
+ self.NoodleArmBones = nil
+ end
+end
+
+function meta:ChangeTeam(teamid)
+ local oldteam = self:Team()
+ self:SetTeam(teamid)
+ if oldteam ~= teamid then
+ gamemode.Call("OnPlayerChangedTeam", self, oldteam, teamid)
+ end
+
+ self:CollisionRulesChanged()
+end
+
+function meta:TrySpawnAsGoreChild()
+ for _, ent in pairs(ents.FindByClass("prop_thrownbaby")) do
+ if not ent.SpawnedOn then
+ ent.SpawnedOn = true
+
+ local ang = self:EyeAngles()
+ ang.roll = 0
+ ang.pitch = 0
+
+ local deathclass = self.DeathClass
+ self:SetZombieClassName("Gore Child")
+ self.DeathClass = nil
+ self:UnSpectateAndSpawn()
+ self.DeathClass = deathclass
+ self:SetPos(ent:GetPos())
+ self:SetEyeAngles(ang)
+ self:StartFeignDeath(true)
+ if IsValid(self.FeignDeath) then
+ self.FeignDeath:SetState(1)
+ self.FeignDeath:SetDirection(math.random(2) == 1 and DIR_FORWARD or DIR_BACK)
+ end
+
+ ent:Remove()
+
+ break
+ end
+ end
+end
+
+function meta:AddLifeBarricadeDamage(amount)
+ self.LifeBarricadeDamage = self.LifeBarricadeDamage + amount
+
+ if not self:Alive() and not self:GetZombieClassTable().NeverAlive then
+ net.Start("zs_lifestatsbd")
+ net.WriteUInt(self.LifeBarricadeDamage, 24)
+ net.Send(self)
+ end
+end
+
+function meta:AddLifeHumanDamage(amount)
+ self.LifeHumanDamage = self.LifeHumanDamage + amount
+
+ if not self:Alive() then
+ net.Start("zs_lifestatshd")
+ net.WriteUInt(math.ceil(self.LifeHumanDamage), 24)
+ net.Send(self)
+ end
+end
+
+function meta:AddLifeBrainsEaten(amount)
+ self.LifeBrainsEaten = self.LifeBrainsEaten + amount
+
+ if not self:Alive() then
+ net.Start("zs_lifestatsbe")
+ net.WriteUInt(self.LifeBrainsEaten, 16)
+ net.Send(self)
+ end
+end
+
+function meta:FloatingScore(victimorpos, effectname, frags, flags)
+ if type(victimorpos) == "Vector" then
+ net.Start("zs_floatscore_vec")
+ net.WriteVector(victimorpos)
+ net.WriteString(effectname)
+ net.WriteInt(frags, 24)
+ net.WriteUInt(flags, 8)
+ net.Send(self)
+ else
+ net.Start("zs_floatscore")
+ net.WriteEntity(victimorpos)
+ net.WriteString(effectname)
+ net.WriteInt(frags, 24)
+ net.WriteUInt(flags, 8)
+ net.Send(self)
+ end
+end
+
+function meta:MarkAsBadProfile()
+ self.NoProfiling = true
+end
+
+function meta:CenterNotify(...)
+ net.Start("zs_centernotify")
+ net.WriteTable({...})
+ net.Send(self)
+end
+
+function meta:TopNotify(...)
+ net.Start("zs_topnotify")
+ net.WriteTable({...})
+ net.Send(self)
+end
+
+function meta:RefreshDynamicSpawnPoint()
+ local target = self:GetObserverTarget()
+ if (GAMEMODE:GetDynamicSpawning() and self:GetObserverMode() == OBS_MODE_CHASE and target and target:IsValid()) and
+ (self.ZombieEscape and target:IsPlayer() and target:Team() == TEAM_UNDEAD
+ or not self.ZombieEscape and target:GetClass() == "prop_creepernest" and target:GetNestBuilt()
+ or string.sub(target:GetClass(), 1, 12) == "info_player_") then
+ self.ForceDynamicSpawn = target
+ self.ForceSpawnAngles = self:EyeAngles()
+ else
+ self.ForceDynamicSpawn = nil
+ self.ForceSpawnAngles = nil
+ end
+end
+
+function meta:PushPackedItem(class, ...)
+ if self.PackedItems and ... ~= nil then
+ local packed = {...}
+
+ self.PackedItems[class] = self.PackedItems[class] or {}
+
+ table.insert(self.PackedItems[class], packed)
+ end
+end
+
+function meta:PopPackedItem(class)
+ if self.PackedItems and self.PackedItems[class] and self.PackedItems[class][1] ~= nil then
+ local index = #self.PackedItems[class]
+ local data = self.PackedItems[class][index]
+ table.remove(self.PackedItems[class], index)
+
+ return data
+ end
+end
+
+function meta:ChangeToCrow()
+ self.StartCrowing = nil
+
+ local crowclass = GAMEMODE.ZombieClasses["Crow"]
+ if not crowclass then return end
+
+ local curclass = self.DeathClass or self:GetZombieClass()
+ local crowindex = crowclass.Index
+ self:SetZombieClass(crowindex)
+ self:DoHulls(crowindex, TEAM_UNDEAD)
+
+ self.DeathClass = nil
+ self:UnSpectateAndSpawn()
+ self.DeathClass = curclass
+end
+
+function meta:SelectRandomPlayerModel()
+ self:SetModel(player_manager.TranslatePlayerModel(GAMEMODE.RandomPlayerModels[math.random(#GAMEMODE.RandomPlayerModels)]))
+end
+
+function meta:GiveEmptyWeapon(weptype)
+ if not self:HasWeapon(weptype) then
+ local wep = self:Give(weptype)
+ if wep:IsValid() and wep:IsWeapon() then
+ wep:EmptyAll()
+ end
+
+ return wep
+ end
+end
+
+-- Here for when garry makes weapons use 357 ammo like he does every other update.
+--[[local oldgive = meta.Give
+function meta:Give(...)
+ local wep = oldgive(self, ...)
+ if wep:IsValid() then
+ if wep.Primary and wep.Primary.Ammo and wep.Primary.Ammo ~= "none" then
+ self:RemoveAmmo(wep.Primary.DefaultClip - wep.Primary.ClipSize, "357")
+ wep:SetClip1(0)
+
+ if wep.Primary.DefaultClip > wep.Primary.ClipSize then
+ self:GiveAmmo(wep.Primary.DefaultClip, wep.Primary.Ammo, true)
+ end
+ wep:SetClip1(wep.Primary.ClipSize)
+ self:RemoveAmmo(wep.Primary.ClipSize, wep.Primary.Ammo)
+ end
+ if wep.Secondary and wep.Secondary.Ammo and wep.Secondary.Ammo ~= "none" then
+ self:RemoveAmmo(wep.Secondary.DefaultClip - wep.Secondary.ClipSize, "357")
+ wep:SetClip2(0)
+
+ if wep.Secondary.DefaultClip > wep.Secondary.ClipSize then
+ self:GiveAmmo(wep.Secondary.DefaultClip, wep.Secondary.Ammo, true)
+ end
+ wep:SetClip2(wep.Secondary.ClipSize)
+ self:RemoveAmmo(wep.Secondary.ClipSize, wep.Secondary.Ammo)
+ end
+ end
+ return wep
+end]]
+
+function meta:StartFeignDeath(force)
+ local feigndeath = self.FeignDeath
+ if feigndeath and feigndeath:IsValid() then
+ if CurTime() >= feigndeath:GetStateEndTime() then
+ feigndeath:SetState(1)
+ feigndeath:SetStateEndTime(CurTime() + 1.5)
+ end
+ elseif force or self:IsOnGround() and not self:IsPlayingTaunt() then
+ local wep = self:GetActiveWeapon()
+ if force or wep:IsValid() and not wep:IsSwinging() and CurTime() > wep:GetNextPrimaryFire() then
+ if wep:IsValid() and wep.StopMoaning then
+ wep:StopMoaning()
+ end
+
+ local status = self:GiveStatus("feigndeath")
+ if status and status:IsValid() then
+ status:SetStateEndTime(CurTime() + 1.5)
+ end
+ end
+ end
+end
+
+function meta:UpdateLegDamage()
+ net.Start("zs_legdamage")
+ net.WriteFloat(self.LegDamage)
+ net.Send(self)
+end
+
+function meta:SendHint()
+end
+
+local function RemoveSkyCade(groundent, timername)
+ if not groundent:IsValid() or not (groundent.IsBarricadeObject or groundent:IsNailedToWorldHierarchy()) then
+ timer.Destroy(timername)
+ return
+ end
+
+ for _, pl in pairs(player.GetAll()) do
+ if pl:Alive() and pl:GetGroundEntity() == groundent then
+ groundent:TakeDamage(3, groundent, groundent)
+ pl:ViewPunch(Angle(math.Rand(-25, 25), math.Rand(-25, 25), math.Rand(-25, 25)))
+ if math.random(9) == 1 then
+ groundent:EmitSound("npc/strider/creak"..math.random(4)..".wav", 65, math.random(95, 105))
+ end
+
+ return
+ end
+ end
+
+ timer.Destroy(timername)
+end
+local checkoffset = Vector(0, 0, -128)
+function meta:PreventSkyCade()
+ local groundent = self:GetGroundEntity()
+ if groundent:IsValid() then
+ if groundent:IsNailedToWorldHierarchy() then
+ local phys = groundent:GetPhysicsObject()
+ if phys:IsValid() and phys:GetMass() <= CARRY_DRAG_MASS then
+ local timername = "RemoveSkyCade"..tostring(groundent)
+ local start = groundent:WorldSpaceCenter()
+ if not timer.Exists(timername) and not util.TraceHull({start = start,
+ endpos = start + checkoffset,
+ mins = groundent:OBBMins() * 0.85, maxs = groundent:OBBMaxs() * 0.85,
+ mask = MASK_SOLID_BRUSHONLY}).Hit then
+ self:MarkAsBadProfile()
+ timer.Create(timername, 0.25, 0, function() RemoveSkyCade(groundent, timername) end) -- Oh dear.
+ end
+ end
+ elseif groundent.IsBarricadeObject then
+ local timername = "RemoveSkyCade"..tostring(groundent)
+ local start = groundent:WorldSpaceCenter()
+ if not timer.Exists(timername) and not util.TraceHull({start = start,
+ endpos = start + checkoffset,
+ mins = groundent:OBBMins() * 0.85, maxs = groundent:OBBMaxs() * 0.85,
+ mask = MASK_SOLID_BRUSHONLY}).Hit then
+ self:MarkAsBadProfile()
+ timer.Create(timername, 0.25, 0, function() RemoveSkyCade(groundent, timername) end) -- Oh dear.
+ end
+ end
+ end
+end
+
+function meta:CoupleWith(plheadcrab)
+ if self:GetZombieClassTable().Headcrab == plheadcrab:GetZombieClassTable().Name then
+ local status = self:GiveStatus("headcrabcouple")
+ if status:IsValid() then
+ status:SetCouple(plheadcrab)
+ end
+ end
+end
+
+function meta:FixModelAngles(velocity)
+ local eye = self:EyeAngles()
+ self:SetLocalAngles(eye)
+ self:SetPoseParameter("move_yaw", math.NormalizeAngle(velocity:Angle().yaw - eye.y))
+end
+
+function meta:RemoveAllStatus(bSilent, bInstant)
+ if bInstant then
+ for _, ent in pairs(ents.FindByClass("status_*")) do
+ if not ent.NoRemoveOnDeath and ent:GetOwner() == self then
+ ent:Remove()
+ end
+ end
+ else
+ for _, ent in pairs(ents.FindByClass("status_*")) do
+ if not ent.NoRemoveOnDeath and ent:GetOwner() == self then
+ ent.SilentRemove = bSilent
+ ent:SetDie()
+ end
+ end
+ end
+end
+
+function meta:RemoveStatus(sType, bSilent, bInstant, sExclude)
+ local removed
+
+ for _, ent in pairs(ents.FindByClass("status_"..sType)) do
+ if ent:GetOwner() == self and not (sExclude and ent:GetClass() == "status_"..sExclude) then
+ if bInstant then
+ ent:Remove()
+ else
+ ent.SilentRemove = bSilent
+ ent:SetDie()
+ end
+ removed = true
+ end
+ end
+
+ return removed
+end
+
+function meta:GetStatus(sType)
+ local ent = self["status_"..sType]
+ if ent and ent:IsValid() and ent.Owner == self then return ent end
+end
+
+function meta:GiveStatus(sType, fDie)
+ local cur = self:GetStatus(sType)
+ if cur then
+ if fDie then
+ cur:SetDie(fDie)
+ end
+ cur:SetPlayer(self, true)
+ return cur
+ else
+ local ent = ents.Create("status_"..sType)
+ if ent:IsValid() then
+ ent:Spawn()
+ if fDie then
+ ent:SetDie(fDie)
+ end
+ ent:SetPlayer(self)
+ return ent
+ end
+ end
+end
+
+function meta:UnSpectateAndSpawn()
+ self:UnSpectate()
+ self:Spawn()
+end
+
+function meta:SecondWind(pl)
+ if self.Gibbed or self:Alive() or self:Team() ~= TEAM_UNDEAD then return end
+
+ local pos = self:GetPos()
+ local angles = self:EyeAngles()
+ local lastattacker = self:GetLastAttacker()
+ local dclass = self.DeathClass
+ self.DeathClass = nil
+ self.Revived = true
+ self:UnSpectateAndSpawn()
+ self.Revived = nil
+ self.DeathClass = dclass
+ self:SetLastAttacker(lastattacker)
+ self:SetPos(pos)
+ self:SetHealth(self:Health() * 0.2)
+ self:SetEyeAngles(angles)
+
+ self:CallZombieFunction("OnSecondWind")
+end
+
+function meta:DropAll()
+ self:DropAllAmmo()
+ self:DropAllWeapons()
+end
+
+local function CreateRagdoll(pl)
+ if pl:IsValid() then pl:OldCreateRagdoll() end
+end
+local function SetModel(pl, mdl)
+ if pl:IsValid() then
+ pl:SetModel(mdl)
+ timer.Simple(0, function() CreateRagdoll(pl) end)
+ end
+end
+
+meta.OldCreateRagdoll = meta.CreateRagdoll
+function meta:CreateRagdoll()
+ local status = self.status_overridemodel
+ if status and status:IsValid() then
+ local mdl = status:GetModel()
+ timer.Simple(0, function() SetModel(self, mdl) end)
+ status:SetRenderMode(RENDERMODE_NONE)
+ else
+ self:OldCreateRagdoll()
+ end
+end
+
+function meta:DropWeaponByType(class)
+ if GAMEMODE.ZombieEscape then return end
+
+ local wep = self:GetWeapon(class)
+ if wep and wep:IsValid() and not wep.Undroppable then
+ local ent = ents.Create("prop_weapon")
+ if ent:IsValid() then
+ ent:SetWeaponType(class)
+ ent:Spawn()
+ ent:SetClip1(wep:Clip1())
+ ent:SetClip2(wep:Clip2())
+
+ self:StripWeapon(class)
+
+ return ent
+ end
+ end
+end
+
+function meta:DropAllWeapons()
+ local vPos = self:GetPos()
+ local vVel = self:GetVelocity()
+ local zmax = self:OBBMaxs().z * 0.75
+ for _, wep in pairs(self:GetWeapons()) do
+ local ent = self:DropWeaponByType(wep:GetClass())
+ if ent and ent:IsValid() then
+ ent:SetPos(vPos + Vector(math.Rand(-16, 16), math.Rand(-16, 16), math.Rand(2, zmax)))
+ ent:SetAngles(VectorRand():Angle())
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:AddAngleVelocity(Vector(math.Rand(-720, 720), math.Rand(-720, 720), math.Rand(-720, 720)))
+ phys:ApplyForceCenter(phys:GetMass() * (math.Rand(32, 328) * VectorRand():GetNormalized() + vVel))
+ end
+ end
+ end
+end
+
+function meta:DropAmmoByType(ammotype, amount)
+ if GAMEMODE.ZombieEscape then return end
+
+ local mycount = self:GetAmmoCount(ammotype)
+ amount = math.min(mycount, amount or mycount)
+ if not amount or amount <= 0 then return end
+
+ local ent = ents.Create("prop_ammo")
+ if ent:IsValid() then
+ ent:SetAmmoType(ammotype)
+ ent:SetAmmo(amount)
+ ent:Spawn()
+
+ self:RemoveAmmo(amount, ammotype)
+
+ return ent
+ end
+end
+
+function meta:DropAllAmmo()
+ local vPos = self:GetPos()
+ local vVel = self:GetVelocity()
+ local zmax = self:OBBMaxs().z * 0.75
+ for ammotype in pairs(GAMEMODE.AmmoCache) do
+ local ent = self:DropAmmoByType(ammotype)
+ if ent and ent:IsValid() then
+ ent:SetPos(vPos + Vector(math.Rand(-16, 16), math.Rand(-16, 16), math.Rand(2, zmax)))
+ ent:SetAngles(VectorRand():Angle())
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:AddAngleVelocity(Vector(math.Rand(-720, 720), math.Rand(-720, 720), math.Rand(-720, 720)))
+ phys:ApplyForceCenter(phys:GetMass() * (math.Rand(32, 328) * VectorRand():GetNormalized() + vVel))
+ end
+ end
+ end
+end
+
+-- Lets other players know about our maximum health.
+meta.OldSetMaxHealth = FindMetaTable("Entity").SetMaxHealth
+function meta:SetMaxHealth(num)
+ num = math.ceil(num)
+ self:SetDTInt(0, num)
+ self:OldSetMaxHealth(num)
+end
+
+function meta:PointCashOut(ent, fmtype)
+ if self.m_PointQueue >= 1 and self:Team() == TEAM_HUMAN then
+ local points = math.floor(self.m_PointQueue)
+ self.m_PointQueue = self.m_PointQueue - points
+
+ self:AddPoints(points)
+ self:FloatingScore(ent or self.m_LastDamageDealtPosition or vector_origin, "floatingscore", points, fmtype or FM_NONE)
+ end
+end
+
+function meta:AddPoints(points)
+ self:AddFrags(points)
+ self:SetPoints(self:GetPoints() + points)
+
+ gamemode.Call("PlayerPointsAdded", self, points)
+end
+
+function meta:TakePoints(points)
+ self:SetPoints(self:GetPoints() - points)
+end
+
+function meta:UpdateAllZombieClasses()
+ for _, pl in pairs(player.GetAll()) do
+ if pl ~= self and pl:Team() == TEAM_UNDEAD then
+ local id = pl:GetZombieClass()
+ if id and 0 < id then
+ net.Start("zs_zclass")
+ net.WriteEntity(pl)
+ net.WriteUInt(id, 8)
+ net.Send(self)
+ end
+ end
+ end
+end
+
+function meta:CreateAmbience(class)
+ class = "status_"..class
+
+ for _, ent in pairs(ents.FindByClass(class)) do
+ if ent:GetOwner() == self then return end
+ end
+
+ local ent = ents.Create(class)
+ if ent:IsValid() then
+ ent:SetPos(self:LocalToWorld(self:OBBCenter()))
+ self[class] = ent
+ ent:SetOwner(self)
+ ent:SetParent(self)
+ ent:Spawn()
+ end
+end
+
+function meta:SetZombieClass(cl, onlyupdate, filter)
+ if onlyupdate then
+ net.Start("zs_zclass")
+ net.WriteEntity(self)
+ net.WriteUInt(cl, 8)
+ if filter then
+ net.Send(filter)
+ else
+ net.Broadcast()
+ end
+
+ return
+ end
+
+ self:CallZombieFunction("SwitchedAway")
+
+ local classtab = GAMEMODE.ZombieClasses[cl]
+ if classtab then
+ self.Class = cl
+ if self:Team() == TEAM_UNDEAD then
+ self:DoHulls(cl)
+ end
+ self:CallZombieFunction("SwitchedTo")
+
+ net.Start("zs_zclass")
+ net.WriteEntity(self)
+ net.WriteUInt(cl, 8)
+ if filter then
+ net.Send(filter)
+ else
+ net.Broadcast()
+ end
+ end
+end
+
+function meta:DoHulls(classid, teamid)
+ teamid = teamid or self:Team()
+ classid = classid or self:GetZombieClass()
+
+ if teamid == TEAM_UNDEAD then
+ local classtab = GAMEMODE.ZombieClasses[classid]
+ if classtab then
+ if self:Alive() then
+ self:SetMoveType(classtab.MoveType or MOVETYPE_WALK)
+ end
+
+ if classtab.ModelScale then
+ self:SetModelScale(classtab.ModelScale, 0)
+ elseif self:GetModelScale() ~= DEFAULT_MODELSCALE then
+ self:SetModelScale(DEFAULT_MODELSCALE, 0)
+ end
+
+ if not classtab.Hull or not classtab.HullDuck then
+ self:ResetHull()
+ end
+ if classtab.ViewOffset then
+ self:SetViewOffset(classtab.ViewOffset)
+ elseif self:GetViewOffset() ~= DEFAULT_VIEW_OFFSET then
+ self:SetViewOffset(DEFAULT_VIEW_OFFSET)
+ end
+ if classtab.ViewOffsetDucked then
+ self:SetViewOffsetDucked(classtab.ViewOffsetDucked)
+ elseif self:GetViewOffsetDucked() ~= DEFAULT_VIEW_OFFSET_DUCKED then
+ self:SetViewOffsetDucked(DEFAULT_VIEW_OFFSET_DUCKED)
+ end
+ if classtab.HullDuck then
+ self:SetHullDuck(classtab.HullDuck[1], classtab.HullDuck[2])
+ end
+ if classtab.Hull then
+ self:SetHull(classtab.Hull[1], classtab.Hull[2])
+ end
+ if classtab.StepSize then
+ self:SetStepSize(classtab.StepSize)
+ elseif self:GetStepSize() ~= DEFAULT_STEP_SIZE then
+ self:SetStepSize(DEFAULT_STEP_SIZE)
+ end
+ if classtab.JumpPower then
+ self:SetJumpPower(classtab.JumpPower)
+ elseif self:GetJumpPower() ~= DEFAULT_JUMP_POWER then
+ self:SetJumpPower(DEFAULT_JUMP_POWER)
+ end
+
+ self:DrawShadow(not classtab.NoShadow)
+
+ self.NoCollideAll = classtab.NoCollideAll
+ self.AllowTeamDamage = classtab.AllowTeamDamage
+ self.NeverAlive = classtab.NeverAlive
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMass(classtab.Mass or DEFAULT_MASS)
+ end
+ end
+ else
+ self:SetModelScale(DEFAULT_MODELSCALE, 0)
+ self:ResetHull()
+ self:SetViewOffset(DEFAULT_VIEW_OFFSET)
+ self:SetViewOffsetDucked(DEFAULT_VIEW_OFFSET_DUCKED)
+ self:SetStepSize(DEFAULT_STEP_SIZE)
+ self:SetJumpPower(DEFAULT_JUMP_POWER)
+
+ self:DrawShadow(true)
+
+ self.NoCollideAll = nil
+ self.AllowTeamDamage = nil
+ self.NeverAlive = nil
+ local phys = self:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:SetMass(DEFAULT_MASS)
+ end
+ end
+
+ net.Start("zs_dohulls")
+ net.WriteEntity(self)
+ net.WriteUInt(classid, 16)
+ net.WriteUInt(teamid, 16)
+ net.Broadcast()
+
+ self:CollisionRulesChanged()
+end
+
+function meta:Redeem()
+ gamemode.Call("PlayerRedeemed", self)
+end
+
+function meta:RedeemNextFrame()
+ timer.Simple(0, function()
+ if IsValid(self) then
+ self:CheckRedeem(true)
+ end
+ end)
+end
+
+function meta:TakeBrains(amount)
+ self:AddFrags(-amount)
+ self.BrainsEaten = self.BrainsEaten - 1
+end
+
+function meta:AddBrains(amount)
+ self:AddFrags(amount)
+ self.BrainsEaten = self.BrainsEaten + 1
+ self:CheckRedeem()
+end
+
+function meta:CheckRedeem(instant)
+ if self:IsValid() and self:Team() == TEAM_UNDEAD and GAMEMODE:GetRedeemBrains() > 0 and GAMEMODE:GetRedeemBrains() <= self:Frags() and GAMEMODE:GetWave() ~= GAMEMODE:GetNumberOfWaves() and not self.NoRedeeming and not self:GetZombieClassTable().Boss then
+ if instant then
+ self:Redeem()
+ else
+ self:RedeemNextFrame()
+ end
+ end
+end
+
+function meta:AntiGrief(dmginfo, overridenostrict)
+ if GAMEMODE.GriefStrict and not overridenostrict then
+ dmginfo:SetDamage(0)
+ dmginfo:ScaleDamage(0)
+ return
+ end
+
+ dmginfo:SetDamage(dmginfo:GetDamage() * GAMEMODE.GriefForgiveness)
+
+ self:GivePenalty(math.ceil(dmginfo:GetDamage() * 0.5))
+ self:ReflectDamage(dmginfo:GetDamage())
+end
+
+function meta:GivePenalty(amount)
+ self.m_PenaltyCarry = (self.m_PenaltyCarry or 0) + amount * 0.1
+ local frags = math.floor(self.m_PenaltyCarry)
+ if frags > 0 then
+ self.m_PenaltyCarry = self.m_PenaltyCarry - frags
+ self:GivePointPenalty(frags)
+ end
+end
+
+function meta:GivePointPenalty(amount)
+ self:SetFrags(self:Frags() - amount)
+
+ net.Start("zs_penalty")
+ net.WriteUInt(amount, 16)
+ net.Send(self)
+end
+
+function meta:ReflectDamage(damage)
+ local frags = self:Frags()
+ if frags < GAMEMODE.GriefReflectThreshold then
+ self:TakeDamage(math.ceil(damage * frags * -0.05 * GAMEMODE.GriefDamageMultiplier))
+ end
+end
+
+function meta:GiveWeaponByType(weapon, plyr, ammo)
+ if ammo then
+ local wep = self:GetActiveWeapon()
+ if not wep or not wep:IsValid() or not wep.Primary then return end
+
+ local ammotype = wep:ValidPrimaryAmmo()
+ local ammocount = wep:GetPrimaryAmmoCount()
+ if ammotype and ammocount then
+ local desiredgive = math.min(ammocount, math.ceil((GAMEMODE.AmmoCache[ammotype] or wep.Primary.ClipSize) * 5))
+ if desiredgive >= 1 then
+ wep:TakeCombinedPrimaryAmmo(desiredgive)
+ plyr:GiveAmmo(desiredgive, ammotype)
+
+ self:PlayGiveAmmoSound()
+ self:RestartGesture(ACT_GMOD_GESTURE_ITEM_GIVE)
+ end
+ end
+ end
+
+ local wep = self:GetActiveWeapon()
+ if wep:IsValid() then
+ local primary = wep:ValidPrimaryAmmo()
+ if primary and 0 < wep:Clip1() then
+ self:GiveAmmo(wep:Clip1(), primary, true)
+ wep:SetClip1(0)
+ end
+ local secondary = wep:ValidSecondaryAmmo()
+ if secondary and 0 < wep:Clip2() then
+ self:GiveAmmo(wep:Clip2(), secondary, true)
+ wep:SetClip2(0)
+ end
+
+ self:StripWeapon(weapon:GetClass())
+
+ local wep2 = plyr:Give(weapon:GetClass())
+ if wep2 and wep2:IsValid() then
+ if wep2.Primary then
+ local primary = wep2:ValidPrimaryAmmo()
+ if primary then
+ wep2:SetClip1(0)
+ plyr:RemoveAmmo(math.max(0, wep2.Primary.DefaultClip - wep2.Primary.ClipSize), primary)
+ end
+ end
+ if wep2.Secondary then
+ local secondary = wep2:ValidSecondaryAmmo()
+ if secondary then
+ wep2:SetClip2(0)
+ plyr:RemoveAmmo(math.max(0, wep2.Secondary.DefaultClip - wep2.Secondary.ClipSize), secondary)
+ end
+ end
+ end
+ end
+end
+
+function meta:Gib()
+ local pos = self:WorldSpaceCenter()
+ local headoffset = self:LocalToWorld(self:OBBMaxs()).z - pos.z
+
+ local effectdata = EffectData()
+ effectdata:SetEntity(self)
+ effectdata:SetOrigin(pos)
+ util.Effect("gib_player", effectdata, true, true)
+
+ self.Gibbed = CurTime()
+
+ timer.Simple(0, function() GAMEMODE:CreateGibs(pos, pos2) end)
+end
+
+function meta:GetLastAttacker()
+ local ent = self.LastAttacker
+ if ent and ent:IsValid() and ent:Team() ~= self:Team() and CurTime() <= self.LastAttacked + 10 then
+ return ent
+ end
+ self:SetLastAttacker()
+end
+
+function meta:SetLastAttacker(ent)
+ if ent then
+ if ent ~= self then
+ self.LastAttacker = ent
+ self.LastAttacked = CurTime()
+ end
+ else
+ self.LastAttacker = nil
+ self.LastAttacked = nil
+ end
+end
+
+meta.OldUnSpectate = meta.UnSpectate
+function meta:UnSpectate()
+ if self:GetObserverMode() ~= OBS_MODE_NONE then
+ self:OldUnSpectate(obsm)
+ end
+end
diff --git a/gamemodes/zombiesurvival/gamemode/obj_vector_extend.lua b/gamemodes/zombiesurvival/gamemode/obj_vector_extend.lua
new file mode 100644
index 0000000..3d59cf1
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/obj_vector_extend.lua
@@ -0,0 +1,6 @@
+local meta = FindMetaTable("Vector")
+if not meta then return end
+
+function meta:DistanceZSkew(vec, skew)
+ return math.sqrt((self.x - vec.x) ^ 2 + (self.y - vec.y) ^ 2 + ((self.z - vec.z) * skew) ^ 2)
+end
diff --git a/gamemodes/zombiesurvival/gamemode/obj_weapon_extend.lua b/gamemodes/zombiesurvival/gamemode/obj_weapon_extend.lua
new file mode 100644
index 0000000..a976b6f
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/obj_weapon_extend.lua
@@ -0,0 +1,281 @@
+local meta = FindMetaTable("Weapon")
+if not meta then return end
+
+meta.GetNextPrimaryAttack = meta.GetNextPrimaryFire
+meta.GetNextSecondaryAttack = meta.GetNextSecondaryFire
+meta.SetNextPrimaryAttack = meta.SetNextPrimaryFire
+meta.SetNextSecondaryAttack = meta.SetNextSecondaryFire
+
+function meta:EmptyAll()
+ if self.Primary and string.lower(self.Primary.Ammo or "") ~= "none" then
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ if self:Clip1() >= 1 then
+ owner:GiveAmmo(self:Clip1(), self.Primary.Ammo, true)
+ end
+ owner:RemoveAmmo(self.Primary.DefaultClip, self.Primary.Ammo)
+ end
+ self:SetClip1(0)
+ end
+ if self.Secondary and string.lower(self.Secondary.Ammo or "") ~= "none" then
+ local owner = self:GetOwner()
+ if owner:IsValid() then
+ if self:Clip2() >= 1 then
+ owner:GiveAmmo(self:Clip2(), self.Secondary.Ammo, true)
+ end
+ owner:RemoveAmmo(self.Secondary.DefaultClip, self.Secondary.Ammo)
+ end
+ self:SetClip2(0)
+ end
+end
+
+function meta:ValidPrimaryAmmo()
+ local ammotype = self:GetPrimaryAmmoTypeString()
+ if ammotype and ammotype ~= "none" then
+ return ammotype
+ end
+end
+
+function meta:ValidSecondaryAmmo()
+ local ammotype = self:GetSecondaryAmmoTypeString()
+ if ammotype and ammotype ~= "none" then
+ return ammotype
+ end
+end
+
+function meta:SetNextReload(fTime)
+ self.m_NextReload = fTime
+end
+
+function meta:GetNextReload()
+ return self.m_NextReload or 0
+end
+
+function meta:GetPrimaryAmmoCount()
+ return self.Owner:GetAmmoCount(self.Primary.Ammo) + self:Clip1()
+end
+
+function meta:GetSecondaryAmmoCount()
+ return self.Owner:GetAmmoCount(self.Secondary.Ammo) + self:Clip2()
+end
+
+function meta:HideViewAndWorldModel()
+ self:HideViewModel()
+ self:HideWorldModel()
+end
+meta.HideWorldAndViewModel = meta.HideViewAndWorldModel
+
+if SERVER then
+ function meta:HideWorldModel()
+ self:DrawShadow(false)
+ end
+
+ function meta:HideViewModel()
+ end
+end
+
+function meta:TakeCombinedPrimaryAmmo(amount)
+ local ammotype = self.Primary.Ammo
+ local owner = self.Owner
+ local clip = self:Clip1()
+ local reserves = owner:GetAmmoCount(ammotype)
+
+ amount = math.min(reserves + clip, amount)
+
+ local fromreserves = math.min(reserves, amount)
+ if fromreserves > 0 then
+ amount = amount - fromreserves
+ self.Owner:RemoveAmmo(fromreserves, ammotype)
+ end
+
+ local fromclip = math.min(clip, amount)
+ if fromclip > 0 then
+ self:SetClip1(clip - fromclip)
+ end
+end
+
+function meta:TakeCombinedSecondaryAmmo(amount)
+ local ammotype = self.Secondary.Ammo
+ local owner = self.Owner
+ local clip = self:Clip2()
+ local reserves = owner:GetAmmoCount(ammotype)
+
+ amount = math.min(reserves + clip, amount)
+
+ local fromreserves = math.min(reserves, amount)
+ if fromreserves > 0 then
+ amount = amount - fromreserves
+ self.Owner:RemoveAmmo(fromreserves, ammotype)
+ end
+
+ local fromclip = math.min(clip, amount)
+ if fromclip > 0 then
+ self:SetClip2(clip - fromclip)
+ end
+end
+
+local TranslatedAmmo = {}
+TranslatedAmmo[-1] = "none"
+TranslatedAmmo[0] = "none"
+TranslatedAmmo[1] = "ar2"
+TranslatedAmmo[2] = "alyxgun"
+TranslatedAmmo[3] = "pistol"
+TranslatedAmmo[4] = "smg1"
+TranslatedAmmo[5] = "357"
+TranslatedAmmo[6] = "xbowbolt"
+TranslatedAmmo[7] = "buckshot"
+TranslatedAmmo[8] = "rpg_round"
+TranslatedAmmo[9] = "smg1_grenade"
+TranslatedAmmo[10] = "sniperround"
+TranslatedAmmo[11] = "sniperpenetratedround"
+TranslatedAmmo[12] = "grenade"
+TranslatedAmmo[13] = "thumper"
+TranslatedAmmo[14] = "gravity"
+TranslatedAmmo[14] = "battery"
+TranslatedAmmo[15] = "gaussenergy"
+TranslatedAmmo[16] = "combinecannon"
+TranslatedAmmo[17] = "airboatgun"
+TranslatedAmmo[18] = "striderminigun"
+TranslatedAmmo[19] = "helicoptergun"
+TranslatedAmmo[20] = "ar2altfire"
+TranslatedAmmo[21] = "slam"
+
+function meta:GetPrimaryAmmoTypeString()
+ if self.Primary and self.Primary.Ammo then return string.lower(self.Primary.Ammo) end
+ return TranslatedAmmo[self:GetPrimaryAmmoType()] or "none"
+end
+
+function meta:GetSecondaryAmmoTypeString()
+ if self.Secondary and self.Secondary.Ammo then return string.lower(self.Secondary.Ammo) end
+ return TranslatedAmmo[self:GetSecondaryAmmoType()] or "none"
+end
+
+if not CLIENT then return end
+
+function meta:DrawCrosshair()
+ if GetConVarNumber("crosshair") ~= 1 then return end
+
+ self:DrawCrosshairCross()
+ self:DrawCrosshairDot()
+end
+
+local ironsightscrosshair = CreateClientConVar("zs_ironsightscrosshair", "0", true, false):GetBool()
+cvars.AddChangeCallback("zs_ironsightscrosshair", function(cvar, oldvalue, newvalue)
+ ironsightscrosshair = tonumber(newvalue) == 1
+end)
+
+local CrossHairScale = 1
+local function DrawDot(x, y)
+ surface.SetDrawColor(GAMEMODE.CrosshairColor)
+ surface.DrawRect(x - 2, y - 2, 4, 4)
+ surface.SetDrawColor(0, 0, 0, 220)
+ surface.DrawOutlinedRect(x - 2, y - 2, 4, 4)
+end
+local matGrad = Material("VGUI/gradient-r")
+local function DrawLine(x, y, rot)
+ rot = 270 - rot
+ surface.SetMaterial(matGrad)
+ surface.SetDrawColor(0, 0, 0, 220)
+ surface.DrawTexturedRectRotated(x, y, 14, 4, rot)
+ surface.SetDrawColor(GAMEMODE.CrosshairColor)
+ surface.DrawTexturedRectRotated(x, y, 12, 2, rot)
+end
+local baserot = 0
+function meta:DrawCrosshairCross()
+ local x = ScrW() * 0.5
+ local y = ScrH() * 0.5
+
+ local ironsights = self.GetIronsights and self:GetIronsights()
+
+ local owner = self.Owner
+
+ local cone = self:GetCone()
+
+ if cone <= 0 or ironsights and not ironsightscrosshair then return end
+
+ cone = ScrH() / 76.8 * cone
+
+ CrossHairScale = math.Approach(CrossHairScale, cone, FrameTime() * math.max(5, math.abs(CrossHairScale - cone) * 0.02))
+
+ local midarea = 40 * CrossHairScale
+
+ local vel = LocalPlayer():GetVelocity()
+ local len = vel:Length()
+ if GAMEMODE.NoCrosshairRotate then
+ baserot = 0
+ else
+ baserot = math.NormalizeAngle(baserot + vel:GetNormalized():Dot(EyeAngles():Right()) * math.min(10, len / 200))
+ end
+
+ local ang = Angle(0, 0, baserot)
+ for i=0, 359, 360 / 4 do
+ ang.roll = baserot + i
+ local p = ang:Up() * midarea
+ DrawLine(math.Round(x + p.y), math.Round(y + p.z), ang.roll)
+ end
+ --[[local x = ScrW() * 0.5
+ local y = ScrH() * 0.5
+
+ local ironsights = self.GetIronsights and self:GetIronsights()
+
+ local owner = self.Owner
+
+ local cone = self:GetCone()
+
+ if cone <= 0 or ironsights and not ironsightscrosshair then return end
+
+ cone = ScrH() / 76.8 * cone
+
+ CrossHairScale = math.Approach(CrossHairScale, cone, FrameTime() * math.max(5, math.abs(CrossHairScale - cone) * 0.02))
+
+ local midarea = 40 * CrossHairScale
+
+ local vel = LocalPlayer():GetVelocity()
+ local len = vel:Length()
+ if GAMEMODE.NoCrosshairRotate then
+ baserot = 0
+ else
+ baserot = math.NormalizeAngle(baserot + vel:GetNormalized():Dot(EyeAngles():Right()) * math.min(10, len / 200))
+ end
+
+ local ang = Angle(0, 0, baserot)
+ for i=0, 359, 60 do
+ ang.roll = baserot + i
+ local p = ang:Up() * midarea
+ DrawDot(x + p.y, y + p.z)
+ end]]
+end
+
+function meta:DrawCrosshairDot()
+ local x = ScrW() * 0.5
+ local y = ScrH() * 0.5
+
+ surface.SetDrawColor(GAMEMODE.CrosshairColor2)
+ surface.DrawRect(x - 2, y - 2, 4, 4)
+ surface.SetDrawColor(0, 0, 0, 220)
+ surface.DrawOutlinedRect(x - 2, y - 2, 4, 4)
+end
+
+function meta:BaseDrawWeaponSelection(x, y, wide, tall, alpha)
+ --if killicon.Get(self:GetClass()) then
+ killicon.Draw(x + wide * 0.5, y + tall * 0.5, self:GetClass(), 255)
+ draw.SimpleTextBlur(self:GetPrintName(), "ZSHUDFontSmaller", x + wide * 0.5, y + tall * 0.25, COLOR_RED, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+ --[[else
+ draw.SimpleTextBlur(self:GetPrintName(), "ZSHUDFontSmaller", x + wide * 0.5, y + tall * 0.5, COLOR_RED, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
+ end]]
+end
+
+local function empty() end
+local function NULLViewModelPosition(self, pos, ang)
+ return pos + ang:Forward() * -256, ang
+end
+
+function meta:HideWorldModel()
+ self:DrawShadow(false)
+ self.DrawWorldModel = empty
+ self.DrawWorldModelTranslucent = empty
+end
+
+function meta:HideViewModel()
+ self.GetViewModelPosition = NULLViewModelPosition
+end
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/cf_haunted_b1.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/cf_haunted_b1.lua
new file mode 100644
index 0000000..51e9a99
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/cf_haunted_b1.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_undead",["Angles"]=Angle(0,179.49533081055,0),["Position"]=Vector(266.41079711914,1808.4088134766,51.171226501465)},{["Class"]="info_player_undead",["Angles"]=Angle(0,179.49533081055,0),["Position"]=Vector(176.85536193848,1809.1976318359,55.758682250977)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-2.1264553070068,0),["Position"]=Vector(-442.92947387695,1961.4650878906,58.328895568848)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-2.383855342865,0),["Position"]=Vector(-363.82998657227,2049.5141601563,58.098937988281)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-89.899879455566,0),["Position"]=Vector(-183.89532470703,1744.5864257813,88.74552154541)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-89.899879455566,-0),["Position"]=Vector(-82.104614257813,1624.8708496094,77.983413696289)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-89.899879455566,0),["Position"]=Vector(-35.548007965088,1466.8937988281,73.210037231445)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-108.69007110596,0),["Position"]=Vector(335.46643066406,1373.1656494141,87.609802246094)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-98.136657714844,0),["Position"]=Vector(302.09771728516,1575.5617675781,79.011108398438)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-98.136657714844,0),["Position"]=Vector(163.04374694824,1595.4422607422,36.982944488525)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-98.136657714844,0),["Position"]=Vector(128.56034851074,1485.6021728516,32.898445129395)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-98.136657714844,0),["Position"]=Vector(-87.829788208008,1352.1727294922,56.76880645752)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-98.136657714844,0),["Position"]=Vector(-269.41857910156,1318.7548828125,46.51921081543)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-98.136657714844,0),["Position"]=Vector(-504.6916809082,1352.2924804688,27.478816986084)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-74.970680236816,0),["Position"]=Vector(-425.25436401367,1658.01171875,51.866355895996)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-58.497055053711,0),["Position"]=Vector(21.228433609009,1941.3823242188,54.535346984863)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-159.39782714844,0),["Position"]=Vector(359.36804199219,2012.3250732422,71.447235107422)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.897148132324,0),["Position"]=Vector(-141.68391418457,-1672.2603759766,56.345706939697)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.897148132324,0),["Position"]=Vector(68.758293151855,-1668.9658203125,55.484016418457)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.897148132324,0),["Position"]=Vector(225.95999145508,-1488.0554199219,53.996948242188)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.897148132324,-0),["Position"]=Vector(223.23797607422,-1314.23046875,42.856792449951)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.897148132324,0),["Position"]=Vector(402.65173339844,-1262.0650634766,51.614189147949)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.897148132324,0),["Position"]=Vector(646.63671875,-1258.2454833984,55.170845031738)},{["Class"]="info_player_human",["Angles"]=Angle(0,133.8830871582,0),["Position"]=Vector(555.33020019531,-987.140625,52.470512390137)},{["Class"]="info_player_human",["Angles"]=Angle(0,168.88955688477,-0),["Position"]=Vector(304.16268920898,-988.36181640625,51.931510925293)},{["Class"]="info_player_human",["Angles"]=Angle(0,37.872932434082,0),["Position"]=Vector(-296.48571777344,-978.54376220703,52.831733703613)},{["Class"]="info_player_human",["Angles"]=Angle(0,20.627170562744,0),["Position"]=Vector(-533.34851074219,-1066.3448486328,53.022979736328)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,0),["Position"]=Vector(-519.32476806641,-1414.9749755859,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,0),["Position"]=Vector(-499.51904296875,-1551.8760986328,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,0),["Position"]=Vector(-487.93884277344,-1626.4073486328,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,0),["Position"]=Vector(-479.25369262695,-1682.3057861328,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,0),["Position"]=Vector(-467.67349243164,-1756.8370361328,47.473609924316)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,0),["Position"]=Vector(-250.87071228027,-1751.4948730469,42.453422546387)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,-0),["Position"]=Vector(-267.73071289063,-1642.5115966797,50.876045227051)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,-0),["Position"]=Vector(-282.3860168457,-1548.1884765625,49.060241699219)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,-0),["Position"]=Vector(-298.01834106445,-1447.5771484375,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,53.831783294678,-0),["Position"]=Vector(-335.14511108398,-1208.6252441406,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,87.551200866699,0),["Position"]=Vector(103.35376739502,-1327.6031494141,35.686904907227)},{["Class"]="info_player_human",["Angles"]=Angle(0,87.551200866699,-0),["Position"]=Vector(-51.61999130249,-1320.9774169922,43.746704101563)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,0),["Position"]=Vector(329.98086547852,-2047.7274169922,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,-0),["Position"]=Vector(200.68173217773,-2048.0102539063,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,-0),["Position"]=Vector(86.136573791504,-2048.2607421875,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,-0),["Position"]=Vector(-15.681373596191,-2048.4833984375,48.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,-0),["Position"]=Vector(-149.31742858887,-2048.7756347656,51.240425109863)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,-0),["Position"]=Vector(-257.49893188477,-2049.0122070313,56.248825073242)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,-0),["Position"]=Vector(-384.77127075195,-2049.2905273438,55.402984619141)},{["Class"]="info_player_human",["Angles"]=Angle(0,90.12523651123,-0),["Position"]=Vector(-492.95275878906,-2049.5270996094,50.394584655762)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/cs_asylum.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/cs_asylum.lua
new file mode 100644
index 0000000..595d4de
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/cs_asylum.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,-83.381393432617,0),["Position"]=Vector(112.02564239502,2807.404296875,168.62425231934)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-42.929847717285,0),["Position"]=Vector(109.43133544922,2891.0932617188,168.62425231934)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-133.70729064941,0),["Position"]=Vector(175.36471557617,2844.7416992188,168.62425231934)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-150.98901367188,0),["Position"]=Vector(1276.9521484375,4377.2724609375,80.530494689941)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-148.50680541992,0),["Position"]=Vector(1412.6801757813,4107.9345703125,66.83324432373)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-121.52670288086,0),["Position"]=Vector(1034.4516601563,4146.2670898438,71.469200134277)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,12.80868434906,0),["Position"]=Vector(-1095.8961181641,627.0419921875,119.95462036133)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-5.7192797660828,0),["Position"]=Vector(-1119.4061279297,320.47164916992,119.95462036133)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,167.4070892334,0),["Position"]=Vector(1503.6135253906,2565.6081542969,800.57312011719)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,7.8192625045776,0),["Position"]=Vector(-437.70123291016,2240.1025390625,782.89862060547)},{["Class"]="zombiegasses",["Angles"]=Angle(0,-81.339965820313,0),["Position"]=Vector(1653.8688964844,4068.0336914063,1460.9046630859)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(104.25633239746,2919.228515625,168.62425231934)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/cs_island_b1.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/cs_island_b1.lua
new file mode 100644
index 0000000..7d537e3
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/cs_island_b1.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,179.67698669434,0),["Position"]=Vector(11439.862304688,7236.8374023438,787.64031982422)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-151.63998413086,0),["Position"]=Vector(11123.712890625,8456.0205078125,820.75347900391)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-139.69512939453,0),["Position"]=Vector(11063.388671875,8968.515625,820.75347900391)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-135.74557495117,0),["Position"]=Vector(10693.963867188,9267.810546875,846.62756347656)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-66.882308959961,0),["Position"]=Vector(8010.0678710938,9751.345703125,783.88812255859)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-75.114883422852,0),["Position"]=Vector(7729.8520507813,9667.6279296875,783.88812255859)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(8075.96875,9119.9453125,593.93505859375)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,165.99678039551,0),["Position"]=Vector(11512.452148438,7069.8232421875,775.33441162109)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,167.92729187012,0),["Position"]=Vector(11553.229492188,7260.5068359375,775.33441162109)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-160.15521240234,0),["Position"]=Vector(11571.541015625,7444.9951171875,775.33441162109)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,175.64920043945,0),["Position"]=Vector(11719.271484375,7231.958984375,783.89624023438)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-153.97760009766,0),["Position"]=Vector(11515.96484375,7627.0458984375,763.86627197266)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,103.83489990234,0),["Position"]=Vector(9933.376953125,6025.79296875,786.66217041016)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,108.46813201904,0),["Position"]=Vector(9639.2509765625,5761.7021484375,777.43023681641)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,42.831302642822,0),["Position"]=Vector(6663.3125,8183.0952148438,906.25939941406)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-61.15832901001,0),["Position"]=Vector(6628.1450195313,8504.6748046875,909.32098388672)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-98.381126403809,0),["Position"]=Vector(9611.9189453125,9774.970703125,770.71838378906)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-98.381126403809,0),["Position"]=Vector(9478.3603515625,9794.640625,770.71838378906)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-98.381126403809,0),["Position"]=Vector(9329.9619140625,9816.49609375,770.71838378906)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-60.028499603271,0),["Position"]=Vector(9162.9248046875,9761.1552734375,767.49011230469)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/cs_sprint_trading.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/cs_sprint_trading.lua
new file mode 100644
index 0000000..20b1c45
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/cs_sprint_trading.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,1.7892336845398,0),["Position"]=Vector(6.3562378883362,1634.5676269531,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,1.7892336845398,0),["Position"]=Vector(164.49366760254,1580.0205078125,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,1.7892336845398,0),["Position"]=Vector(344.79959106445,1557.2377929688,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,1.7892336845398,0),["Position"]=Vector(595.13873291016,1564.8397216797,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,1.7892336845398,0),["Position"]=Vector(776.95825195313,1532.7711181641,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-81.865791320801,0),["Position"]=Vector(962.28619384766,1258.3853759766,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-81.865791320801,0),["Position"]=Vector(968.45343017578,1096.9393310547,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-81.865791320801,0),["Position"]=Vector(984.12493896484,986.73461914063,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-95.765403747559,0),["Position"]=Vector(1002.295715332,447.42028808594,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.90573120117,-0),["Position"]=Vector(1011.1494140625,82.219505310059,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.90573120117,-0),["Position"]=Vector(1013.6997070313,-51.331890106201,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.90573120117,-0),["Position"]=Vector(1016.25,-184.88325500488,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,126.52542114258,0),["Position"]=Vector(1030.3385009766,-432.00476074219,56.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,93.835731506348,0),["Position"]=Vector(-134.27395629883,-759.40460205078,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,94.224914550781,0),["Position"]=Vector(-213.36650085449,-639.33612060547,64.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/cs_urban_v2.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/cs_urban_v2.lua
new file mode 100644
index 0000000..5f44bf7
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/cs_urban_v2.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_undead",["Angles"]=Angle(0,-26.911340713501,0),["Position"]=Vector(-834.61260986328,702.19067382813,-559.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-26.911340713501,0),["Position"]=Vector(-842.49523925781,638.87084960938,-559.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-26.911340713501,0),["Position"]=Vector(-735.96246337891,746.56750488281,-551.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.83637046813965,0),["Position"]=Vector(-1206.0075683594,463.45358276367,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,0),["Position"]=Vector(-1205.8140869141,293.24908447266,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,0),["Position"]=Vector(-1205.7354736328,224.24908447266,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,0),["Position"]=Vector(-1205.6397705078,140.24908447266,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,0),["Position"]=Vector(-1035.7039794922,114.45239257813,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,-0),["Position"]=Vector(-1035.8427734375,236.65682983398,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,-0),["Position"]=Vector(-1035.9487304688,329.65682983398,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,-0),["Position"]=Vector(-1036.0444335938,413.65682983398,-196.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.064170457422733,-0),["Position"]=Vector(-1036.1401367188,497.65682983398,-196.96875)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/rd_zombocity_f.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/rd_zombocity_f.lua
new file mode 100644
index 0000000..fd31eca
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/rd_zombocity_f.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_undead",["Angles"]=Angle(0,-89.821304321289,0),["Position"]=Vector(969.45697021484,-376.62551879883,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-89.821304321289,0),["Position"]=Vector(870.00250244141,-376.93594360352,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-89.821304321289,0),["Position"]=Vector(870.68139648438,-594.94897460938,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-89.821304321289,0),["Position"]=Vector(976.14038085938,-596.06182861328,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-179.91157531738,0),["Position"]=Vector(811.67309570313,-71.39306640625,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-179.91157531738,0),["Position"]=Vector(704.58215332031,-38.537967681885,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,91.285461425781,0),["Position"]=Vector(562.36273193359,41.106063842773,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,91.285461425781,0),["Position"]=Vector(624.10540771484,226.02728271484,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,91.285461425781,0),["Position"]=Vector(560.87115478516,344.66305541992,2)},{["Class"]="info_player_undead",["Angles"]=Angle(0,91.285461425781,0),["Position"]=Vector(652.01159667969,422.61703491211,2)},{["Class"]="zombiegasses",["Angles"]=Angle(0,-89.047828674316,0),["Position"]=Vector(599.80163574219,376.7414855957,64.03125)},{["Class"]="zombiegasses",["Angles"]=Angle(0,-151.33853149414,0),["Position"]=Vector(831.65734863281,-45.869968414307,64.03125)},{["Class"]="zombiegasses",["Angles"]=Angle(0,-90.592094421387,0),["Position"]=Vector(923.57495117188,-599.26953125,64.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_airport_panic_beta1.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_airport_panic_beta1.lua
new file mode 100644
index 0000000..47cf83c
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_airport_panic_beta1.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-5177.3920898438,881.87573242188,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-5008.5498046875,882.27380371094,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-4947.1875,882.41845703125,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-4814.6264648438,882.73425292969,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-4806.4038085938,723.31970214844,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-4995.7001953125,722.87341308594,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-5073.42578125,722.69018554688,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.864891052246,0),["Position"]=Vector(-5186.1079101563,722.42449951172,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2501.1276855469,-4177.1557617188,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2501.2978515625,-4041.0400390625,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2501.3901367188,-3967.4052734375,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2501.5209960938,-3862.9047851563,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2338.8469238281,-3832.9125976563,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2338.6921386719,-3956.7556152344,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2338.6101074219,-4022.2087402344,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,0.070129007101059,0),["Position"]=Vector(-2338.4177246094,-4175.7993164063,300.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,3.466961145401,0),["Position"]=Vector(295.60876464844,2517.2038574219,64.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-88.939659118652,0),["Position"]=Vector(418.4680480957,2642.9868164063,64.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.969177246094,0),["Position"]=Vector(399.61096191406,2737.3371582031,64.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-95.529174804688,0),["Position"]=Vector(142.32482910156,2707.4641113281,64.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-95.529174804688,0),["Position"]=Vector(126.27494812012,2600.9431152344,64.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-95.529174804688,0),["Position"]=Vector(23.337768554688,2511.5346679688,64.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-86.984092712402,0),["Position"]=Vector(0.8810875415802,1615.1925048828,348.6696472168)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,90.776710510254,0),["Position"]=Vector(-0.97451484203339,-587.27484130859,338.22326660156)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.558349609375,0),["Position"]=Vector(-2526.5407714844,3066.7595214844,49.67798614502)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.558349609375,0),["Position"]=Vector(-2369.9714355469,3067.9650878906,49.773193359375)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.558349609375,0),["Position"]=Vector(-2272.3166503906,2951.3112792969,48.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.558349609375,0),["Position"]=Vector(-2421.1579589844,2893.0270996094,48.03125)},{["Class"]="info_player_terrorist",["Angles"]=Angle(0,-89.558349609375,0),["Position"]=Vector(-2621.8522949219,2897.1752929688,48.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_airport_panic_bobpoblo2.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_airport_panic_bobpoblo2.lua
new file mode 100644
index 0000000..8baba63
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_airport_panic_bobpoblo2.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,94.208526611328,0),["Position"]=Vector(0.70359867811203,-563.35388183594,291.58831787109)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-82.008033752441,0),["Position"]=Vector(0.94603204727173,1619.2587890625,294.5888671875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-25.838996887207,0),["Position"]=Vector(-2752.4768066406,-1340.2722167969,65.909980773926)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-39.210514068604,0),["Position"]=Vector(-2650.9807128906,-1311.9095458984,46.83390045166)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-39.210514068604,0),["Position"]=Vector(-2606.6291503906,-1348.0960693359,28.848808288574)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-39.210514068604,0),["Position"]=Vector(-2594.6633300781,-1435.2951660156,8.6155624389648)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-90.046928405762,0),["Position"]=Vector(-2578.14453125,-1553.7076416016,45.451591491699)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-34.938396453857,0),["Position"]=Vector(-2731.8713378906,-1174.8201904297,85.265144348145)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-48.323066711426,0),["Position"]=Vector(2.1428146362305,1502.4555664063,380.42538452148)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-76.775764465332,0),["Position"]=Vector(116.96301269531,1467.6391601563,378.39559936523)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-44.19310760498,0),["Position"]=Vector(-128.31594848633,1460.2230224609,372.91348266602)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,84.804176330566,0),["Position"]=Vector(-103.82947540283,-434.30938720703,358.95153808594)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,141.45643615723,0),["Position"]=Vector(121.70021057129,-451.2063293457,340.25900268555)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.309272766113,0),["Position"]=Vector(-2532.5078125,-1036.2810058594,326.05996704102)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-65.002670288086,0),["Position"]=Vector(-2828.994140625,-1086.7244873047,310.60717773438)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-85.342903137207,0),["Position"]=Vector(-2664.099609375,-1105.0885009766,308.28125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_countrytrain_b4.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_countrytrain_b4.lua
new file mode 100644
index 0000000..805f8dd
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_countrytrain_b4.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2283.3566894531,-356.65811157227,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2301.0249023438,-109.78955841064,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2310.1267089844,17.385183334351,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2321.3701171875,174.4833984375,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2331.0073242188,309.13897705078,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2341.1799316406,451.27542114258,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2351.8879394531,600.89300537109,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2362.060546875,743.03002929688,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2370.0915527344,855.24346923828,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2378.1225585938,967.45690917969,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2121.9406738281,876.75396728516,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2142.9118652344,660.26818847656,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2160.9904785156,473.64236450195,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2177.6228027344,301.94604492188,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2193.5319824219,137.71479797363,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2210.8874511719,-41.446578979492,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2226.0734863281,-198.21276855469,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1866.1898193359,-406.07916259766,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1941.2454833984,-162.37565612793,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1907.9040527344,603.64263916016,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1913.3283691406,948.60052490234,-39.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1559.1120605469,927.50061035156,-39.968780517578)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1549.2573242188,635.16723632813,-39.968780517578)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1541.6767578125,410.29541015625,-39.968780517578)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1511.1018066406,-496.68859863281,-39.968780517578)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1694.2387695313,-291.76129150391,-39.968780517578)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1249.1533203125,243.01565551758,-39.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-733.59930419922,-1866.8619384766,24.549224853516)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-914.61810302734,-1840.1225585938,24.327178955078)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-907.76702880859,-1671.8056640625,24.092933654785)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-733.45739746094,-1678.8974609375,24.124599456787)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-574.13525390625,-1685.3795166016,27.344688415527)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-363.85452270508,-1693.9346923828,92.574867248535)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-191.33279418945,-1653.646484375,112.3578414917)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-316.61505126953,-1543.9284667969,86.603569030762)},{["Class"]="info_player_undead",["Angles"]=Angle(0,87.669334411621,0),["Position"]=Vector(-721.73376464844,-1527.4466552734,24.03125)},{["Class"]="zombiegasses",["Angles"]=Angle(0,0,0),["Position"]=Vector(2326.2819824219,1316.8853759766,-247.96875)},{["Class"]="info_player_undead",["Angles"]=Angle(0,175.54666137695,0),["Position"]=Vector(-521.44866943359,1488.1628417969,53.552997589111)},{["Class"]="info_player_undead",["Angles"]=Angle(0,161.90469360352,0),["Position"]=Vector(-618.80981445313,1076.1794433594,26.424129486084)},{["Class"]="info_player_undead",["Angles"]=Angle(0,158.55857849121,0),["Position"]=Vector(-499.69006347656,1943.0633544922,51.498229980469)},{["Class"]="info_player_undead",["Angles"]=Angle(0,158.55857849121,0),["Position"]=Vector(-561.62939453125,1768.0362548828,52.462871551514)},{["Class"]="info_player_undead",["Angles"]=Angle(0,94.465721130371,0),["Position"]=Vector(-299.77606201172,2158.9619140625,37.194038391113)},{["Class"]="info_player_undead",["Angles"]=Angle(0,94.465721130371,0),["Position"]=Vector(-186.06781005859,2237.2316894531,24.940475463867)},{["Class"]="info_player_undead",["Angles"]=Angle(0,94.72314453125,0),["Position"]=Vector(138.06378173828,2235.4145507813,24.043266296387)},{["Class"]="info_player_undead",["Angles"]=Angle(0,90.604698181152,0),["Position"]=Vector(935.02667236328,2145.8947753906,36.031253814697)},{["Class"]="info_player_undead",["Angles"]=Angle(0,83.912338256836,0),["Position"]=Vector(851.232421875,2214.4675292969,32.263763427734)},{["Class"]="info_player_undead",["Angles"]=Angle(0,126.64091491699,0),["Position"]=Vector(1055.6389160156,2053.4914550781,33.352592468262)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_gilmanhouse_v2.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_gilmanhouse_v2.lua
new file mode 100644
index 0000000..bceb35c
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_gilmanhouse_v2.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(478.84704589844,2097.7121582031,-127.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1570.5426025391,2301.7939453125,-124.19820404053)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1753.4514160156,993.09088134766,-126.03686523438)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1749.9487304688,880.62506103516,-123.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1752.720703125,768.08325195313,-127.96350097656)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1748.43359375,693.12963867188,-124.69854736328)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1639.2078857422,696.43688964844,-125.82936096191)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1633.9425048828,861.35430908203,-123.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1630.9052734375,988.81970214844,-125.76992797852)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-89.98819732666,0),["Position"]=Vector(-227.21459960938,2280.6857910156,-47.376403808594)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-133.48905944824,0),["Position"]=Vector(1105.5577392578,665.96514892578,-63.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-92.305122375488,0),["Position"]=Vector(866.81414794922,655.40032958984,-63.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-92.047668457031,0),["Position"]=Vector(741.56134033203,613.06842041016,-62.785820007324)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-158.19943237305,0),["Position"]=Vector(1112.7219238281,541.21301269531,-59.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,170.44807434082,0),["Position"]=Vector(2017.8321533203,-699.46020507813,-59.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,170.44807434082,0),["Position"]=Vector(2035.8214111328,-592.55639648438,-59.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,177.91264343262,0),["Position"]=Vector(1923.9602050781,-589.78967285156,-59.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,177.91264343262,0),["Position"]=Vector(1920.02734375,-697.68725585938,-59.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,177.91264343262,0),["Position"]=Vector(1915.1812744141,-830.6298828125,-63.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,133.12510681152,0),["Position"]=Vector(1760.9949951172,-840.99938964844,-63.96875)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_macd_island17.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_macd_island17.lua
new file mode 100644
index 0000000..926bc1a
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_macd_island17.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="zombiegasses",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1261.6928710938,752.59942626953,-484.22457885742)},{["Class"]="zombiegasses",["Angles"]=Angle(0,0,0),["Position"]=Vector(4.5803527832031,769.865234375,-498.99688720703)},{["Class"]="info_player_undead",["Angles"]=Angle(0,80.489120483398,0),["Position"]=Vector(-1219.4189453125,-1423.4625244141,-368.30584716797)},{["Class"]="info_player_undead",["Angles"]=Angle(0,80.489120483398,0),["Position"]=Vector(-1099.873046875,-1443.4908447266,-368.30584716797)},{["Class"]="info_player_undead",["Angles"]=Angle(0,81.003952026367,0),["Position"]=Vector(-1078.5760498047,-1308.96875,-375.04183959961)},{["Class"]="info_player_undead",["Angles"]=Angle(0,81.003952026367,0),["Position"]=Vector(-1198.2967529297,-1290.015625,-375.04183959961)},{["Class"]="info_player_undead",["Angles"]=Angle(0,81.003952026367,0),["Position"]=Vector(-1279.4541015625,-1415.0611572266,-368.30584716797)},{["Class"]="info_player_undead",["Angles"]=Angle(0,81.003952026367,0),["Position"]=Vector(-1414.1398925781,-1393.7388916016,-368.30584716797)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-105.81706237793,0),["Position"]=Vector(29.790426254272,2076.8994140625,76.373329162598)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-105.81706237793,0),["Position"]=Vector(-9.9477834701538,1936.6263427734,118.01152038574)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-105.81706237793,0),["Position"]=Vector(-156.39741516113,1985.2071533203,119.83190917969)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-105.81706237793,0),["Position"]=Vector(-307.74627685547,2031.2620849609,116.58746337891)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-105.81706237793,0),["Position"]=Vector(-487.01440429688,2047.8312988281,100.84573364258)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-105.81706237793,0),["Position"]=Vector(-654.56030273438,2077.2150878906,84.57723236084)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-101.18389129639,0),["Position"]=Vector(-476.15606689453,2181.6181640625,96.826393127441)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-101.18389129639,0),["Position"]=Vector(-348.71481323242,2156.9099121094,105.06744384766)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-101.18389129639,0),["Position"]=Vector(-233.75730895996,1817.6870117188,137.04006958008)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-151.11936950684,0),["Position"]=Vector(704.87432861328,991.32629394531,-68.721725463867)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-151.11936950684,0),["Position"]=Vector(577.83068847656,1185.5118408203,-47.93180847168)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-151.11936950684,0),["Position"]=Vector(433.36639404297,974.91381835938,-70.211715698242)},{["Class"]="zombiegasses",["Angles"]=Angle(0,0,0),["Position"]=Vector(50.204395294189,199.12615966797,800.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_mall_beta_b1.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_mall_beta_b1.lua
new file mode 100644
index 0000000..03c27be
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_mall_beta_b1.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,33.253566741943,0),["Position"]=Vector(-1057.1306152344,-571.69378662109,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,33.253566741943,0),["Position"]=Vector(-970.69226074219,-703.51623535156,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-12.821060180664,0),["Position"]=Vector(-1078.8520507813,-377.36697387695,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-12.821060180664,0),["Position"]=Vector(-1040.9637451172,-210.88706970215,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-12.821060180664,0),["Position"]=Vector(-1069.7459716797,-90.333786010742,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-12.821060180664,0),["Position"]=Vector(-1041.5379638672,68.967910766602,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-98.792694091797,0),["Position"]=Vector(-927.45532226563,-19.888782501221,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-84.89306640625,0),["Position"]=Vector(-921.71276855469,-316.94296264648,400.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,68.877304077148,0),["Position"]=Vector(-1023.4549560547,-750.56842041016,400.03125)},{["Class"]="zombiegasses",["Angles"]=Angle(0,-16.756702423096,0),["Position"]=Vector(-1179.3800048828,-1046.6837158203,686.26385498047)},{["Class"]="zombiegasses",["Angles"]=Angle(0,98.815856933594,0),["Position"]=Vector(-979.36505126953,-490.10113525391,701.48748779297)},{["Class"]="info_player_undead",["Angles"]=Angle(0,16.705177307129,0),["Position"]=Vector(-1138.6627197266,-1156.177734375,672.03125)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-7.4904227256775,0),["Position"]=Vector(-1171.4055175781,-915.64013671875,672.03125)},{["Class"]="info_player_undead",["Angles"]=Angle(0,0.48896411061287,0),["Position"]=Vector(-1024.8121337891,-1081.0244140625,672.03125)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-1.4414720535278,0),["Position"]=Vector(-2810.0278320313,-424.20336914063,680.03125)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-1.4414720535278,0),["Position"]=Vector(-2817.1452636719,-706.73199462891,680.03125)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-1.4414720535278,0),["Position"]=Vector(-2634.0356445313,-711.3388671875,674.03125)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-1.4414720535278,0),["Position"]=Vector(-2627.3356933594,-445.38003540039,674.03125)},{["Class"]="info_player_undead",["Angles"]=Angle(0,-1.4414720535278,0),["Position"]=Vector(-2618.798828125,-106.51457977295,674.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_mini_petrols_v6.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_mini_petrols_v6.lua
new file mode 100644
index 0000000..41e7892
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_mini_petrols_v6.lua
@@ -0,0 +1 @@
+SRL={{["Angles"]=Angle(0,-87.750694274902,0),["Position"]=Vector(-1898.0695800781,-1604.0020751953,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-87.750694274902,0),["Position"]=Vector(-1892.7457275391,-1739.5328369141,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-87.750694274902,0),["Position"]=Vector(-1884.3265380859,-1953.8663330078,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-98.486686706543,0),["Position"]=Vector(-1434.8188476563,-1929.6275634766,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-98.486686706543,0),["Position"]=Vector(-1440.7945556641,-1800.3289794922,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-98.486686706543,0),["Position"]=Vector(-1432.1508789063,-1674.5036621094,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-127.61452484131,0),["Position"]=Vector(-1387.5904541016,-2302.611328125,50.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-44.28666305542,0),["Position"]=Vector(-1876.7000732422,-2732.4299316406,53.71501159668),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,93.69734954834,0),["Position"]=Vector(-1305.2596435547,-4879.533203125,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,93.69734954834,0),["Position"]=Vector(-1304.2386474609,-5030.6069335938,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,93.69734954834,0),["Position"]=Vector(-1310.1351318359,-5132.7172851563,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,93.69734954834,0),["Position"]=Vector(-1304.56640625,-5222.0512695313,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,93.69734954834,0),["Position"]=Vector(-1311.0111083984,-5338.0629882813,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,88.505386352539,0),["Position"]=Vector(-1764.4903564453,-5183.3168945313,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,88.505386352539,0),["Position"]=Vector(-1767.6828613281,-5027.3017578125,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,88.505386352539,0),["Position"]=Vector(-1765.1447753906,-4932.6596679688,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,88.505386352539,0),["Position"]=Vector(-1763.0249023438,-4851.412109375,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-170.83099365234,0),["Position"]=Vector(2240.7080078125,-3599.41796875,53.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-170.83099365234,0),["Position"]=Vector(2233.9282226563,-3653.5532226563,50.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-91.190956115723,0),["Position"]=Vector(4206.8701171875,-1894.6364746094,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-91.190956115723,0),["Position"]=Vector(4209.1176757813,-1786.8790283203,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-91.190956115723,0),["Position"]=Vector(4208.3798828125,-1665.7077636719,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-91.190956115723,0),["Position"]=Vector(4210.4956054688,-1562.1838378906,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-89.782913208008,0),["Position"]=Vector(3752.5632324219,-1939.9093017578,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-89.782913208008,0),["Position"]=Vector(3752.1713867188,-1835.6391601563,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-89.782913208008,0),["Position"]=Vector(3751.9406738281,-1774.2139892578,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-89.782913208008,0),["Position"]=Vector(3751.5517578125,-1670.6687011719,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,87.801063537598,0),["Position"]=Vector(3748.1025390625,-6388.1245117188,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,87.801063537598,0),["Position"]=Vector(3754.5432128906,-6220.5546875,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,87.801063537598,0),["Position"]=Vector(3758.1350097656,-6127.02734375,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,87.801063537598,0),["Position"]=Vector(3760.5295410156,-6064.67578125,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,92.465057373047,0),["Position"]=Vector(4202.73828125,-6026.1254882813,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,92.465057373047,0),["Position"]=Vector(4205.2661132813,-6084.7124023438,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,92.465057373047,0),["Position"]=Vector(4206.0712890625,-6177.7431640625,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,92.465057373047,0),["Position"]=Vector(4202.9702148438,-6298.9228515625,121.03125),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,150.80912780762,0),["Position"]=Vector(6063.8989257813,-3055.8273925781,212.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,150.80912780762,0),["Position"]=Vector(6008.0966796875,-2934.7570800781,212.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,150.80912780762,0),["Position"]=Vector(6023.2006835938,-2813.3764648438,212.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,-26.854692459106,0),["Position"]=Vector(4845.7001953125,-2544.6472167969,258.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,-26.854692459106,0),["Position"]=Vector(4829.443359375,-2659.1135253906,258.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,-26.854692459106,0),["Position"]=Vector(4970.228515625,-2549.265625,258.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,12.209557533264,0),["Position"]=Vector(-2825.8852539063,-3744.7561035156,724.68359375),["Class"]="info_player_human"},{["Angles"]=Angle(0,12.209557533264,0),["Position"]=Vector(-2857.8669433594,-3596.9416503906,735.36352539063),["Class"]="info_player_human"},{["Angles"]=Angle(0,12.209557533264,0),["Position"]=Vector(-2884.2575683594,-3474.9650878906,731.15759277344),["Class"]="info_player_human"},{["Angles"]=Angle(0,12.209557533264,0),["Position"]=Vector(-2956.2849121094,-3142.05859375,736.94055175781),["Class"]="info_player_human"},{["Angles"]=Angle(0,73.017639160156,0),["Position"]=Vector(-76.771034240723,-5610.5361328125,50.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,73.017639160156,0),["Position"]=Vector(95.032257080078,-5617.2177734375,50.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,73.017639160156,0),["Position"]=Vector(309.17056274414,-5681.6157226563,50.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,-126.7342300415,0),["Position"]=Vector(1756.5330810547,-3010.525390625,50.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,-126.7342300415,0),["Position"]=Vector(1621.6956787109,-2925.3032226563,50.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,-126.7342300415,0),["Position"]=Vector(1300.3564453125,-2960.3046875,50.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,-126.7342300415,0),["Position"]=Vector(1003.5184936523,-3030.4790039063,50.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,96.433776855469,0),["Position"]=Vector(2641.0739746094,-5403.525390625,145.77557373047),["Class"]="info_player_human"},{["Angles"]=Angle(0,96.433776855469,0),["Position"]=Vector(2648.6716308594,-5470.9125976563,146.83924865723),["Class"]="info_player_human"},{["Angles"]=Angle(0,75.313552856445,0),["Position"]=Vector(1456.9422607422,-5728.642578125,64.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,75.313552856445,0),["Position"]=Vector(1697.5856933594,-5722.3852539063,64.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,82.52953338623,0),["Position"]=Vector(1670.7596435547,-5411.6645507813,64.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,-166.59072875977,0),["Position"]=Vector(416.9638671875,-2424.9165039063,59.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,-166.59072875977,0),["Position"]=Vector(214.32472229004,-2422.6376953125,59.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,173.38536071777,0),["Position"]=Vector(4634.07421875,-4362.9291992188,50.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,3.0175333023071,0),["Position"]=Vector(4857.822265625,-2575.2653808594,1366.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,90.615188598633,0),["Position"]=Vector(553.39636230469,-2996.5749511719,74.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,90.615188598633,0),["Position"]=Vector(556.75506591797,-3155.3923339844,74.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,90.615188598633,0),["Position"]=Vector(561.82800292969,-3320.8325195313,74.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,84.931457519531,0),["Position"]=Vector(3215.4624023438,-4321.0991210938,1143.03125),["Class"]="info_player_zombie"}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_portal.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_portal.lua
new file mode 100644
index 0000000..5d5de8f
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_portal.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,-95.884979248047,0),["Position"]=Vector(-2481.1955566406,1457.8311767578,65.251358032227)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-84.430656433105,0),["Position"]=Vector(-2490.6472167969,1554.7725830078,69.629936218262)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-84.430656433105,0),["Position"]=Vector(-2474.0698242188,1616.6125488281,72.324447631836)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-140.80120849609,0),["Position"]=Vector(-2201.8845214844,1630.7214355469,56.527584075928)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-140.80120849609,0),["Position"]=Vector(-2168.0498046875,1490.2692871094,51.741508483887)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.66864013672,0),["Position"]=Vector(-2263.7248535156,1401.6044921875,79.121276855469)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_rundown.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_rundown.lua
new file mode 100644
index 0000000..0c33930
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_rundown.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,165.58557128906,0),["Position"]=Vector(2679.4357910156,1345.5612792969,-32.536735534668)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2678.6936035156,1420.5576171875,-32.536735534668)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2677.8771972656,1503.0535888672,-32.536735534668)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2676.7639160156,1615.5480957031,-32.536735534668)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2571.7707519531,1614.5107421875,-32.536949157715)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2572.8098144531,1509.5158691406,-32.536949157715)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2573.9973144531,1389.5217285156,-32.536949157715)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2575.1105957031,1277.0272216797,-32.536949157715)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2575.8527832031,1202.0308837891,-32.536949157715)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2463.4343261719,1193.4197998047,-32.537178039551)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2462.3952636719,1298.4146728516,-32.537178039551)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-179.4337310791,0),["Position"]=Vector(2461.2819824219,1410.9091796875,-32.537178039551)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-47.182506561279,0),["Position"]=Vector(-616.04760742188,2608.9611816406,-0.18497467041016)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-52.845317840576,0),["Position"]=Vector(-507.50048828125,2588.6520996094,-0.098777770996094)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-52.845317840576,0),["Position"]=Vector(-621.23864746094,2462.5378417969,-0.065223693847656)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_ryan_valley.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_ryan_valley.lua
new file mode 100644
index 0000000..f629cef
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_ryan_valley.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,-92.471572875977,0),["Position"]=Vector(-1112.5595703125,-213.70275878906,64.031204223633)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-92.471572875977,0),["Position"]=Vector(-1181.7622070313,-210.71572875977,64.031204223633)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-92.471572875977,0),["Position"]=Vector(-1189.6352539063,-393.09518432617,64.031188964844)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-92.471572875977,0),["Position"]=Vector(-1103.3397216797,-396.81991577148,64.031188964844)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-92.471572875977,0),["Position"]=Vector(-1164.4696044922,-510.32281494141,64.031188964844)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,90.952743530273,0),["Position"]=Vector(2756.0036621094,-4609.6274414063,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,176.92451477051,0),["Position"]=Vector(2743.3967285156,-4399.708984375,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,176.92451477051,0),["Position"]=Vector(2738.1301269531,-4497.7612304688,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,176.92451477051,0),["Position"]=Vector(2629.8334960938,-4491.9379882813,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,176.92451477051,0),["Position"]=Vector(2635.0075683594,-4395.6245117188,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,176.92451477051,0),["Position"]=Vector(2550.67578125,-4391.0903320313,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,176.92451477051,0),["Position"]=Vector(2545.0190429688,-4496.390625,64.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.44190979004,0),["Position"]=Vector(1217.0399169922,-1723.4877929688,81.781753540039)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.44190979004,0),["Position"]=Vector(1129.6169433594,-1725.865234375,70.528755187988)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_satisfaction_b1.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_satisfaction_b1.lua
new file mode 100644
index 0000000..d5f7d63
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_satisfaction_b1.lua
@@ -0,0 +1 @@
+SRL={{["Angles"]=Angle(0,0,0),["Position"]=Vector(1141.0535888672,522.19451904297,-87.96875),["Class"]="prop_blocker"},{["Angles"]=Angle(0,0,0),["Position"]=Vector(-1375.8060302734,-255.11293029785,162.03125),["Class"]="prop_blocker"},{["Angles"]=Angle(0,18.060001373291,-2.1011048829678e-006),["Position"]=Vector(-1884.1385498047,157.21321105957,-30.831848144531),["Class"]="prop_blocker"},{["Angles"]=Angle(0,89.670036315918,-2.1011048829678e-006),["Position"]=Vector(-1882.0345458984,159.42082214355,-90.822692871094),["Class"]="prop_blocker"},{["Angles"]=Angle(0,160.40800476074,0),["Position"]=Vector(2979.08984375,17.218254089355,139.49755859375),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-176.49195861816,0),["Position"]=Vector(2967.15625,211.85285949707,139.49755859375),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-176.49195861816,0),["Position"]=Vector(2957.05859375,376.54342651367,139.49755859375),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-176.49195861816,0),["Position"]=Vector(2949.255859375,503.80426025391,139.49755859375),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,179.50396728516,0),["Position"]=Vector(2892.3547363281,638.70385742188,153.55355834961),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,179.50396728516,0),["Position"]=Vector(2893.1989746094,736.19989013672,153.55355834961),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,179.50396728516,0),["Position"]=Vector(2894.3029785156,863.69470214844,153.55355834961),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,179.50396728516,0),["Position"]=Vector(2895.0822753906,953.69104003906,153.55355834961),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-170.79397583008,0),["Position"]=Vector(2680.9792480469,801.685546875,158.92269897461),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-170.79397583008,0),["Position"]=Vector(2582.1313476563,892.57501220703,158.71701049805),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,-170.79397583008,0),["Position"]=Vector(2441.4682617188,869.77709960938,158.36404418945),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,95.111885070801,0),["Position"]=Vector(2018.3719482422,-78.427040100098,143.80459594727),["Class"]="info_player_zombie"},{["Angles"]=Angle(0,86.079902648926,0),["Position"]=Vector(271.81274414063,-776.26446533203,124.20829772949),["Class"]="info_player_human"},{["Angles"]=Angle(0,86.079902648926,0),["Position"]=Vector(384.0495300293,-783.95581054688,124.20829772949),["Class"]="info_player_human"},{["Angles"]=Angle(0,86.079902648926,0),["Position"]=Vector(533.69848632813,-794.2109375,124.20829772949),["Class"]="info_player_human"},{["Angles"]=Angle(0,86.079902648926,0),["Position"]=Vector(690.82934570313,-804.97882080078,124.20829772949),["Class"]="info_player_human"},{["Angles"]=Angle(0,93.163879394531,0),["Position"]=Vector(700.15753173828,-533.23968505859,118.39696502686),["Class"]="info_player_human"},{["Angles"]=Angle(0,93.163879394531,0),["Position"]=Vector(573.45477294922,-489.95245361328,118.39044952393),["Class"]="info_player_human"},{["Angles"]=Angle(0,93.163879394531,0),["Position"]=Vector(425.4602355957,-497.93765258789,117.92371368408),["Class"]="info_player_human"},{["Angles"]=Angle(0,93.163879394531,0),["Position"]=Vector(276.42816162109,-506.17138671875,123.88252258301),["Class"]="info_player_human"},{["Angles"]=Angle(0,93.163879394531,0),["Position"]=Vector(191.80046081543,-403.11334228516,134.66290283203),["Class"]="info_player_human"},{["Angles"]=Angle(0,93.163879394531,0),["Position"]=Vector(180.55920410156,-235.07006835938,139.1148223877),["Class"]="info_player_human"},{["Angles"]=Angle(0,-0.62204265594482,0),["Position"]=Vector(-591.77276611328,423.59286499023,147.05798339844),["Class"]="info_player_human"},{["Angles"]=Angle(0,-0.62204265594482,0),["Position"]=Vector(-471.03164672852,387.5361328125,133.59588623047),["Class"]="info_player_human"},{["Angles"]=Angle(0,-0.62204265594482,0),["Position"]=Vector(-332.96331787109,259.02835083008,122.64764404297),["Class"]="info_player_human"},{["Angles"]=Angle(0,-68.074142456055,0),["Position"]=Vector(-437.49438476563,1198.3969726563,352.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,-68.074142456055,0),["Position"]=Vector(-310.82769775391,1165.703125,352.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,-68.074142456055,0),["Position"]=Vector(123.30609893799,1147.6600341797,352.03125),["Class"]="info_player_human"},{["Angles"]=Angle(0,-68.074142456055,0),["Position"]=Vector(276.16961669922,1209.1003417969,352.03125),["Class"]="info_player_human"}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_vegas_b2.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_vegas_b2.lua
new file mode 100644
index 0000000..2364a0e
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zm_vegas_b2.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.75692749023,0),["Position"]=Vector(543.18536376953,-6.8670520782471,685.93585205078)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.75692749023,0),["Position"]=Vector(413.01290893555,0.53862178325653,645.88916015625)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-178.75692749023,0),["Position"]=Vector(302.24990844727,-1.8648445606232,611.80810546875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-454.98114013672,2460.3229980469,88.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-272.42373657227,2540.0397949219,91.819473266602)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-146.35029602051,2661.4389648438,90.735443115234)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-127.26793670654,2793.7097167969,88.011512756348)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-187.04411315918,2830.4084472656,88.011512756348)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-261.48306274414,2774.294921875,88.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-338.23223876953,2649.3439941406,88.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-31.540925979614,0),["Position"]=Vector(-181.00827026367,2364.2822265625,91.313377380371)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0.4111455976963,0),["Position"]=Vector(-1789.4370117188,657.39410400391,120.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0.4111455976963,0),["Position"]=Vector(-1800.6716308594,793.13043212891,120.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0.4111455976963,0),["Position"]=Vector(-1670.1231689453,798.80676269531,120.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0.4111455976963,0),["Position"]=Vector(-1520.9969482422,785.85827636719,120.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0.4111455976963,0),["Position"]=Vector(-1476.4438476563,683.97564697266,120.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-2.2462017536163,0),["Position"]=Vector(-1510.1142578125,485.15933227539,120.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-9.8304996490479,0),["Position"]=Vector(-1587.0327148438,410.27966308594,120.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-15.135381698608,0),["Position"]=Vector(-1695.7869873047,341.62866210938,120.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,10.045001029968,0),["Position"]=Vector(-1723.8834228516,388.03848266602,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,6.8426365852356,0),["Position"]=Vector(-1621.6451416016,403.95626831055,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,3.8406736850739,0),["Position"]=Vector(-1613.4573974609,321.54705810547,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,1.6598534584045,0),["Position"]=Vector(-1701.4595947266,476.98834228516,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0.37076249718666,0),["Position"]=Vector(-1738.0891113281,593.16662597656,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-1.0910625457764,0),["Position"]=Vector(-1746.9387207031,767.83416748047,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-2.2889890670776,0),["Position"]=Vector(-1794.6461181641,769.23486328125,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-2.6556177139282,0),["Position"]=Vector(-1800.603515625,633.55023193359,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-2.6556177139282,0),["Position"]=Vector(-1759.9444580078,498.19912719727,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-154.98364257813,0),["Position"]=Vector(-395.18872070313,789.1279296875,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-154.98364257813,0),["Position"]=Vector(-700.78527832031,828.39526367188,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,95.720268249512,0),["Position"]=Vector(-103.2610168457,1030.7119140625,216.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-21.839691162109,0),["Position"]=Vector(22.527704238892,1711.9497070313,504.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-21.839691162109,0),["Position"]=Vector(101.77830505371,1562.3090820313,504.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-21.839691162109,0),["Position"]=Vector(176.60768127441,1386.1588134766,504.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-97.825981140137,0),["Position"]=Vector(-1963.3778076172,1452.6138916016,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,-97.825981140137,0),["Position"]=Vector(-2029.1851806641,1319.3250732422,386.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,117.60589599609,0),["Position"]=Vector(-1341.4119873047,467.94543457031,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,117.60589599609,0),["Position"]=Vector(-1407.2569580078,633.58068847656,384.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,117.60589599609,0),["Position"]=Vector(-1463.63671875,742.55499267578,384.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_abandoned_mall_v4.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_abandoned_mall_v4.lua
new file mode 100644
index 0000000..a370b0a
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_abandoned_mall_v4.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.575614929199,0),["Position"]=Vector(410.48590087891,4182.78125,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.575614929199,0),["Position"]=Vector(551.11871337891,4178.9096679688,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.575614929199,0),["Position"]=Vector(581.24987792969,4036.3286132813,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.575614929199,0),["Position"]=Vector(692.17840576172,3970.5593261719,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.575614929199,0),["Position"]=Vector(578.57592773438,3845.4409179688,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-87.725524902344,0),["Position"]=Vector(220.41596984863,4008.7465820313,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-87.725524902344,0),["Position"]=Vector(54.488754272461,3943.6423339844,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-35.057514190674,0),["Position"]=Vector(-256.78802490234,3790.6596679688,80.017524719238)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2023.8112792969,2714.9885253906,16.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2023.3077392578,2821.4377441406,16.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2006.9027099609,2563.1286621094,16.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2007.2639160156,2486.4050292969,16.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2007.5607910156,2423.4089355469,16.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_abandoned_mall_v5f.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_abandoned_mall_v5f.lua
new file mode 100644
index 0000000..3bc1b4d
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_abandoned_mall_v5f.lua
@@ -0,0 +1 @@
+SRL={{["Angles"]=Angle(0,34.391754150391,0),["Position"]=Vector(-475.69149780273,1811.4334716797,24.03125),["Class"]="zombiegasses"},{["Angles"]=Angle(0,-171.71630859375,0),["Position"]=Vector(928.49047851563,1468.03125,80.03125),["Class"]="zombiegasses"},{["Angles"]=Angle(0,-172.47521972656,0),["Position"]=Vector(774.76324462891,1543.5361328125,80.03125),["Class"]="zombiegasses"},{["Angles"]=Angle(0,-44.171901702881,0),["Position"]=Vector(-404.54904174805,2125.1989746094,80.03125),["Class"]="zombiegasses"}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_abandoned_motel_final.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_abandoned_motel_final.lua
new file mode 100644
index 0000000..4b72bd9
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_abandoned_motel_final.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(12.097787857056,-83.647125244141,0),["Position"]=Vector(-88.215301513672,948.83001708984,-769.30535888672)},{["Class"]="info_player_zombie",["Angles"]=Angle(12.097787857056,-83.647125244141,0),["Position"]=Vector(150.09777832031,858.90356445313,-778.85272216797)},{["Class"]="info_player_zombie",["Angles"]=Angle(7.721987247467,-84.161743164063,0),["Position"]=Vector(-332.27993774414,732.59112548828,-801.39300537109)},{["Class"]="info_player_zombie",["Angles"]=Angle(7.721987247467,-84.161743164063,0),["Position"]=Vector(-82.933174133301,758.08764648438,-772.73742675781)},{["Class"]="info_player_zombie",["Angles"]=Angle(7.721987247467,-84.161743164063,0),["Position"]=Vector(31.414106369019,769.77996826172,-769.53344726563)},{["Class"]="info_player_zombie",["Angles"]=Angle(6.6923861503601,-100.12055206299,0),["Position"]=Vector(439.25109863281,864.81079101563,-832.47149658203)},{["Class"]="info_player_zombie",["Angles"]=Angle(1.5444043874741,83.405708312988,0),["Position"]=Vector(-602.19354248047,-509.89099121094,-822.36529541016)},{["Class"]="info_player_zombie",["Angles"]=Angle(1.5444043874741,83.405708312988,0),["Position"]=Vector(-373.58245849609,-458.60223388672,-823.56256103516)},{["Class"]="info_player_zombie",["Angles"]=Angle(-1.2870172262192,68.836380004883,0),["Position"]=Vector(-962.76129150391,19.063621520996,-829.51812744141)},{["Class"]="info_player_zombie",["Angles"]=Angle(-1.029617190361,68.836380004883,0),["Position"]=Vector(-888.50946044922,252.73442077637,-828.74676513672)},{["Class"]="info_player_zombie",["Angles"]=Angle(9.2663812637329,-74.020645141602,0),["Position"]=Vector(-1004.6726074219,260.71377563477,-830.84045410156)},{["Class"]="info_player_zombie",["Angles"]=Angle(9.2663812637329,-74.020645141602,0),["Position"]=Vector(-843.08380126953,36.356174468994,-855.52374267578)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_bunker.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_bunker.lua
new file mode 100644
index 0000000..052c42b
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_bunker.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="zombiegasses",["Angles"]=Angle(0,103.12794494629,0),["Position"]=Vector(-521.33850097656,-1204.6079101563,-251.39431762695)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_haunted_manor_beta.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_haunted_manor_beta.lua
new file mode 100644
index 0000000..6e9d62a
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_haunted_manor_beta.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="zombiegasses",["Angles"]=Angle(0,-5.800464630127,0),["Position"]=Vector(-649.18768310547,454.41580200195,-1407.96875)},{["Class"]="zombiegasses",["Angles"]=Angle(0,20.94349861145,0),["Position"]=Vector(-665.25830078125,441.64990234375,-1380.0942382813)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_infected_city_b1.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_infected_city_b1.lua
new file mode 100644
index 0000000..625d06f
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_infected_city_b1.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,-114.80297088623,0),["Position"]=Vector(1529.556640625,2935.6630859375,-351.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-161.94329833984,0),["Position"]=Vector(1531.6019287109,2698.0905761719,-351.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-167.41758728027,0),["Position"]=Vector(1544.0848388672,2458.2739257813,-351.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-93.795570373535,0),["Position"]=Vector(1392.3697509766,2892.7141113281,-391.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-91.411094665527,0),["Position"]=Vector(1226.1566162109,2853.7238769531,-371.58312988281)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-89.090927124023,0),["Position"]=Vector(1111.5850830078,2820.5793457031,-357.69244384766)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-82.576148986816,0),["Position"]=Vector(1056.2716064453,2704.0500488281,-327.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-111.16773986816,0),["Position"]=Vector(1248.4578857422,2585.0168457031,-391.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-106.12110900879,0),["Position"]=Vector(1405.3708496094,2510.0786132813,-391.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-151.83157348633,0),["Position"]=Vector(1576.5661621094,2436.8127441406,-351.96875)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_peekay_highway17_01.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_peekay_highway17_01.lua
new file mode 100644
index 0000000..56f50a3
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_peekay_highway17_01.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(3.3461999893188,-78.138595581055,0),["Position"]=Vector(-1474.4702148438,191.99964904785,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(3.3461999893188,-78.138595581055,0),["Position"]=Vector(-1591.8939208984,167.33729553223,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(3.3461999893188,-78.138595581055,0),["Position"]=Vector(-1699.8421630859,144.66505432129,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(3.3461999893188,-78.138595581055,0),["Position"]=Vector(-1796.0579833984,124.45696258545,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(1.4318823104986e-007,-1.6907994747162,0),["Position"]=Vector(-1530.3336181641,-85.115386962891,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.6627998352051,-84.831008911133,0),["Position"]=Vector(-1309.7841796875,-36.310207366943,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.4054026603699,-171.83218383789,0),["Position"]=Vector(-1144.7758789063,63.759227752686,320.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(11.840404510498,-5.8091773986816,0),["Position"]=Vector(-888.31939697266,44.34158706665,320.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.1480059623718,-95.899169921875,0),["Position"]=Vector(-689.90447998047,68.908416748047,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.1480059623718,-95.899169921875,0),["Position"]=Vector(-503.03497314453,49.600151062012,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.1480059623718,-95.899169921875,0),["Position"]=Vector(-418.63555908203,40.879600524902,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.1480059623718,-95.899169921875,0),["Position"]=Vector(-371.92294311523,-125.17939758301,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.1480059623718,-95.899169921875,0),["Position"]=Vector(-545.91015625,-126.3844833374,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.1480059623718,-95.899169921875,0),["Position"]=Vector(-711.62677001953,-163.97529602051,321.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(5.1480059623718,-95.899169921875,0),["Position"]=Vector(-629.76641845703,-262.69570922852,321.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1111.7999267578,-2570.9545898438,260.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-918.54827880859,-2540.138671875,260.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-999.46154785156,-2538.2683105469,260.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1132.9802246094,-2310.9809570313,260.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1026.154296875,-2230.8935546875,260.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1190.0466308594,-2219.2734375,260.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1313.9781494141,-2307.7067871094,260.03125)},{["Class"]="info_player_human",["Angles"]=Angle(0,0,0),["Position"]=Vector(-1084.1000976563,-2587.8737792969,392.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_school.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_school.lua
new file mode 100644
index 0000000..b9f80bf
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_school.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-956.74139404297,-850.40509033203,356.95526123047)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-958.49877929688,-772.64721679688,356.95526123047)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-881.91168212891,-686.60418701172,356.95526123047)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1460.1417236328,-313.86346435547,356.81225585938)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1050.2445068359,-319.27752685547,356.81225585938)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1174.9249267578,-315.91256713867,356.81225585938)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(473.55883789063,-1197.8994140625,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(385.45025634766,-1101.5399169922,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(214.77722167969,-1108.0576171875,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-225.04792785645,-1113.0131835938,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-384.45269775391,-1114.8092041016,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-560.01531982422,-1116.787109375,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-262.05206298828,1834.3687744141,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(118.1318359375,1838.5329589844,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(454.70971679688,1832.7912597656,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(804.56475830078,1732.5345458984,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-484.17163085938,1740.8912353516,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(-663.55169677734,1571.9674072266,-6.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1624.3937988281,-1286.8486328125,-7.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1898.9047851563,-1281.2886962891,-7.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(1087.0125732422,-1342.0225830078,-7.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2085.2734375,852.02819824219,212.17425537109)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2214.220703125,1071.9543457031,212.17425537109)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2215.7624511719,976.77740478516,212.17425537109)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,0,0),["Position"]=Vector(2217.3041992188,881.60095214844,212.17425537109)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_subway_v8.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_subway_v8.lua
new file mode 100644
index 0000000..a01f314
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_subway_v8.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,81.158760070801,0),["Position"]=Vector(-131.15821838379,-2534.6545410156,96.03125)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,81.158760070801,0),["Position"]=Vector(-91.431938171387,-2252.4736328125,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,81.158760070801,0),["Position"]=Vector(41.341178894043,-2251.4147949219,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,81.158760070801,0),["Position"]=Vector(152.10539245605,-2233.998046875,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,0),["Position"]=Vector(135.79827880859,-2123.7199707031,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,-0),["Position"]=Vector(73.630851745605,-2125.5769042969,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,-0),["Position"]=Vector(16.521320343018,-2127.283203125,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,-0),["Position"]=Vector(-27.469058990479,-2128.59765625,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,0),["Position"]=Vector(-118.14763641357,-2059.0317382813,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,0),["Position"]=Vector(-50.575801849365,-2050.3298339844,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,0),["Position"]=Vector(24.899143218994,-2048.0278320313,-31.96875)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,91.712181091309,0),["Position"]=Vector(142.62985229492,-2019.8032226563,-31.96875)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_tunnels_fixed_v2.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_tunnels_fixed_v2.lua
new file mode 100644
index 0000000..f111dd8
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_tunnels_fixed_v2.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,96.060150146484,0),["Position"]=Vector(710.29382324219,-1395.2973632813,124.51078796387)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,95.030548095703,0),["Position"]=Vector(493.6311340332,-1414.3675537109,124.51078796387)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,95.030548095703,0),["Position"]=Vector(306.85363769531,-1430.8073730469,124.51078796387)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,95.030548095703,0),["Position"]=Vector(97.662544250488,-1449.2199707031,124.51078796387)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,49.985542297363,0),["Position"]=Vector(319.1953125,-1237.6873779297,116.81788635254)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,100.17853546143,0),["Position"]=Vector(676.552734375,-1240.7888183594,111.28171539307)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,102.49514007568,0),["Position"]=Vector(830.32159423828,-1206.7125244141,111.28171539307)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-127.51789093018,0),["Position"]=Vector(953.54467773438,1412.9068603516,117.04342651367)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-127.51789093018,0),["Position"]=Vector(1167.6989746094,1248.4722900391,117.04342651367)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-124.17168426514,0),["Position"]=Vector(899.64630126953,1190.0889892578,112.37947845459)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-47.208976745605,0),["Position"]=Vector(-1203.7399902344,1417.1822509766,126.55266571045)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-47.208976745605,0),["Position"]=Vector(-1341.3345947266,1289.8079833984,126.55266571045)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-47.208976745605,0),["Position"]=Vector(-1429.3951416016,1208.2884521484,126.55266571045)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,-51.069980621338,0),["Position"]=Vector(-1204.3985595703,1192.8255615234,112.84037780762)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,41.079235076904,0),["Position"]=Vector(-1272.7183837891,-1162.4512939453,141.78689575195)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,41.079235076904,0),["Position"]=Vector(-1110.0870361328,-1349.0189208984,141.78689575195)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,41.079235076904,0),["Position"]=Vector(-941.46612548828,-1202.0291748047,117.57444763184)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,41.079235076904,0),["Position"]=Vector(-1187.8782958984,-919.35211181641,117.57444763184)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,41.079235076904,0),["Position"]=Vector(-1052.9808349609,-801.76031494141,98.204544067383)},{["Class"]="info_player_zombie",["Angles"]=Angle(0,41.079235076904,0),["Position"]=Vector(-808.16265869141,-978.29547119141,90.785552978516)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_zombienowhere_v3.lua b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_zombienowhere_v3.lua
new file mode 100644
index 0000000..cd14981
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/prepackagedmapprofiles/zs_zombienowhere_v3.lua
@@ -0,0 +1 @@
+SRL={{["Class"]="info_player_zombie",["Angles"]=Angle(0,88.396209716797,0),["Position"]=Vector(-511.33920288086,667.03381347656,408.03125)}}
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/sh_animations.lua b/gamemodes/zombiesurvival/gamemode/sh_animations.lua
new file mode 100644
index 0000000..93bfafa
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sh_animations.lua
@@ -0,0 +1,62 @@
+local TEAM_UNDEAD = TEAM_UNDEAD
+local ACT_MP_STAND_IDLE = ACT_MP_STAND_IDLE
+
+function GM:PlayerShouldTaunt(pl, actid)
+ return (pl:Team() == TEAM_HUMAN or pl:GetZombieClassTable().CanTaunt) and not IsValid(pl.Revive) and not IsValid(pl.FeignDeath)
+end
+
+function GM:CalcMainActivity(pl, velocity)
+ pl.CalcIdeal = ACT_MP_STAND_IDLE
+ pl.CalcSeqOverride = -1
+
+ --[[if pl:CallZombieFunction("CalcMainActivity", velocity) then
+ return pl.CalcIdeal, pl.CalcSeqOverride
+ end]]
+ if pl:Team() == TEAM_UNDEAD then
+ local tab = pl:GetZombieClassTable()
+ if tab.CalcMainActivity and tab:CalcMainActivity(pl, velocity) then
+ return pl.CalcIdeal, pl.CalcSeqOverride
+ end
+ end
+
+ return self.BaseClass.CalcMainActivity(self, pl, velocity)
+end
+
+function GM:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.UpdateAnimation and wep:UpdateAnimation(pl, velocity, maxseqgroundspeed) or pl:CallZombieFunction("UpdateAnimation", velocity, maxseqgroundspeed) then
+ --[[if CLIENT then
+ GAMEMODE:GrabEarAnimation(pl)
+ GAMEMODE:MouthMoveAnimation(pl)
+ end]]
+
+ return
+ end
+
+ return self.BaseClass.UpdateAnimation(self, pl, velocity, maxseqgroundspeed)
+end
+
+function GM:DoAnimationEvent(pl, event, data)
+ return pl:CallZombieFunction("DoAnimationEvent", event, data) or self.BaseClass:DoAnimationEvent(pl, event, data)
+end
+
+local CarryingActivityTranslate = {}
+CarryingActivityTranslate[ACT_MP_STAND_IDLE] = ACT_HL2MP_IDLE_SLAM
+CarryingActivityTranslate[ACT_MP_WALK] = ACT_HL2MP_IDLE_SLAM + 1
+CarryingActivityTranslate[ACT_MP_RUN] = ACT_HL2MP_IDLE_SLAM + 2
+CarryingActivityTranslate[ACT_MP_CROUCH_IDLE] = ACT_HL2MP_IDLE_SLAM + 3
+CarryingActivityTranslate[ACT_MP_CROUCHWALK] = ACT_HL2MP_IDLE_SLAM + 4
+CarryingActivityTranslate[ACT_MP_ATTACK_STAND_PRIMARYFIRE] = ACT_HL2MP_IDLE_SLAM + 5
+CarryingActivityTranslate[ACT_MP_ATTACK_CROUCH_PRIMARYFIRE] = ACT_HL2MP_IDLE_SLAM + 5
+CarryingActivityTranslate[ACT_MP_RELOAD_STAND] = ACT_HL2MP_IDLE_SLAM + 6
+CarryingActivityTranslate[ACT_MP_RELOAD_CROUCH] = ACT_HL2MP_IDLE_SLAM + 6
+CarryingActivityTranslate[ACT_MP_JUMP] = ACT_HL2MP_IDLE_SLAM + 7
+CarryingActivityTranslate[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_SLAM + 8
+
+function GM:TranslateActivity(pl, act)
+ if pl:IsCarrying() then
+ return CarryingActivityTranslate[act] or act
+ end
+
+ return self.BaseClass:TranslateActivity(pl, act)
+end
diff --git a/gamemodes/zombiesurvival/gamemode/sh_colors.lua b/gamemodes/zombiesurvival/gamemode/sh_colors.lua
new file mode 100644
index 0000000..a2ee148
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sh_colors.lua
@@ -0,0 +1,41 @@
+color_black_alpha220 = Color(0, 0, 0, 180)
+color_black_alpha200 = Color(0, 0, 0, 180)
+color_black_alpha180 = Color(0, 0, 0, 180)
+color_black_alpha120 = Color(0, 0, 0, 120)
+color_black_alpha90 = Color(0, 0, 0, 90)
+
+color_white_alpha220 = Color(255, 255, 255, 200)
+color_white_alpha200 = Color(255, 255, 255, 200)
+color_white_alpha180 = Color(255, 255, 255, 180)
+color_white_alpha120 = Color(255, 255, 255, 120)
+color_white_alpha90 = Color(255, 255, 255, 90)
+
+COLOR_GRAY = Color(190, 190, 190)
+COLOR_RED = Color(255, 0, 0)
+COLOR_BLUE = Color(0, 0, 255)
+COLOR_GREEN = Color(0, 255, 0)
+COLOR_LIMEGREEN = Color(50, 255, 50)
+COLOR_YELLOW = Color(255, 255, 0)
+COLOR_CYAN = Color(0, 255, 255)
+COLOR_WHITE = Color(255, 255, 255)
+COLOR_PURPLE = Color(255, 0, 255)
+
+COLOR_DARKGRAY = Color(40, 40, 40)
+COLOR_DARKRED = Color(185, 0, 0)
+COLOR_DARKGREEN = Color(0, 150, 0)
+COLOR_DARKBLUE = Color(5, 75, 150)
+
+COLOR_FRIENDLY = COLOR_DARKGREEN
+COLOR_HEALTHY = COLOR_DARKGREEN
+COLOR_SCRATCHED = Color(80, 210, 0)
+COLOR_HURT = Color(150, 50, 0)
+COLOR_CRITICAL = COLOR_DARKRED
+
+function util.ColorCopy(source, dest, copyalpha)
+ dest.r = source.r
+ dest.g = source.g
+ dest.b = source.b
+ if copyalpha then
+ dest.a = source.a
+ end
+end
diff --git a/gamemodes/zombiesurvival/gamemode/sh_crafts.lua b/gamemodes/zombiesurvival/gamemode/sh_crafts.lua
new file mode 100644
index 0000000..be69d6b
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sh_crafts.lua
@@ -0,0 +1,215 @@
+GM.CraftingRange = 72
+
+GM.Crafts = {
+ {
+ Name = "a big wooden crate",
+ a = {"*physics*", {"models/props_junk/wood_crate001a.mdl", "models/props_junk/wood_crate001a_damaged.mdl", "models/props_junk/wood_crate001a_damagedmax.mdl"}},
+ b = {"*physics*", {"models/props_junk/wood_crate001a.mdl", "models/props_junk/wood_crate001a_damaged.mdl", "models/props_junk/wood_crate001a_damagedmax.mdl"}},
+ Result = {"prop_physics", Model("models/props_junk/wood_crate002a.mdl")}
+ },
+ {
+ Name = "a bust-on-a-stick",
+ callback = function(enta, entb)
+ return enta:IsPhysicsModel("models/props_combine/breenbust.mdl") and entb:IsWeaponType("weapon_zs_plank")
+ end,
+ Result = {"weapon_zs_bust"}
+ },
+ {
+ Name = "an oil-filled barrel",
+ a = {"*physics*", "models/props_junk/gascan001a.mdl"},
+ b = {"*physics*", "models/props_c17/oildrum001.mdl"},
+ Result = {"prop_physics", Model("models/props_c17/oildrum001_explosive.mdl")}
+ },
+ {
+ Name = "a sawhack",
+ callback = function(enta, entb)
+ return enta:IsPhysicsModel("models/props_junk/sawblade001a.mdl") and entb:IsWeaponType("weapon_zs_axe")
+ end,
+ Result = {"weapon_zs_sawhack"}
+ },
+ {
+ Name = "a mega masher",
+ callback = function(enta, entb)
+ return enta:IsPhysicsModel("models/props_c17/oildrum001_explosive.mdl") and entb:IsWeaponType("weapon_zs_sledgehammer")
+ end,
+ Result = {"weapon_zs_megamasher"}
+ },
+ {
+ Name = "an electrohammer",
+ callback = function(enta, entb)
+ return enta:IsPhysicsModel("models/items/car_battery01.mdl") and entb:IsWeaponType("weapon_zs_hammer")
+ end,
+ Result = {"weapon_zs_electrohammer"}
+ },
+ {
+ Name = "a 'Waraxe' handgun",
+ callback = function(enta, entb)
+ return enta:IsWeaponType("weapon_zs_battleaxe") and entb:IsWeaponType("weapon_zs_battleaxe")
+ end,
+ Result = {"weapon_zs_waraxe"}
+ },
+ {
+ Name = "a modified manhack",
+ callback = function(enta, entb)
+ return enta:IsPhysicsModel("models/props_junk/sawblade001a.mdl") and entb:IsWeaponType("weapon_zs_manhack")
+ end,
+ Result = {"weapon_zs_manhack_saw"}
+ }
+}
+
+function GM:GetCraftingRecipe(enta, entb)
+ if not enta:IsValid() or not entb:IsValid() or enta == entb then return end
+
+ for _, recipe in pairs(self.Crafts) do
+ if self:CraftingRecipeMatches(enta, entb, recipe) then return recipe end
+ end
+end
+
+function GM:GetCraftTarget(enta, entb)
+ return enta:OBBMaxs():Distance(enta:OBBMins()) > entb:OBBMaxs():Distance(entb:OBBMins()) and enta or entb
+end
+
+function GM:CraftingRecipeMatches(enta, entb, recipe, checkedswap)
+ local entaclass = enta:GetClass()
+ local entbclass = entb:GetClass()
+ local entaisphysics = string.sub(entaclass, 1, 12) == "prop_physics"
+ local entbisphysics = string.sub(entbclass, 1, 12) == "prop_physics"
+
+ if recipe.callback and recipe.callback(enta, entb) then
+ return true
+ end
+
+ if recipe.a and recipe.b and (recipe.a[1] == entaclass or entaisphysics and recipe.a[1] == "*physics*") and (recipe.b[1] == entbclass or entaisphysics and recipe.a[1] == "*physics*") then
+ local mdla = string.lower(enta:GetModel())
+ local mdlb = string.lower(entb:GetModel())
+ if (recipe.a[2] == nil or type(recipe.a[2]) == "table" and table.HasValue(recipe.a[2], mdla) or mdla == recipe.a[2]) and (recipe.b[2] == nil or type(recipe.b[2]) == "table" and table.HasValue(recipe.b[2], mdlb) or mdlb == recipe.b[2]) then
+ return true
+ end
+ end
+
+ if not checkedswap then
+ return self:CraftingRecipeMatches(entb, enta, recipe, true)
+ end
+end
+
+function GM:CanCraft(pl, enta, entb)
+ if self:GetCraftingRecipe(enta, entb) == nil or not pl:IsValid() or not pl:Alive() or pl:Team() ~= TEAM_HUMAN then return false end
+
+ if enta:IsBarricadeProp() or entb:IsBarricadeProp() or enta:GetName() ~= "" or entb:GetName() ~= "" then return false end
+
+ local nearestb = entb:NearestPoint(enta:LocalToWorld(enta:OBBCenter()))
+ local nearesta = enta:NearestPoint(entb:LocalToWorld(entb:OBBCenter()))
+ if nearesta:Distance(nearestb) > self.CraftingRange or not TrueVisibleFilters(nearesta, nearestb, pl, enta, entb) then return false end
+
+ local eyepos = pl:EyePos()
+ if enta:NearestPoint(eyepos):Distance(eyepos) > self.CraftingRange or entb:NearestPoint(eyepos):Distance(eyepos) > self.CraftingRange then return false end
+
+ if not TrueVisibleFilters(nearesta, eyepos, pl, enta, entb) or not TrueVisibleFilters(nearestb, eyepos, pl, enta, entb) then return false end
+
+ return true
+end
+
+local meta = FindMetaTable("Entity")
+if not meta then return end
+
+function meta:IsPhysicsModel(mdl)
+ return string.sub(self:GetClass(), 1, 12) == "prop_physics" and (not mdl or string.lower(self:GetModel()) == string.lower(mdl))
+end
+
+function meta:IsWeaponType(class)
+ return self:GetClass() == "prop_weapon" and self:GetWeaponType() == class
+end
+
+if true then return end
+
+function GM:GetCraftingRecipe(enta, entb)
+ if not enta:IsValid() or not entb:IsValid() or enta == entb then return end
+
+ for _, recipe in pairs(self.Crafts) do
+ if self:CraftingRecipeMatches(enta, entb, recipe) then return recipe end
+ end
+end
+
+function GM:GetCraftTarget(enta, entb)
+ return enta:OBBMaxs():Distance(enta:OBBMins()) > entb:OBBMaxs():Distance(entb:OBBMins()) and enta or entb
+end
+
+function GM:CraftingRecipeMatches(enta, entb, recipe, checkedswap)
+ local entaclass = enta:GetClass()
+ local entbclass = entb:GetClass()
+ local entaisphysics = string.sub(entaclass, 1, 12) == "prop_physics"
+ local entbisphysics = string.sub(entbclass, 1, 12) == "prop_physics"
+
+ if recipe.callback and recipe.callback(enta, entb) then
+ return true
+ end
+
+ if recipe.a and recipe.b and (recipe.a[1] == entaclass or entaisphysics and recipe.a[1] == "*physics*") and (recipe.b[1] == entbclass or entaisphysics and recipe.a[1] == "*physics*") then
+ local mdla = string.lower(enta:GetModel())
+ local mdlb = string.lower(entb:GetModel())
+ if (recipe.a[2] == nil or type(recipe.a[2]) == "table" and table.HasValue(recipe.a[2], mdla) or mdla == recipe.a[2]) and (recipe.b[2] == nil or type(recipe.b[2]) == "table" and table.HasValue(recipe.b[2], mdlb) or mdlb == recipe.b[2]) then
+ return true
+ end
+ end
+
+ if not checkedswap then
+ return self:CraftingRecipeMatches(entb, enta, recipe, true)
+ end
+end
+
+function GM:GetAllValidCraftingRecipes(pl)
+ local craftable = {}
+
+ for _, craft in pairs(self.Crafts) do
+ if self:CanCraft(pl, craft) then
+ table.insert(craftable, craft)
+ end
+ end
+
+ return craftable
+end
+
+-- Preliminary tests for all entity types.
+-- Classes are enforced by the recipes so if someone makes a recipe inolving players or worldspawn then oh well.
+function GM:IsValidCraftingEntity(ent, pl)
+ return not ent:IsWeapon()
+ and not (ent:IsPhysicsModel() and ent:GetName() ~= "")
+ and not (ent:IsWeapon() and ent:GetOwner() ~= pl)
+end
+
+-- This checks everything and is what determines if a recipe displays to the player in their menu.
+function GM:CanCraft(pl, craft)
+ if not pl:IsValid() or not pl:Alive() or pl:Team() ~= TEAM_HUMAN then return false end
+
+ local plpos = pl:EyePos()
+ local entities = ents.FindInSphere(plpos, self.CraftingRange)
+
+ if craft.CanCraft and not craft:CanCraft(pl, entities, plpos) then return false end
+
+ local ingredients = {}
+
+ for _, ent in pairs(entities) do
+ if craft.CanUseEntity and not craft:CanUseEntity(ent, pl) then continue end
+ end
+
+ -- All ingredients accounted for?
+ --for _, ingredient
+
+ local nearestb = entb:NearestPoint(enta:LocalToWorld(enta:OBBCenter()))
+ local nearesta = enta:NearestPoint(entb:LocalToWorld(entb:OBBCenter()))
+ if nearesta:Distance(nearestb) > self.CraftingRange or not TrueVisibleFilters(nearesta, nearestb, pl, enta, entb) then return false end
+
+ local eyepos = pl:EyePos()
+ if enta:NearestPoint(eyepos):Distance(eyepos) > self.CraftingRange or entb:NearestPoint(eyepos):Distance(eyepos) > self.CraftingRange then return false end
+
+ if not TrueVisibleFilters(nearesta, eyepos, pl, enta, entb) or not TrueVisibleFilters(nearestb, eyepos, pl, enta, entb) then return false end
+
+ return true
+end
+
+local meta = FindMetaTable("Entity")
+if not meta then return end
+
+function meta:IsPhysicsModel(mdl)
+ return string.sub(self:GetClass(), 1, 12) == "prop_physics" and (not mdl or string.lower(self:GetModel()) == string.lower(mdl))
+end
diff --git a/gamemodes/zombiesurvival/gamemode/sh_globals.lua b/gamemodes/zombiesurvival/gamemode/sh_globals.lua
new file mode 100644
index 0000000..958c39a
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sh_globals.lua
@@ -0,0 +1,209 @@
+TEAM_ZOMBIE = 3
+TEAM_ZOMBIES = TEAM_ZOMBIE
+TEAM_UNDEAD = TEAM_ZOMBIE
+TEAM_SURVIVOR = 4
+TEAM_SURVIVORS = TEAM_SURVIVOR
+TEAM_HUMAN = TEAM_SURVIVOR
+TEAM_HUMANS = TEAM_SURVIVOR
+
+DISMEMBER_HEAD = 1
+DISMEMBER_LEFTARM = 2
+DISMEMBER_RIGHTARM = 4
+DISMEMBER_LEFTLEG = 8
+DISMEMBER_RIGHTLEG = 16
+
+HM_MOSTZOMBIESKILLED = 1
+HM_MOSTDAMAGETOUNDEAD = 2
+HM_PACIFIST = 3
+HM_MOSTHELPFUL = 4
+HM_LASTHUMAN = 5
+HM_OUTLANDER = 6
+HM_GOODDOCTOR = 7
+HM_HANDYMAN = 8
+HM_SCARECROW = 9
+HM_MOSTBRAINSEATEN = 10
+HM_MOSTDAMAGETOHUMANS = 11
+HM_LASTBITE = 12
+HM_USEFULTOOPPOSITE = 13
+HM_STUPID = 14
+HM_SALESMAN = 15
+HM_WAREHOUSE = 16
+HM_BARRICADEDESTROYER = 17
+HM_SPAWNPOINT = 18
+HM_CROWFIGHTER = 19
+HM_CROWBARRICADEDAMAGE = 20
+HM_NESTDESTROYER = 21
+HM_NESTMASTER = 22
+
+FM_NONE = 0
+FM_LOCALKILLOTHERASSIST = 1
+FM_LOCALASSISTOTHERKILL = 2
+
+DIR_FORWARD = 0
+DIR_RIGHT = 1
+DIR_BACK = 2
+DIR_LEFT = 3
+
+DEFAULT_VIEW_OFFSET = Vector(0, 0, 64)
+DEFAULT_VIEW_OFFSET_DUCKED = Vector(0, 0, 28)
+DEFAULT_JUMP_POWER = 185
+DEFAULT_STEP_SIZE = 18
+DEFAULT_MASS = 80
+DEFAULT_MODELSCALE = 1
+
+-- Humans can not carry OR drag anything heavier than this (in kg.)
+CARRY_MAXIMUM_MASS = 300
+-- Humans can not carry anything with a volume more than this (OBBMins():Length() + OBBMaxs():Length()).
+CARRY_MAXIMUM_VOLUME = 150
+-- Objects with more mass than this will be dragged instead of carried.
+CARRY_DRAG_MASS = 145
+-- Anything bigger than this is dragged regardless of mass.
+CARRY_DRAG_VOLUME = 120
+-- Humans are slowed by this amount per kg carried...
+CARRY_SPEEDLOSS_PERKG = 1.3
+-- but can never be slower than this.
+CARRY_SPEEDLOSS_MINSPEED = 88
+
+GM.MaxLegDamage = 3
+
+GM.UtilityKey = IN_SPEED
+GM.MenuKey = IN_WALK -- I would use the spawn menu but it has no IN_ key assignment.
+
+-- Cost multiplier for being near an arsenal crate.
+GM.ArsenalCrateMultiplier = 0.8
+GM.ArsenalCrateDiscount = 1 - GM.ArsenalCrateMultiplier
+GM.ArsenalCrateDiscountPercentage = GM.ArsenalCrateDiscount * 100
+
+SPEED_NORMAL = 225
+SPEED_SLOWEST = SPEED_NORMAL - 20
+SPEED_SLOWER = SPEED_NORMAL - 14
+SPEED_SLOW = SPEED_NORMAL - 7
+SPEED_FAST = SPEED_NORMAL + 7
+SPEED_FASTER = SPEED_NORMAL + 14
+SPEED_FASTEST = SPEED_NORMAL + 20
+
+SPEED_ZOMBIEESCAPE_SLOWEST = 190
+SPEED_ZOMBIEESCAPE_SLOWER = 200
+SPEED_ZOMBIEESCAPE_SLOW = 210
+SPEED_ZOMBIEESCAPE_NORMAL = 220
+SPEED_ZOMBIEESCAPE_ZOMBIE = 250
+
+ZE_KNOCKBACKSCALE = 0.1
+
+MASK_HOVER = bit.bor(CONTENTS_OPAQUE, CONTENTS_GRATE, CONTENTS_HITBOX, CONTENTS_DEBRIS, CONTENTS_SOLID, CONTENTS_WATER, CONTENTS_SLIME, CONTENTS_WINDOW, CONTENTS_LADDER, CONTENTS_PLAYERCLIP, CONTENTS_MOVEABLE, CONTENTS_DETAIL, CONTENTS_TRANSLUCENT)
+
+GM.BarricadeHealthMin = 50
+GM.BarricadeHealthMax = 1100
+GM.BarricadeHealthMassFactor = 3
+GM.BarricadeHealthVolumeFactor = 4
+
+GM.HumanGibs = {
+Model("models/gibs/HGIBS.mdl"),
+Model("models/gibs/HGIBS_spine.mdl"),
+
+Model("models/gibs/HGIBS_rib.mdl"),
+Model("models/gibs/HGIBS_scapula.mdl"),
+Model("models/gibs/antlion_gib_medium_2.mdl"),
+Model("models/gibs/Antlion_gib_Large_1.mdl"),
+Model("models/gibs/Strider_Gib4.mdl")
+}
+
+GM.BannedProps = {
+ --"models/props_wasteland/kitchen_shelf001a.mdl"
+}
+
+GM.PropHealthMultipliers = {
+}
+
+GM.CleanupFilter = {
+ "zs_hands"
+}
+
+GM.AmmoNames = {}
+GM.AmmoNames["ar2"] = "5.56"
+GM.AmmoNames["pistol"] = "Pistol"
+GM.AmmoNames["smg1"] = "SMG"
+GM.AmmoNames["357"] = "Rifle"
+GM.AmmoNames["xbowbolt"] = "Bolts"
+GM.AmmoNames["buckshot"] = "Buckshot"
+GM.AmmoNames["sniperround"] = "Boards"
+GM.AmmoNames["grenade"] = "Grenades"
+GM.AmmoNames["thumper"] = "Turrets"
+GM.AmmoNames["battery"] = "Medical Supplies"
+GM.AmmoNames["gaussenergy"] = "Nails"
+GM.AmmoNames["airboatgun"] = "Arsenal Crates"
+GM.AmmoNames["striderminigun"] = "Beacons"
+GM.AmmoNames["slam"] = "Force Field Emitters"
+GM.AmmoNames["spotlamp"] = "Spot Lamps"
+GM.AmmoNames["stone"] = "Stones"
+GM.AmmoNames["pulse"] = "Pulse Shots"
+
+GM.AmmoTranslations = {}
+GM.AmmoTranslations["weapon_physcannon"] = "pistol"
+GM.AmmoTranslations["weapon_ar2"] = "ar2"
+GM.AmmoTranslations["weapon_shotgun"] = "buckshot"
+GM.AmmoTranslations["weapon_smg1"] = "smg1"
+GM.AmmoTranslations["weapon_pistol"] = "pistol"
+GM.AmmoTranslations["weapon_357"] = "357"
+GM.AmmoTranslations["weapon_slam"] = "pistol"
+GM.AmmoTranslations["weapon_crowbar"] = "pistol"
+GM.AmmoTranslations["weapon_stunstick"] = "pistol"
+
+GM.AmmoModels = {}
+GM.AmmoModels["pistol"] = "models/Items/BoxSRounds.mdl" -- Pistols
+GM.AmmoModels["smg1"] = "models/Items/BoxMRounds.mdl" -- SMGs
+GM.AmmoModels["ar2"] = "models/Items/357ammobox.mdl" -- Assault rifles
+GM.AmmoModels["battery"] = "models/healthvial.mdl" -- Medical Kit charge
+GM.AmmoModels["buckshot"] = "models/Items/BoxBuckshot.mdl" -- Buckshot
+GM.AmmoModels["357"] = "models/Items/357ammobox.mdl" -- Slugs
+GM.AmmoModels["xbowbolt"] = "models/Items/CrossbowRounds.mdl" -- Bolts
+GM.AmmoModels["gaussenergy"] = "models/Items/CrossbowRounds.mdl" -- Nails
+GM.AmmoModels["grenade"] = "models/weapons/w_grenade.mdl" -- Grenades
+GM.AmmoModels["thumper"] = "models/Combine_turrets/Floor_turret.mdl" -- Gun turrets
+GM.AmmoModels["airboatgun"] = "models/Items/item_item_crate.mdl" -- Arsenal crates
+GM.AmmoModels["striderminigun"] = "models/props_combine/combine_mine01.mdl" -- Message beacons
+GM.AmmoModels["helicoptergun"] = "models/Items/ammocrate_ar2.mdl" -- Resupply boxes
+GM.AmmoModels["slam"] = "models/props_lab/lab_flourescentlight002b.mdl" -- Force Field Emitters
+GM.AmmoModels["spotlamp"] = "models/props_combine/combine_light001a.mdl"
+GM.AmmoModels["stone"] = "models/props_junk/rock001a.mdl"
+GM.AmmoModels["pulse"] = "models/Items/combine_rifle_ammo01.mdl"
+
+-- Handled in languages file.
+GM.ValidBeaconMessages = {
+ "message_beacon_1",
+ "message_beacon_2",
+ "message_beacon_3",
+ "message_beacon_4",
+ "message_beacon_5",
+ "message_beacon_6",
+ "message_beacon_7",
+ "message_beacon_8",
+ "message_beacon_9",
+ "message_beacon_10",
+ "message_beacon_11",
+ "message_beacon_12",
+ "message_beacon_13",
+ "message_beacon_14",
+ "message_beacon_15",
+ "message_beacon_16",
+ "message_beacon_17",
+ "message_beacon_18",
+ "message_beacon_19",
+ "message_beacon_20",
+ "message_beacon_21",
+ "message_beacon_22",
+ "message_beacon_23",
+ "message_beacon_24",
+ "message_beacon_25"
+}
+
+GM.FanList = {
+ "1418945843",
+ "1595085577",
+ "3311458935",
+ "3023059541",
+ "2000875318",
+ "778584317",
+ "6086255",
+ "2867054481"
+}
diff --git a/gamemodes/zombiesurvival/gamemode/sh_options.lua b/gamemodes/zombiesurvival/gamemode/sh_options.lua
new file mode 100644
index 0000000..ab14084
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sh_options.lua
@@ -0,0 +1,393 @@
+GM.ZombieEscapeWeapons = {
+ "weapon_zs_zedeagle",
+ "weapon_zs_zeakbar",
+ "weapon_zs_zesweeper",
+ "weapon_zs_zesmg",
+ "weapon_zs_zestubber",
+ "weapon_zs_zebulletstorm"
+}
+
+-- Change this if you plan to alter the cost of items or you severely change how Worth works.
+-- Having separate cart files allows people to have separate loadouts for different servers.
+GM.CartFile = "zscarts.txt"
+
+ITEMCAT_GUNS = 1
+ITEMCAT_AMMO = 2
+ITEMCAT_MELEE = 3
+ITEMCAT_TOOLS = 4
+ITEMCAT_OTHER = 5
+ITEMCAT_TRAITS = 6
+ITEMCAT_RETURNS = 7
+
+GM.ItemCategories = {
+ [ITEMCAT_GUNS] = "Guns",
+ [ITEMCAT_AMMO] = "Ammunition",
+ [ITEMCAT_MELEE] = "Melee Weapons",
+ [ITEMCAT_TOOLS] = "Tools",
+ [ITEMCAT_OTHER] = "Other",
+ [ITEMCAT_TRAITS] = "Traits",
+ [ITEMCAT_RETURNS] = "Returns"
+}
+
+--[[
+Humans select what weapons (or other things) they want to start with and can even save favorites. Each object has a number of 'Worth' points.
+Signature is a unique signature to give in case the item is renamed or reordered. Don't use a number or a string number!
+A human can only use 100 points (default) when they join. Redeeming or joining late starts you out with a random loadout from above.
+SWEP is a swep given when the player spawns with that perk chosen.
+Callback is a function called. Model is a display model. If model isn't defined then the SWEP model will try to be used.
+swep, callback, and model can all be nil or empty
+]]
+GM.Items = {}
+function GM:AddItem(signature, name, desc, category, worth, swep, callback, model, worthshop, pointshop)
+ local tab = {Signature = signature, Name = name, Description = desc, Category = category, Worth = worth or 0, SWEP = swep, Callback = callback, Model = model, WorthShop = worthshop, PointShop = pointshop}
+ self.Items[#self.Items + 1] = tab
+
+ return tab
+end
+
+function GM:AddStartingItem(signature, name, desc, category, points, worth, callback, model)
+ return self:AddItem(signature, name, desc, category, points, worth, callback, model, true, false)
+end
+
+function GM:AddPointShopItem(signature, name, desc, category, points, worth, callback, model)
+ return self:AddItem("ps_"..signature, name, desc, category, points, worth, callback, model, false, true)
+end
+
+-- Weapons are registered after the gamemode.
+timer.Simple(0, function()
+ for _, tab in pairs(GAMEMODE.Items) do
+ if not tab.Description and tab.SWEP then
+ local sweptab = weapons.GetStored(tab.SWEP)
+ if sweptab then
+ tab.Description = sweptab.Description
+ end
+ end
+ end
+end)
+
+-- How much ammo is considered one 'clip' of ammo? For use with setting up weapon defaults. Works directly with zs_survivalclips
+GM.AmmoCache = {}
+GM.AmmoCache["ar2"] = 30 -- Assault rifles.
+GM.AmmoCache["alyxgun"] = 24 -- Not used.
+GM.AmmoCache["pistol"] = 12 -- Pistols.
+GM.AmmoCache["smg1"] = 30 -- SMG's and some rifles.
+GM.AmmoCache["357"] = 6 -- Rifles, especially of the sniper variety.
+GM.AmmoCache["xbowbolt"] = 4 -- Crossbows
+GM.AmmoCache["buckshot"] = 8 -- Shotguns
+GM.AmmoCache["ar2altfire"] = 1 -- Not used.
+GM.AmmoCache["slam"] = 1 -- Force Field Emitters.
+GM.AmmoCache["rpg_round"] = 1 -- Not used. Rockets?
+GM.AmmoCache["smg1_grenade"] = 1 -- Not used.
+GM.AmmoCache["sniperround"] = 1 -- Barricade Kit
+GM.AmmoCache["sniperpenetratedround"] = 1 -- Remote Det pack.
+GM.AmmoCache["grenade"] = 1 -- Grenades.
+GM.AmmoCache["thumper"] = 1 -- Gun turret.
+GM.AmmoCache["gravity"] = 1 -- Unused.
+GM.AmmoCache["battery"] = 30 -- Used with the Medical Kit.
+GM.AmmoCache["gaussenergy"] = 1 -- Nails used with the Carpenter's Hammer.
+GM.AmmoCache["combinecannon"] = 1 -- Not used.
+GM.AmmoCache["airboatgun"] = 1 -- Arsenal crates.
+GM.AmmoCache["striderminigun"] = 1 -- Message beacons.
+GM.AmmoCache["helicoptergun"] = 1 --Resupply boxes.
+GM.AmmoCache["spotlamp"] = 1
+GM.AmmoCache["manhack"] = 1
+GM.AmmoCache["pulse"] = 30
+
+-- These ammo types are available at ammunition boxes.
+-- The amount is the ammo to give them.
+-- If the player isn't holding a weapon that uses one of these then they will get smg1 ammo.
+GM.AmmoResupply = {}
+GM.AmmoResupply["ar2"] = 20
+GM.AmmoResupply["alyxgun"] = GM.AmmoCache["alyxgun"]
+GM.AmmoResupply["pistol"] = GM.AmmoCache["pistol"]
+GM.AmmoResupply["smg1"] = 20
+GM.AmmoResupply["357"] = GM.AmmoCache["357"]
+GM.AmmoResupply["xbowbolt"] = GM.AmmoCache["xbowbolt"]
+GM.AmmoResupply["buckshot"] = GM.AmmoCache["buckshot"]
+GM.AmmoResupply["battery"] = 20
+GM.AmmoResupply["pulse"] = GM.AmmoCache["pulse"]
+
+
+-----------
+-- Worth --
+-----------
+
+GM:AddStartingItem("pshtr", "'Peashooter' Handgun", nil, ITEMCAT_GUNS, 40, "weapon_zs_peashooter")
+GM:AddStartingItem("btlax", "'Battleaxe' Handgun", nil, ITEMCAT_GUNS, 40, "weapon_zs_battleaxe")
+GM:AddStartingItem("owens", "'Owens' Handgun", nil, ITEMCAT_GUNS, 40, "weapon_zs_owens")
+GM:AddStartingItem("blstr", "'Blaster' Shotgun", nil, ITEMCAT_GUNS, 55, "weapon_zs_blaster")
+GM:AddStartingItem("tossr", "'Tosser' SMG", nil, ITEMCAT_GUNS, 50, "weapon_zs_tosser")
+GM:AddStartingItem("stbbr", "'Stubber' Rifle", nil, ITEMCAT_GUNS, 55, "weapon_zs_stubber")
+GM:AddStartingItem("crklr", "'Crackler' Assault Rifle", nil, ITEMCAT_GUNS, 50, "weapon_zs_crackler")
+GM:AddStartingItem("z9000", "'Z9000' Pulse Pistol", nil, ITEMCAT_GUNS, 50, "weapon_zs_z9000")
+
+GM:AddStartingItem("2pcp", "3 pistol ammo boxes", nil, ITEMCAT_AMMO, 15, nil, function(pl) pl:GiveAmmo((GAMEMODE.AmmoCache["pistol"] or 12) * 3, "pistol", true) end, "models/Items/BoxSRounds.mdl")
+GM:AddStartingItem("2sgcp", "3 shotgun ammo boxes", nil, ITEMCAT_AMMO, 15, nil, function(pl) pl:GiveAmmo((GAMEMODE.AmmoCache["buckshot"] or 8) * 3, "buckshot", true) end, "models/Items/BoxBuckshot.mdl")
+GM:AddStartingItem("2smgcp", "3 SMG ammo boxes", nil, ITEMCAT_AMMO, 15, nil, function(pl) pl:GiveAmmo((GAMEMODE.AmmoCache["smg1"] or 30) * 3, "smg1", true) end, "models/Items/BoxMRounds.mdl")
+GM:AddStartingItem("2arcp", "3 assault rifle ammo boxes", nil, ITEMCAT_AMMO, 15, nil, function(pl) pl:GiveAmmo((GAMEMODE.AmmoCache["ar2"] or 30) * 3, "ar2", true) end, "models/Items/357ammobox.mdl")
+GM:AddStartingItem("2rcp", "3 rifle ammo boxes", nil, ITEMCAT_AMMO, 15, nil, function(pl) pl:GiveAmmo((GAMEMODE.AmmoCache["357"] or 6) * 3, "357", true) end, "models/Items/BoxSniperRounds.mdl")
+GM:AddStartingItem("2pls", "3 pulse ammo boxes", nil, ITEMCAT_AMMO, 20, nil, function(pl) pl:GiveAmmo((GAMEMODE.AmmoCache["pulse"] or 30) * 3, "pulse", true) end, "models/Items/combine_rifle_ammo01.mdl")
+GM:AddStartingItem("3pcp", "5 pistol ammo boxes", nil, ITEMCAT_AMMO, 20, nil, function(pl) pl:GiveAmmo((GAMEMODE.AmmoCache["pistol"] or 12) * 5, "pistol", true) end, "models/Items/BoxSRounds.mdl")
+GM:AddStartingItem("3sgcp", "5 shotgun ammo boxes", nil, ITEMCAT_AMMO, 20, nil, function(pl) pl:GiveAmmo((GAMEMODE.AmmoCache["buckshot"] or 8) * 5, "buckshot", true) end, "models/Items/BoxBuckshot.mdl")
+GM:AddStartingItem("3smgcp", "5 SMG ammo boxes", nil, ITEMCAT_AMMO, 20, nil, function(pl) pl:GiveAmmo((GAMEMODE.AmmoCache["smg1"] or 30) * 5, "smg1", true) end, "models/Items/BoxMRounds.mdl")
+GM:AddStartingItem("3arcp", "5 assault rifle ammo boxes", nil, ITEMCAT_AMMO, 20, nil, function(pl) pl:GiveAmmo((GAMEMODE.AmmoCache["ar2"] or 30) * 5, "ar2", true) end, "models/Items/357ammobox.mdl")
+GM:AddStartingItem("3rcp", "5 rifle ammo boxes", nil, ITEMCAT_AMMO, 20, nil, function(pl) pl:GiveAmmo((GAMEMODE.AmmoCache["357"] or 6) * 5, "357", true) end, "models/Items/BoxSniperRounds.mdl")
+GM:AddStartingItem("3pls", "5 pulse ammo boxes", nil, ITEMCAT_AMMO, 20, nil, function(pl) pl:GiveAmmo((GAMEMODE.AmmoCache["pulse"] or 30) * 5, "pulse", true) end, "models/Items/combine_rifle_ammo01.mdl")
+
+GM:AddStartingItem("zpaxe", "Axe", nil, ITEMCAT_MELEE, 30, "weapon_zs_axe")
+GM:AddStartingItem("crwbar", "Crowbar", nil, ITEMCAT_MELEE, 30, "weapon_zs_crowbar")
+GM:AddStartingItem("stnbtn", "Stun Baton", nil, ITEMCAT_MELEE, 45, "weapon_zs_stunbaton")
+GM:AddStartingItem("csknf", "Knife", nil, ITEMCAT_MELEE, 10, "weapon_zs_swissarmyknife")
+GM:AddStartingItem("zpplnk", "Plank", nil, ITEMCAT_MELEE, 10, "weapon_zs_plank")
+GM:AddStartingItem("zpfryp", "Frying Pan", nil, ITEMCAT_MELEE, 20, "weapon_zs_fryingpan")
+GM:AddStartingItem("zpcpot", "Cooking Pot", nil, ITEMCAT_MELEE, 20, "weapon_zs_pot")
+GM:AddStartingItem("pipe", "Lead Pipe", nil, ITEMCAT_MELEE, 45, "weapon_zs_pipe")
+GM:AddStartingItem("hook", "Meat Hook", nil, ITEMCAT_MELEE, 30, "weapon_zs_hook")
+
+GM:AddStartingItem("medkit", "Medical Kit", nil, ITEMCAT_TOOLS, 50, "weapon_zs_medicalkit")
+GM:AddStartingItem("medgun", "Medic Gun", nil, ITEMCAT_TOOLS, 45, "weapon_zs_medicgun")
+GM:AddStartingItem("150mkit", "150 Medical Kit power", "150 extra power for the Medical Kit.", ITEMCAT_TOOLS, 30, nil, function(pl) pl:GiveAmmo(150, "Battery", true) end, "models/healthvial.mdl")
+GM:AddStartingItem("arscrate", "Arsenal Crate", nil, ITEMCAT_TOOLS, 50, "weapon_zs_arsenalcrate").Countables = "prop_arsenalcrate"
+GM:AddStartingItem("resupplybox", "Resupply Box", nil, ITEMCAT_TOOLS, 70, "weapon_zs_resupplybox").Countables = "prop_resupplybox"
+local item = GM:AddStartingItem("infturret", "Infrared Gun Turret", nil, ITEMCAT_TOOLS, 75, "weapon_zs_gunturret")
+item.Countables = "prop_gunturret"
+item.NoClassicMode = true
+local item = GM:AddStartingItem("manhack", "Manhack", nil, ITEMCAT_TOOLS, 60, "weapon_zs_manhack")
+item.Countables = "prop_manhack"
+GM:AddStartingItem("wrench", "Mechanic's Wrench", nil, ITEMCAT_TOOLS, 15, "weapon_zs_wrench").NoClassicMode = true
+GM:AddStartingItem("crphmr", "Carpenter's Hammer", nil, ITEMCAT_TOOLS, 45, "weapon_zs_hammer").NoClassicMode = true
+GM:AddStartingItem("6nails", "Box of 12 nails", "An extra box of nails for all your barricading needs.", ITEMCAT_TOOLS, 25, nil, function(pl) pl:GiveAmmo(6, "GaussEnergy", true) end, "models/Items/BoxMRounds.mdl")
+GM:AddStartingItem("junkpack", "Junk Pack", nil, ITEMCAT_TOOLS, 40, "weapon_zs_boardpack")
+GM:AddStartingItem("spotlamp", "Spot Lamp", nil, ITEMCAT_TOOLS, 25, "weapon_zs_spotlamp").Countables = "prop_spotlamp"
+GM:AddStartingItem("msgbeacon", "Message Beacon", nil, ITEMCAT_TOOLS, 10, "weapon_zs_messagebeacon").Countables = "prop_messagebeacon"
+--GM:AddStartingItem("ffemitter", "Force Field Emitter", nil, ITEMCAT_TOOLS, 60, "weapon_zs_ffemitter").Countables = "prop_ffemitter"
+
+GM:AddStartingItem("stone", "Stone", nil, ITEMCAT_OTHER, 5, "weapon_zs_stone")
+GM:AddStartingItem("grenade", "Grenade", nil, ITEMCAT_OTHER, 30, "weapon_zs_grenade")
+GM:AddStartingItem("detpck", "Detonation Pack", nil, ITEMCAT_OTHER, 35, "weapon_zs_detpack").Countables = "prop_detpack"
+GM:AddStartingItem("oxtank", "Oxygen Tank", "Grants signitifantly more underwater breathing time to the user.", ITEMCAT_OTHER, 15, "weapon_zs_oxygentank")
+
+GM:AddStartingItem("10hp", "Fit", "Increases survivability by increasing maximum health by a small amount.", ITEMCAT_TRAITS, 10, nil, function(pl) pl:SetMaxHealth(pl:GetMaxHealth() + 10) pl:SetHealth(pl:Health() + 10) end, "models/healthvial.mdl")
+GM:AddStartingItem("25hp", "Tough", "Increases survivability by increasing maximum health.", ITEMCAT_TRAITS, 20, nil, function(pl) pl:SetMaxHealth(pl:GetMaxHealth() + 25) pl:SetHealth(pl:Health() + 25) end, "models/items/healthkit.mdl")
+local item = GM:AddStartingItem("5spd", "Quick", "Gives a slight bonus to running speed.", ITEMCAT_TRAITS, 10, nil, function(pl) pl.HumanSpeedAdder = (pl.HumanSpeedAdder or 0) + 7 pl:ResetSpeed() end, "models/props_lab/jar01a.mdl")
+item.NoClassicMode = true
+item.NoZombieEscape = true
+local item = GM:AddStartingItem("10spd", "Surged", "Gives a noticeable bonus to running speed.", ITEMCAT_TRAITS, 15, nil, function(pl) pl.HumanSpeedAdder = (pl.HumanSpeedAdder or 0) + 14 pl:ResetSpeed() end, "models/props_lab/jar01a.mdl")
+item.NoClassicMode = true
+item.NoZombieEscape = true
+GM:AddStartingItem("bfhandy", "Handy", "Gives a 25% bonus to all repair rates.", ITEMCAT_TRAITS, 25, nil, function(pl) pl.HumanRepairMultiplier = (pl.HumanRepairMultiplier or 1) + 0.25 end, "models/props_c17/tools_wrench01a.mdl")
+GM:AddStartingItem("bfsurgeon", "Surgeon", "Increases the rate by which you can heal yourself and others with the Medical Kit by 30%. Increases Medic Gun effectiveness by 33%.", ITEMCAT_TRAITS, 25, nil, function(pl) pl.HumanHealMultiplier = (pl.HumanHealMultiplier or 1) + 0.3 end, "models/healthvial.mdl")
+GM:AddStartingItem("bfresist", "Resistant", "You will take half damage from poison.", ITEMCAT_TRAITS, 25, nil, function(pl) pl.BuffResistant = true end, "models/healthvial.mdl")
+GM:AddStartingItem("bfregen", "Regenerative", "If you drop below 50% health, you will regenerate 1 health every 6 seconds.", ITEMCAT_TRAITS, 25, nil, function(pl) pl.BuffRegenerative = true end, "models/healthvial.mdl")
+GM:AddStartingItem("bfmusc", "Muscular", "You do 20% extra damage with melee weapons and you can carry heavy objects instead of dragging them.", ITEMCAT_TRAITS, 25, nil, function(pl) pl.BuffMuscular = true pl:DoMuscularBones() end, "models/props_wasteland/kitchen_shelf001a.mdl")
+
+GM:AddStartingItem("dbfweak", "Weakness", "Reduces health by 30 in exchange for Worth.", ITEMCAT_RETURNS, -15, nil, function(pl) pl:SetMaxHealth(math.max(1, pl:GetMaxHealth() - 30)) pl:SetHealth(pl:GetMaxHealth()) pl.IsWeak = true end, "models/gibs/HGIBS.mdl")
+GM:AddStartingItem("dbfslow", "Slowness", "Reduces speed by a significant amount in exchange for Worth.", ITEMCAT_RETURNS, -5, nil, function(pl) pl.HumanSpeedAdder = (pl.HumanSpeedAdder or 1) - 20 pl:ResetSpeed() pl.IsSlow = true end, "models/gibs/HGIBS.mdl")
+GM:AddStartingItem("dbfpalsy", "Palsy", "Reduces aiming ability while hurt in exchange for Worth.", ITEMCAT_RETURNS, -5, nil, function(pl) pl:SetPalsy(true) end, "models/gibs/HGIBS.mdl")
+GM:AddStartingItem("dbfhemo", "Hemophilia", "Applies bleeding damage when hit in exchange for Worth.", ITEMCAT_RETURNS, -15, nil, function(pl) pl:SetHemophilia(true) end, "models/gibs/HGIBS.mdl")
+GM:AddStartingItem("dbfunluc", "Banned for Life", "Disallows point purchases in exchange for Worth.", ITEMCAT_RETURNS, -25, nil, function(pl) pl:SetUnlucky(true) end, "models/gibs/HGIBS.mdl")
+GM:AddStartingItem("dbfclumsy", "Clumsy", "Makes you extremely easy to knock down in exchange for Worth.", ITEMCAT_RETURNS, -25, nil, function(pl) pl.Clumsy = true end, "models/gibs/HGIBS.mdl")
+GM:AddStartingItem("dbfnoghosting", "Wide Load", "Prevents you from ghosting through props in exchange for Worth.", ITEMCAT_RETURNS, -20, nil, function(pl) pl.NoGhosting = true end, "models/gibs/HGIBS.mdl").NoClassicMode = true
+GM:AddStartingItem("dbfnopickup", "Noodle Arms", "Disallows picking up of objects in exchange for Worth.", ITEMCAT_RETURNS, -10, nil, function(pl) pl.NoObjectPickup = true pl:DoNoodleArmBones() end, "models/gibs/HGIBS.mdl")
+
+------------
+-- Points --
+------------
+
+GM:AddPointShopItem("deagle", "'Zombie Drill' Desert Eagle", nil, ITEMCAT_GUNS, 30, "weapon_zs_deagle")
+GM:AddPointShopItem("glock3", "'Crossfire' Glock 3", nil, ITEMCAT_GUNS, 30, "weapon_zs_glock3")
+GM:AddPointShopItem("magnum", "'Ricochet' Magnum", nil, ITEMCAT_GUNS, 35, "weapon_zs_magnum")
+GM:AddPointShopItem("eraser", "'Eraser' Tactical Pistol", nil, ITEMCAT_GUNS, 35, "weapon_zs_eraser")
+
+GM:AddPointShopItem("uzi", "'Sprayer' Uzi 9mm", nil, ITEMCAT_GUNS, 70, "weapon_zs_uzi")
+GM:AddPointShopItem("shredder", "'Shredder' SMG", nil, ITEMCAT_GUNS, 70, "weapon_zs_smg")
+GM:AddPointShopItem("bulletstorm", "'Bullet Storm' SMG", nil, ITEMCAT_GUNS, 70, "weapon_zs_bulletstorm")
+GM:AddPointShopItem("silencer", "'Silencer' SMG", nil, ITEMCAT_GUNS, 70, "weapon_zs_silencer")
+GM:AddPointShopItem("hunter", "'Hunter' Rifle", nil, ITEMCAT_GUNS, 70, "weapon_zs_hunter")
+
+GM:AddPointShopItem("reaper", "'Reaper' UMP", nil, ITEMCAT_GUNS, 80, "weapon_zs_reaper")
+GM:AddPointShopItem("ender", "'Ender' Automatic Shotgun", nil, ITEMCAT_GUNS, 75, "weapon_zs_ender")
+GM:AddPointShopItem("akbar", "'Akbar' Assault Rifle", nil, ITEMCAT_GUNS, 80, "weapon_zs_akbar")
+
+GM:AddPointShopItem("stalker", "'Stalker' Assault Rifle", nil, ITEMCAT_GUNS, 125, "weapon_zs_m4")
+GM:AddPointShopItem("inferno", "'Inferno' Assault Rifle", nil, ITEMCAT_GUNS, 125, "weapon_zs_inferno")
+GM:AddPointShopItem("annabelle", "'Annabelle' Rifle", nil, ITEMCAT_GUNS, 100, "weapon_zs_annabelle")
+
+GM:AddPointShopItem("crossbow", "'Impaler' Crossbow", nil, ITEMCAT_GUNS, 175, "weapon_zs_crossbow")
+
+GM:AddPointShopItem("sweeper", "'Sweeper' Shotgun", nil, ITEMCAT_GUNS, 200, "weapon_zs_sweepershotgun")
+GM:AddPointShopItem("boomstick", "Boom Stick", nil, ITEMCAT_GUNS, 200, "weapon_zs_boomstick")
+GM:AddPointShopItem("slugrifle", "'Tiny' Slug Rifle", nil, ITEMCAT_GUNS, 200, "weapon_zs_slugrifle")
+GM:AddPointShopItem("pulserifle", "'Adonis' Pulse Rifle", nil, ITEMCAT_GUNS, 225, "weapon_zs_pulserifle")
+
+GM:AddPointShopItem("pistolammo", "pistol ammo box", nil, ITEMCAT_AMMO, 6, nil, function(pl) pl:GiveAmmo(GAMEMODE.AmmoCache["pistol"] or 12, "pistol", true) end, "models/Items/BoxSRounds.mdl")
+GM:AddPointShopItem("shotgunammo", "shotgun ammo box", nil, ITEMCAT_AMMO, 7, nil, function(pl) pl:GiveAmmo(GAMEMODE.AmmoCache["buckshot"] or 8, "buckshot", true) end, "models/Items/BoxBuckshot.mdl")
+GM:AddPointShopItem("smgammo", "SMG ammo box", nil, ITEMCAT_AMMO, 7, nil, function(pl) pl:GiveAmmo(GAMEMODE.AmmoCache["smg1"] or 30, "smg1", true) end, "models/Items/BoxMRounds.mdl")
+GM:AddPointShopItem("assaultrifleammo", "assault rifle ammo box", nil, ITEMCAT_AMMO, 7, nil, function(pl) pl:GiveAmmo(GAMEMODE.AmmoCache["ar2"] or 30, "ar2", true) end, "models/Items/357ammobox.mdl")
+GM:AddPointShopItem("rifleammo", "rifle ammo box", nil, ITEMCAT_AMMO, 7, nil, function(pl) pl:GiveAmmo(GAMEMODE.AmmoCache["357"] or 6, "357", true) end, "models/Items/BoxSniperRounds.mdl")
+GM:AddPointShopItem("crossbowammo", "crossbow bolt", nil, ITEMCAT_AMMO, 5, nil, function(pl) pl:GiveAmmo(1, "XBowBolt", true) end, "models/Items/CrossbowRounds.mdl")
+GM:AddPointShopItem("pulseammo", "pulse ammo box", nil, ITEMCAT_AMMO, 7, nil, function(pl) pl:GiveAmmo(GAMEMODE.AmmoCache["pulse"] or 30, "pulse", true) end, "models/Items/combine_rifle_ammo01.mdl")
+
+GM:AddPointShopItem("axe", "Axe", nil, ITEMCAT_MELEE, 20, "weapon_zs_axe")
+GM:AddPointShopItem("crowbar", "Crowbar", nil, ITEMCAT_MELEE, 20, "weapon_zs_crowbar")
+GM:AddPointShopItem("stunbaton", "Stun Baton", nil, ITEMCAT_MELEE, 25, "weapon_zs_stunbaton")
+GM:AddPointShopItem("knife", "Knife", nil, ITEMCAT_MELEE, 5, "weapon_zs_swissarmyknife")
+GM:AddPointShopItem("shovel", "Shovel", nil, ITEMCAT_MELEE, 30, "weapon_zs_shovel")
+GM:AddPointShopItem("sledgehammer", "Sledge Hammer", nil, ITEMCAT_MELEE, 30, "weapon_zs_sledgehammer")
+
+GM:AddPointShopItem("crphmr", "Carpenter's Hammer", nil, ITEMCAT_TOOLS, 50, "weapon_zs_hammer").NoClassicMode = true
+GM:AddPointShopItem("wrench", "Mechanic's Wrench", nil, ITEMCAT_TOOLS, 25, "weapon_zs_wrench").NoClassicMode = true
+GM:AddPointShopItem("arsenalcrate", "Arsenal Crate", nil, ITEMCAT_TOOLS, 50, "weapon_zs_arsenalcrate")
+GM:AddPointShopItem("resupplybox", "Resupply Box", nil, ITEMCAT_TOOLS, 200, "weapon_zs_resupplybox")
+GM:AddPointShopItem("infturret", "Infrared Gun Turret", nil, ITEMCAT_TOOLS, 50, "weapon_zs_gunturret").NoClassicMode = true
+GM:AddPointShopItem("manhack", "Manhack", nil, ITEMCAT_TOOLS, 45, "weapon_zs_manhack")
+GM:AddPointShopItem("barricadekit", "'Aegis' Barricade Kit", nil, ITEMCAT_TOOLS, 125, "weapon_zs_barricadekit")
+GM:AddPointShopItem("nail", "Nail", "It's just one nail.", ITEMCAT_TOOLS, 5, nil, function(pl) pl:GiveAmmo(1, "GaussEnergy", true) end, "models/crossbow_bolt.mdl").NoClassicMode = true
+GM:AddPointShopItem("50mkit", "50 Medical Kit power", "50 extra power for the Medical Kit.", ITEMCAT_TOOLS, 30, nil, function(pl) pl:GiveAmmo(50, "Battery", true) end, "models/healthvial.mdl")
+
+GM:AddPointShopItem("grenade", "Grenade", nil, ITEMCAT_OTHER, 60, "weapon_zs_grenade")
+GM:AddPointShopItem("detpck", "Detonation Pack", nil, ITEMCAT_OTHER, 70, "weapon_zs_detpack")
+
+
+-- These are the honorable mentions that come at the end of the round.
+
+local function genericcallback(pl, magnitude) return pl:Name(), magnitude end
+GM.HonorableMentions = {}
+GM.HonorableMentions[HM_MOSTZOMBIESKILLED] = {Name = "Most zombies killed", String = "by %s, with %d killed zombies.", Callback = genericcallback, Color = COLOR_CYAN}
+GM.HonorableMentions[HM_MOSTDAMAGETOUNDEAD] = {Name = "Most damage to undead", String = "goes to %s, with a total of %d damage dealt to the undead.", Callback = genericcallback, Color = COLOR_CYAN}
+GM.HonorableMentions[HM_PACIFIST] = {Name = "Pacifist", String = "goes to %s for not killing a single zombie and still surviving!", Callback = genericcallback, Color = COLOR_CYAN}
+GM.HonorableMentions[HM_MOSTHELPFUL] = {Name = "Most helpful", String = "goes to %s for assisting in the disposal of %d zombies.", Callback = genericcallback, Color = COLOR_CYAN}
+GM.HonorableMentions[HM_LASTHUMAN] = {Name = "Last Human", String = "goes to %s for being the last person alive.", Callback = genericcallback, Color = COLOR_CYAN}
+GM.HonorableMentions[HM_OUTLANDER] = {Name = "Outlander", String = "goes to %s for getting killed %d feet away from a zombie spawn.", Callback = genericcallback, Color = COLOR_CYAN}
+GM.HonorableMentions[HM_GOODDOCTOR] = {Name = "Good Doctor", String = "goes to %s for healing their team for %d points of health.", Callback = genericcallback, Color = COLOR_CYAN}
+GM.HonorableMentions[HM_HANDYMAN] = {Name = "Handy Man", String = "goes to %s for getting %d barricade assistance points.", Callback = genericcallback, Color = COLOR_CYAN}
+GM.HonorableMentions[HM_SCARECROW] = {Name = "Scarecrow", String = "goes to %s for killing %d poor crows.", Callback = genericcallback, Color = COLOR_WHITE}
+GM.HonorableMentions[HM_MOSTBRAINSEATEN] = {Name = "Most brains eaten", String = "by %s, with %d brains eaten.", Callback = genericcallback, Color = COLOR_LIMEGREEN}
+GM.HonorableMentions[HM_MOSTDAMAGETOHUMANS] = {Name = "Most damage to humans", String = "goes to %s, with a total of %d damage given to living players.", Callback = genericcallback, Color = COLOR_LIMEGREEN}
+GM.HonorableMentions[HM_LASTBITE] = {Name = "Last Bite", String = "goes to %s for ending the round.", Callback = genericcallback, Color = COLOR_LIMEGREEN}
+GM.HonorableMentions[HM_USEFULTOOPPOSITE] = {Name = "Most useful to opposite team", String = "goes to %s for giving up a whopping %d kills!", Callback = genericcallback, Color = COLOR_RED}
+GM.HonorableMentions[HM_STUPID] = {Name = "Stupid", String = "is what %s is for getting killed %d feet away from a zombie spawn.", Callback = genericcallback, Color = COLOR_RED}
+GM.HonorableMentions[HM_SALESMAN] = {Name = "Salesman", String = "is what %s is for having %d points worth of items taken from their arsenal crate.", Callback = genericcallback, Color = COLOR_CYAN}
+GM.HonorableMentions[HM_WAREHOUSE] = {Name = "Warehouse", String = "describes %s well since they had their resupply boxes used %d times.", Callback = genericcallback, Color = COLOR_CYAN}
+GM.HonorableMentions[HM_SPAWNPOINT] = {Name = "Spawn Point", String = "goes to %s for having %d zombies spawn on them.", Callback = genericcallback, Color = COLOR_LIMEGREEN}
+GM.HonorableMentions[HM_CROWFIGHTER] = {Name = "Crow Fighter", String = "goes to %s for annihilating %d of his crow brethren.", Callback = genericcallback, Color = COLOR_WHITE}
+GM.HonorableMentions[HM_CROWBARRICADEDAMAGE] = {Name = "Minor Annoyance", String = "is what %s is for dealing %d damage to barricades while a crow.", Callback = genericcallback, Color = COLOR_LIMEGREEN}
+GM.HonorableMentions[HM_BARRICADEDESTROYER] = {Name = "Barricade Destroyer", String = "goes to %s for doing %d damage to barricades.", Callback = genericcallback, Color = COLOR_LIMEGREEN}
+GM.HonorableMentions[HM_NESTDESTROYER] = {Name = "Nest Destroyer", String = "goes to %s for destroying %d nests.", Callback = genericcallback, Color = COLOR_LIMEGREEN}
+GM.HonorableMentions[HM_NESTMASTER] = {Name = "Nest Master", String = "goes to %s for having %d zombies spawn through their nest.", Callback = genericcallback, Color = COLOR_LIMEGREEN}
+
+-- Don't let humans use these models because they look like undead models. Must be lower case.
+GM.RestrictedModels = {
+ "models/player/zombie_classic.mdl",
+ "models/player/zombine.mdl",
+ "models/player/zombie_soldier.mdl",
+ "models/player/zombie_fast.mdl",
+ "models/player/corpse1.mdl",
+ "models/player/charple.mdl",
+ "models/player/skeleton.mdl"
+}
+
+-- If a person has no player model then use one of these (auto-generated).
+GM.RandomPlayerModels = {}
+for name, mdl in pairs(player_manager.AllValidModels()) do
+ if not table.HasValue(GM.RestrictedModels, string.lower(mdl)) then
+ table.insert(GM.RandomPlayerModels, name)
+ end
+end
+
+-- Utility function to setup a weapon's DefaultClip.
+function GM:SetupDefaultClip(tab)
+ tab.DefaultClip = math.ceil(tab.ClipSize * self.SurvivalClips * (tab.ClipMultiplier or 1))
+end
+
+GM.MaxSigils = CreateConVar("zs_maxsigils", "3", FCVAR_ARCHIVE + FCVAR_NOTIFY, "How many sigils to spawn. 0 for none."):GetInt()
+cvars.AddChangeCallback("zs_maxsigils", function(cvar, oldvalue, newvalue)
+ GAMEMODE.MaxSigils = math.Clamp(tonumber(newvalue) or 0, 0, 10)
+end)
+
+GM.DefaultRedeem = CreateConVar("zs_redeem", "4", FCVAR_REPLICATED + FCVAR_ARCHIVE + FCVAR_NOTIFY, "The amount of kills a zombie needs to do in order to redeem. Set to 0 to disable."):GetInt()
+cvars.AddChangeCallback("zs_redeem", function(cvar, oldvalue, newvalue)
+ GAMEMODE.DefaultRedeem = math.max(0, tonumber(newvalue) or 0)
+end)
+
+GM.WaveOneZombies = math.ceil(100 * CreateConVar("zs_waveonezombies", "0.1", FCVAR_REPLICATED + FCVAR_ARCHIVE + FCVAR_NOTIFY, "The percentage of players that will start as zombies when the game begins."):GetFloat()) * 0.01
+cvars.AddChangeCallback("zs_waveonezombies", function(cvar, oldvalue, newvalue)
+ GAMEMODE.WaveOneZombies = math.ceil(100 * (tonumber(newvalue) or 1)) * 0.01
+end)
+
+GM.NumberOfWaves = CreateConVar("zs_numberofwaves", "6", FCVAR_REPLICATED + FCVAR_ARCHIVE + FCVAR_NOTIFY, "Number of waves in a game."):GetInt()
+cvars.AddChangeCallback("zs_numberofwaves", function(cvar, oldvalue, newvalue)
+ GAMEMODE.NumberOfWaves = tonumber(newvalue) or 1
+end)
+
+-- Game feeling too easy? Just change these values!
+GM.ZombieSpeedMultiplier = math.ceil(100 * CreateConVar("zs_zombiespeedmultiplier", "1", FCVAR_REPLICATED + FCVAR_ARCHIVE + FCVAR_NOTIFY, "Zombie running speed will be scaled by this value."):GetFloat()) * 0.01
+cvars.AddChangeCallback("zs_zombiespeedmultiplier", function(cvar, oldvalue, newvalue)
+ GAMEMODE.ZombieSpeedMultiplier = math.ceil(100 * (tonumber(newvalue) or 1)) * 0.01
+end)
+
+-- This is a resistance, not for claw damage. 0.5 will make zombies take half damage, 0.25 makes them take 1/4, etc.
+GM.ZombieDamageMultiplier = math.ceil(100 * CreateConVar("zs_zombiedamagemultiplier", "1", FCVAR_REPLICATED + FCVAR_ARCHIVE + FCVAR_NOTIFY, "Scales the amount of damage that zombies take. Use higher values for easy zombies, lower for harder."):GetFloat()) * 0.01
+cvars.AddChangeCallback("zs_zombiedamagemultiplier", function(cvar, oldvalue, newvalue)
+ GAMEMODE.ZombieDamageMultiplier = math.ceil(100 * (tonumber(newvalue) or 1)) * 0.01
+end)
+
+GM.TimeLimit = CreateConVar("zs_timelimit", "15", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Time in minutes before the game will change maps. It will not change maps if a round is currently in progress but after the current round ends. -1 means never switch maps. 0 means always switch maps."):GetInt() * 60
+cvars.AddChangeCallback("zs_timelimit", function(cvar, oldvalue, newvalue)
+ GAMEMODE.TimeLimit = tonumber(newvalue) or 15
+ if GAMEMODE.TimeLimit ~= -1 then
+ GAMEMODE.TimeLimit = GAMEMODE.TimeLimit * 60
+ end
+end)
+
+GM.RoundLimit = CreateConVar("zs_roundlimit", "3", FCVAR_ARCHIVE + FCVAR_NOTIFY, "How many times the game can be played on the same map. -1 means infinite or only use time limit. 0 means once."):GetInt()
+cvars.AddChangeCallback("zs_roundlimit", function(cvar, oldvalue, newvalue)
+ GAMEMODE.RoundLimit = tonumber(newvalue) or 3
+end)
+
+-- Static values that don't need convars...
+
+-- Initial length for wave 1.
+GM.WaveOneLength = 220
+
+-- For Classic Mode
+GM.WaveOneLengthClassic = 120
+
+-- Add this many seconds for each additional wave.
+GM.TimeAddedPerWave = 15
+
+-- For Classic Mode
+GM.TimeAddedPerWaveClassic = 10
+
+-- New players are put on the zombie team if the current wave is this or higher. Do not put it lower than 1 or you'll break the game.
+GM.NoNewHumansWave = 2
+
+-- Humans can not commit suicide if the current wave is this or lower.
+GM.NoSuicideWave = 1
+
+-- How long 'wave 0' should last in seconds. This is the time you should give for new players to join and get ready.
+GM.WaveZeroLength = 150
+
+-- Time humans have between waves to do stuff without NEW zombies spawning. Any dead zombies will be in spectator (crow) view and any living ones will still be living.
+GM.WaveIntermissionLength = 90
+
+-- For Classic Mode
+GM.WaveIntermissionLengthClassic = 20
+
+-- Time in seconds between end round and next map.
+GM.EndGameTime = 60
+
+-- How many clips of ammo guns from the Worth menu start with. Some guns such as shotguns and sniper rifles have multipliers on this.
+GM.SurvivalClips = 2
+
+-- Put your unoriginal, 5MB Rob Zombie and Metallica music here.
+GM.LastHumanSound = Sound("zombiesurvival/lasthuman.ogg")
+
+-- Sound played when humans all die.
+GM.AllLoseSound = Sound("zombiesurvival/music_lose.ogg")
+
+-- Sound played when humans survive.
+GM.HumanWinSound = Sound("zombiesurvival/music_win.ogg")
+
+-- Sound played to a person when they die as a human.
+GM.DeathSound = Sound("music/stingers/HL1_stinger_song28.mp3")
diff --git a/gamemodes/zombiesurvival/gamemode/sh_serialization.lua b/gamemodes/zombiesurvival/gamemode/sh_serialization.lua
new file mode 100644
index 0000000..984cfce
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sh_serialization.lua
@@ -0,0 +1,86 @@
+function Deserialize(sIn)
+ SRL = nil
+
+ if #sIn == 0 then return {} end
+
+ if string.sub(sIn, 1, 4) ~= "SRL=" then sIn = "SRL="..sIn end RunString(sIn)
+
+ return SRL
+end
+
+local allowedtypes = {}
+allowedtypes["string"] = true
+allowedtypes["number"] = true
+allowedtypes["table"] = true
+allowedtypes["Vector"] = true
+allowedtypes["Angle"] = true
+allowedtypes["boolean"] = true
+local function MakeTable(tab, done)
+ local str = ""
+ local done = done or {}
+
+ local sequential = table.IsSequential(tab)
+
+ for key, value in pairs(tab) do
+ local keytype = type(key)
+ local valuetype = type(value)
+
+ if allowedtypes[keytype] and allowedtypes[valuetype] then
+ if sequential then
+ key = ""
+ else
+ if keytype == "number" or keytype == "boolean" then
+ key ="["..tostring(key).."]="
+ else
+ key = "["..string.format("%q", tostring(key)).."]="
+ end
+ end
+
+ if valuetype == "table" and not done[value] then
+ done[value] = true
+ if type(value._serialize) == "function" then
+ str = str..key..value:_serialize()..","
+ else
+ str = str..key.."{"..MakeTable(value, done).."},"
+ end
+ else
+ if valuetype == "string" then
+ value = string.format("%q", value)
+ elseif valuetype == "Vector" then
+ value = "Vector("..value.x..","..value.y..","..value.z..")"
+ elseif valuetype == "Angle" then
+ value = "Angle("..value.pitch..","..value.yaw..","..value.roll..")"
+ else
+ value = tostring(value)
+ end
+
+ str = str .. key .. value .. ","
+ end
+ end
+ end
+
+ if string.sub(str, -1) == "," then
+ return string.sub(str, 1, #str - 1)
+ else
+ return str
+ end
+end
+
+function Serialize(tIn, bRaw)
+ if #tIn == 0 then
+ local empty = true
+ for k in pairs(tIn) do
+ empty = false
+ break
+ end
+ if empty then
+ return ""
+ end
+ end
+
+ if bRaw then
+ return "{"..MakeTable(tIn).."}"
+ end
+
+ return "SRL={"..MakeTable(tIn).."}"
+end
diff --git a/gamemodes/zombiesurvival/gamemode/sh_sigils.lua b/gamemodes/zombiesurvival/gamemode/sh_sigils.lua
new file mode 100644
index 0000000..89a51c9
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sh_sigils.lua
@@ -0,0 +1,37 @@
+ESCAPESTAGE_NONE = 0
+ESCAPESTAGE_ESCAPE = 1
+ESCAPESTAGE_BOSS = 2
+ESCAPESTAGE_DEATH = 3
+
+function GM:GetSigils()
+ local sigils = {}
+
+ for _, ent in pairs(ents.FindByClass("prop_obj_sigil")) do
+ if ent:GetSigilHealthBase() ~= 0 then
+ sigils[#sigils + 1] = ent
+ end
+ end
+
+ return sigils
+end
+
+function GM:NumSigils()
+ return #self:GetSigils()
+end
+
+function GM:GetUseSigils(use)
+ return GetGlobalBool("sigils", false)
+end
+
+function GM:GetEscapeSequence()
+ return self:GetUseSigils() and self:GetEscapeStage() ~= ESCAPESTAGE_NONE
+end
+GM.IsEscapeSequence = GM.GetEscapeSequence
+
+function GM:SetEscapeStage(stage)
+ SetGlobalInt("esstg", stage)
+end
+
+function GM:GetEscapeStage()
+ return GetGlobalInt("esstg", ESCAPESTAGE_NONE)
+end
diff --git a/gamemodes/zombiesurvival/gamemode/sh_translate.lua b/gamemodes/zombiesurvival/gamemode/sh_translate.lua
new file mode 100644
index 0000000..adfe236
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sh_translate.lua
@@ -0,0 +1,104 @@
+-- Translation library by William Moodhe
+-- Feel free to use this in your own addons.
+-- See the languages folder to add your own languages.
+
+translate = {}
+
+local Languages = {}
+local Translations = {}
+local AddingLanguage
+local DefaultLanguage = "en"
+local CurrentLanguage = DefaultLanguage
+
+if CLIENT then
+ -- Need to make a new convar since gmod_language isn't sent to server.
+ CreateClientConVar("gmod_language_rep", "en", false, true)
+
+ timer.Create("checklanguagechange", 1, 0, function()
+ CurrentLanguage = GetConVarString("gmod_language")
+ if CurrentLanguage ~= GetConVarString("gmod_language_rep") then
+ -- Let server know our language changed.
+ RunConsoleCommand("gmod_language_rep", CurrentLanguage)
+ end
+ end)
+end
+
+function translate.GetLanguages()
+ return Languages
+end
+
+function translate.GetLanguageName(short)
+ return Languages[short]
+end
+
+function translate.GetTranslations(short)
+ return Translations[short] or Translations[DefaultLanguage]
+end
+
+function translate.AddLanguage(short, long)
+ Languages[short] = long
+ Translations[short] = Translations[short] or {}
+ AddingLanguage = short
+end
+
+function translate.AddTranslation(id, text)
+ if not AddingLanguage or not Translations[AddingLanguage] then return end
+
+ Translations[AddingLanguage][id] = text
+end
+
+function translate.Get(id)
+ return translate.GetTranslations(CurrentLanguage)[id] or translate.GetTranslations(DefaultLanguage)[id] or ("@"..id.."@")
+end
+
+function translate.Format(id, ...)
+ return string.format(translate.Get(id), ...)
+end
+
+if SERVER then
+ function translate.ClientGet(pl, ...)
+ CurrentLanguage = pl:GetInfo("gmod_language_rep")
+ return translate.Get(...)
+ end
+
+ function translate.ClientFormat(pl, ...)
+ CurrentLanguage = pl:GetInfo("gmod_language_rep")
+ return translate.Format(...)
+ end
+
+ function PrintTranslatedMessage(printtype, str, ...)
+ for _, pl in pairs(player.GetAll()) do
+ pl:PrintMessage(printtype, translate.ClientFormat(pl, str, ...))
+ end
+ end
+end
+
+if CLIENT then
+ function translate.ClientGet(_, ...)
+ return translate.Get(...)
+ end
+ function translate.ClientFormat(_, ...)
+ return translate.Format(...)
+ end
+end
+
+for i, filename in pairs(file.Find(GM.FolderName.."/gamemode/languages/*.lua", "LUA")) do
+ LANGUAGE = {}
+ AddCSLuaFile("languages/"..filename)
+ include("languages/"..filename)
+ for k, v in pairs(LANGUAGE) do
+ translate.AddTranslation(k, v)
+ end
+ LANGUAGE = nil
+end
+
+local meta = FindMetaTable("Player")
+if not meta then return end
+
+function meta:PrintTranslatedMessage(hudprinttype, translateid, ...)
+ if ... ~= nil then
+ self:PrintMessage(hudprinttype, translate.ClientFormat(self, translateid, ...))
+ else
+ self:PrintMessage(hudprinttype, translate.ClientGet(self, translateid))
+ end
+end
diff --git a/gamemodes/zombiesurvival/gamemode/sh_util.lua b/gamemodes/zombiesurvival/gamemode/sh_util.lua
new file mode 100644
index 0000000..59025d0
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sh_util.lua
@@ -0,0 +1,242 @@
+function FindStartingItem(id)
+ if not id then return end
+
+ local t
+
+ local num = tonumber(id)
+ if num then
+ t = GAMEMODE.Items[num]
+ else
+ for i, tab in pairs(GAMEMODE.Items) do
+ if tab.Signature == id then
+ t = tab
+ break
+ end
+ end
+ end
+
+ if t and t.WorthShop then return t end
+end
+
+function FindItem(id)
+ if not id then return end
+
+ local t
+
+ local num = tonumber(id)
+ if num then
+ t = GAMEMODE.Items[num]
+ else
+ for i, tab in pairs(GAMEMODE.Items) do
+ if tab.Signature == id then
+ t = tab
+ break
+ end
+ end
+ end
+
+ return t
+end
+
+function TrueVisible(posa, posb, filter)
+ local filt = ents.FindByClass("projectile_*")
+ filt = table.Add(filt, player.GetAll())
+ if filter then
+ filt[#filt + 1] = filter
+ end
+
+ return not util.TraceLine({start = posa, endpos = posb, filter = filt, mask = MASK_SHOT}).Hit
+end
+
+function TrueVisibleFilters(posa, posb, ...)
+ local filt = ents.FindByClass("projectile_*")
+ filt = table.Add(filt, player.GetAll())
+ if ... ~= nil then
+ for k, v in pairs({...}) do
+ filt[#filt + 1] = v
+ end
+ end
+
+ return not util.TraceLine({start = posa, endpos = posb, filter = filt, mask = MASK_SHOT}).Hit
+end
+
+function WorldVisible(posa, posb)
+ return not util.TraceLine({start = posa, endpos = posb, mask = MASK_SOLID_BRUSHONLY}).Hit
+end
+
+function ValidFunction(ent, funcname, ...)
+ if ent and ent:IsValid() and ent[funcname] then
+ return ent[funcname](ent, ...)
+ end
+end
+
+function CosineInterpolation(y1, y2, mu)
+ local mu2 = (1 - math.cos(mu * math.pi)) / 2
+ return y1 * (1 - mu2) + y2 * mu2
+end
+
+function string.AndSeparate(list)
+ local length = #list
+ if length <= 0 then return "" end
+ if length == 1 then return list[1] end
+ if length == 2 then return list[1].." and "..list[2] end
+
+ return table.concat(list, ", ", 1, length - 1)..", and "..list[length]
+end
+
+function util.SkewedDistance(a, b, skew)
+ if a.z > b.z then
+ return math.sqrt((b.x - a.x) ^ 2 + (b.y - a.y) ^ 2 + ((a.z - b.z) * skew) ^ 2)
+ end
+
+ return a:Distance(b)
+end
+
+function util.Blood(pos, amount, dir, force, noprediction)
+ local effectdata = EffectData()
+ effectdata:SetOrigin(pos)
+ effectdata:SetMagnitude(amount)
+ effectdata:SetNormal(dir)
+ effectdata:SetScale(math.max(128, force))
+ util.Effect("bloodstream", effectdata, nil, noprediction)
+end
+
+-- I had to make this since the default function checks visibility vs. the entitiy's center and not the nearest position.
+function util.BlastDamageEx(inflictor, attacker, epicenter, radius, damage, damagetype)
+ local filter = inflictor
+ for _, ent in pairs(ents.FindInSphere(epicenter, radius)) do
+ local nearest = ent:NearestPoint(epicenter)
+ if TrueVisibleFilters(epicenter, nearest, inflictor, ent) then
+ ent:TakeSpecialDamage(((radius - nearest:Distance(epicenter)) / radius) * damage, damagetype, attacker, inflictor, nearest)
+ end
+ end
+end
+
+function util.BlastDamage2(inflictor, attacker, epicenter, radius, damage)
+ util.BlastDamageEx(inflictor, attacker, epicenter, radius, damage, DMG_BLAST)
+end
+
+function util.PoisonBlastDamage(inflictor, attacker, epicenter, radius, damage, noreduce)
+ local filter = inflictor
+ for _, ent in pairs(ents.FindInSphere(epicenter, radius)) do
+ local nearest = ent:NearestPoint(epicenter)
+ if TrueVisibleFilters(epicenter, nearest, inflictor, ent) then
+ ent:PoisonDamage(((radius - nearest:Distance(epicenter)) / radius) * damage, attacker, inflictor, nil, noreduce)
+ end
+ end
+end
+
+function util.ToMinutesSeconds(seconds)
+ local minutes = math.floor(seconds / 60)
+ seconds = seconds - minutes * 60
+
+ return string.format("%02d:%02d", minutes, math.floor(seconds))
+end
+
+function util.ToMinutesSecondsMilliseconds(seconds)
+ local minutes = math.floor(seconds / 60)
+ seconds = seconds - minutes * 60
+
+ local milliseconds = math.floor(seconds % 1 * 100)
+
+ return string.format("%02d:%02d.%02d", minutes, math.floor(seconds), milliseconds)
+end
+
+function util.RemoveAll(class)
+ for _, ent in pairs(ents.FindByClass(class)) do
+ ent:Remove()
+ end
+end
+
+local function TooNear(spawn, tab, dist)
+ local spawnpos = spawn:GetPos()
+ for _, ent in pairs(tab) do
+ if ent:GetPos():Distance(spawnpos) <= dist then
+ return true
+ end
+ end
+
+ return false
+end
+function team.GetSpawnPointGrouped(teamid, dist)
+ dist = dist or 200
+
+ local tab = {}
+ local spawns = team.GetSpawnPoint(teamid)
+
+ for _, spawn in pairs(spawns) do
+ if not TooNear(spawn, tab, dist) then
+ table.insert(tab, spawn)
+ end
+ end
+
+ return tab
+end
+
+function AccessorFuncDT(tab, membername, type, id)
+ local emeta = FindMetaTable("Entity")
+ local setter = emeta["SetDT"..type]
+ local getter = emeta["GetDT"..type]
+
+ tab["Set"..membername] = function(me, val)
+ setter(me, id, val)
+ end
+
+ tab["Get"..membername] = function(me)
+ return getter(me, id)
+ end
+end
+
+function team.GetValidSpawnPoint(teamid)
+ local t = {}
+
+ local spawns = team.GetSpawnPoint(teamid)
+ if spawns then
+ for _, ent in pairs(spawns) do
+ if ent:IsValid() then
+ t[#t + 1] = ent
+ end
+ end
+ end
+
+ return t
+end
+
+function timer.SimpleEx(delay, action, ...)
+ if ... == nil then
+ timer.Simple(delay, action)
+ else
+ local a, b, c, d, e, f, g, h, i, j, k = ...
+ timer.Simple(delay, function() action(a, b, c, d, e, f, g, h, i, j, k) end)
+ end
+end
+
+function timer.CreateEx(timername, delay, repeats, action, ...)
+ if ... == nil then
+ timer.Create(timername, delay, repeats, action)
+ else
+ local a, b, c, d, e, f, g, h, i, j, k = ...
+ timer.Create(timername, delay, repeats, function() action(a, b, c, d, e, f, g, h, i, j, k) end)
+ end
+end
+
+function ents.CreateLimited(class, limit)
+ if #ents.FindByClass(class) >= (limit or 200) then return NULL end
+
+ return ents.Create(class)
+end
+
+function tonumbersafe(a)
+ local n = tonumber(a)
+
+ if n then
+ if n == 0 or n < 0 or n > 0 then
+ return n
+ end
+
+ -- NaN!
+ return 0
+ end
+
+ return nil
+end
diff --git a/gamemodes/zombiesurvival/gamemode/sh_zombieclasses.lua b/gamemodes/zombiesurvival/gamemode/sh_zombieclasses.lua
new file mode 100644
index 0000000..32850f4
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sh_zombieclasses.lua
@@ -0,0 +1,101 @@
+GM.RevertableZombieClasses = {}
+
+function GM:IsClassUnlocked(classname)
+ local classtab = self.ZombieClasses[classname]
+ if not classtab then return false end
+
+ if classtab.IsClassUnlocked then
+ local ret = classtab:IsClassUnlocked()
+ if ret ~= nil then return ret end
+ end
+
+ return not classtab.Locked and (classtab.Unlocked or classtab.Wave and self:GetWave() >= classtab.Wave or not self:GetWaveActive() and self:GetWave() + 1 >= classtab.Wave)
+end
+
+local function ReorderZombieClassesSort(a, b)
+ if (a.Order or b.Order) and a.Order ~= b.Order then
+ return (a.Order or 255) < (b.Order or 255)
+ end
+
+ if (a.Wave or b.Wave) and a.Wave ~= b.Wave then
+ return (a.Wave or 255) < (b.Wave or 255)
+ end
+
+ return a.Name < b.Name
+end
+function GM:ReorderZombieClasses()
+ table.sort(self.ZombieClasses, ReorderZombieClassesSort)
+ for k, v in pairs(self.ZombieClasses) do
+ if type(k) == "number" then
+ self.ZombieClasses[v.Name] = v
+ v.Index = k
+
+ if v.IsDefault then
+ self.DefaultZombieClass = k
+ end
+ end
+ end
+end
+
+function GM:RegisterZombieClass(name, tab)
+ local gm = GAMEMODE or GM
+
+ if tab.Wave then tab.Wave = math.floor(tab.Wave * self:GetNumberOfWaves()) end
+ table.insert(gm.ZombieClasses, tab)
+ tab.Index = #gm.ZombieClasses
+ if CLIENT then
+ tab.Icon = tab.Icon or "zombiesurvival/killicons/genericundead"
+ end
+
+ if tab.IsDefault then
+ gm.DefaultZombieClass = tab.Index
+ end
+
+ tab.TranslationName = tab.TranslationName or tab.Name
+
+ gm.ZombieClasses[name] = tab
+end
+
+function GM:RevertZombieClasses()
+ self.ZombieClasses = table.Copy(self.RevertableZombieClasses)
+end
+
+function GM:RegisterZombieClasses()
+ self.ZombieClasses = {}
+ self.DefaultZombieClass = self.DefaultZombieClass or 1
+
+ local included = {}
+
+ local classes = file.Find(self.FolderName.."/gamemode/zombieclasses/*.lua", "LUA")
+ table.sort(classes)
+ for i, filename in ipairs(classes) do
+ AddCSLuaFile("zombieclasses/"..filename)
+ CLASS = {}
+ include("zombieclasses/"..filename)
+ if CLASS.Name then
+ self:RegisterZombieClass(CLASS.Name, CLASS)
+ else
+ ErrorNoHalt("CLASS "..filename.." has no 'Name' member!")
+ end
+ included[filename] = CLASS
+ CLASS = nil
+ end
+
+ for k, v in pairs(self.ZombieClasses) do
+ local base = v.Base
+ if base then
+ base = base..".lua"
+ if included[base] then
+ table.Inherit(v, included[base])
+ else
+ ErrorNoHalt("CLASS "..tostring(v.Name).." uses base class "..base.." but it doesn't exist!")
+ end
+ end
+ end
+
+ self:ReorderZombieClasses()
+
+ self.RevertableZombieClasses = table.Copy(self.ZombieClasses)
+end
+
+GM:RegisterZombieClasses()
diff --git a/gamemodes/zombiesurvival/gamemode/sh_zombieescape.lua b/gamemodes/zombiesurvival/gamemode/sh_zombieescape.lua
new file mode 100644
index 0000000..1f1569e
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sh_zombieescape.lua
@@ -0,0 +1,85 @@
+if string.sub(string.lower(game.GetMap()), 1, 3) ~= "ze_" then return end
+
+GM.ZombieEscape = true
+GM.WaveZeroLength = 90
+GM.EndGameTime = 35
+GM.ZE_FreezeTime = 20
+GM.ZE_TimeLimit = 60 * 16
+
+GM.DefaultZombieClass = GM.ZombieClasses["Super Zombie"].Index
+
+function GM:Move(pl, move)
+ if pl:Team() == TEAM_HUMAN then
+ if pl:GetBarricadeGhosting() then
+ move:SetMaxSpeed(36)
+ move:SetMaxClientSpeed(36)
+ elseif move:GetForwardSpeed() < 0 then
+ move:SetMaxSpeed(move:GetMaxSpeed() * 0.9)
+ move:SetMaxClientSpeed(move:GetMaxClientSpeed() * 0.9)
+ elseif move:GetForwardSpeed() == 0 then
+ move:SetMaxSpeed(move:GetMaxSpeed() * 0.95)
+ move:SetMaxClientSpeed(move:GetMaxClientSpeed() * 0.95)
+ end
+ elseif pl:CallZombieFunction("Move", move) then
+ return
+ end
+
+ local legdamage = pl:GetLegDamage()
+ if legdamage > 0 then
+ local scale = 1 - math.min(1, legdamage * 0.25)
+ move:SetMaxSpeed(move:GetMaxSpeed() * scale)
+ move:SetMaxClientSpeed(move:GetMaxClientSpeed() * scale)
+ end
+end
+
+function GM:GetZombieDamageScale(pos, ignore)
+ return self.ZombieDamageMultiplier
+end
+
+function GM:ScalePlayerDamage(pl, hitgroup, dmginfo)
+ if dmginfo:IsBulletDamage() then
+ if hitgroup == HITGROUP_HEAD then
+ pl.m_LastHeadShot = CurTime()
+ end
+ end
+
+ if not pl:CallZombieFunction("ScalePlayerDamage", hitgroup, dmginfo) then
+ if hitgroup == HITGROUP_HEAD then
+ dmginfo:SetDamage(dmginfo:GetDamage() * 2)
+ elseif hitgroup == HITGROUP_LEFTLEG or hitgroup == HITGROUP_RIGHTLEG or hitgroup == HITGROUP_GEAR then
+ dmginfo:SetDamage(dmginfo:GetDamage() * 0.25)
+ elseif hitgroup == HITGROUP_STOMACH or hitgroup == HITGROUP_LEFTARM or hitgroup == HITGROUP_RIGHTARM then
+ dmginfo:SetDamage(dmginfo:GetDamage() * 0.75)
+ end
+ end
+
+ if pl:Team() == TEAM_UNDEAD and self:PlayerShouldTakeDamage(pl, dmginfo:GetAttacker()) then
+ pl:AddLegDamage(((hitgroup == HITGROUP_LEFTLEG or hitgroup == HITGROUP_RIGHTLEG) and 1 or 0.125) * dmginfo:GetDamage())
+ end
+end
+
+-- Creates some dummy entities so we don't get spammed in the console.
+
+local ENT = {}
+
+ENT.Type = "anim"
+ENT.RenderGroup = RENDERGROUP_NONE
+
+function ENT:Initialize()
+ self:SetNoDraw(true)
+end
+
+if SERVER then
+function ENT:Think()
+ self:Remove()
+end
+end
+
+hook.Add("Initialize", "RegisterDummyEntities", function()
+ scripted_ents.Register(ENT, "weapon_elite")
+ scripted_ents.Register(ENT, "weapon_knife")
+ scripted_ents.Register(ENT, "weapon_deagle")
+ scripted_ents.Register(ENT, "ammo_50ae")
+ scripted_ents.Register(ENT, "ammo_556mm_box")
+ scripted_ents.Register(ENT, "player_weaponstrip")
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/shared.lua b/gamemodes/zombiesurvival/gamemode/shared.lua
new file mode 100644
index 0000000..5450ae8
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/shared.lua
@@ -0,0 +1,745 @@
+GM.Name = "Zombie Survival"
+GM.Author = "William \"JetBoom\" Moodhe"
+GM.Email = "williammoodhe@gmail.com"
+GM.Website = "http://www.noxiousnet.com"
+
+-- No, adding a gun doesn't make your name worth being here.
+GM.Credits = {
+ {"William \"JetBoom\" Moodhe", "williammoodhe@gmail.com (www.noxiousnet.com)", "Creator / Programmer"},
+ {"11k", "tjd113@gmail.com", "Zombie view models"},
+ {"Eisiger", "k2deseve@gmail.com", "Zombie kill icons"},
+ {"Austin \"Little Nemo\" Killey", "austin_odyssey@yahoo.com", "Ambient music"},
+ {"Zombie Panic: Source", "http://www.zombiepanic.org/", "Melee weapon sounds"},
+ {"Samuel", "samuel_games@hotmail.com", "Board Kit model"},
+ {"Typhon", "lukas-tinel@hotmail.com", "HUD textures"},
+
+ {"Mr. Darkness", "", "Russian translation"},
+ {"honsal", "", "Korean translation"},
+ {"rui_troia", "", "Portuguese translation"},
+ {"Shinyshark", "", "Dutch translation"},
+ {"Kradar", "", "Italian translation"},
+ {"Raptor", "", "German translation"},
+ {"The Special Duckling", "", "Danish translation"},
+ {"Box, ptown, Dr. Broly", "", "Spanish translation"}
+}
+
+include("nixthelag.lua")
+include("buffthefps.lua")
+
+function GM:GetNumberOfWaves()
+ local default = GetGlobalBool("classicmode") and 10 or self.NumberOfWaves
+ local num = GetGlobalInt("numwaves", default) -- This is controlled by logic_waves.
+ return num == -2 and default or num
+end
+
+function GM:GetWaveOneLength()
+ return GetGlobalBool("classicmode") and self.WaveOneLengthClassic or self.WaveOneLength
+end
+
+include("sh_translate.lua")
+include("sh_colors.lua")
+include("sh_serialization.lua")
+
+include("sh_globals.lua")
+include("sh_crafts.lua")
+include("sh_util.lua")
+include("sh_options.lua")
+include("sh_zombieclasses.lua")
+include("sh_animations.lua")
+include("sh_sigils.lua")
+
+include("noxapi/noxapi.lua")
+
+include("obj_vector_extend.lua")
+include("obj_entity_extend.lua")
+include("obj_player_extend.lua")
+include("obj_weapon_extend.lua")
+
+include("workshopfix.lua")
+
+----------------------
+
+GM.EndRound = false
+GM.StartingWorth = 100
+GM.ZombieVolunteers = {}
+
+team.SetUp(TEAM_ZOMBIE, "The Undead", Color(0, 255, 0, 255))
+team.SetUp(TEAM_SURVIVORS, "Survivors", Color(0, 160, 255, 255))
+
+local validmodels = player_manager.AllValidModels()
+validmodels["tf01"] = nil
+validmodels["tf02"] = nil
+
+vector_tiny = Vector(0.001, 0.001, 0.001)
+
+-- ogg/mp3 still doesn't work with SoundDuration() function
+GM.SoundDuration = {
+ ["zombiesurvival/music_win.ogg"] = 33.149,
+ ["zombiesurvival/music_lose.ogg"] = 45.714,
+ ["zombiesurvival/lasthuman.ogg"] = 120.503,
+
+ ["zombiesurvival/beats/defaulthuman/1.ogg"] = 7.111,
+ ["zombiesurvival/beats/defaulthuman/2.ogg"] = 7.111,
+ ["zombiesurvival/beats/defaulthuman/3.ogg"] = 7.111,
+ ["zombiesurvival/beats/defaulthuman/4.ogg"] = 7.111,
+ ["zombiesurvival/beats/defaulthuman/5.ogg"] = 7.111,
+ ["zombiesurvival/beats/defaulthuman/6.ogg"] = 14.222,
+ ["zombiesurvival/beats/defaulthuman/7.ogg"] = 14.222,
+ ["zombiesurvival/beats/defaulthuman/8.ogg"] = 7.111,
+ ["zombiesurvival/beats/defaulthuman/9.ogg"] = 14.222,
+
+ ["zombiesurvival/beats/defaultzombiev2/1.ogg"] = 8,
+ ["zombiesurvival/beats/defaultzombiev2/2.ogg"] = 8,
+ ["zombiesurvival/beats/defaultzombiev2/3.ogg"] = 8,
+ ["zombiesurvival/beats/defaultzombiev2/4.ogg"] = 8,
+ ["zombiesurvival/beats/defaultzombiev2/5.ogg"] = 8,
+ ["zombiesurvival/beats/defaultzombiev2/6.ogg"] = 6.038,
+ ["zombiesurvival/beats/defaultzombiev2/7.ogg"] = 6.038,
+ ["zombiesurvival/beats/defaultzombiev2/8.ogg"] = 6.038,
+ ["zombiesurvival/beats/defaultzombiev2/9.ogg"] = 6.038,
+ ["zombiesurvival/beats/defaultzombiev2/10.ogg"] = 6.038
+}
+
+function GM:AddCustomAmmo()
+ game.AddAmmoType({name = "pulse"})
+ game.AddAmmoType({name = "stone"})
+
+ game.AddAmmoType({name = "spotlamp"})
+ game.AddAmmoType({name = "manhack"})
+ game.AddAmmoType({name = "manhack_saw"})
+ game.AddAmmoType({name = "drone"})
+end
+
+function GM:CanRemoveOthersNail(pl, nailowner, ent)
+ local plpoints = pl:Frags()
+ local ownerpoints = nailowner:Frags()
+ if plpoints >= 75 or ownerpoints < 75 then return true end
+
+ pl:PrintTranslatedMessage(HUD_PRINTCENTER, "cant_remove_nails_of_superior_player")
+
+ return false
+end
+
+function GM:SetRedeemBrains(amount)
+ SetGlobalInt("redeembrains", amount)
+end
+
+function GM:GetRedeemBrains()
+ return GetGlobalInt("redeembrains", self.DefaultRedeem)
+end
+
+function GM:PlayerIsAdmin(pl)
+ return pl:IsAdmin()
+end
+
+function GM:GetFallDamage(pl, fallspeed)
+ return 0
+end
+
+function GM:ShouldRestartRound()
+ if self.TimeLimit == -1 or self.RoundLimit == -1 then return true end
+
+ local roundlimit = self.RoundLimit
+ if self.ZombieEscape and roundlimit > 0 then
+ roundlimit = math.ceil(roundlimit * 1.5)
+ end
+
+ local timelimit = self.TimeLimit
+ if self.ZombieEscape and timelimit > 0 then
+ timelimit = timelimit * 1.5
+ end
+
+ if timelimit > 0 and CurTime() >= timelimit or roundlimit > 0 and self.CurrentRound >= roundlimit then return false end
+
+ return true
+end
+
+function GM:ZombieSpawnDistanceSort(other)
+ return self._ZombieSpawnDistance < other._ZombieSpawnDistance
+end
+
+function GM:SortZombieSpawnDistances(allplayers)
+ local curtime = CurTime()
+
+ local zspawns = ents.FindByClass("zombiegasses")
+ if #zspawns == 0 then
+ zspawns = team.GetValidSpawnPoint(TEAM_UNDEAD)
+ end
+
+ for _, pl in pairs(allplayers) do
+ if pl:Team() == TEAM_UNDEAD or pl:GetInfo("zs_alwaysvolunteer") == "1" then
+ pl._ZombieSpawnDistance = -1
+ elseif CLIENT or pl.LastNotAFK and CurTime() <= pl.LastNotAFK + 60 then
+ local plpos = pl:GetPos()
+ local closest = 9999999
+ for _, ent in pairs(zspawns) do
+ local dist = ent:GetPos():Distance(plpos)
+ if dist < closest then
+ closest = dist
+ end
+ end
+ pl._ZombieSpawnDistance = closest
+ else
+ pl._ZombieSpawnDistance = 9999999
+ end
+ end
+
+ table.sort(allplayers, self.ZombieSpawnDistanceSort)
+end
+
+function GM:SetDynamicSpawning(onoff)
+ SetGlobalBool("DynamicSpawningDisabled", not onoff)
+ self.DynamicSpawning = onoff
+end
+
+function GM:ValidMenuLockOnTarget(pl, ent)
+ if ent and ent:IsValid() and ent:IsPlayer() and ent:Team() == TEAM_HUMAN and ent:Alive() then
+ local startpos = pl:EyePos()
+ local endpos = ent:NearestPoint(startpos)
+ if startpos:Distance(endpos) <= 48 and TrueVisible(startpos, endpos) then
+ return true
+ end
+ end
+
+ return false
+end
+
+function GM:GetHandsModel(pl)
+ return player_manager.TranslatePlayerHands(pl:GetInfo("cl_playermodel"))
+end
+
+local playerheight = Vector(0, 0, 72)
+local playermins = Vector(-17, -17, 0)
+local playermaxs = Vector(17, 17, 4)
+local SkewedDistance = util.SkewedDistance
+
+GM.DynamicSpawnDistVisOld = 2048
+GM.DynamicSpawnDistOld = 640
+function GM:DynamicSpawnIsValidOld(zombie, humans, allplayers)
+ -- I didn't make this check where trigger_hurt entities are. Rather I made it check the time since the last time you were hit with a trigger_hurt.
+ -- I'm not sure if it's possible to check if a trigger_hurt is enabled or disabled through the Lua bindings.
+ if SERVER and zombie.LastHitWithTriggerHurt and CurTime() < zombie.LastHitWithTriggerHurt + 2 then
+ return false
+ end
+
+ -- Optional caching for these.
+ if not humans then humans = team.GetPlayers(TEAM_HUMAN) end
+ if not allplayers then allplayers = player.GetAll() end
+
+ local pos = zombie:GetPos() + Vector(0, 0, 1)
+ if zombie:Alive() and zombie:GetMoveType() == MOVETYPE_WALK and zombie:OnGround()
+ and not util.TraceHull({start = pos, endpos = pos + playerheight, mins = playermins, maxs = playermaxs, mask = MASK_SOLID, filter = allplayers}).Hit then
+ local vtr = util.TraceHull({start = pos, endpos = pos - playerheight, mins = playermins, maxs = playermaxs, mask = MASK_SOLID_BRUSHONLY})
+ if not vtr.HitSky and not vtr.HitNoDraw then
+ local valid = true
+
+ for _, human in pairs(humans) do
+ local hpos = human:GetPos()
+ local nearest = zombie:NearestPoint(hpos)
+ local dist = SkewedDistance(hpos, nearest, 2.75) -- We make it so that the Z distance between a human and a zombie is skewed if the zombie is below the human.
+ if dist <= self.DynamicSpawnDistOld or dist <= self.DynamicSpawnDistVisOld and WorldVisible(hpos, nearest) then -- Zombies can't be in radius of any humans. Zombies can't be clearly visible by any humans.
+ valid = false
+ break
+ end
+ end
+
+ return valid
+ end
+ end
+
+ return false
+end
+
+function GM:GetBestDynamicSpawnOld(pl, pos)
+ local spawns = self:GetDynamicSpawnsOld(pl)
+ if #spawns == 0 then return end
+
+ return self:GetClosestSpawnPoint(spawns, pos or self:GetTeamEpicentre(TEAM_HUMAN)) or table.Random(spawns)
+end
+
+function GM:GetDynamicSpawnsOld(pl)
+ local tab = {}
+
+ local allplayers = player.GetAll()
+ local humans = team.GetPlayers(TEAM_HUMAN)
+ for _, zombie in pairs(team.GetPlayers(TEAM_UNDEAD)) do
+ if zombie ~= pl and self:DynamicSpawnIsValidOld(zombie, humans, allplayers) then
+ table.insert(tab, zombie)
+ end
+ end
+
+ return tab
+end
+
+GM.DynamicSpawnDist = 400
+GM.DynamicSpawnDistBuild = 650
+function GM:DynamicSpawnIsValid(nest, humans, allplayers)
+ if self:ShouldUseAlternateDynamicSpawn() then
+ return self:DynamicSpawnIsValidOld(nest, humans, allplayers)
+ end
+
+ -- Optional caching for these.
+ if not humans then humans = team.GetPlayers(TEAM_HUMAN) end
+ --if not allplayers then allplayers = player.GetAll() end
+
+ local pos = nest:GetPos() + Vector(0, 0, 1)
+ if nest.GetNestBuilt and nest:GetNestBuilt() and not util.TraceHull({start = pos, endpos = pos + playerheight, mins = playermins, maxs = playermaxs, mask = MASK_SOLID_BRUSHONLY}).Hit then
+ local vtr = util.TraceHull({start = pos, endpos = pos - playerheight, mins = playermins, maxs = playermaxs, mask = MASK_SOLID_BRUSHONLY})
+ if not vtr.HitSky and not vtr.HitNoDraw then
+ local valid = true
+ local nearest = nest:GetPos()
+
+ for _, human in pairs(humans) do
+ local hpos = human:GetPos()
+ local dist = SkewedDistance(hpos, nearest, 2.75) -- We make it so that the Z distance between a human and a nest is skewed if the nest is below the human.
+ if dist <= self.DynamicSpawnDist then
+ valid = false
+ break
+ end
+ end
+
+ return valid
+ end
+ end
+
+ return false
+end
+
+function GM:GetBestDynamicSpawn(pl, pos)
+ if self:ShouldUseAlternateDynamicSpawn() then
+ return self:GetBestDynamicSpawnOld(pl, pos)
+ end
+
+ local spawns = self:GetDynamicSpawns(pl)
+ if #spawns == 0 then return end
+
+ return self:GetClosestSpawnPoint(spawns, pos or self:GetTeamEpicentre(TEAM_HUMAN)) or table.Random(spawns)
+end
+
+function GM:GetDynamicSpawns(pl)
+ if self:ShouldUseAlternateDynamicSpawn() then
+ return self:GetDynamicSpawnsOld(pl)
+ end
+
+ local tab = {}
+
+ --local allplayers = player.GetAll()
+ local humans = team.GetPlayers(TEAM_HUMAN)
+ for _, nest in pairs(ents.FindByClass("prop_creepernest")) do
+ if self:DynamicSpawnIsValid(nest, humans--[[, allplayers]]) then
+ table.insert(tab, nest)
+ end
+ end
+
+ return tab
+end
+
+function GM:GetDesiredStartingZombies()
+ local numplayers = #player.GetAll()
+ return math.min(math.max(1, math.ceil(numplayers * self.WaveOneZombies)), numplayers - 1)
+end
+
+function GM:GetEndRound()
+ return self.RoundEnded
+end
+
+function GM:PrecacheResources()
+ util.PrecacheSound("physics/body/body_medium_break2.wav")
+ util.PrecacheSound("physics/body/body_medium_break3.wav")
+ util.PrecacheSound("physics/body/body_medium_break4.wav")
+ for name, mdl in pairs(player_manager.AllValidModels()) do
+ util.PrecacheModel(mdl)
+ end
+end
+
+function GM:ShouldCollide(enta, entb)
+ if enta.ShouldNotCollide and enta:ShouldNotCollide(entb) or entb.ShouldNotCollide and entb:ShouldNotCollide(enta) then
+ return false
+ end
+
+ return true
+end
+
+function GM:Move(pl, move)
+ if pl:Team() == TEAM_HUMAN then
+ if pl:GetBarricadeGhosting() then
+ move:SetMaxSpeed(36)
+ move:SetMaxClientSpeed(36)
+ elseif move:GetForwardSpeed() < 0 then
+ move:SetMaxSpeed(move:GetMaxSpeed() * 0.5)
+ move:SetMaxClientSpeed(move:GetMaxClientSpeed() * 0.5)
+ elseif move:GetForwardSpeed() == 0 then
+ move:SetMaxSpeed(move:GetMaxSpeed() * 0.85)
+ move:SetMaxClientSpeed(move:GetMaxClientSpeed() * 0.85)
+ end
+ elseif pl:CallZombieFunction("Move", move) then
+ return
+ end
+
+ local legdamage = pl:GetLegDamage()
+ if legdamage > 0 then
+ local scale = 1 - math.min(1, legdamage * 0.33)
+ move:SetMaxSpeed(move:GetMaxSpeed() * scale)
+ move:SetMaxClientSpeed(move:GetMaxClientSpeed() * scale)
+ end
+end
+
+function GM:OnPlayerHitGround(pl, inwater, hitfloater, speed)
+ if inwater then return true end
+
+ local isundead = pl:Team() == TEAM_UNDEAD
+
+ if isundead then
+ if pl:GetZombieClassTable().NoFallDamage then return true end
+ else
+ pl:PreventSkyCade()
+ end
+
+ if not isundead or not pl:GetZombieClassTable().NoFallSlowdown then
+ pl:RawCapLegDamage(CurTime() + math.min(2, speed * 0.0035))
+ end
+
+ if SERVER then
+ if isundead then
+ speed = math.max(0, speed - 200)
+ end
+
+ local damage = (0.1 * (speed - 525)) ^ 1.45
+ if hitfloater then damage = damage / 2 end
+
+ if math.floor(damage) > 0 then
+ if 20 <= damage and damage < pl:Health() then
+ pl:KnockDown(damage * 0.05)
+ end
+ pl:TakeSpecialDamage(damage, DMG_FALL, game.GetWorld(), game.GetWorld(), pl:GetPos())
+ pl:EmitSound("player/pl_fallpain"..(math.random(2) == 1 and 3 or 1)..".wav")
+ end
+ end
+
+ return true
+end
+
+function GM:PlayerCanBeHealed(pl)
+ return true
+end
+
+function GM:PlayerCanPurchase(pl)
+ return pl:Team() == TEAM_HUMAN and self:GetWave() > 0 and pl:Alive() and pl:NearArsenalCrate()
+end
+
+function GM:PlayerCanHearPlayersVoice(listener, talker)
+ return listener:Team() == talker:Team()
+ --[[if self:GetEndRound() then return true, false end
+
+ if listener:Team() == talker:Team() then
+ return true, listener:GetPos():DistanceZSkew(talker:GetPos(), 2) <= 128
+ end
+
+ return false]]
+end
+
+function GM:PlayerTraceAttack(pl, dmginfo, dir, trace)
+end
+
+function GM:ScalePlayerDamage(pl, hitgroup, dmginfo)
+ if hitgroup == HITGROUP_HEAD and dmginfo:IsBulletDamage() then
+ pl.m_LastHeadShot = CurTime()
+ end
+
+ if not pl:CallZombieFunction("ScalePlayerDamage", hitgroup, dmginfo) then
+ if hitgroup == HITGROUP_HEAD then
+ dmginfo:SetDamage(dmginfo:GetDamage() * 2)
+ elseif hitgroup == HITGROUP_LEFTLEG or hitgroup == HITGROUP_RIGHTLEG or hitgroup == HITGROUP_GEAR then
+ dmginfo:SetDamage(dmginfo:GetDamage() * 0.25)
+ elseif hitgroup == HITGROUP_STOMACH or hitgroup == HITGROUP_LEFTARM or hitgroup == HITGROUP_RIGHTARM then
+ dmginfo:SetDamage(dmginfo:GetDamage() * 0.75)
+ end
+ end
+
+ if (hitgroup == HITGROUP_LEFTLEG or hitgroup == HITGROUP_RIGHTLEG) and self:PlayerShouldTakeDamage(pl, dmginfo:GetAttacker()) then
+ pl:AddLegDamage(dmginfo:GetDamage())
+ end
+end
+
+function GM:CanDamageNail(ent, attacker, inflictor, damage, dmginfo)
+ return not attacker:IsPlayer() or attacker:Team() ~= TEAM_HUMAN
+end
+
+function GM:CanPlaceNail(pl, tr)
+ return true
+end
+
+function GM:CanRemoveNail(pl, nail)
+ return true
+end
+
+function GM:GetDamageResistance(fearpower)
+ return fearpower * 0.35
+end
+
+function GM:FindUseEntity(pl, ent)
+ if not ent:IsValid() then
+ local e = pl:TraceLine(90, MASK_SOLID, pl:GetMeleeFilter()).Entity
+ if e:IsValid() then return e end
+ end
+
+ return ent
+end
+
+function GM:ShouldUseAlternateDynamicSpawn()
+ return self.ZombieEscape or self:IsClassicMode() or self.PantsMode or self:IsBabyMode()
+end
+
+function GM:GetZombieDamageScale(pos, ignore)
+ return self.ZombieDamageMultiplier * (1 - self:GetDamageResistance(self:GetFearMeterPower(pos, TEAM_UNDEAD, ignore)))
+end
+
+local temppos
+local function SortByDistance(a, b)
+ return a:GetPos():Distance(temppos) < b:GetPos():Distance(temppos)
+end
+
+function GM:GetClosestSpawnPoint(teamid, pos)
+ temppos = pos
+ local spawnpoints
+ if type(teamid) == "table" then
+ spawnpoints = teamid
+ else
+ spawnpoints = team.GetValidSpawnPoint(teamid)
+ end
+ table.sort(spawnpoints, SortByDistance)
+ return spawnpoints[1]
+end
+
+local FEAR_RANGE = 768
+local FEAR_PERINSTANCE = 0.075
+local RALLYPOINT_THRESHOLD = 0.3
+
+local function GetEpicenter(tab)
+ local vec = Vector(0, 0, 0)
+ if #tab == 0 then return vec end
+
+ for k, v in pairs(tab) do
+ vec = vec + v:GetPos()
+ end
+
+ return vec / #tab
+end
+
+function GM:GetTeamRallyGroups(teamid)
+ local groups = {}
+ local ingroup = {}
+
+ local plys = team.GetPlayers(teamid)
+
+ for _, pl in pairs(plys) do
+ if not ingroup[pl] and pl:Alive() then
+ local plpos = pl:GetPos()
+ local group = {pl}
+
+ for __, otherpl in pairs(plys) do
+ if otherpl ~= pl and not ingroup[otherpl] and otherpl:Alive() and otherpl:GetPos():Distance(plpos) <= FEAR_RANGE then
+ group[#group + 1] = otherpl
+ end
+ end
+
+ if #group * FEAR_PERINSTANCE >= RALLYPOINT_THRESHOLD then
+ for k, v in pairs(group) do
+ ingroup[v] = true
+ end
+ groups[#groups + 1] = group
+ end
+ end
+ end
+
+ return groups
+end
+
+function GM:GetTeamRallyPoints(teamid)
+ local points = {}
+
+ for _, group in pairs(self:GetTeamRallyGroups(teamid)) do
+ points[#points + 1] = {GetEpicenter(group), math.min(1, (#group * FEAR_PERINSTANCE - RALLYPOINT_THRESHOLD) / (1 - RALLYPOINT_THRESHOLD))}
+ end
+
+ return points
+end
+
+local CachedEpicentreTimes = {}
+local CachedEpicentres = {}
+function GM:GetTeamEpicentre(teamid, nocache)
+ if not nocache and CachedEpicentres[teamid] and CurTime() < CachedEpicentreTimes[teamid] then
+ return CachedEpicentres[teamid]
+ end
+
+ local plys = team.GetPlayers(teamid)
+ local vVec = Vector(0, 0, 0)
+ for _, pl in pairs(plys) do
+ if pl:Alive() then
+ vVec = vVec + pl:GetPos()
+ end
+ end
+
+ local epicentre = vVec / #plys
+ if not nocache then
+ CachedEpicentreTimes[teamid] = CurTime() + 0.5
+ CachedEpicentres[teamid] = epicentre
+ end
+
+ return epicentre
+end
+GM.GetTeamEpicenter = GM.GetTeamEpicentre
+
+function GM:GetCurrentEquipmentCount(id)
+ local count = 0
+
+ local item = self.Items[id]
+ if item then
+ if item.Countables then
+ if type(item.Countables) == "table" then
+ for k, v in pairs(item.Countables) do
+ count = count + #ents.FindByClass(v)
+ end
+ else
+ count = count + #ents.FindByClass(item.Countables)
+ end
+ end
+
+ if item.SWEP then
+ count = count + #ents.FindByClass(item.SWEP)
+ end
+ end
+
+ return count
+end
+
+function GM:GetFearMeterPower(pos, teamid, ignore)
+ if LASTHUMAN then return 1 end
+
+ local power = 0
+
+ for _, pl in pairs(player.GetAll()) do
+ if pl ~= ignore and pl:Team() == teamid and not pl:CallZombieFunction("DoesntGiveFear") and pl:Alive() then
+ local dist = pl:NearestPoint(pos):Distance(pos)
+ if dist <= FEAR_RANGE then
+ power = power + ((FEAR_RANGE - dist) / FEAR_RANGE) * (pl:GetZombieClassTable().FearPerInstance or FEAR_PERINSTANCE)
+ end
+ end
+ end
+
+ return math.min(1, power)
+end
+
+function GM:GetRagdollEyes(pl)
+ local Ragdoll = pl:GetRagdollEntity()
+ if not Ragdoll then return end
+
+ local att = Ragdoll:GetAttachment(Ragdoll:LookupAttachment("eyes"))
+ if att then
+ att.Pos = att.Pos + att.Ang:Forward() * -2
+ att.Ang = att.Ang
+
+ return att.Pos, att.Ang
+ end
+end
+
+function GM:PlayerNoClip(pl, on)
+ if pl:IsAdmin() then
+ if SERVER then
+ PrintMessage(HUD_PRINTCONSOLE, translate.Format(on and "x_turned_on_noclip" or "x_turned_off_noclip", pl:Name()))
+ end
+
+ if SERVER then
+ pl:MarkAsBadProfile()
+ end
+
+ return true
+ end
+
+ return false
+end
+
+function GM:IsSpecialPerson(pl, image)
+ local img, tooltip
+
+ if pl:SteamID() == "STEAM_0:1:3307510" then
+ img = "VGUI/steam/games/icon_sourcesdk"
+ tooltip = "JetBoom\nCreator of Zombie Survival!"
+ elseif pl:IsAdmin() then
+ img = "VGUI/servers/icon_robotron"
+ tooltip = "Admin"
+ elseif pl:IsNoxSupporter() then
+ img = "noxiousnet/noxicon.png"
+ tooltip = "Nox Supporter"
+ end
+
+ if img then
+ if CLIENT then
+ image:SetImage(img)
+ image:SetTooltip(tooltip)
+ end
+
+ return true
+ end
+
+ return false
+end
+
+function GM:GetWaveEnd()
+ return GetGlobalFloat("waveend", 0)
+end
+
+function GM:SetWaveEnd(wave)
+ SetGlobalFloat("waveend", wave)
+end
+
+function GM:GetWaveStart()
+ return GetGlobalFloat("wavestart", self.WaveZeroLength)
+end
+
+function GM:SetWaveStart(wave)
+ SetGlobalFloat("wavestart", wave)
+end
+
+function GM:GetWave()
+ return GetGlobalInt("wave", 0)
+end
+
+if GM:GetWave() == 0 then
+ GM:SetWaveStart(GM.WaveZeroLength)
+ GM:SetWaveEnd(GM.WaveZeroLength + GM:GetWaveOneLength())
+end
+
+function GM:GetWaveActive()
+ return GetGlobalBool("waveactive", false)
+end
+
+function GM:SetWaveActive(active)
+ if self.RoundEnded then return end
+
+ if self:GetWaveActive() ~= active then
+ SetGlobalBool("waveactive", active)
+
+ if SERVER then
+ gamemode.Call("WaveStateChanged", active)
+ end
+ end
+end
+
+if not FixedSoundDuration then
+FixedSoundDuration = true
+local OldSoundDuration = SoundDuration
+function SoundDuration(snd)
+ if snd then
+ local ft = string.sub(snd, -4)
+ if ft == ".mp3" then
+ return OldSoundDuration(snd) * 2.25
+ end
+ if ft == ".ogg" then
+ return OldSoundDuration(snd) * 3
+ end
+ end
+
+ return OldSoundDuration(snd)
+end
+end
diff --git a/gamemodes/zombiesurvival/gamemode/sv_crafts.lua b/gamemodes/zombiesurvival/gamemode/sv_crafts.lua
new file mode 100644
index 0000000..21f7b48
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sv_crafts.lua
@@ -0,0 +1,96 @@
+function GM:CraftItem(pl, recipe, enta, entb)
+ if enta._USEDINCRAFTING or entb._USEDINCRAFTING then return end
+
+ if not recipe.OnCraft or not recipe.OnCraft(pl, enta, entb) then
+ enta._USEDINCRAFTING = true
+ entb._USEDINCRAFTING = true
+
+ local result = recipe.Result
+ if result then
+ local resultclass = result[1]
+ if string.sub(resultclass, 1, 7) == "weapon_" then
+ if pl:HasWeapon(resultclass) then
+ local target = self:GetCraftTarget(enta, entb)
+ local ent = ents.Create("prop_weapon")
+ if ent:IsValid() then
+ ent:SetPos(target:GetPos())
+ ent:SetAngles(target:GetAngles())
+ ent:SetWeaponType(resultclass)
+ ent:Spawn()
+
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:SetVelocity(target:GetVelocity())
+ end
+ end
+ else
+ local weptab = weapons.GetStored(resultclass)
+ if weptab and weptab.AmmoIfHas then
+ pl:GiveAmmo(weptab.Primary.DefaultClip, weptab.Primary.Ammo)
+ else
+ pl:Give(resultclass)
+ end
+ end
+ else
+ local target = self:GetCraftTarget(enta, entb)
+ local ent = ents.Create(resultclass)
+ if ent:IsValid() then
+ ent:SetPos(target:GetPos())
+ ent:SetAngles(target:GetAngles())
+ if result[2] then
+ ent:SetModel(result[2])
+ end
+ ent:Spawn()
+
+ if recipe.OnCrafted then
+ recipe.OnCrafted(pl, recipe, enta, entb, ent)
+ end
+
+ ent:TemporaryBarricadeObject()
+
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:SetVelocity(target:GetVelocity())
+ end
+ end
+ end
+ end
+
+ enta:Remove()
+ entb:Remove()
+ end
+
+ pl:CenterNotify(COLOR_LIMEGREEN, translate.ClientGet(pl, "crafting_successful"), color_white, " ("..recipe.Name..")")
+ pl:SendLua("surface.PlaySound(\"buttons/lever"..math.random(5)..".wav\")")
+ PrintMessage(HUD_PRINTCONSOLE, translate.Format("x_crafted_y", pl:Name(), recipe.Name))
+end
+
+concommand.Add("_zs_craftcombine", function(sender, command, arguments)
+ local enta = Entity(tonumbersafe(arguments[1] or 0) or 0)
+ local entb = Entity(tonumbersafe(arguments[2] or 0) or 0)
+
+ local recipe = GAMEMODE:GetCraftingRecipe(enta, entb)
+ if recipe and gamemode.Call("CanCraft", sender, enta, entb) then
+ gamemode.Call("CraftItem", sender, recipe, enta, entb)
+ end
+end)
+
+concommand.Add("_zs_useobject", function(sender, command, arguments)
+ if not pl:IsValid() or not pl:Alive() or pl:Team() ~= TEAM_HUMAN then return end
+
+ local ent = Entity(tonumbersafe(arguments[1] or 0) or 0)
+ local action = arguments[2] or ""
+
+ if ent:IsValid() then
+ local func = ent["Action_"..string.upper(action)]
+ if func then
+ local eyepos = sender:EyePos()
+ local nearest = ent:NearestPoint(eyepos)
+ if eyepos:Distance(nearest) <= 64 and TrueVisibleFilters(eyepos, nearest, sender, ent) then
+ func(ent, sender, unpack(arguments[3]))
+ end
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/sv_options.lua b/gamemodes/zombiesurvival/gamemode/sv_options.lua
new file mode 100644
index 0000000..8961101
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sv_options.lua
@@ -0,0 +1,284 @@
+-- Weapon sets that humans can start with if they choose RANDOM.
+GM.StartLoadouts = {
+ {"pshtr", "3pcp", "2pcp", "csknf"},
+ {"btlax", "3pcp", "zpaxe", "stone"},
+ {"stbbr", "3rcp", "zpcpot", "stone"},
+ {"tossr", "3smgcp", "2smgcp", "zpplnk", "stone"},
+ {"blstr", "3sgcp", "2sgcp", "csknf"},
+ {"owens", "3pcp", "2pcp", "csknf"},
+ {"zpcpot", "medkit", "150mkit"},
+ {"crklr", "3arcp", "2arcp", "zpplnk", "stone"},
+ {"crphmr", "6nails", "hook"},
+ {"blstr", "pipe"}
+}
+
+
+GM.BossZombies = CreateConVar("zs_bosszombies", "1", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Summon a boss zombie in the middle of each wave break."):GetBool()
+cvars.AddChangeCallback("zs_bosszombies", function(cvar, oldvalue, newvalue)
+ GAMEMODE.BossZombies = tonumber(newvalue) == 1
+end)
+
+GM.BossZombiePlayersRequired = CreateConVar("zs_bosszombiethreshold", "10", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Don't summon boss zombies if less than this amount of players. 0 to disable."):GetInt()
+cvars.AddChangeCallback("zs_bosszombiethreshold", function(cvar, oldvalue, newvalue)
+ GAMEMODE.BossZombiePlayersRequired = tonumber(newvalue) or 0
+end)
+
+GM.OutnumberedHealthBonus = CreateConVar("zs_outnumberedhealthbonus", "4", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Give zombies some extra maximum health if there are less than or equal to this many zombies. 0 to disable."):GetInt()
+cvars.AddChangeCallback("zs_outnumberedhealthbonus", function(cvar, oldvalue, newvalue)
+ GAMEMODE.OutnumberedHealthBonus = tonumber(newvalue) or 0
+end)
+
+GM.PantsMode = CreateConVar("zs_pantsmode", "0", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Only the dead can know peace from this evil."):GetBool()
+cvars.AddChangeCallback("zs_pantsmode", function(cvar, oldvalue, newvalue)
+ GAMEMODE:SetPantsMode(tonumber(newvalue) == 1)
+end)
+
+GM.ClassicMode = CreateConVar("zs_classicmode", "0", FCVAR_ARCHIVE + FCVAR_NOTIFY, "No nails, no class selection, final destination."):GetBool()
+cvars.AddChangeCallback("zs_classicmode", function(cvar, oldvalue, newvalue)
+ GAMEMODE:SetClassicMode(tonumber(newvalue) == 1)
+end)
+
+GM.BabyMode = CreateConVar("zs_babymode", "0", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Babby mode."):GetBool()
+cvars.AddChangeCallback("zs_babymode", function(cvar, oldvalue, newvalue)
+ GAMEMODE:SetBabyMode(tonumber(newvalue) == 1)
+end)
+
+GM.EndWaveHealthBonus = CreateConVar("zs_endwavehealthbonus", "0", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Humans will get this much health after every wave. 0 to disable."):GetInt()
+cvars.AddChangeCallback("zs_endwavehealthbonus", function(cvar, oldvalue, newvalue)
+ GAMEMODE.EndWaveHealthBonus = tonumber(newvalue) or 0
+end)
+
+GM.GibLifeTime = CreateConVar("zs_giblifetime", "25", FCVAR_ARCHIVE, "Specifies how many seconds player gibs will stay in the world if not eaten or destroyed."):GetFloat()
+cvars.AddChangeCallback("zs_giblifetime", function(cvar, oldvalue, newvalue)
+ GAMEMODE.GibLifeTime = tonumber(newvalue) or 1
+end)
+
+GM.GriefForgiveness = math.ceil(100 * CreateConVar("zs_grief_forgiveness", "0.5", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Scales the damage given to griefable objects by this amount. Does not actually prevent damage, it only decides how much of a penalty to give the player. Use smaller values for more forgiving, larger for less forgiving."):GetFloat()) * 0.01
+cvars.AddChangeCallback("zs_grief_forgiveness", function(cvar, oldvalue, newvalue)
+ GAMEMODE.GriefForgiveness = math.ceil(100 * (tonumber(newvalue) or 1)) * 0.01
+end)
+
+GM.GriefStrict = CreateConVar("zs_grief_strict", "1", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Anti-griefing system. Gives points and eventually health penalties to humans who destroy friendly barricades."):GetBool()
+cvars.AddChangeCallback("zs_grief_strict", function(cvar, oldvalue, newvalue)
+ GAMEMODE.GriefStrict = tonumber(newvalue) == 1
+end)
+
+GM.GriefMinimumHealth = CreateConVar("zs_grief_minimumhealth", "100", FCVAR_ARCHIVE + FCVAR_NOTIFY, "The minimum health for an object to be considered griefable."):GetInt()
+cvars.AddChangeCallback("zs_grief_minimumhealth", function(cvar, oldvalue, newvalue)
+ GAMEMODE.GriefMinimumHealth = tonumber(newvalue) or 100
+end)
+
+GM.GriefDamageMultiplier = math.ceil(100 * CreateConVar("zs_grief_damagemultiplier", "0.5", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Multiplies damage done to griefable objects from humans by this amount."):GetFloat()) * 0.01
+cvars.AddChangeCallback("zs_grief_damagemultiplier", function(cvar, oldvalue, newvalue)
+ GAMEMODE.GriefDamageMultiplier = math.ceil(100 * (tonumber(newvalue) or 0.5)) * 0.01
+end)
+
+GM.GriefReflectThreshold = CreateConVar("zs_grief_reflectthreshold", "-5", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Start giving damage if the player has less than this many points."):GetInt()
+cvars.AddChangeCallback("zs_grief_reflectthreshold", function(cvar, oldvalue, newvalue)
+ GAMEMODE.GriefReflectThreshold = tonumber(newvalue) or -5
+end)
+
+GM.MaxPropsInBarricade = CreateConVar("zs_maxpropsinbarricade", "8", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Limits the amount of props that can be in one 'contraption' of nails."):GetInt()
+cvars.AddChangeCallback("zs_maxpropsinbarricade", function(cvar, oldvalue, newvalue)
+ GAMEMODE.MaxPropsInBarricade = tonumber(newvalue) or 8
+end)
+
+GM.MaxDroppedItems = CreateConVar("zs_maxdroppeditems", "32", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Maximum amount of dropped items. Prevents spam or lag when lots of people die."):GetInt()
+cvars.AddChangeCallback("zs_maxdroppeditems", function(cvar, oldvalue, newvalue)
+ GAMEMODE.MaxDroppedItems = tonumber(newvalue) or 32
+end)
+
+GM.NailHealthPerRepair = CreateConVar("zs_nailhealthperrepair", "10", FCVAR_ARCHIVE + FCVAR_NOTIFY, "How much health a nail gets when being repaired."):GetInt()
+cvars.AddChangeCallback("zs_nailhealthperrepair", function(cvar, oldvalue, newvalue)
+ GAMEMODE.NailHealthPerRepair = tonumber(newvalue) or 1
+end)
+
+GM.NoPropDamageFromHumanMelee = CreateConVar("zs_nopropdamagefromhumanmelee", "1", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Melee from humans doesn't damage props."):GetBool()
+cvars.AddChangeCallback("zs_nopropdamagefromhumanmelee", function(cvar, oldvalue, newvalue)
+ GAMEMODE.NoPropDamageFromHumanMelee = tonumber(newvalue) == 1
+end)
+
+GM.MedkitPointsPerHealth = CreateConVar("zs_medkitpointsperhealth", "5", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Specifies the amount of healing for players to be given a point. For use with the medkit and such."):GetInt()
+cvars.AddChangeCallback("zs_medkitpointsperhealth", function(cvar, oldvalue, newvalue)
+ GAMEMODE.MedkitPointsPerHealth = tonumber(newvalue) or 1
+end)
+
+GM.RepairPointsPerHealth = CreateConVar("zs_repairpointsperhealth", "30", FCVAR_ARCHIVE + FCVAR_NOTIFY, "Specifies the amount of repairing for players to be given a point. For use with nails and such."):GetInt()
+cvars.AddChangeCallback("zs_repairpointsperhealth", function(cvar, oldvalue, newvalue)
+ GAMEMODE.RepairPointsPerHealth = tonumber(newvalue) or 1
+end)
+
+local function GetMostKey(key, top)
+ top = top or 0
+ local toppl
+ for _, pl in pairs(player.GetAll()) do
+ if pl[key] and pl[key] > top then
+ top = pl[key]
+ toppl = pl
+ end
+ end
+
+ if toppl and top > 0 then
+ return toppl, top
+ end
+end
+
+local function GetMostFunc(func, top)
+ top = top or 0
+ local toppl
+ for _, pl in pairs(player.GetAll()) do
+ local amount = pl[func](pl)
+ if amount > top then
+ top = amount
+ toppl = pl
+ end
+ end
+
+ if toppl and top > 0 then
+ return toppl, top
+ end
+end
+
+GM.HonorableMentions[HM_MOSTZOMBIESKILLED].GetPlayer = function(self)
+ return GetMostKey("ZombiesKilled")
+end
+
+GM.HonorableMentions[HM_MOSTBRAINSEATEN].GetPlayer = function(self)
+ return GetMostKey("BrainsEaten")
+end
+
+GM.HonorableMentions[HM_SCARECROW].GetPlayer = function(self)
+ return GetMostKey("CrowKills")
+end
+
+GM.HonorableMentions[HM_CROWFIGHTER].GetPlayer = function(self)
+ return GetMostKey("CrowVsCrowKills")
+end
+
+GM.HonorableMentions[HM_CROWBARRICADEDAMAGE].GetPlayer = function(self)
+ return GetMostKey("CrowBarricadeDamage")
+end
+
+GM.HonorableMentions[HM_BARRICADEDESTROYER].GetPlayer = function(self)
+ return GetMostKey("BarricadeDamage")
+end
+
+GM.HonorableMentions[HM_SPAWNPOINT].GetPlayer = function(self)
+ return GetMostKey("DynamicSpawnedOn")
+end
+
+GM.HonorableMentions[HM_HANDYMAN].GetPlayer = function(self)
+ local pl, amount = GetMostKey("RepairedThisRound")
+ if pl and amount then
+ return pl, math.ceil(amount)
+ end
+end
+
+GM.HonorableMentions[HM_LASTHUMAN].GetPlayer = function(self)
+ if self.TheLastHuman and self.TheLastHuman:IsValid() then return self.TheLastHuman end
+end
+
+GM.HonorableMentions[HM_MOSTHELPFUL].GetPlayer = function(self)
+ return GetMostKey("ZombiesKilledAssists")
+end
+
+GM.HonorableMentions[HM_GOODDOCTOR].GetPlayer = function(self)
+ return GetMostKey("HealedThisRound")
+end
+
+GM.HonorableMentions[HM_MOSTDAMAGETOUNDEAD].GetPlayer = function(self)
+ local top = 0
+ local toppl
+ for _, pl in pairs(player.GetAll()) do
+ if pl.DamageDealt and pl.DamageDealt[TEAM_HUMAN] > top then
+ top = pl.DamageDealt[TEAM_HUMAN]
+ toppl = pl
+ end
+ end
+
+ if toppl and top >= 1 then
+ return toppl, math.ceil(top)
+ end
+end
+
+GM.HonorableMentions[HM_MOSTDAMAGETOHUMANS].GetPlayer = function(self)
+ local top = 0
+ local toppl
+ for _, pl in pairs(player.GetAll()) do
+ if pl.DamageDealt and pl.DamageDealt[TEAM_UNDEAD] > top then
+ top = pl.DamageDealt[TEAM_UNDEAD]
+ toppl = pl
+ end
+ end
+
+ if toppl and top >= 1 then
+ return toppl, math.ceil(top)
+ end
+end
+
+GM.HonorableMentions[HM_LASTBITE].GetPlayer = function(self)
+ if LAST_BITE and LAST_BITE:IsValid() then
+ return LAST_BITE
+ end
+end
+
+GM.HonorableMentions[HM_USEFULTOOPPOSITE].GetPlayer = function(self)
+ local pl, mag = GetMostFunc("Deaths")
+ if mag and mag >= 30 then
+ return pl, mag
+ end
+end
+
+GM.HonorableMentions[HM_PACIFIST].GetPlayer = function(self)
+ if WINNER == TEAM_HUMAN then
+ for _, pl in pairs(player.GetAll()) do
+ if pl.ZombiesKilled == 0 and pl:Team() == TEAM_HUMAN then return pl end
+ end
+ end
+end
+
+GM.HonorableMentions[HM_STUPID].GetPlayer = function(self)
+ local dist = 99999
+ local finalpl
+ for _, pl in pairs(player.GetAll()) do
+ if pl.ZombieSpawnDeathDistance and pl.ZombieSpawnDeathDistance < dist then
+ finalpl = pl
+ dist = pl.ZombieSpawnDeathDistance
+ end
+ end
+
+ if finalpl and dist <= 1000 then
+ return finalpl, math.ceil(dist / 12)
+ end
+end
+
+GM.HonorableMentions[HM_OUTLANDER].GetPlayer = function(self)
+ local dist = 0
+ local finalpl
+ for _, pl in pairs(player.GetAll()) do
+ if pl.ZombieSpawnDeathDistance and dist < pl.ZombieSpawnDeathDistance then
+ finalpl = pl
+ dist = pl.ZombieSpawnDeathDistance
+ end
+ end
+
+ if finalpl and 8000 <= dist then
+ return finalpl, math.ceil(dist / 12)
+ end
+end
+
+GM.HonorableMentions[HM_SALESMAN].GetPlayer = function(self)
+ return GetMostKey("PointsCommission")
+end
+
+GM.HonorableMentions[HM_WAREHOUSE].GetPlayer = function(self)
+ return GetMostKey("ResupplyBoxUsedByOthers")
+end
+
+GM.HonorableMentions[HM_NESTDESTROYER].GetPlayer = function(self)
+ return GetMostKey("NestsDestroyed")
+end
+
+GM.HonorableMentions[HM_NESTMASTER].GetPlayer = function(self)
+ return GetMostKey("NestSpawns")
+end
diff --git a/gamemodes/zombiesurvival/gamemode/sv_playerspawnentities.lua b/gamemodes/zombiesurvival/gamemode/sv_playerspawnentities.lua
new file mode 100644
index 0000000..aba56cb
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sv_playerspawnentities.lua
@@ -0,0 +1,40 @@
+-- thanks garry
+
+local ENT = {}
+
+ENT.Type = "point"
+
+function ENT:Initialize()
+end
+
+function ENT:Think()
+end
+
+function ENT:KeyValue(key, value)
+ key = string.lower(key)
+ if key == "disabled" then
+ self.Disabled = tonumber(value) == 1
+ elseif key == "active" then
+ self.Disabled = tonumber(value) == 0
+ end
+end
+
+function ENT:AcceptInput(name, activator, caller, arg)
+ name = string.lower(name)
+ if name == "enable" then
+ self.Disabled = false
+ return true
+ elseif name == "disable" then
+ self.Disabled = true
+ return true
+ elseif name == "toggle" then
+ self.Disabled = not self.Disabled
+ return true
+ end
+end
+
+function GM:RegisterPlayerSpawnEntities()
+ scripted_ents.Register(ENT, "info_player_zombie")
+ scripted_ents.Register(ENT, "info_player_undead")
+ scripted_ents.Register(ENT, "info_player_human")
+end
diff --git a/gamemodes/zombiesurvival/gamemode/sv_profiling.lua b/gamemodes/zombiesurvival/gamemode/sv_profiling.lua
new file mode 100644
index 0000000..0b41f83
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sv_profiling.lua
@@ -0,0 +1,248 @@
+-- This system creates nodes which can be used to spawn dynamic objectives.
+
+GM.ProfilerNodes = {}
+GM.ProfilerFolder = "zsprofiler"
+GM.ProfilerFolderPreMade = "profiler_premade"
+GM.MaxProfilerNodes = 128
+
+hook.Add("Initialize", "ZSProfiler", function()
+ file.CreateDir(GAMEMODE.ProfilerFolder)
+ file.CreateDir(GAMEMODE.ProfilerFolderPreMade)
+end)
+
+local mapname = string.lower(game.GetMap())
+if file.Exists(GM.ProfilerFolderPreMade.."/"..mapname..".txt", "DATA") then
+ GM.ProfilerIsPreMade = true
+ GM.ProfilerNodes = Deserialize(file.Read(GM.ProfilerFolderPreMade.."/"..mapname..".txt", "DATA"))
+ SRL = nil
+elseif file.Exists(GM.FolderName.."/gamemode/"..GM.ProfilerFolderPreMade.."/"..mapname..".lua", "LUA") then
+ include(GM.ProfilerFolderPreMade.."/"..mapname..".lua")
+ GM.ProfilerIsPreMade = true
+ GM.ProfilerNodes = SRL or GM.ProfilerNodes
+ SRL = nil
+end
+
+function GM:ClearProfiler()
+ if not self:ProfilerEnabled() then return end
+
+ self:SaveProfiler()
+end
+
+function GM:SaveProfilerPreMade(tab)
+ file.Write(self:GetProfilerFilePreMade(), Serialize(tab))
+end
+
+function GM:DeleteProfilerPreMade()
+ file.Delete(self:GetProfilerFilePreMade())
+end
+
+function GM:SaveProfiler()
+ if not self:ProfilerEnabled() or self.ProfilerIsPreMade then return end
+
+ file.Write(self:GetProfilerFile(), Serialize(self.ProfilerNodes))
+end
+
+function GM:LoadProfiler()
+ if not self:ProfilerEnabled() or self.ProfilerIsPreMade then return end
+
+ local filename = self:GetProfilerFile()
+ if file.Exists(filename, "DATA") then
+ self.ProfilerNodes = Deserialize(file.Read(filename, "DATA"))
+ end
+end
+
+function GM:GetProfilerFile()
+ return self.ProfilerFolder.."/"..string.lower(game.GetMap())..".txt"
+end
+
+function GM:GetProfilerFilePreMade()
+ return self.ProfilerFolderPreMade.."/"..string.lower(game.GetMap())..".txt"
+end
+
+function GM:ProfilerEnabled()
+ return not self.ZombieEscape and not self.ObjectiveMap
+end
+
+function GM:NeedsProfiling()
+ return #self.ProfilerNodes <= self.MaxProfilerNodes and not self.ProfilerIsPreMade
+end
+
+function GM:DebugProfiler()
+ for _, node in pairs(self.ProfilerNodes) do
+ local spawned = false
+ for __, e in pairs(ents.FindByClass("prop_dynamic*")) do
+ if e.IsNode and e:GetPos() == node then spawned = true end
+ end
+ if not spawned then
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetModel("models/player/breen.mdl")
+ ent:SetKeyValue("solid", "0")
+ ent:SetColor(Color(255, 0, 0))
+ ent:SetPos(node)
+ ent:Spawn()
+ ent.IsNode = true
+ end
+ end
+ end
+end
+
+local playerheight = Vector(0, 0, 92)
+local playermins = Vector(-24, -24, 0)
+local playermaxs = Vector(24, 24, 4)
+local vecsky = Vector(0, 0, 32000)
+local function SkewedDistance(a, b, skew)
+ if a.z > b.z then
+ return math.sqrt((b.x - a.x) ^ 2 + (b.y - a.y) ^ 2 + ((a.z - b.z) * skew) ^ 2)
+ end
+
+ return a:Distance(b)
+end
+
+function GM:ProfilerPlayerValid(pl)
+ -- Preliminary checks. We need to mark players as incompatible when they do certain things.
+ if pl.NoProfiling then return false end
+
+ -- Basic checks (movement, etc.)
+ if not (pl:Team() == TEAM_HUMAN and pl:Alive()
+ and pl:GetMoveType() == MOVETYPE_WALK and not pl:Crouching()
+ and pl:OnGround() and pl:IsOnGround() and pl:GetGroundEntity() == game.GetWorld()) then return false end
+
+ local plcenter = pl:LocalToWorld(pl:OBBCenter())
+ local plpos = pl:GetPos()
+
+ -- Are they near another node?
+ for _, node in pairs(self.ProfilerNodes) do
+ if SkewedDistance(node, plpos, 3) <= 128 then
+ --print('near')
+ return false
+ end
+ end
+
+ -- Are they inside something?
+ local pos = plpos + Vector(0, 0, 1)
+ if util.TraceHull({start = pos, endpos = pos + playerheight, mins = playermins, maxs = playermaxs, mask = MASK_SOLID, filter = team.GetPlayers(pl:Team())}).Hit then
+ --print('inside')
+ return false
+ end
+
+ -- Are they near a trigger hurt?
+ for _, ent in pairs(ents.FindInSphere(plcenter, 256)) do
+ local entclass = ent:GetClass()
+ if entclass == "trigger_hurt" then
+ --print('trigger hurt')
+ return false
+ end
+ end
+
+ -- What about zombie spawns?
+ for _, ent in pairs(team.GetValidSpawnPoint(TEAM_UNDEAD)) do
+ if ent:GetPos():Distance(plcenter) < 420 then
+ --print('near spawn')
+ return false
+ end
+ end
+
+ -- Time for the more complicated stuff.
+ local trace = {start = plcenter, endpos = plcenter + vecsky, mins = playermins, maxs = playermaxs, mask = MASK_SOLID_BRUSHONLY}
+ local trsky = util.TraceHull(trace)
+ if trsky.HitSky or trsky.HitNoDraw then
+ --print('outside')
+ return false
+ end
+
+ -- Check to see if they're near a window or the entrance of somewhere. This also doubles as a check for long hallways.
+ local ang = Angle(0, 0, 0)
+ for t = 0, 359, 15 do
+ ang.yaw = t
+
+ for d = 32, 92, 24 do
+ trace.start = plcenter + ang:Forward() * d
+ trace.endpos = trace.start + Vector(0, 0, 640)
+ local tr = util.TraceHull(trace)
+ if not tr.Hit or tr.HitNormal.z > -0.65 then
+ --print('not hit ceiling')
+ return false
+ end
+ trace.endpos = trace.start + Vector(0, 0, -64)
+ local tr = util.TraceHull(trace)
+ if not tr.Hit or tr.HitNormal.z < 0.65 then
+ --print('not hit floor')
+ return false
+ end
+ end
+ end
+
+ -- Are they outside?
+ --[[local trace = {start = plcenter, endpos = plcenter + vecsky, mins = playermins, maxs = playermaxs, mask = MASK_SOLID_BRUSHONLY}
+ local trsky = util.TraceHull(trace)
+ if trsky.HitSky or trsky.HitNoDraw then
+ --print('outside')
+ return false
+ end
+
+ -- Check to see if they're near a window or the entrance of somewhere. This also doubles as a check for long hallways.
+ local ang = Angle(-30, 0, 0)
+ for t = 0, 359, 15 do
+ ang.yaw = t
+
+ trace.endpos = trace.start + ang:Forward() * 350
+ local tr = util.TraceLine(trace)
+ if not tr.Hit then
+ --print('not hit ceiling')
+ return false
+ end
+ end
+
+ local ang = Angle(-50, 0, 0)
+ for t = 0, 359, 15 do
+ ang.yaw = t
+
+ trace.endpos = trace.start + ang:Forward() * 300
+ local tr = util.TraceLine(trace)
+ if tr.Fraction == 0 or tr.HitSky or tr.HitNoDraw or tr.HitNormal.z > -0.65 then
+ print('fractions differ')
+ return false
+ end
+ end
+
+ -- Check to make sure the floor is even all around.
+ local ang = Angle(55, 0, 0)
+ local floordist = playerheight.z
+ for t = 0, 359, 15 do
+ ang.yaw = t
+
+ trace.endpos = trace.start + ang:Forward() * floordist
+ local tr = util.TraceLine(trace)
+ if not tr.Hit then
+ --print('floor uneven')
+ return false
+ end
+ end]]
+
+ --print('valid')
+ return true
+end
+
+function GM:ProfilerTick()
+ if not self:ProfilerEnabled() or not self:NeedsProfiling() then return end
+
+ local changed = false
+ for _, pl in pairs(player.GetAll()) do
+ if not self:ProfilerPlayerValid(pl) then continue end
+
+ table.insert(self.ProfilerNodes, pl:GetPos())
+
+ changed = true
+ end
+
+ if changed then
+ self:SaveProfiler() --self:DebugProfiler()
+ end
+end
+timer.Create("ZSProfiler", 3, 0, function() GAMEMODE:ProfilerTick() end)
+hook.Add("OnWaveStateChanged", "ZSProfiler", function() -- Only profile during start
+ if GAMEMODE:GetWave() > 0 then
+ timer.Destroy("ZSProfiler")
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/sv_sigils.lua b/gamemodes/zombiesurvival/gamemode/sv_sigils.lua
new file mode 100644
index 0000000..12a9ee6
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sv_sigils.lua
@@ -0,0 +1,94 @@
+function GM:OnSigilDestroyed(ent, dmginfo)
+ local numsigils = self:NumSigils()
+ if numsigils > 0 then
+ for _, pl in pairs(player.GetAll()) do
+ pl:CenterNotify({killicon = "default"}, " ", COLOR_RED, translate.ClientGet(pl, "sigil_destroyed"), {killicon = "default"})
+ if numsigils == 1 then
+ pl:CenterNotify(COLOR_RED, translate.ClientGet(pl, pl:Team() == TEAM_HUMAN and "sigil_destroyed_only_one_remain_h" or "sigil_destroyed_only_one_remain_z"))
+ else
+ pl:CenterNotify(COLOR_RED, translate.ClientFormat(pl, "sigil_destroyed_x_remain", numsigils))
+ end
+ end
+ else
+ for _, pl in pairs(player.GetAll()) do
+ pl:CenterNotify({killicon = "default"}, " ", COLOR_RED, translate.ClientGet(pl, "last_sigil_destroyed_all_is_lost"), {killicon = "default"})
+ pl:CenterNotify(COLOR_RED, translate.ClientGet(pl, "last_sigil_destroyed_all_is_lost2"))
+ end
+
+ self.LastHumanPosition = ent:LocalToWorld(ent:OBBCenter())
+ timer.Simple(4, function() gamemode.Call("EndRound", TEAM_UNDEAD) end)
+ end
+end
+
+local function SortDistFromLast(a, b)
+ return a.d < b.d
+end
+function GM:CreateSigils()
+ if #self.ProfilerNodes < self.MaxSigils
+ or self.ZombieEscape or self.ObjectiveMap
+ or self:IsClassicMode() or self.PantsMode or self:IsBabyMode() then
+ self:SetUseSigils(false)
+ return
+ end
+
+ -- Copy
+ local nodes = {}
+ for _, node in pairs(self.ProfilerNodes) do
+ local vec = Vector()
+ vec:Set(node)
+ nodes[#nodes + 1] = {v = vec}
+ end
+
+ local spawns = team.GetSpawnPoint(TEAM_UNDEAD)
+ for i=1, self.MaxSigils do
+ local id
+ local sigs = ents.FindByClass("prop_obj_sigil")
+
+ for _, n in pairs(nodes) do
+ n.d = 999999
+
+ for __, spawn in pairs(spawns) do
+ n.d = math.min(n.d, n.v:Distance(spawn:GetPos()))
+ end
+ for __, sig in pairs(sigs) do
+ n.d = math.min(n.d, n.v:Distance(sig.NodePos))
+ end
+
+ local tr = util.TraceLine({start = n.v + Vector(0, 0, 8), endpos = n.v + Vector(0, 0, 512), mask = MASK_SOLID_BRUSHONLY})
+ n.d = n.d * (2 - tr.Fraction)
+ end
+
+ -- Sort the nodes by their distances.
+ table.sort(nodes, SortDistFromLast)
+
+ -- Now select a node using an exponential weight.
+ -- We use a random float between 0 and 1 then sqrt it.
+ -- This way we're much more likely to get a lower index but a higher index is still possible.
+ id = math.Rand(0, 0.7) ^ 0.3
+ id = math.Clamp(math.ceil(id * #nodes), 1, #nodes)
+
+ -- Remove the chosen point from the temp table and make the sigil.
+ local point = nodes[id].v
+ table.remove(nodes, id)
+
+ local ent = ents.Create("prop_obj_sigil")
+ if ent:IsValid() then
+ ent:SetPos(point)
+ ent:Spawn()
+ ent.NodePos = point
+ end
+ end
+
+ self:SetUseSigils(#ents.FindByClass("prop_obj_sigil") > 0)
+end
+
+function GM:SetUseSigils(use)
+ if self:GetUseSigils() ~= use then
+ self.UseSigils = use
+ SetGlobalBool("sigils", true)
+ end
+end
+
+function GM:GetUseSigils(use)
+ return self.UseSigils
+end
diff --git a/gamemodes/zombiesurvival/gamemode/sv_zombieescape.lua b/gamemodes/zombiesurvival/gamemode/sv_zombieescape.lua
new file mode 100644
index 0000000..a7d5729
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/sv_zombieescape.lua
@@ -0,0 +1,150 @@
+AddCSLuaFile("cl_zombieescape.lua")
+AddCSLuaFile("sh_zombieescape.lua")
+
+include("sh_zombieescape.lua")
+
+if not GM.ZombieEscape then return end
+
+table.insert(GM.CleanupFilter, "func_brush")
+table.insert(GM.CleanupFilter, "env_global")
+
+-- We need to fix these important entities.
+hook.Add("EntityKeyValue", "zombieescape", function(ent, key, value)
+ -- The teamid for Terrorist and Counter Terrorist is different than Zombie and Human in ZS.
+ if ent:GetClass() == "filter_activator_team" and not ent.ZEFix then
+ if string.lower(key) == "filterteam" then
+ if value == "2" then
+ ent.ZEFix = tostring(TEAM_UNDEAD)
+ elseif value == "3" then
+ ent.ZEFix = tostring(TEAM_HUMAN)
+ end
+ end
+
+ return true
+ end
+
+ -- Some maps have brushes that regenerate or set health to dumb values. We don't want them. Although this can break maps I can't think of a way to remove the output instead.
+ if (ent:GetClass() == "trigger_multiple" or ent:GetClass() == "trigger_once") and string.find(string.lower(value), "%!.*%,.+%,health") then
+ ent.ZEDelete = true
+ end
+end)
+
+hook.Add("InitPostEntityMap", "zombieescape", function(fromze)
+ for _, ent in pairs(ents.FindByClass("filter_activator_team")) do
+ if ent.ZEFix then
+ ent:SetKeyValue("filterteam", ent.ZEFix)
+ end
+ end
+
+ for _, ent in pairs(ents.GetAll()) do
+ if ent.ZEDelete then
+ ent:Remove()
+ end
+ end
+
+ -- Forced dynamic spawning.
+ -- It'd be pretty damn boring for the zombies with it off since there's only one spawn usually.
+ GAMEMODE.DynamicSpawning = true
+
+ if not fromze then
+ GAMEMODE:SetRedeemBrains(0)
+ if GAMEMODE.CurrentRound <= 1 then
+ GAMEMODE:SetWaveStart(CurTime() + GAMEMODE.WaveZeroLength + 30) -- 30 extra seconds for late joiners
+ else
+ GAMEMODE:SetWaveStart(CurTime() + GAMEMODE.ZE_FreezeTime + 5)
+ end
+ end
+end)
+
+hook.Add("PlayerSpawn", "zombieescape", function(pl)
+ timer.Simple(0, function()
+ if not pl:IsValid() then return end
+
+ if GAMEMODE:GetWave() == 0 and not GAMEMODE:GetWaveActive() and (pl:Team() == TEAM_UNDEAD or CurTime() < GAMEMODE:GetWaveStart() - GAMEMODE.ZE_FreezeTime) then
+ pl.ZEFreeze = true
+ pl:Freeze(true)
+ pl:GodEnable()
+ end
+ end)
+end)
+
+-- In ze_ the winning condition is when all players on the zombie team are dead at the exact same time.
+-- Usually set on by a trigger_hurt that takes over the entire map.
+-- So if all living zombies get killed at the same time from a trigger_hurt that did massive damage, we end the round in favor of the humans.
+-- But in order to do that we have to force zombies to spawn. Which is shitty.
+
+hook.Add("OnWaveStateChanged", "zombieescape", function()
+ if GAMEMODE:GetWave() == 1 and GAMEMODE:GetWaveActive() then
+ for _, pl in pairs(player.GetAll()) do
+ pl:Freeze(false)
+ pl:GodDisable()
+ end
+ end
+end)
+
+local CheckTime
+local FreezeTime = true
+local NextDamage = 0
+hook.Add("Think", "zombieescape", function()
+ if GAMEMODE:GetWave() == 0 then
+ if FreezeTime and CurTime() >= GAMEMODE:GetWaveStart() - GAMEMODE.ZE_FreezeTime then
+ FreezeTime = false
+
+ game.CleanUpMap(false, GAMEMODE.CleanupFilter)
+ gamemode.Call("InitPostEntityMap", true)
+
+ for _, pl in pairs(team.GetPlayers(TEAM_HUMAN)) do
+ pl.ZEFreeze = nil
+ pl:Freeze(false)
+ pl:GodDisable()
+ local ent = GAMEMODE:PlayerSelectSpawn(pl)
+ if IsValid(ent) then
+ pl:SetPos(ent:GetPos())
+ end
+ end
+ end
+
+ return
+ end
+
+ FreezeTime = true
+
+ if CurTime() >= GAMEMODE:GetWaveStart() + GAMEMODE.ZE_TimeLimit and CurTime() >= NextDamage then
+ NextDamage = CurTime() + 1
+
+ for _, pl in pairs(team.GetPlayers(TEAM_HUMAN)) do
+ pl:TakeDamage(5)
+ end
+ end
+
+ local undead = team.GetPlayers(TEAM_UNDEAD)
+ if #undead == 0 then return end
+
+ for _, pl in pairs(undead) do
+ if not pl.KilledByTriggerHurt or CurTime() > pl.KilledByTriggerHurt + 12 then
+ CheckTime = nil
+ return
+ end
+ end
+
+ CheckTime = CheckTime or (CurTime() + 2.5)
+
+ if CheckTime and CurTime() >= CheckTime then
+ gamemode.Call("EndRound", TEAM_HUMAN)
+ end
+end)
+
+hook.Add("DoPlayerDeath", "zombieescape", function(pl, attacker, dmginfo)
+ pl.KilledPos = pl:GetPos()
+
+ if pl:Team() == TEAM_UNDEAD then
+ if attacker:IsValid() and attacker:GetClass() == "trigger_hurt" --[[and dmginfo:GetDamage() >= 1000]] then
+ pl.KilledByTriggerHurt = CurTime()
+ pl.NextSpawnTime = CurTime() + 10
+ elseif GAMEMODE.RoundEnded then
+ pl.NextSpawnTime = CurTime() + 9999
+ else
+ pl.NextSpawnTime = CurTime() + 5
+ end
+ end
+end)
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/dammocounter.lua b/gamemodes/zombiesurvival/gamemode/vgui/dammocounter.lua
new file mode 100644
index 0000000..b9ca470
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/dammocounter.lua
@@ -0,0 +1,90 @@
+local PANEL = {}
+
+PANEL.NextRefresh = 0
+PANEL.RefreshTime = 1
+
+local col2 = Color(180, 100, 0, 200)
+
+local function GetTargetEntIndex()
+ return GAMEMODE.HumanMenuLockOn and GAMEMODE.HumanMenuLockOn:IsValid() and GAMEMODE.HumanMenuLockOn:EntIndex() or 0
+end
+
+local function DropDoClick(self)
+ RunConsoleCommand("zsdropammo", self:GetParent():GetAmmoType())
+end
+
+local function GiveDoClick(self)
+ RunConsoleCommand("zsgiveammo", self:GetParent():GetAmmoType(), GetTargetEntIndex())
+end
+
+function PANEL:Init()
+ self.m_AmmoCountLabel = EasyLabel(self, "0", "DefaultFontBold", color_black)
+
+ self.m_AmmoTypeLabel = EasyLabel(self, " ", "ZSAmmoName", col2)
+
+ self.m_DropButton = vgui.Create("DImageButton", self)
+ self.m_DropButton:SetImage("icon16/box.png")
+ self.m_DropButton:SizeToContents()
+ self.m_DropButton:SetTooltip("Drop")
+ self.m_DropButton.DoClick = DropDoClick
+
+ self.m_GiveButton = vgui.Create("DImageButton", self)
+ self.m_GiveButton:SetImage("icon16/user_go.png")
+ self.m_GiveButton:SizeToContents()
+ self.m_GiveButton:SetTooltip("Give")
+ self.m_GiveButton.DoClick = GiveDoClick
+
+ self:SetAmmoType("pistol")
+end
+
+local colBG = Color(5, 5, 5, 180)
+function PANEL:Paint()
+ local tall = self:GetTall()
+ local csize = tall - 8
+ draw.RoundedBox(8, 0, 0, self:GetWide(), tall, colBG)
+ draw.RoundedBox(8, 8, tall * 0.5 - csize * 0.5, csize, csize, col2)
+
+ return true
+end
+
+function PANEL:Think()
+ if RealTime() >= self.NextRefresh then
+ self.NextRefresh = RealTime() + self.RefreshTime
+ self:Refresh()
+ end
+end
+
+function PANEL:Refresh()
+ self.m_AmmoCountLabel:SetText(MySelf:GetAmmoCount(self:GetAmmoType()))
+ self.m_AmmoCountLabel:SizeToContents()
+
+ self:InvalidateLayout()
+end
+
+function PANEL:PerformLayout()
+ self.m_AmmoTypeLabel:Center()
+
+ self.m_AmmoCountLabel:SetPos(8 + (self:GetTall() - 8) * 0.5 - self.m_AmmoCountLabel:GetWide() / 2, 0)
+ self.m_AmmoCountLabel:CenterVertical()
+
+ self.m_DropButton:AlignTop(1)
+ self.m_DropButton:AlignRight(8)
+
+ self.m_GiveButton:AlignBottom(1)
+ self.m_GiveButton:AlignRight(8)
+end
+
+function PANEL:SetAmmoType(ammotype)
+ self.m_AmmoType = ammotype
+
+ self.m_AmmoTypeLabel:SetText(GAMEMODE.AmmoNames[ammotype] or ammotype)
+ self.m_AmmoTypeLabel:SizeToContents()
+
+ self:Refresh()
+end
+
+function PANEL:GetAmmoType()
+ return self.m_AmmoType
+end
+
+vgui.Register("DAmmoCounter", PANEL, "DPanel")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/dexchanginglabel.lua b/gamemodes/zombiesurvival/gamemode/vgui/dexchanginglabel.lua
new file mode 100644
index 0000000..824b01c
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/dexchanginglabel.lua
@@ -0,0 +1,36 @@
+local PANEL = {}
+
+local function empty() end
+
+function PANEL:SetChangeFunction(func, autosize)
+ self.Think = function(me)
+ local val = func()
+ if self.LastValue ~= val and val ~= nil then
+ self.LastValue = val
+
+ self:SetText(val)
+
+ if autosize then
+ self:SizeToContents()
+ end
+
+ if self.OnChanged then
+ self:OnChanged(val)
+ end
+ end
+ end
+end
+
+function PANEL:RemoveChangeFunction()
+ self.Think = empty
+end
+
+function PANEL:SetChangedFunction(func)
+ self.OnChanged = func
+end
+
+function PANEL:RemoveChangedFunction()
+ self.OnChanged = empty
+end
+
+vgui.Register("DEXChangingLabel", PANEL, "DLabel")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/dexnotificationslist.lua b/gamemodes/zombiesurvival/gamemode/vgui/dexnotificationslist.lua
new file mode 100644
index 0000000..bd8fd11
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/dexnotificationslist.lua
@@ -0,0 +1,186 @@
+GM.NotifyFadeTime = 8
+
+local DefaultFont = "ZSHUDFontSmallest"
+local DefaultFontEntity = "ZSHUDFontSmallest"
+
+local PANEL = {}
+
+function PANEL:Init()
+ self:DockPadding(8, 2, 8, 2)
+end
+
+local matGrad = Material("VGUI/gradient-r")
+function PANEL:Paint()
+ surface.SetMaterial(matGrad)
+ surface.SetDrawColor(0, 0, 0, 180)
+
+ local align = self:GetParent():GetAlign()
+ if align == RIGHT then
+ surface.DrawTexturedRect(self:GetWide() * 0.25, 0, self:GetWide(), self:GetTall())
+ elseif align == CENTER then
+ surface.DrawTexturedRect(self:GetWide() * 0.25, 0, self:GetWide() * 0.25, self:GetTall())
+ surface.DrawTexturedRectRotated(self:GetWide() * 0.625, self:GetTall() / 2, self:GetWide() * 0.25, self:GetTall(), 180)
+ else
+ surface.DrawTexturedRectRotated(self:GetWide() * 0.25, self:GetTall() / 2, self:GetWide() / 2, self:GetTall(), 180)
+ end
+end
+
+function PANEL:AddLabel(text, col, font, extramargin)
+ local label = vgui.Create("DLabel", self)
+ label:SetText(text)
+ label:SetFont(font or DefaultFont)
+ label:SetTextColor(col or color_white)
+ label:SizeToContents()
+ if extramargin then
+ label:SetContentAlignment(7)
+ label:DockMargin(0, label:GetTall() * 0.2, 0, 0)
+ else
+ label:SetContentAlignment(4)
+ end
+ label:Dock(LEFT)
+end
+
+function PANEL:AddImage(mat, col)
+ local img = vgui.Create("DImage", self)
+ img:SetImage(mat)
+ if col then
+ img:SetImageColor(col)
+ end
+ img:SizeToContents()
+ local height = img:GetTall()
+ if height > self:GetTall() then
+ img:SetSize(self:GetTall() / height * img:GetWide(), self:GetTall())
+ end
+ img:DockMargin(0, (self:GetTall() - img:GetTall()) / 2, 0, 0)
+ img:Dock(LEFT)
+end
+
+function PANEL:AddKillIcon(class)
+ local icondata = killicon.GetIcon(class)
+
+ if icondata then
+ self:AddImage(icondata[1], icondata[2])
+ else
+ local fontdata = killicon.GetFont(class) or killicon.GetFont("default")
+ if fontdata then
+ self:AddLabel(fontdata[2], fontdata[3], fontdata[1], true)
+ end
+ end
+end
+
+function PANEL:SetNotification(...)
+ local args = {...}
+
+ local defaultcol = color_white
+ local defaultfont
+ for k, v in ipairs(args) do
+ local vtype = type(v)
+
+ if vtype == "table" then
+ if v.r and v.g and v.b then
+ defaultcol = v
+ elseif v.font then
+ if v.font == "" then
+ defaultfont = nil
+ else
+ local th = draw.GetFontHeight(v.font)
+ if tw then
+ defaultfont = v.font
+ end
+ end
+ elseif v.killicon then
+ self:AddKillIcon(v.killicon)
+ if v.headshot then
+ self:AddKillIcon("headshot")
+ end
+ elseif v.image then
+ self:AddImage(v.image, v.color)
+ end
+ elseif vtype == "Player" then
+ local avatar = vgui.Create("AvatarImage", self)
+ local size = self:GetTall() >= 32 and 32 or 16
+ avatar:SetSize(size, size)
+ if v:IsValid() then
+ avatar:SetPlayer(v, size)
+ end
+ avatar:SetAlpha(220)
+ avatar:Dock(LEFT)
+ avatar:DockMargin(0, (self:GetTall() - avatar:GetTall()) / 2, 0, 0)
+
+ if v:IsValid() then
+ self:AddLabel(" "..v:Name(), team.GetColor(v:Team()), DefaultFontEntity)
+ else
+ self:AddLabel(" ?", team.GetColor(TEAM_UNASSIGNED), DefaultFontEntity)
+ end
+ elseif vtype == "Entity" then
+ self:AddLabel("["..(v:IsValid() and v:GetClass() or "?").."]", COLOR_RED, DefaultFontEntity)
+ else
+ local text = tostring(v)
+
+ self:AddLabel(text, defaultcol, defaultfont)
+ end
+ end
+end
+
+vgui.Register("DEXNotification", PANEL, "Panel")
+
+local PANEL = {}
+
+AccessorFunc(PANEL, "m_Align", "Align", FORCE_NUMBER)
+AccessorFunc(PANEL, "m_MessageHeight", "MessageHeight", FORCE_NUMBER)
+
+function PANEL:Init()
+ self:SetAlign(LEFT)
+ self:SetMessageHeight(32)
+ self:ParentToHUD()
+ self:InvalidateLayout()
+end
+
+function PANEL:PerformLayout()
+end
+
+function PANEL:Paint()
+end
+
+function PANEL:AddNotification(...)
+ local notif = vgui.Create("DEXNotification", self)
+ notif:SetTall(BetterScreenScale() * self:GetMessageHeight())
+ notif:SetNotification(...)
+ local w = 0
+ for _, p in pairs(notif:GetChildren()) do
+ w = w + p:GetWide()
+ end
+ if self:GetAlign() == RIGHT then
+ notif:DockPadding(self:GetWide() - w - 32, 0, 8, 0)
+ elseif self:GetAlign() == CENTER then
+ notif:DockPadding((self:GetWide() - w) / 2, 0, 0, 0)
+ else
+ notif:DockPadding(8, 0, 8, 0)
+ end
+
+ notif:Dock(TOP)
+
+ notif:SetAlpha(1)
+ notif:AlphaTo(255, 0.5)
+ notif:AlphaTo(1, 1, GAMEMODE.NotifyFadeTime - 1)
+
+ notif.DieTime = CurTime() + GAMEMODE.NotifyFadeTime
+
+ return notif
+end
+
+function PANEL:Think()
+ local time = CurTime()
+
+ for i, pan in pairs(self:GetChildren()) do
+ if pan.DieTime and time >= pan.DieTime then
+ pan:Remove()
+ local dummy = vgui.Create("Panel", self)
+ dummy:SetTall(0)
+ dummy:Dock(TOP)
+ dummy:Remove()
+ end
+ end
+end
+
+vgui.Register("DEXNotificationsList", PANEL, "Panel")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/dexrotatedimage.lua b/gamemodes/zombiesurvival/gamemode/vgui/dexrotatedimage.lua
new file mode 100644
index 0000000..c3157a8
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/dexrotatedimage.lua
@@ -0,0 +1,77 @@
+local PANEL = {}
+
+function PANEL:PaintAt( x, y, dw, dh )
+
+ self:LoadMaterial()
+
+ if ( !self.m_Material ) then return true end
+
+ surface.SetMaterial( self.m_Material )
+ surface.SetDrawColor( self.m_Color.r, self.m_Color.g, self.m_Color.b, self.m_Color.a )
+
+ if ( self:GetKeepAspect() ) then
+
+ local w = self.ActualWidth
+ local h = self.ActualHeight
+
+ -- Image is bigger than panel, shrink to suitable size
+ if ( w > dw && h > dh ) then
+
+ if ( w > dw ) then
+
+ local diff = dw / w
+ w = w * diff
+ h = h * diff
+
+ end
+
+ if ( h > dh ) then
+
+ local diff = dh / h
+ w = w * diff
+ h = h * diff
+
+ end
+
+ end
+
+ if ( w < dw ) then
+
+ local diff = dw / w
+ w = w * diff
+ h = h * diff
+
+ end
+
+ if ( h < dh ) then
+
+ local diff = dh / h
+ w = w * diff
+ h = h * diff
+
+ end
+
+ local OffX = (dw - w) * 0.5
+ local OffY = (dh - h) * 0.5
+
+ surface.DrawTexturedRect( OffX+x, OffY+y, w, h )
+
+ return true
+
+ end
+
+
+ surface.DrawTexturedRectRotated( x + dw / 2, y + dh / 2, dw, dh, self:GetRotation() )
+ return true
+
+end
+
+function PANEL:SetRotation(m)
+ self.m_Rotation = m
+end
+
+function PANEL:GetRotation()
+ return self.m_Rotation or 0
+end
+
+vgui.Register("DEXRotatedImage", PANEL, "DImage")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/dexroundedframe.lua b/gamemodes/zombiesurvival/gamemode/vgui/dexroundedframe.lua
new file mode 100644
index 0000000..0a40bee
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/dexroundedframe.lua
@@ -0,0 +1,72 @@
+local PANEL = {}
+
+AccessorFunc(PANEL, "m_iBorderRadius", "BorderRadius", FORCE_NUMBER)
+AccessorFunc(PANEL, "m_bCurveTopLeft", "CurveTopLeft", FORCE_BOOL)
+AccessorFunc(PANEL, "m_bCurveTopRight", "CurveTopRight", FORCE_BOOL)
+AccessorFunc(PANEL, "m_bCurveBottomLeft", "CurveBottomLeft", FORCE_BOOL)
+AccessorFunc(PANEL, "m_bCurveBottomRight", "CurveBottomRight", FORCE_BOOL)
+
+AccessorFunc(PANEL, "m_tColor", "Color")
+
+local function CloseDoClick(self)
+ self:GetParent():Close()
+end
+
+function PANEL:Init()
+ self:SetBorderRadius(8)
+ self:SetCurve(true)
+
+ self:SetColor(Color(0, 0, 0, 180))
+
+ self:ShowCloseButton(false)
+ self:SetTitle(" ")
+
+ self.CloseButton = vgui.Create("DImageButton", self)
+ self.CloseButton:SetImage("VGUI/notices/error")
+ self.CloseButton:SetSize(32, 32)
+ self.CloseButton:NoClipping(true)
+ self.CloseButton:SetZPos(-10)
+ self.CloseButton.DoClick = CloseDoClick
+ local oldpaint = self.CloseButton.m_Image.Paint
+ self.CloseButton.m_Image.Paint = function(me)
+ surface.DisableClipping(true)
+ oldpaint(me)
+ surface.DisableClipping(false)
+ end
+
+ self.lblTitle:SetFont("dexfont_med")
+
+ self:InvalidateLayout()
+end
+
+function PANEL:PerformLayout()
+ self.lblTitle:SetWide(self:GetWide() - 25)
+ self.lblTitle:SetPos(8, 2)
+
+ self.CloseButton:AlignRight(self.CloseButton:GetWide() * -0.25)
+ self.CloseButton:AlignTop(self.CloseButton:GetTall() * -0.25)
+end
+
+function PANEL:SetTitle(title)
+ self.lblTitle:SetText(title)
+ self.lblTitle:SizeToContents()
+
+ self:InvalidateLayout()
+end
+
+function PANEL:SetCurve(curve)
+ self:SetCurveTopLeft(curve)
+ self:SetCurveTopRight(curve)
+ self:SetCurveBottomLeft(curve)
+ self:SetCurveBottomRight(curve)
+end
+
+function PANEL:SetColorAlpha(a)
+ self:GetColor().a = a
+end
+
+function PANEL:Paint()
+ draw.RoundedBoxEx(self:GetBorderRadius(), 0, 0, self:GetWide(), self:GetTall(), self:GetColor(), self:GetCurveTopLeft(), self:GetCurveTopRight(), self:GetCurveBottomLeft(), self:GetCurveBottomRight())
+end
+
+vgui.Register("DEXRoundedFrame", PANEL, "DFrame")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/dexroundedpanel.lua b/gamemodes/zombiesurvival/gamemode/vgui/dexroundedpanel.lua
new file mode 100644
index 0000000..f659983
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/dexroundedpanel.lua
@@ -0,0 +1,35 @@
+surface.CreateFont("dexfont_med", {font = "impact", size = 19, weight = 0, antialias = false, shadow = false, outline = true})
+
+local PANEL = {}
+
+AccessorFunc(PANEL, "m_iBorderRadius", "BorderRadius", FORCE_NUMBER)
+AccessorFunc(PANEL, "m_bCurveTopLeft", "CurveTopLeft", FORCE_BOOL)
+AccessorFunc(PANEL, "m_bCurveTopRight", "CurveTopRight", FORCE_BOOL)
+AccessorFunc(PANEL, "m_bCurveBottomLeft", "CurveBottomLeft", FORCE_BOOL)
+AccessorFunc(PANEL, "m_bCurveBottomRight", "CurveBottomRight", FORCE_BOOL)
+
+AccessorFunc(PANEL, "m_tColor", "Color")
+
+function PANEL:Init()
+ self:SetBorderRadius(8)
+ self:SetCurve(true)
+
+ self:SetColor(Color(10, 10, 10, 120))
+end
+
+function PANEL:SetCurve(curve)
+ self:SetCurveTopLeft(curve)
+ self:SetCurveTopRight(curve)
+ self:SetCurveBottomLeft(curve)
+ self:SetCurveBottomRight(curve)
+end
+
+function PANEL:SetColorAlpha(a)
+ self:GetColor().a = a
+end
+
+function PANEL:Paint(w, h)
+ draw.RoundedBoxEx(self:GetBorderRadius(), 0, 0, w, h, self:GetColor(), self:GetCurveTopLeft(), self:GetCurveTopRight(), self:GetCurveBottomLeft(), self:GetCurveBottomRight())
+end
+
+vgui.Register("DEXRoundedPanel", PANEL, "DPanel")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/dgamestate.lua b/gamemodes/zombiesurvival/gamemode/vgui/dgamestate.lua
new file mode 100644
index 0000000..cfb4d2c
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/dgamestate.lua
@@ -0,0 +1,139 @@
+local PANEL = {}
+
+function PANEL:Init()
+ self.m_HumanCount = vgui.Create("DTeamCounter", self)
+ self.m_HumanCount:SetTeam(TEAM_HUMAN)
+ self.m_HumanCount:SetImage("zombiesurvival/humanhead")
+
+ self.m_ZombieCount = vgui.Create("DTeamCounter", self)
+ self.m_ZombieCount:SetTeam(TEAM_UNDEAD)
+ self.m_ZombieCount:SetImage("zombiesurvival/zombiehead")
+
+ self.m_Text1 = vgui.Create("DLabel", self)
+ self.m_Text2 = vgui.Create("DLabel", self)
+ self.m_Text3 = vgui.Create("DLabel", self)
+ self:SetTextFont("ZSHUDFontTiny")
+
+ self.m_Text1.Paint = self.Text1Paint
+ self.m_Text2.Paint = self.Text2Paint
+ self.m_Text3.Paint = self.Text3Paint
+
+ self:InvalidateLayout()
+end
+
+function PANEL:SetTextFont(font)
+ self.m_Text1.Font = font
+ self.m_Text1:SetFont(font)
+ self.m_Text2.Font = font
+ self.m_Text2:SetFont(font)
+ self.m_Text3.Font = font
+ self.m_Text3:SetFont(font)
+
+ self:InvalidateLayout()
+end
+
+function PANEL:PerformLayout()
+ local hs = self:GetTall() * 0.5
+ self.m_HumanCount:SetSize(hs, hs)
+ self.m_ZombieCount:SetSize(hs, hs)
+ self.m_ZombieCount:AlignTop(hs)
+
+ self.m_Text1:SetWide(self:GetWide())
+ self.m_Text1:SizeToContentsY()
+ self.m_Text1:MoveRightOf(self.m_HumanCount, 12)
+ self.m_Text1:AlignTop(4)
+ self.m_Text2:SetWide(self:GetWide())
+ self.m_Text2:SizeToContentsY()
+ self.m_Text2:MoveRightOf(self.m_HumanCount, 12)
+ self.m_Text2:CenterVertical()
+ self.m_Text3:SetWide(self:GetWide())
+ self.m_Text3:SizeToContentsY()
+ self.m_Text3:MoveRightOf(self.m_HumanCount, 12)
+ self.m_Text3:AlignBottom(4)
+end
+
+function PANEL:Text1Paint()
+ local text
+ local override = MySelf:IsValid() and GetGlobalString("hudoverride"..MySelf:Team(), "")
+
+ if override and #override > 0 then
+ text = override
+ else
+ local wave = GAMEMODE:GetWave()
+ if GAMEMODE:IsEscapeSequence() then
+ text = translate.Get(MySelf:IsValid() and MySelf:Team() == TEAM_UNDEAD and "prop_obj_exit_z" or "prop_obj_exit_h")
+ elseif wave <= 0 then
+ text = translate.Get("prepare_yourself")
+ elseif GAMEMODE.ZombieEscape then
+ text = translate.Get("zombie_escape")
+ else
+ local maxwaves = GAMEMODE:GetNumberOfWaves()
+ if maxwaves ~= -1 then
+ text = translate.Format("wave_x_of_y", wave, maxwaves)
+ if not GAMEMODE:GetWaveActive() then
+ text = translate.Get("intermission").." - "..text
+ end
+ elseif not GAMEMODE:GetWaveActive() then
+ text = translate.Get("intermission")
+ end
+ end
+ end
+
+ if text then
+ draw.SimpleText(text, self.Font, 0, 0, COLOR_GRAY)
+ end
+
+ return true
+end
+
+function PANEL:Text2Paint()
+ if GAMEMODE:GetWave() <= 0 then
+ local col
+ local timeleft = math.max(0, GAMEMODE:GetWaveStart() - CurTime())
+ if timeleft < 10 then
+ local glow = math.sin(RealTime() * 8) * 200 + 255
+ col = Color(255, glow, glow)
+ else
+ col = COLOR_GRAY
+ end
+
+ draw.SimpleText(translate.Format("zombie_invasion_in_x", util.ToMinutesSeconds(timeleft)), self.Font, 0, 0, col)
+ elseif GAMEMODE:GetWaveActive() then
+ local waveend = GAMEMODE:GetWaveEnd()
+ if waveend ~= -1 then
+ local timeleft = math.max(0, waveend - CurTime())
+ draw.SimpleText(translate.Format("wave_ends_in_x", util.ToMinutesSeconds(timeleft)), self.Font, 0, 0, 10 < timeleft and COLOR_GRAY or Color(255, 0, 0, math.abs(math.sin(RealTime() * 8)) * 180 + 40))
+ end
+ else
+ local wavestart = GAMEMODE:GetWaveStart()
+ if wavestart ~= -1 then
+ local timeleft = math.max(0, wavestart - CurTime())
+ draw.SimpleText(translate.Format("next_wave_in_x", util.ToMinutesSeconds(timeleft)), self.Font, 0, 0, 10 < timeleft and COLOR_GRAY or Color(255, 0, 0, math.abs(math.sin(RealTime() * 8)) * 180 + 40))
+ end
+ end
+
+ return true
+end
+
+function PANEL:Text3Paint()
+ if MySelf:IsValid() then
+ if MySelf:Team() == TEAM_UNDEAD then
+ local toredeem = GAMEMODE:GetRedeemBrains()
+ if toredeem > 0 then
+ draw.SimpleText(translate.Format("brains_eaten_x", MySelf:Frags().." / "..toredeem), self.Font, 0, 0, COLOR_DARKRED)
+ else
+ draw.SimpleText(translate.Format("brains_eaten_x", MySelf:Frags()), self.Font, 0, 0, COLOR_DARKRED)
+ end
+ else
+ draw.SimpleText(translate.Format("points_x", MySelf:GetPoints().." / "..MySelf:Frags()), self.Font, 0, 0, COLOR_DARKRED)
+ end
+ end
+
+ return true
+end
+
+function PANEL:Paint()
+ return true
+end
+
+vgui.Register("DGameState", PANEL, "DPanel")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/dmodelpanelex.lua b/gamemodes/zombiesurvival/gamemode/vgui/dmodelpanelex.lua
new file mode 100644
index 0000000..b2fa73a
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/dmodelpanelex.lua
@@ -0,0 +1,32 @@
+local PANEL = {}
+
+function PANEL:SetModel(strModelName)
+ if IsValid(self.Entity) then
+ self.Entity:Remove()
+ self.Entity = nil
+ end
+
+ if not ClientsideModel then return end
+
+ self.Entity = ClientsideModel(strModelName, RENDER_GROUP_OPAQUE_ENTITY)
+ if not IsValid(self.Entity) then return end
+
+ self.Entity:SetNoDraw(true)
+
+ local iSeq = self.Entity:LookupSequence("walk")
+ if iSeq <= 0 then iSeq = self.Entity:LookupSequence("Run1") end
+ if iSeq <= 0 then iSeq = self.Entity:LookupSequence("walk_all") end
+ if iSeq <= 0 then iSeq = self.Entity:LookupSequence("WalkUnarmed_all") end
+ if iSeq <= 0 then iSeq = self.Entity:LookupSequence("walk_all_moderate") end
+ if iSeq > 0 then self.Entity:ResetSequence(iSeq) end
+end
+
+function PANEL:AutoCam()
+ if IsValid(self.Entity) then
+ local mins, maxs = self.Entity:GetRenderBounds()
+ self:SetCamPos(mins:Distance(maxs) * Vector(0.75, 0.75, 0.5))
+ self:SetLookAt((mins + maxs) / 2)
+ end
+end
+
+vgui.Register("DModelPanelEx", PANEL, "DModelPanel")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/dpingmeter.lua b/gamemodes/zombiesurvival/gamemode/vgui/dpingmeter.lua
new file mode 100644
index 0000000..a3f8a77
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/dpingmeter.lua
@@ -0,0 +1,81 @@
+local PANEL = {}
+
+PANEL.IdealPing = 50
+PANEL.MaxPing = 400
+PANEL.RefreshTime = 1
+PANEL.PingBars = 4
+
+PANEL.m_Player = NULL
+PANEL.m_Ping = 0
+PANEL.NextRefresh = 0
+
+function PANEL:Init()
+end
+
+local colPing = Color(255, 255, 60, 255)
+function PANEL:Paint()
+ local ping = self:GetPing()
+ local pingmul = 1 - math.Clamp((ping - self.IdealPing) / self.MaxPing, 0, 1)
+ local wid, hei = self:GetWide(), self:GetTall()
+ local pingbars = math.max(1, self.PingBars)
+ local barwidth = wid / pingbars
+ local baseheight = hei / pingbars
+
+ colPing.r = (1 - pingmul) * 255
+ colPing.g = pingmul * 255
+
+ for i=1, pingbars do
+ local barheight = baseheight * i
+ local x, y = (i - 1) * barwidth, hei - barheight
+
+ surface.SetDrawColor(20, 20, 20, 255)
+ surface.DrawRect(x, y, barwidth, barheight)
+
+ if i == 1 or pingmul >= i / pingbars then
+ surface.SetDrawColor(colPing)
+ surface.DrawRect(x, y, barwidth, barheight)
+ end
+
+ surface.SetDrawColor(80, 80, 80, 255)
+ surface.DrawOutlinedRect(x, y, barwidth, barheight)
+ end
+
+ draw.SimpleText(ping, "DefaultFontSmall", 0, 0, colPing)
+
+ return true
+end
+
+function PANEL:Refresh()
+ local pl = self:GetPlayer()
+ if pl:IsValid() then
+ self:SetPing(pl:Ping())
+ else
+ self:SetPing(0)
+ end
+end
+
+function PANEL:Think()
+ if RealTime() >= self.NextRefresh then
+ self.NextRefresh = RealTime() + self.RefreshTime
+ self:Refresh()
+ end
+end
+
+function PANEL:SetPlayer(pl)
+ self.m_Player = pl or NULL
+ self:Refresh()
+end
+
+function PANEL:GetPlayer()
+ return self.m_Player
+end
+
+function PANEL:SetPing(ping)
+ self.m_Ping = ping
+end
+
+function PANEL:GetPing()
+ return self.m_Ping
+end
+
+vgui.Register("DPingMeter", PANEL, "Panel")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/dsidemenu.lua b/gamemodes/zombiesurvival/gamemode/vgui/dsidemenu.lua
new file mode 100644
index 0000000..05454eb
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/dsidemenu.lua
@@ -0,0 +1,92 @@
+local PANEL = {}
+
+PANEL.Spacing = 8
+PANEL.SlideTime = 0 --0.2
+
+function PANEL:Init()
+ self:RefreshSize()
+ self:SetPos(ScrW() - 1, 0)
+
+ self.Items = {}
+end
+
+function PANEL:Think()
+ if self.CloseTime and RealTime() >= self.CloseTime then
+ self.CloseTime = nil
+ self:SetVisible(false)
+ elseif self.StartChecking and RealTime() >= self.StartChecking and not MySelf:KeyDown(GAMEMODE.MenuKey) then
+ self:CloseMenu()
+ end
+end
+
+function PANEL:RefreshSize()
+ self:SetSize(BetterScreenScale() * 256, ScrH())
+end
+
+function PANEL:OpenMenu()
+ if self.StartChecking and RealTime() < self.StartChecking then return end
+
+ self.CloseTime = nil
+
+ self:RefreshSize()
+ self:SetPos(ScrW() - self:GetWide(), 0, self.SlideTime, 0, self.SlideTime * 0.8) --self:MoveTo(ScrW() - self:GetWide(), 0, self.SlideTime, 0, self.SlideTime * 0.8)
+ self:SetVisible(true)
+ self:MakePopup()
+ self.StartChecking = RealTime() + 0.1
+
+ timer.Simple(0, function() gui.SetMousePos(ScrW() - self:GetWide() * 0.5, ScrH() * 0.5) end)
+end
+
+function PANEL:CloseMenu()
+ if self.CloseTime then return end
+ self.CloseTime = RealTime() + self.SlideTime
+
+ --self:MoveTo(ScrW() - 1, 0, self.SlideTime, 0, self.SlideTime * 0.8)
+end
+
+local texRightEdge = surface.GetTextureID("gui/gradient")
+function PANEL:Paint()
+ surface.SetDrawColor(5, 5, 5, 180)
+ surface.DrawRect(self:GetWide() * 0.4, 0, self:GetWide() * 0.6, self:GetTall())
+ surface.SetTexture(texRightEdge)
+ surface.DrawTexturedRectRotated(self:GetWide() * 0.2, self:GetTall() * 0.5, self:GetWide() * 0.4, self:GetTall(), 180)
+end
+
+function PANEL:AddItem(item)
+ item:SetParent(self)
+ item:SetWide(self:GetWide() - 16)
+
+ table.insert(self.Items, item)
+
+ self:InvalidateLayout()
+end
+
+function PANEL:RemoveItem(item)
+ for k, v in ipairs(self.Items) do
+ if v == item then
+ item:Remove()
+ table.remove(self.Items, k)
+ self:InvalidateLayout()
+ break
+ end
+ end
+end
+
+function PANEL:PerformLayout()
+ local y = ScrH() * 0.5
+ for k, item in pairs(self.Items) do
+ if item and item:Valid() then
+ y = y - (item:GetTall() + self.Spacing) * 0.5
+ end
+ end
+
+ for k, item in ipairs(self.Items) do
+ if item and item:Valid() then
+ item:SetPos(0, y)
+ item:CenterHorizontal()
+ y = y + item:GetTall() + self.Spacing
+ end
+ end
+end
+
+vgui.Register("DSideMenu", PANEL, "DPanel")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/dteamcounter.lua b/gamemodes/zombiesurvival/gamemode/vgui/dteamcounter.lua
new file mode 100644
index 0000000..a7f12a3
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/dteamcounter.lua
@@ -0,0 +1,71 @@
+local PANEL = {}
+
+PANEL.m_Team = 0
+
+PANEL.NextRefresh = 0
+
+local function ImageThink(self)
+ self:SetRotation(math.sin((RealTime() + self.Seed) * 0.5) * 25)
+ self:OldPaint()
+end
+
+function PANEL:Init()
+ self.m_Image = vgui.Create("DEXRotatedImage", self)
+ self.m_Image:SetImage("icon16/check_off.png")
+ self.m_Image.Seed = math.Rand(0, 1000)
+ self.m_Image.OldPaint = self.m_Image.Paint
+ self.m_Image.Paint = ImageThink
+
+ self.m_Counter = vgui.Create("DLabel", self)
+ self.m_Counter:SetFont("ZSHUDFontSmaller")
+
+ self:Refresh()
+end
+
+function PANEL:Paint()
+ return true
+end
+
+function PANEL:Think()
+ if RealTime() >= self.NextRefresh then
+ self.NextRefresh = RealTime() + 1
+ self:Refresh()
+ end
+end
+
+function PANEL:SetTeam(teamid)
+ self.m_Team = teamid
+ self.m_Counter:SetTextColor(team.GetColor(teamid))
+end
+
+function PANEL:SetImage(mat)
+ self.m_Image:SetImage(mat)
+
+ self:InvalidateLayout()
+end
+
+function PANEL:PerformLayout()
+ self.m_Image:SetSize(self:GetSize())
+ self.m_Counter:AlignBottom()
+ self.m_Counter:AlignRight()
+end
+
+function PANEL:Refresh()
+ local numplayers = team.NumPlayers(self.m_Team)
+ self.m_PrevPlayers = self.m_PrevPlayers or numplayers
+
+ self.m_Counter:SetText(numplayers)
+ self.m_Counter:SizeToContents()
+
+ if self.m_PrevPlayers ~= numplayers then
+ self.m_Counter:Stop()
+ self.m_Counter:SetColor(numplayers > self.m_PrevPlayers and color_white or COLOR_RED)
+ self.m_Counter:ColorTo(team.GetColor(self.m_Team), 2)
+
+ self.m_PrevPlayers = numplayers
+ end
+
+ self:InvalidateLayout()
+end
+
+vgui.Register("DTeamCounter", PANEL, "DPanel")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/dteamheading.lua b/gamemodes/zombiesurvival/gamemode/vgui/dteamheading.lua
new file mode 100644
index 0000000..f8c2323
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/dteamheading.lua
@@ -0,0 +1,76 @@
+local PANEL = {}
+PANEL.m_Team = 0
+PANEL.NextRefresh = 0
+PANEL.RefreshTime = 2
+
+function PANEL:Init()
+ self.m_TeamNameLabel = EasyLabel(self, " ", "ZSScoreBoardHeading", color_black)
+ self.m_TeamCountLabel = EasyLabel(self, " ", "ZSScoreBoardHeading", color_black)
+
+ self.m_Icon = vgui.Create("DImage", self)
+ self.m_Icon:SetVisible(false)
+ self.m_Icon:NoClipping(true)
+
+ self:InvalidateLayout()
+end
+
+function PANEL:Think()
+ if RealTime() >= self.NextRefresh then
+ self.NextRefresh = RealTime() + self.RefreshTime
+ self:Refresh()
+ end
+end
+
+function PANEL:PerformLayout()
+ self.m_TeamNameLabel:Center()
+
+ self.m_TeamCountLabel:AlignRight(16)
+ self.m_TeamCountLabel:CenterVertical()
+
+ self.m_Icon:AlignLeft(2)
+ self.m_Icon:CenterVertical()
+end
+
+function PANEL:Refresh()
+ local teamid = self:GetTeam()
+
+ self.m_TeamNameLabel:SetText(team.GetName(teamid))
+ self.m_TeamNameLabel:SizeToContents()
+
+ self.m_TeamCountLabel:SetText(team.NumPlayers(teamid))
+ self.m_TeamCountLabel:SizeToContents()
+
+ self:InvalidateLayout()
+end
+
+function PANEL:Paint()
+ local wid, hei = self:GetWide(), self:GetTall()
+
+ surface.SetDrawColor(130, 130, 130, 180)
+ surface.DrawRect(0, 0, wid, hei)
+ surface.SetDrawColor(60, 60, 60, 180)
+ surface.DrawOutlinedRect(0, 0, wid, hei)
+
+ return true
+end
+
+function PANEL:SetTeam(teamid)
+ self.m_Team = teamid
+
+ if teamid == TEAM_HUMAN then
+ self.m_Icon:SetVisible(true)
+ self.m_Icon:SetImage("zombiesurvival/humanhead")
+ self.m_Icon:SizeToContents()
+ self:InvalidateLayout()
+ elseif teamid == TEAM_UNDEAD then
+ self.m_Icon:SetVisible(true)
+ self.m_Icon:SetImage("zombiesurvival/zombiehead")
+ self.m_Icon:SizeToContents()
+ self:InvalidateLayout()
+ else
+ self.m_Icon:SetVisible(false)
+ end
+end
+function PANEL:GetTeam() return self.m_Team end
+
+vgui.Register("DTeamHeading", PANEL, "Panel")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/pclassselect.lua b/gamemodes/zombiesurvival/gamemode/vgui/pclassselect.lua
new file mode 100644
index 0000000..d5be9fc
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/pclassselect.lua
@@ -0,0 +1,324 @@
+CreateClientConVar("zs_bossclass", "", true, true)
+
+local Window
+local HoveredClassWindow
+
+local function CreateHoveredClassWindow(classtable)
+ if HoveredClassWindow and HoveredClassWindow:Valid() then
+ HoveredClassWindow:Remove()
+ end
+
+ HoveredClassWindow = vgui.Create("ClassInfo")
+ HoveredClassWindow:SetSize(ScrW() * 0.5, 128)
+ HoveredClassWindow:CenterHorizontal()
+ HoveredClassWindow:MoveBelow(Window, 32)
+ HoveredClassWindow:SetClassTable(classtable)
+end
+
+function GM:OpenClassSelect(bossmode)
+ if Window and Window:Valid() then Window:Remove() end
+
+ Window = vgui.Create(bossmode and "ClassSelectBoss" or "ClassSelect")
+ Window:SetSize(ScrW(), 240)
+ Window:Center()
+
+ Window:SetAlpha(0)
+ Window:AlphaTo(255, 0.5)
+
+ Window:MakePopup()
+
+ PlayMenuOpenSound()
+end
+
+local PANEL = {}
+
+local function BossTypeDoClick(self)
+ GAMEMODE:OpenClassSelect(true)
+end
+
+function PANEL:Init()
+ self.ClassButtons = {}
+
+ for i = 1, #GAMEMODE.ZombieClasses do
+ local classtab = GAMEMODE.ZombieClasses[i]
+ if classtab and not classtab.Hidden or classtab.CanUse and classtab:CanUse(MySelf) then
+ local button = vgui.Create("ClassButton", self)
+ button:SetClassTable(classtab)
+
+ table.insert(self.ClassButtons, button)
+ end
+ end
+
+ local button = EasyButton(self, "Select desired boss class...", 8, 4)
+ self.ClassTypeButton = button
+ button.DoClick = BossTypeDoClick
+
+ self:InvalidateLayout()
+end
+
+function PANEL:PerformLayout()
+ local spacing = self:GetWide() / math.max(1, #self.ClassButtons)
+ local tall = self:GetTall()
+
+ for i, classbutton in ipairs(self.ClassButtons) do
+ classbutton:SetSize(spacing, tall)
+ classbutton:SetPos((i - 1) * spacing + spacing * 0.5 - classbutton:GetWide() * 0.5, 0)
+ classbutton:CenterVertical()
+ end
+
+ self.ClassTypeButton:AlignLeft(4)
+ self.ClassTypeButton:AlignTop(4)
+end
+
+local texUpEdge = surface.GetTextureID("gui/gradient_up")
+local texDownEdge = surface.GetTextureID("gui/gradient_down")
+function PANEL:Paint()
+ local wid, hei = self:GetSize()
+ local edgesize = 32
+
+ DisableClipping(true)
+ surface.SetDrawColor(color_black_alpha220)
+ surface.DrawRect(0, 0, wid, hei)
+ surface.SetTexture(texUpEdge)
+ surface.DrawTexturedRect(0, -edgesize, wid, edgesize)
+ surface.SetTexture(texDownEdge)
+ surface.DrawTexturedRect(0, hei, wid, edgesize)
+ DisableClipping(false)
+
+ return true
+end
+
+vgui.Register("ClassSelect", PANEL, "Panel")
+
+local PANEL = {}
+
+local function ClassTypeDoClick(self)
+ GAMEMODE:OpenClassSelect(false)
+end
+
+function PANEL:Init()
+ self.ClassButtons = {}
+
+ for i = 1, #GAMEMODE.ZombieClasses do
+ local classtab = GAMEMODE.ZombieClasses[i]
+ if classtab and classtab.Boss then
+ local button = vgui.Create("ClassButton", self)
+ button:SetClassTable(classtab)
+
+ table.insert(self.ClassButtons, button)
+ end
+ end
+
+ local button = EasyButton(self, "Back to normal class menu...", 8, 4)
+ self.ClassTypeButton = button
+ button.DoClick = ClassTypeDoClick
+
+ self:InvalidateLayout()
+end
+
+function PANEL:PerformLayout()
+ local spacing = self:GetWide() / math.max(1, #self.ClassButtons)
+ local tall = self:GetTall()
+
+ for i, classbutton in ipairs(self.ClassButtons) do
+ classbutton:SetSize(spacing, tall)
+ classbutton:SetPos((i - 1) * spacing + spacing * 0.5 - classbutton:GetWide() * 0.5, 0)
+ classbutton:CenterVertical()
+ end
+
+ self.ClassTypeButton:AlignLeft(4)
+ self.ClassTypeButton:AlignTop(4)
+end
+
+function PANEL:Paint()
+ local wid, hei = self:GetSize()
+ local edgesize = 32
+
+ DisableClipping(true)
+ surface.SetDrawColor(color_black_alpha220)
+ surface.DrawRect(0, 0, wid, hei)
+ surface.SetTexture(texUpEdge)
+ surface.DrawTexturedRect(0, -edgesize, wid, edgesize)
+ surface.SetTexture(texDownEdge)
+ surface.DrawTexturedRect(0, hei, wid, edgesize)
+ DisableClipping(false)
+end
+
+vgui.Register("ClassSelectBoss", PANEL, "Panel")
+
+local PANEL = {}
+
+function PANEL:Init()
+ self.NameLabel = vgui.Create("DLabel", self)
+ self.NameLabel:SetFont("ZSHUDFontSmaller")
+ self.NameLabel:SetAlpha(180)
+ self.Image = vgui.Create("DImage", self)
+
+ self:InvalidateLayout()
+end
+
+function PANEL:PerformLayout()
+ local imgsize = math.min(self:GetWide(), self:GetTall()) * 0.75
+ self.Image:SetSize(imgsize, imgsize)
+ self.Image:Center()
+
+ self.NameLabel:SizeToContents()
+ self.NameLabel:CenterHorizontal()
+ self.NameLabel:AlignBottom()
+end
+
+function PANEL:SetClassTable(classtable)
+ self.ClassTable = classtable
+
+ self.NameLabel:SetText(translate.Get(classtable.TranslationName))
+ self.Image:SetImage(classtable.Icon)
+
+ self:InvalidateLayout()
+end
+
+function PANEL:Paint()
+ return true
+end
+
+function PANEL:OnCursorEntered()
+ self.NameLabel:SetAlpha(255)
+
+ CreateHoveredClassWindow(self.ClassTable)
+end
+
+function PANEL:OnCursorExited()
+ self.NameLabel:SetAlpha(180)
+
+ if HoveredClassWindow and HoveredClassWindow:Valid() and HoveredClassWindow.ClassTable == self.ClassTable then
+ HoveredClassWindow:Remove()
+ end
+end
+
+function PANEL:DoClick()
+ if self.ClassTable then
+ if self.ClassTable.Boss then
+ RunConsoleCommand("zs_bossclass", self.ClassTable.Name)
+ GAMEMODE:CenterNotify(translate.Format("boss_class_select", self.ClassTable.Name))
+ else
+ RunConsoleCommand("zs_class", self.ClassTable.Name)
+ end
+ end
+
+ surface.PlaySound("buttons/button15.wav")
+
+ Window:Remove()
+end
+
+function PANEL:Think()
+ if not self.ClassTable then return end
+
+ local enabled = LocalPlayer():GetZombieClass() == self.ClassTable.Index and 2 or gamemode.Call("IsClassUnlocked", self.ClassTable.Index) and 1 or 0
+ if enabled ~= self.LastEnabledState then
+ self.LastEnabledState = enabled
+
+ if enabled == 2 then
+ self.NameLabel:SetTextColor(COLOR_GREEN)
+ self.Image:SetImageColor(color_white)
+ elseif enabled == 1 then
+ self.NameLabel:SetTextColor(COLOR_GRAY)
+ self.Image:SetImageColor(color_white)
+ else
+ self.NameLabel:SetTextColor(COLOR_DARKRED)
+ self.Image:SetImageColor(COLOR_RED)
+ end
+ end
+end
+
+vgui.Register("ClassButton", PANEL, "Button")
+
+local PANEL = {}
+
+function PANEL:Init()
+ self.NameLabel = vgui.Create("DLabel", self)
+ self.NameLabel:SetFont("ZSHUDFontSmaller")
+
+ self.DescLabels = self.DescLabels or {}
+
+ self:InvalidateLayout()
+end
+
+function PANEL:SetClassTable(classtable)
+ self.ClassTable = classtable
+
+ self.NameLabel:SetText(translate.Get(classtable.TranslationName))
+ self.NameLabel:SizeToContents()
+
+ self:CreateDescLabels()
+
+ self:InvalidateLayout()
+end
+
+function PANEL:RemoveDescLabels()
+ for _, label in pairs(self.DescLabels) do
+ label:Remove()
+ end
+
+ self.DescLabels = {}
+end
+
+function PANEL:CreateDescLabels()
+ self:RemoveDescLabels()
+
+ self.DescLabels = {}
+
+ local classtable = self.ClassTable
+ if not classtable or not classtable.Description then return end
+
+ local lines = string.Explode("\n", translate.Get(classtable.Description))
+ if classtable.Wave and classtable.Wave > 0 then
+ table.insert(lines, 1, "("..translate.Format("unlocked_on_wave_x", classtable.Wave)..")")
+ end
+
+ if classtable.Help then
+ table.insert(lines, " ")
+ table.Add(lines, string.Explode("\n", translate.Get(classtable.Help)))
+ end
+
+ for _, line in ipairs(lines) do
+ local label = vgui.Create("DLabel", self)
+ label:SetText(line)
+ label:SetFont("ZSHUDFontTiny")
+ label:SizeToContents()
+ table.insert(self.DescLabels, label)
+ end
+end
+
+function PANEL:PerformLayout()
+ self.NameLabel:SizeToContents()
+ self.NameLabel:CenterHorizontal()
+
+ local maxw = self.NameLabel:GetWide()
+ for _, label in pairs(self.DescLabels) do
+ maxw = math.max(maxw, label:GetWide())
+ end
+ self:SetWide(maxw + 64)
+ self:CenterHorizontal()
+
+ for i, label in ipairs(self.DescLabels) do
+ label:MoveBelow(self.DescLabels[i - 1] or self.NameLabel)
+ label:CenterHorizontal()
+ end
+
+ local lastlabel = self.DescLabels[#self.DescLabels] or self.NameLabel
+ local x, y = lastlabel:GetPos()
+ self:SetTall(y + lastlabel:GetTall())
+end
+
+function PANEL:Think()
+ if not Window or not Window:Valid() or not Window:IsVisible() then
+ self:Remove()
+ end
+end
+
+function PANEL:Paint(w, h)
+ derma.SkinHook("Paint", "Frame", self, w, h)
+
+ return true
+end
+
+vgui.Register("ClassInfo", PANEL, "Panel")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/pendboard.lua b/gamemodes/zombiesurvival/gamemode/vgui/pendboard.lua
new file mode 100644
index 0000000..13711d9
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/pendboard.lua
@@ -0,0 +1,130 @@
+function GM:AddHonorableMention(pl, mentionid, ...)
+ if not (pEndBoard and pEndBoard:Valid()) then
+ MakepEndBoard(ROUNDWINNER)
+ end
+
+ local mentiontab = self.HonorableMentions[mentionid]
+ if not mentiontab then return end
+
+ local pan = vgui.Create("DEndBoardPlayerPanel", pEndBoard.List)
+ pan:SetPlayer(pl, mentiontab.Color, string.format(mentiontab.String, mentiontab.Callback(pl, ...)), nil, mentiontab.Name)
+ pEndBoard.List:AddItem(pan)
+end
+
+function MakepEndBoard(winner)
+ if pEndBoard and pEndBoard:IsValid() then
+ pEndBoard:Remove()
+ pEndBoard = nil
+ end
+
+ local localwin = winner == TEAM_HUMAN and LocalPlayer():Team() == winner
+
+ local wid = 640
+
+ local frame = vgui.Create("DFrame")
+ frame:SetWide(wid)
+ frame:SetKeyboardInputEnabled(false)
+ frame:SetDeleteOnClose(false)
+ frame:SetCursor("pointer")
+ frame:SetTitle(" ")
+ pEndBoard = frame
+
+ local y = 8
+
+ local heading
+ if localwin then
+ surface.PlaySound("beams/beamstart5.wav")
+ heading = EasyLabel(frame, "You have won!", "ZSHUDFont", COLOR_CYAN)
+ else
+ surface.PlaySound("ambient/levels/citadel/strange_talk"..math.random(3, 11)..".wav")
+ heading = EasyLabel(frame, "You have lost.", "ZSHUDFont", COLOR_RED)
+ end
+ heading:SetPos(wid * 0.5 - heading:GetWide() * 0.5, y)
+ y = y + heading:GetTall() + 4
+
+ local subheading
+ if localwin then
+ subheading = EasyLabel(frame, "The humans have survived for now.", "ZSHUDFontSmall", COLOR_WHITE)
+ else
+ subheading = EasyLabel(frame, "The undead army grows stronger.", "ZSHUDFontSmall", COLOR_LIMEGREEN)
+ end
+ subheading:SetPos(wid * 0.5 - subheading:GetWide() * 0.5, y)
+ y = y + subheading:GetTall() + 8
+
+ local starty = y
+
+ local svpan = EasyLabel(frame, "Honorable Mentions", "ZSHUDFontSmall", COLOR_WHITE)
+ svpan:SetPos(wid * 0.5 - svpan:GetWide() * 0.5, y)
+ y = y + svpan:GetTall() + 4
+
+ local list = vgui.Create("DPanelList", frame)
+ list:SetSize(wid - 16, 420)
+ list:SetPos(8, y)
+ list:SetPadding(2)
+ list:SetSpacing(2)
+ list:EnableVerticalScrollbar()
+ y = y + list:GetTall() + 8
+
+ frame.List = list
+
+ frame:SetTall(y)
+ frame:Center()
+
+ frame:MakePopup()
+
+ return frame
+end
+
+local PANEL = {}
+function PANEL:OnMousePressed(mc)
+ if mc == MOUSE_LEFT then
+ local pl = self:GetPlayer()
+ if pl:IsValid() then
+ gamemode.Call("ClickedEndBoardPlayerButton", pl, self)
+ end
+ end
+end
+
+function PANEL:Init()
+ self:SetSize(200, 40)
+end
+
+function PANEL:GetPlayer()
+ return self.m_Player or NULL
+end
+
+function PANEL:SetPlayer(pl, col, misc, misccol, overridename)
+ if self.m_pAvatar then
+ self.m_pAvatar:Remove()
+ self.m_pAvatar = nil
+ end
+ if self.m_pName then
+ self.m_pName:Remove()
+ self.m_pName = nil
+ end
+ if self.m_pMisc then
+ self.m_pMisc:Remove()
+ self.m_pMisc = nil
+ end
+
+ if pl:IsValid() and pl:IsPlayer() then
+ local name = overridename or pl:Name()
+
+ local avatar = vgui.Create("AvatarImage", self)
+ avatar:SetPos(4, 4)
+ avatar:SetSize(32, 32)
+ avatar:SetPlayer(pl)
+ avatar:SetTooltip("Click here to view their Steam Community profile.")
+ self.m_pAvatar = avatar
+
+ local namelab = EasyLabel(self, name, "ZSHUDFontTiny", col)
+ namelab:SetPos(40, 4)
+ self.m_pName = namelab
+
+ if misc then
+ local misclab = EasyLabel(self, misc, nil, misccol)
+ misclab:SetPos(40, self:GetTall() - 4 - misclab:GetTall())
+ end
+ end
+end
+vgui.Register("DEndBoardPlayerPanel", PANEL, "DPanel")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/phelp.lua b/gamemodes/zombiesurvival/gamemode/vgui/phelp.lua
new file mode 100644
index 0000000..ec8d76c
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/phelp.lua
@@ -0,0 +1,143 @@
+GM.Help = {
+{Name = "help_cat_introduction",
+Content = "help_cont_introduction"},
+
+{Name = "help_cat_survival",
+Content = "help_cont_survival"},
+
+{Name = "help_cat_barricading",
+Content = "help_cont_barricading"},
+
+{Name = "help_cat_upgrades",
+Content = "help_cont_upgrades"},
+
+{Name = "help_cat_being_a_zombie",
+Content = "help_cont_being_a_zombie"}
+}
+
+function MakepCredits()
+ PlayMenuOpenSound()
+
+ local wid = math.min(ScrW(), 750)
+
+ local y = 8
+
+ local frame = vgui.Create("DEXRoundedFrame")
+ frame:SetColorAlpha(230)
+ frame:SetWide(wid)
+ frame:SetTitle(" ")
+ frame:SetKeyboardInputEnabled(false)
+
+ local label = EasyLabel(frame, GAMEMODE.Name.." Credits", "ZSHUDFontNS", color_white)
+ label:AlignTop(y)
+ label:CenterHorizontal()
+ y = y + label:GetTall() + 8
+
+ for authorindex, authortab in ipairs(GAMEMODE.Credits) do
+ local lineleft = EasyLabel(frame, string.Replace(authortab[1], "@", "(at)"), "ZSHUDFontSmallestNS", color_white)
+ local linemid = EasyLabel(frame, "-", "ZSHUDFontSmallestNS", color_white)
+ local lineright = EasyLabel(frame, authortab[3], "ZSHUDFontSmallestNS", color_white)
+ local linesub
+ if authortab[2] then
+ linesub = EasyLabel(frame, authortab[2], "DefaultFont", color_white)
+ end
+
+ lineleft:AlignLeft(8)
+ lineleft:AlignTop(y)
+ lineright:AlignRight(8)
+ lineright:AlignTop(y)
+ linemid:CenterHorizontal()
+ linemid:AlignTop(y)
+
+ y = y + lineleft:GetTall()
+ if linesub then
+ linesub:AlignTop(y)
+ linesub:AlignLeft(8)
+ y = y + linesub:GetTall()
+ end
+ y = y + 10
+ end
+
+ frame:SetTall(y + 8)
+ frame:Center()
+ frame:SetAlpha(0)
+ frame:AlphaTo(255, 0.5, 0)
+ frame:MakePopup()
+end
+
+function MakepHelp()
+ PlayMenuOpenSound()
+
+ if pHelp then
+ pHelp:SetAlpha(0)
+ pHelp:AlphaTo(255, 0.5, 0)
+ pHelp:SetVisible(true)
+ pHelp:MakePopup()
+ return
+ end
+
+ local wide, tall = 500, 480
+
+ local Window = vgui.Create("DFrame")
+ Window:SetSize(wide, tall)
+ Window:Center()
+ Window:SetTitle(" ")
+ Window:SetDraggable(false)
+ Window:SetDeleteOnClose(false)
+ Window:SetKeyboardInputEnabled(false)
+ Window:SetCursor("pointer")
+ pHelp = Window
+
+ local label = EasyLabel(Window, "Help", "ZSHUDFont", color_white)
+ label:CenterHorizontal()
+ label:AlignTop(8)
+
+ local propertysheet = vgui.Create("DPropertySheet", Window)
+ propertysheet:StretchToParent(12, 52, 12, 64)
+
+ for _, helptab in ipairs(GAMEMODE.Help) do
+ local htmlpanel = vgui.Create("DHTML", propertysheet)
+ htmlpanel:StretchToParent(4, 4, 4, 24)
+ htmlpanel:SetHTML([[
+
+
+
+
+Zombie Survival
+]]..translate.Get(helptab.Name)..[[]]..translate.Get(helptab.Content)..[[
+
+]])
+ propertysheet:AddSheet(translate.Get(helptab.Name), htmlpanel, helptab.Icon, false, false)
+ end
+
+ Window:Center()
+ Window:MakePopup()
+
+ local button = EasyButton(Window, "Credits", 8, 4)
+ button:SetPos(wide - button:GetWide() - 12, tall - button:GetTall() - 12)
+ button:SetText("Credits")
+ button.DoClick = function(btn) MakepCredits() end
+
+ gamemode.Call("BuildHelpMenu", Window, propertysheet)
+
+ Window:SetAlpha(0)
+ Window:AlphaTo(255, 0.5, 0)
+ Window:MakePopup()
+end
+
+function GM:BuildHelpMenu(window, propertysheet)
+end
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/pmainmenu.lua b/gamemodes/zombiesurvival/gamemode/vgui/pmainmenu.lua
new file mode 100644
index 0000000..0e4fffc
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/pmainmenu.lua
@@ -0,0 +1,187 @@
+local function HelpMenuPaint(self)
+ Derma_DrawBackgroundBlur(self, self.Created)
+ Derma_DrawBackgroundBlur(self, self.Created)
+end
+
+local pPlayerModel
+local function SwitchPlayerModel(self)
+ surface.PlaySound("buttons/button14.wav")
+ RunConsoleCommand("cl_playermodel", self.m_ModelName)
+ chat.AddText(COLOR_LIMEGREEN, "You've changed your desired player model to "..tostring(self.m_ModelName))
+
+ pPlayerModel:Close()
+end
+function MakepPlayerModel()
+ if pPlayerModel and pPlayerModel:Valid() then pPlayerModel:Remove() end
+
+ PlayMenuOpenSound()
+
+ local numcols = 8
+ local wid = numcols * 68 + 24
+ local hei = 400
+
+ pPlayerModel = vgui.Create("DFrame")
+ pPlayerModel:SetSkin("Default")
+ pPlayerModel:SetTitle("Player model selection")
+ pPlayerModel:SetSize(wid, hei)
+ pPlayerModel:Center()
+ pPlayerModel:SetDeleteOnClose(true)
+
+ local list = vgui.Create("DPanelList", pPlayerModel)
+ list:StretchToParent(8, 24, 8, 8)
+ list:EnableVerticalScrollbar()
+
+ local grid = vgui.Create("DGrid", pPlayerModel)
+ grid:SetCols(numcols)
+ grid:SetColWide(68)
+ grid:SetRowHeight(68)
+
+ for name, mdl in pairs(player_manager.AllValidModels()) do
+ local button = vgui.Create("SpawnIcon", grid)
+ button:SetPos(0, 0)
+ button:SetModel(mdl)
+ button.m_ModelName = name
+ button.OnMousePressed = SwitchPlayerModel
+ grid:AddItem(button)
+ end
+ grid:SetSize(wid - 16, math.ceil(table.Count(player_manager.AllValidModels()) / numcols) * grid:GetRowHeight())
+
+ list:AddItem(grid)
+
+ pPlayerModel:SetSkin("Default")
+ pPlayerModel:MakePopup()
+end
+
+function MakepPlayerColor()
+ if pPlayerColor and pPlayerColor:Valid() then pPlayerColor:Remove() end
+
+ PlayMenuOpenSound()
+
+ pPlayerColor = vgui.Create("DFrame")
+ pPlayerColor:SetWide(math.min(ScrW(), 500))
+ pPlayerColor:SetTitle(" ")
+ pPlayerColor:SetDeleteOnClose(true)
+
+ local y = 8
+
+ local label = EasyLabel(pPlayerColor, "Colors", "ZSHUDFont", color_white)
+ label:SetPos((pPlayerColor:GetWide() - label:GetWide()) / 2, y)
+ y = y + label:GetTall() + 8
+
+ local lab = EasyLabel(pPlayerColor, "Player color")
+ lab:SetPos(8, y)
+ y = y + lab:GetTall()
+
+ local colpicker = vgui.Create("DColorMixer", pPlayerColor)
+ colpicker:SetAlphaBar(false)
+ colpicker:SetPalette(false)
+ colpicker.UpdateConVars = function(me, color)
+ me.NextConVarCheck = SysTime() + 0.2
+ RunConsoleCommand("cl_playercolor", color.r / 100 .." ".. color.g / 100 .." ".. color.b / 100)
+ end
+ local r, g, b = string.match(GetConVarString("cl_playercolor"), "(%g+) (%g+) (%g+)")
+ if r then
+ colpicker:SetColor(Color(r * 100, g * 100, b * 100))
+ end
+ colpicker:SetSize(pPlayerColor:GetWide() - 16, 72)
+ colpicker:SetPos(8, y)
+ y = y + colpicker:GetTall()
+
+ local lab = EasyLabel(pPlayerColor, "Weapon color")
+ lab:SetPos(8, y)
+ y = y + lab:GetTall()
+
+ local colpicker = vgui.Create("DColorMixer", pPlayerColor)
+ colpicker:SetAlphaBar(false)
+ colpicker:SetPalette(false)
+ colpicker.UpdateConVars = function(me, color)
+ me.NextConVarCheck = SysTime() + 0.2
+ RunConsoleCommand("cl_weaponcolor", color.r / 100 .." ".. color.g / 100 .." ".. color.b / 100)
+ end
+ local r, g, b = string.match(GetConVarString("cl_weaponcolor"), "(%g+) (%g+) (%g+)")
+ if r then
+ colpicker:SetColor(Color(r * 100, g * 100, b * 100))
+ end
+ colpicker:SetSize(pPlayerColor:GetWide() - 16, 72)
+ colpicker:SetPos(8, y)
+ y = y + colpicker:GetTall()
+
+ pPlayerColor:SetTall(y + 8)
+ pPlayerColor:Center()
+ pPlayerColor:MakePopup()
+end
+
+function GM:ShowHelp()
+ if self.HelpMenu and self.HelpMenu:Valid() then
+ self.HelpMenu:Remove()
+ end
+
+ PlayMenuOpenSound()
+
+ local menu = vgui.Create("Panel")
+ menu:SetSize(BetterScreenScale() * 420, ScrH())
+ menu:Center()
+ menu.Paint = HelpMenuPaint
+ menu.Created = SysTime()
+
+ local header = EasyLabel(menu, self.Name, "ZSHUDFont")
+ header:SetContentAlignment(8)
+ header:DockMargin(0, ScrH() * 0.25, 0, 64)
+ header:Dock(TOP)
+
+ local but = vgui.Create("DButton", menu)
+ but:SetFont("ZSHUDFontSmaller")
+ but:SetText("Help")
+ but:SetTall(32)
+ but:DockMargin(0, 0, 0, 12)
+ but:DockPadding(0, 12, 0, 12)
+ but:Dock(TOP)
+ but.DoClick = function() MakepHelp() end
+
+ local but = vgui.Create("DButton", menu)
+ but:SetFont("ZSHUDFontSmaller")
+ but:SetText("Player Model")
+ but:SetTall(32)
+ but:DockMargin(0, 0, 0, 12)
+ but:DockPadding(0, 12, 0, 12)
+ but:Dock(TOP)
+ but.DoClick = function() MakepPlayerModel() end
+
+ local but = vgui.Create("DButton", menu)
+ but:SetFont("ZSHUDFontSmaller")
+ but:SetText("Player Color")
+ but:SetTall(32)
+ but:DockMargin(0, 0, 0, 12)
+ but:DockPadding(0, 12, 0, 12)
+ but:Dock(TOP)
+ but.DoClick = function() MakepPlayerColor() end
+
+ local but = vgui.Create("DButton", menu)
+ but:SetFont("ZSHUDFontSmaller")
+ but:SetText("Options")
+ but:SetTall(32)
+ but:DockMargin(0, 0, 0, 12)
+ but:DockPadding(0, 12, 0, 12)
+ but:Dock(TOP)
+ but.DoClick = function() MakepOptions() end
+
+ local but = vgui.Create("DButton", menu)
+ but:SetFont("ZSHUDFontSmaller")
+ but:SetText("Credits")
+ but:SetTall(32)
+ but:DockMargin(0, 0, 0, 12)
+ but:DockPadding(0, 12, 0, 12)
+ but:Dock(TOP)
+ but.DoClick = function() MakepCredits() end
+
+ local but = vgui.Create("DButton", menu)
+ but:SetFont("ZSHUDFontSmaller")
+ but:SetText("Close")
+ but:SetTall(32)
+ but:DockMargin(0, 24, 0, 0)
+ but:DockPadding(0, 12, 0, 12)
+ but:Dock(TOP)
+ but.DoClick = function() menu:Remove() end
+
+ menu:MakePopup()
+end
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/poptions.lua b/gamemodes/zombiesurvival/gamemode/vgui/poptions.lua
new file mode 100644
index 0000000..fe00ea4
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/poptions.lua
@@ -0,0 +1,244 @@
+function MakepOptions()
+ PlayMenuOpenSound()
+
+ if pOptions then
+ pOptions:SetAlpha(0)
+ pOptions:AlphaTo(255, 0.5, 0)
+ pOptions:SetVisible(true)
+ pOptions:MakePopup()
+ return
+ end
+
+ local Window = vgui.Create("DFrame")
+ local wide = math.min(ScrW(), 500)
+ local tall = math.min(ScrH(), 580)
+ Window:SetSize(wide, tall)
+ Window:Center()
+ Window:SetTitle(" ")
+ Window:SetDeleteOnClose(false)
+ pOptions = Window
+
+ local y = 8
+
+ local label = EasyLabel(Window, "Options", "ZSHUDFont", color_white)
+ label:SetPos(wide * 0.5 - label:GetWide() * 0.5, y)
+ y = y + label:GetTall() + 8
+
+ local list = vgui.Create("DPanelList", pOptions)
+ list:EnableVerticalScrollbar()
+ list:EnableHorizontal(false)
+ list:SetSize(wide - 24, tall - y - 12)
+ list:SetPos(12, y)
+ list:SetPadding(8)
+ list:SetSpacing(4)
+
+ gamemode.Call("AddExtraOptions", list, Window)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("Don't show point floaters")
+ check:SetConVar("zs_nofloatingscore")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("Draw crosshair in ironsights.")
+ check:SetConVar("zs_ironsightscrosshair")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("Film Mode (disable most of the HUD)")
+ check:SetConVar("zs_filmmode")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("Enable ambient music")
+ check:SetConVar("zs_beats")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("Enable last human music")
+ check:SetConVar("zs_playmusic")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("Enable post processing")
+ check:SetConVar("zs_postprocessing")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("Enable film grain")
+ check:SetConVar("zs_filmgrain")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("Enable Color Mod")
+ check:SetConVar("zs_colormod")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("Enable pain flashes")
+ check:SetConVar("zs_drawpainflash")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("No crosshair rotate")
+ check:SetConVar("zs_nocrosshairrotate")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("Enable human health auras")
+ check:SetConVar("zs_auras")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("Enable damage indicators")
+ check:SetConVar("zs_damagefloaters")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("Enable movement view roll")
+ check:SetConVar("zs_movementviewroll")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("Always display nail health")
+ check:SetConVar("zs_alwaysshownails")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("Disable automatic redeeming (next round)")
+ check:SetConVar("zs_noredeem")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ local check = vgui.Create("DCheckBoxLabel", Window)
+ check:SetText("Always volunteer to start as a zombie")
+ check:SetConVar("zs_alwaysvolunteer")
+ check:SizeToContents()
+ list:AddItem(check)
+
+ list:AddItem(EasyLabel(Window, "Weapon HUD display style", "DefaultFontSmall", color_white))
+ local dropdown = vgui.Create("DComboBox", Window)
+ dropdown:SetMouseInputEnabled(true)
+ dropdown:AddChoice("3D")
+ dropdown:AddChoice("2D")
+ dropdown:AddChoice("Both")
+ dropdown.OnSelect = function(me, index, value, data)
+ RunConsoleCommand("zs_weaponhudmode", value == "Both" and 2 or value == "2D" and 1 or 0)
+ end
+ dropdown:SetText(GAMEMODE.WeaponHUDMode == 2 and "Both" or GAMEMODE.WeaponHUDMode == 1 and "2D" or "3D")
+ list:AddItem(dropdown)
+
+ list:AddItem(EasyLabel(Window, "Human ambient beat set", "DefaultFontSmall", color_white))
+ local dropdown = vgui.Create("DComboBox", Window)
+ dropdown:SetMouseInputEnabled(true)
+ for setname in pairs(GAMEMODE.Beats) do
+ if setname ~= GAMEMODE.BeatSetHumanDefualt then
+ dropdown:AddChoice(setname)
+ end
+ end
+ dropdown:AddChoice("none")
+ dropdown:AddChoice("default")
+ dropdown.OnSelect = function(me, index, value, data)
+ RunConsoleCommand("zs_beatset_human", value)
+ end
+ dropdown:SetText(GAMEMODE.BeatSetHuman == GAMEMODE.BeatSetHumanDefault and "default" or GAMEMODE.BeatSetHuman)
+ list:AddItem(dropdown)
+
+ list:AddItem(EasyLabel(Window, "Zombie ambient beat set", "DefaultFontSmall", color_white))
+ local dropdown = vgui.Create("DComboBox", Window)
+ dropdown:SetMouseInputEnabled(true)
+ for setname in pairs(GAMEMODE.Beats) do
+ if setname ~= GAMEMODE.BeatSetZombieDefualt then
+ dropdown:AddChoice(setname)
+ end
+ end
+ dropdown:AddChoice("none")
+ dropdown:AddChoice("default")
+ dropdown.OnSelect = function(me, index, value, data)
+ RunConsoleCommand("zs_beatset_zombie", value)
+ end
+ dropdown:SetText(GAMEMODE.BeatSetZombie == GAMEMODE.BeatSetZombieDefault and "default" or GAMEMODE.BeatSetZombie)
+ list:AddItem(dropdown)
+
+ local slider = vgui.Create("DNumSlider", Window)
+ slider:SetDecimals(0)
+ slider:SetMinMax(0, 100)
+ slider:SetConVar("zs_beatsvolume")
+ slider:SetText("Music volume")
+ slider:SizeToContents()
+ list:AddItem(slider)
+
+ local slider = vgui.Create("DNumSlider", Window)
+ slider:SetDecimals(0)
+ slider:SetMinMax(0, 512)
+ slider:SetConVar("zs_transparencyradius")
+ slider:SetText("Transparency radius")
+ slider:SizeToContents()
+ list:AddItem(slider)
+
+ local slider = vgui.Create("DNumSlider", Window)
+ slider:SetDecimals(1)
+ slider:SetMinMax(0, 255)
+ slider:SetConVar("zs_filmgrainopacity")
+ slider:SetText("Film grain")
+ slider:SizeToContents()
+ list:AddItem(slider)
+
+ list:AddItem(EasyLabel(Window, "Crosshair primary color"))
+ local colpicker = vgui.Create("DColorMixer", Window)
+ colpicker:SetAlphaBar(false)
+ colpicker:SetPalette(false)
+ colpicker:SetConVarR("zs_crosshair_colr")
+ colpicker:SetConVarG("zs_crosshair_colg")
+ colpicker:SetConVarB("zs_crosshair_colb")
+ colpicker:SetTall(72)
+ list:AddItem(colpicker)
+
+ list:AddItem(EasyLabel(Window, "Crosshair secondary color"))
+ local colpicker = vgui.Create("DColorMixer", Window)
+ colpicker:SetAlphaBar(false)
+ colpicker:SetPalette(false)
+ colpicker:SetConVarR("zs_crosshair_colr2")
+ colpicker:SetConVarG("zs_crosshair_colg2")
+ colpicker:SetConVarB("zs_crosshair_colb2")
+ colpicker:SetTall(72)
+ list:AddItem(colpicker)
+
+ list:AddItem(EasyLabel(Window, "Health aura color - Full health"))
+ local colpicker = vgui.Create("DColorMixer", Window)
+ colpicker:SetAlphaBar(false)
+ colpicker:SetPalette(false)
+ colpicker:SetConVarR("zs_auracolor_full_r")
+ colpicker:SetConVarG("zs_auracolor_full_g")
+ colpicker:SetConVarB("zs_auracolor_full_b")
+ colpicker:SetTall(72)
+ list:AddItem(colpicker)
+
+ list:AddItem(EasyLabel(Window, "Health aura color - No health"))
+ local colpicker = vgui.Create("DColorMixer", Window)
+ colpicker:SetAlphaBar(false)
+ colpicker:SetPalette(false)
+ colpicker:SetConVarR("zs_auracolor_empty_r")
+ colpicker:SetConVarG("zs_auracolor_empty_g")
+ colpicker:SetConVarB("zs_auracolor_empty_b")
+ colpicker:SetTall(72)
+ list:AddItem(colpicker)
+
+ Window:SetAlpha(0)
+ Window:AlphaTo(255, 0.5, 0)
+ Window:MakePopup()
+end
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/ppointshop.lua b/gamemodes/zombiesurvival/gamemode/vgui/ppointshop.lua
new file mode 100644
index 0000000..eadbdbe
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/ppointshop.lua
@@ -0,0 +1,282 @@
+local function pointslabelThink(self)
+ local points = MySelf:GetPoints()
+ if self.m_LastPoints ~= points then
+ self.m_LastPoints = points
+
+ self:SetText("Points to spend: "..points)
+ self:SizeToContents()
+ end
+end
+
+hook.Add("Think", "PointsShopThink", function()
+ local pan = GAMEMODE.m_PointsShop
+ if pan and pan:Valid() and pan:IsVisible() then
+ local newstate = not GAMEMODE:GetWaveActive()
+ if newstate ~= pan.m_LastNearArsenalCrate then
+ pan.m_LastNearArsenalCrate = newstate
+
+ if newstate then
+ pan.m_DiscountLabel:SetText(GAMEMODE.ArsenalCrateDiscountPercentage.."% discount for buying between waves!")
+ pan.m_DiscountLabel:SetTextColor(COLOR_GREEN)
+ else
+ pan.m_DiscountLabel:SetText("All sales are final!")
+ pan.m_DiscountLabel:SetTextColor(COLOR_GRAY)
+ end
+
+ pan.m_DiscountLabel:SizeToContents()
+ pan.m_DiscountLabel:AlignRight(8)
+ end
+
+ local mx, my = gui.MousePos()
+ local x, y = pan:GetPos()
+ if mx < x - 16 or my < y - 16 or mx > x + pan:GetWide() + 16 or my > y + pan:GetTall() + 16 then
+ pan:SetVisible(false)
+ surface.PlaySound("npc/dog/dog_idle3.wav")
+ end
+ end
+end)
+
+local function PointsShopCenterMouse(self)
+ local x, y = self:GetPos()
+ local w, h = self:GetSize()
+ gui.SetMousePos(x + w * 0.5, y + h * 0.5)
+end
+
+local ammonames = {
+ ["pistol"] = "pistolammo",
+ ["buckshot"] = "shotgunammo",
+ ["smg1"] = "smgammo",
+ ["ar2"] = "assaultrifleammo",
+ ["357"] = "rifleammo",
+ ["XBowBolt"] = "crossbowammo"
+}
+
+local warnedaboutammo = CreateClientConVar("_zs_warnedaboutammo", "0", true, false)
+local function PurchaseDoClick(self)
+ if not warnedaboutammo:GetBool() then
+ local itemtab = FindItem(self.ID)
+ if itemtab and itemtab.SWEP then
+ local weptab = weapons.GetStored(itemtab.SWEP)
+ if weptab and weptab.Primary and weptab.Primary.Ammo and ammonames[weptab.Primary.Ammo] then
+ RunConsoleCommand("_zs_warnedaboutammo", "1")
+ Derma_Message("Be sure to buy extra ammo. Weapons purchased do not contain any extra ammo!", "Warning")
+ end
+ end
+ end
+
+ RunConsoleCommand("zs_pointsshopbuy", self.ID)
+end
+
+local function BuyAmmoDoClick(self)
+ RunConsoleCommand("zs_pointsshopbuy", "ps_"..self.AmmoType)
+end
+
+local function worthmenuDoClick()
+ MakepWorth()
+ GAMEMODE.m_PointsShop:Close()
+end
+
+local function ItemPanelThink(self)
+ local itemtab = FindItem(self.ID)
+ if itemtab then
+ local newstate = MySelf:GetPoints() >= math.ceil(itemtab.Worth * (GAMEMODE.m_PointsShop.m_LastNearArsenalCrate and GAMEMODE.ArsenalCrateMultiplier or 1)) and not (itemtab.NoClassicMode and GAMEMODE:IsClassicMode())
+ if newstate ~= self.m_LastAbleToBuy then
+ self.m_LastAbleToBuy = newstate
+ if newstate then
+ self:AlphaTo(255, 0.75, 0)
+ self.m_NameLabel:SetTextColor(COLOR_WHITE)
+ self.m_BuyButton:SetImage("icon16/accept.png")
+ else
+ self:AlphaTo(90, 0.75, 0)
+ self.m_NameLabel:SetTextColor(COLOR_RED)
+ self.m_BuyButton:SetImage("icon16/exclamation.png")
+ end
+
+ self.m_BuyButton:SizeToContents()
+ end
+ end
+end
+
+local function PointsShopThink(self)
+ if GAMEMODE:GetWave() ~= self.m_LastWaveWarning and not GAMEMODE:GetWaveActive() and CurTime() >= GAMEMODE:GetWaveStart() - 10 and CurTime() > (self.m_LastWaveWarningTime or 0) + 11 then
+ self.m_LastWaveWarning = GAMEMODE:GetWave()
+ self.m_LastWaveWarningTime = CurTime()
+
+ surface.PlaySound("ambient/alarms/klaxon1.wav")
+ timer.Simple(0.6, function() surface.PlaySound("ambient/alarms/klaxon1.wav") end)
+ timer.Simple(1.2, function() surface.PlaySound("ambient/alarms/klaxon1.wav") end)
+ timer.Simple(2, function() surface.PlaySound("vo/npc/Barney/ba_hurryup.wav") end)
+ end
+end
+
+function GM:OpenPointsShop()
+ if self.m_PointsShop and self.m_PointsShop:Valid() then
+ self.m_PointsShop:SetVisible(true)
+ self.m_PointsShop:CenterMouse()
+ return
+ end
+
+ local wid, hei = 480, math.max(ScrH() * 0.5, 400)
+
+ local frame = vgui.Create("DFrame")
+ frame:SetSize(wid, hei)
+ frame:Center()
+ frame:SetDeleteOnClose(false)
+ frame:SetTitle(" ")
+ frame:SetDraggable(false)
+ if frame.btnClose and frame.btnClose:Valid() then frame.btnClose:SetVisible(false) end
+ if frame.btnMinim and frame.btnMinim:Valid() then frame.btnMinim:SetVisible(false) end
+ if frame.btnMaxim and frame.btnMaxim:Valid() then frame.btnMaxim:SetVisible(false) end
+ frame.CenterMouse = PointsShopCenterMouse
+ frame.Think = PointsShopThink
+ self.m_PointsShop = frame
+
+ local topspace = vgui.Create("DPanel", frame)
+ topspace:SetWide(wid - 16)
+
+ local title = EasyLabel(topspace, "The Points Shop", "ZSHUDFontSmall", COLOR_WHITE)
+ title:CenterHorizontal()
+ local subtitle = EasyLabel(topspace, "For all of your zombie apocalypse needs!", "ZSHUDFontTiny", COLOR_WHITE)
+ subtitle:CenterHorizontal()
+ subtitle:MoveBelow(title, 4)
+
+ local _, y = subtitle:GetPos()
+ topspace:SetTall(y + subtitle:GetTall() + 4)
+ topspace:AlignTop(8)
+ topspace:CenterHorizontal()
+
+ local tt = vgui.Create("DImage", topspace)
+ tt:SetImage("gui/info")
+ tt:SizeToContents()
+ tt:SetPos(8, 8)
+ tt:SetMouseInputEnabled(true)
+ tt:SetTooltip("This shop is armed with the QUIK - Anti-zombie backstab device.\nMove your mouse outside of the shop to quickly close it!")
+
+ local wsb = EasyButton(topspace, "Worth Menu", 8, 4)
+ wsb:AlignRight(8)
+ wsb:AlignTop(8)
+ wsb.DoClick = worthmenuDoClick
+
+
+ local bottomspace = vgui.Create("DPanel", frame)
+ bottomspace:SetWide(topspace:GetWide())
+
+ local pointslabel = EasyLabel(bottomspace, "Points to spend: 0", "ZSHUDFontTiny", COLOR_GREEN)
+ pointslabel:AlignTop(4)
+ pointslabel:AlignLeft(8)
+ pointslabel.Think = pointslabelThink
+
+ local lab = EasyLabel(bottomspace, " ", "ZSHUDFontTiny")
+ lab:AlignTop(4)
+ lab:AlignRight(4)
+ frame.m_DiscountLabel = lab
+
+ local _, y = lab:GetPos()
+ bottomspace:SetTall(y + lab:GetTall() + 4)
+ bottomspace:AlignBottom(8)
+ bottomspace:CenterHorizontal()
+
+ local topx, topy = topspace:GetPos()
+ local botx, boty = bottomspace:GetPos()
+
+ local propertysheet = vgui.Create("DPropertySheet", frame)
+ propertysheet:SetSize(wid - 8, boty - topy - 8 - topspace:GetTall())
+ propertysheet:MoveBelow(topspace, 4)
+ propertysheet:CenterHorizontal()
+
+ local isclassic = GAMEMODE:IsClassicMode()
+
+ for catid, catname in ipairs(GAMEMODE.ItemCategories) do
+ local hasitems = false
+ for i, tab in ipairs(GAMEMODE.Items) do
+ if tab.Category == catid and tab.PointShop then
+ hasitems = true
+ break
+ end
+ end
+
+ if hasitems then
+ local list = vgui.Create("DPanelList", propertysheet)
+ list:SetPaintBackground(false)
+ propertysheet:AddSheet(catname, list, GAMEMODE.ItemCategoryIcons[catid], false, false)
+ list:EnableVerticalScrollbar(true)
+ list:SetWide(propertysheet:GetWide() - 16)
+ list:SetSpacing(2)
+ list:SetPadding(2)
+
+ for i, tab in ipairs(GAMEMODE.Items) do
+ if tab.Category == catid and tab.PointShop then
+ local itempan = vgui.Create("DPanel")
+ itempan:SetSize(list:GetWide(), 40)
+ itempan.ID = tab.Signature or i
+ itempan.Think = ItemPanelThink
+ list:AddItem(itempan)
+
+ local mdlframe = vgui.Create("DPanel", itempan)
+ mdlframe:SetSize(32, 32)
+ mdlframe:SetPos(4, 4)
+
+ local weptab = weapons.GetStored(tab.SWEP) or tab
+ local mdl = tab.Model or weptab.WorldModel
+ if mdl then
+ local mdlpanel = vgui.Create("DModelPanel", mdlframe)
+ mdlpanel:SetSize(mdlframe:GetSize())
+ mdlpanel:SetModel(mdl)
+ local mins, maxs = mdlpanel.Entity:GetRenderBounds()
+ mdlpanel:SetCamPos(mins:Distance(maxs) * Vector(0.75, 0.75, 0.5))
+ mdlpanel:SetLookAt((mins + maxs) / 2)
+ end
+
+ if tab.SWEP or tab.Countables then
+ local counter = vgui.Create("ItemAmountCounter", itempan)
+ counter:SetItemID(i)
+ end
+
+ local name = tab.Name or ""
+ local namelab = EasyLabel(itempan, name, "ZSHUDFontSmall", COLOR_WHITE)
+ namelab:SetPos(42, itempan:GetTall() * 0.5 - namelab:GetTall() * 0.5)
+ itempan.m_NameLabel = namelab
+
+ local pricelab = EasyLabel(itempan, tostring(tab.Worth).." Points", "ZSHUDFontTiny")
+ pricelab:SetPos(itempan:GetWide() - 20 - pricelab:GetWide(), 4)
+ itempan.m_PriceLabel = pricelab
+
+ local button = vgui.Create("DImageButton", itempan)
+ button:SetImage("icon16/lorry_add.png")
+ button:SizeToContents()
+ button:SetPos(itempan:GetWide() - 20 - button:GetWide(), itempan:GetTall() - 20)
+ button:SetTooltip("Purchase "..name)
+ button.ID = itempan.ID
+ button.DoClick = PurchaseDoClick
+ itempan.m_BuyButton = button
+
+ if weptab and weptab.Primary then
+ local ammotype = weptab.Primary.Ammo
+ if ammonames[ammotype] then
+ local ammobutton = vgui.Create("DImageButton", itempan)
+ ammobutton:SetImage("icon16/add.png")
+ ammobutton:SizeToContents()
+ ammobutton:CopyPos(button)
+ ammobutton:MoveLeftOf(button, 2)
+ ammobutton:SetTooltip("Purchase ammunition")
+ ammobutton.AmmoType = ammonames[ammotype]
+ ammobutton.DoClick = BuyAmmoDoClick
+ end
+ end
+
+ if tab.Description then
+ itempan:SetTooltip(tab.Description)
+ end
+
+ if tab.NoClassicMode and isclassic or tab.NoZombieEscape and GAMEMODE.ZombieEscape then
+ itempan:SetAlpha(120)
+ end
+ end
+ end
+ end
+ end
+
+ frame:MakePopup()
+ frame:CenterMouse()
+end
+GM.OpenPointShop = GM.OpenPointsShop
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/pweapons.lua b/gamemodes/zombiesurvival/gamemode/vgui/pweapons.lua
new file mode 100644
index 0000000..0b75ba3
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/pweapons.lua
@@ -0,0 +1,148 @@
+local function WeaponButtonDoClick(self)
+ local swep = self.SWEP
+ if swep then
+ pWeapons:SetWeaponViewerSWEP(self.SWEP)
+ end
+end
+
+local Features = {
+{"WalkSpeed", "Movement speed"},
+{"MeleeDamage", "Damage"},
+{"MeleeRange", "Range"},
+{"MeleeSize", "Size"},
+
+{"ClipSize", "Clip size", 0, 50, false, "Primary"},
+{"Damage", "Damage", 2, 100, false, "Primary"},
+{"NumShots", "Number of shots", 1, 12, false, "Primary"},
+{"Delay", "Rate of fire", 0.05, 3, true, "Primary"},
+
+{"ConeMax", "Minimum accuracy"},
+{"ConeMin", "Maximum accuracy"}
+}
+
+local function SetWeaponViewerSWEP(self, swep)
+ if self.Viewer then
+ if self.Viewer:Valid() then
+ self.Viewer:Remove()
+ end
+ self.Viewer = nil
+ end
+
+ local wid, hei = self:GetWide() * 0.6 - 16, self:GetTall() - self.ViewerY - 8
+ local halfwid = wid * 0.5
+
+ local viewer = vgui.Create("DPanel", self)
+ viewer:SetPaintBackground(false)
+ viewer:SetSize(wid, hei)
+ viewer:SetPos(self:GetWide() - viewer:GetWide() - 8, self.ViewerY)
+ self.Viewer = viewer
+
+ if not swep then return end
+ local sweptable = weapons.GetStored(swep)
+ if not sweptable then return end
+
+ local title = EasyLabel(viewer, sweptable.PrintName or swep, "ZSHUDFontSmall", COLOR_GRAY)
+ title:SetContentAlignment(8)
+ title:Dock(TOP)
+
+ if sweptable.WorldModel then
+ local bg = vgui.Create("DPanel", viewer)
+ bg:SetSize(92, 92)
+ bg:Dock(TOP)
+ bg:DockMargin(100, 0, 100, 0)
+
+ local modelpanel = vgui.Create("DModelPanelEx", bg)
+ modelpanel:SetModel(sweptable.WorldModel)
+ modelpanel:AutoCam()
+ modelpanel:Dock(FILL)
+ end
+
+ local text = ""
+
+ if sweptable.Description then
+ text = text..sweptable.Description
+ end
+
+ for i, featuretab in ipairs(Features) do
+ local touse
+ if featuretab[6] then
+ touse = sweptable[ featuretab[6] ]
+ else
+ touse = sweptable
+ end
+
+ local value = touse[ featuretab[1] ]
+ if value then
+ text = text.."\n"..featuretab[2]..": "..value
+ end
+ end
+
+ local desc = vgui.Create("DLabel", viewer)
+ desc:SetText(text)
+ desc:SetMultiline(true)
+ desc:SetWrap(true)
+ desc:Dock(FILL)
+end
+
+function MakepWeapons(silent)
+ if not silent then
+ PlayMenuOpenSound()
+ end
+
+ if pWeapons then
+ pWeapons:SetAlpha(0)
+ pWeapons:AlphaTo(255, 0.5, 0)
+ pWeapons:SetVisible(true)
+ pWeapons:MakePopup()
+ return
+ end
+
+ local added = {}
+
+ local weps = {}
+ for _, tab in pairs(GAMEMODE.Items) do
+ if tab.SWEP and not added[tab.SWEP] then
+ weps[#weps + 1] = tab.SWEP
+ end
+ end
+
+ local wid, hei = 600, 400
+
+ local frame = vgui.Create("DFrame")
+ frame:SetDeleteOnClose(false)
+ frame:SetSize(wid, hei)
+ frame:SetTitle(" ")
+ frame:Center()
+ frame.SetWeaponViewerSWEP = SetWeaponViewerSWEP
+ pWeapons = frame
+
+ local y = 8
+
+ local title = EasyLabel(frame, "Weapon Database", "ZSHUDFont", color_white)
+ title:SetPos(wid * 0.5 - title:GetWide() * 0.5, y)
+ y = y + title:GetTall() + 8
+
+ frame.ViewerY = y
+
+ local tree = vgui.Create("DTree", frame)
+ tree:SetSize(wid * 0.4 - 8, hei - y - 8)
+ tree:SetPos(8, y)
+ tree:SetIndentSize(4)
+ frame.Tree = tree
+
+ for _, wep in pairs(weps) do
+ local enttab = weapons.GetStored(wep)
+ local wepnode
+ if enttab then
+ wepnode = tree:AddNode(enttab.PrintName or wep)
+ else
+ wepnode = tree:AddNode(wep)
+ end
+ wepnode.SWEP = wep
+ wepnode.DoClick = WeaponButtonDoClick
+ end
+
+ frame:SetWeaponViewerSWEP()
+
+ MakepWeapons(true)
+end
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/pworth.lua b/gamemodes/zombiesurvival/gamemode/vgui/pworth.lua
new file mode 100644
index 0000000..2a90134
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/pworth.lua
@@ -0,0 +1,508 @@
+hook.Add("SetWave", "CloseWorthOnWave1", function(wave)
+ if wave > 0 then
+ if pWorth and pWorth:Valid() then
+ pWorth:Close()
+ end
+
+ hook.Remove("SetWave", "CloseWorthOnWave1")
+ end
+end)
+
+local cvarDefaultCart = CreateClientConVar("zs_defaultcart", "", true, false)
+
+local function DefaultDoClick(btn)
+ if cvarDefaultCart:GetString() == btn.Name then
+ RunConsoleCommand("zs_defaultcart", "")
+ surface.PlaySound("buttons/button11.wav")
+ else
+ RunConsoleCommand("zs_defaultcart", btn.Name)
+ surface.PlaySound("buttons/button14.wav")
+ end
+
+ timer.Simple(0.1, MakepWorth)
+end
+
+local WorthRemaining = 0
+local WorthButtons = {}
+local function CartDoClick(self, silent, force)
+ local id = self.ID
+ local tab = FindStartingItem(id)
+ if not tab then return end
+
+ if self.On then
+ self.On = nil
+ self:SetImage("icon16/cart_add.png")
+ if not silent then
+ surface.PlaySound("buttons/button18.wav")
+ end
+ self:SetTooltip("Add to cart")
+ WorthRemaining = WorthRemaining + tab.Worth
+ else
+ if WorthRemaining < tab.Worth and not force then
+ surface.PlaySound("buttons/button8.wav")
+ return
+ end
+ self.On = true
+ self:SetImage("icon16/cart_delete.png")
+ if not silent then
+ surface.PlaySound("buttons/button17.wav")
+ end
+ self:SetTooltip("Remove from cart")
+ WorthRemaining = WorthRemaining - tab.Worth
+ end
+
+ pWorth.WorthLab:SetText("Worth: ".. WorthRemaining)
+ if WorthRemaining <= 0 then
+ pWorth.WorthLab:SetTextColor(COLOR_RED)
+ elseif WorthRemaining <= GAMEMODE.StartingWorth * 0.25 then
+ pWorth.WorthLab:SetTextColor(COLOR_YELLOW)
+ else
+ pWorth.WorthLab:SetTextColor(COLOR_LIMEGREEN)
+ end
+ pWorth.WorthLab:SizeToContents()
+end
+
+local function Checkout(tobuy)
+ if tobuy and #tobuy > 0 then
+ gamemode.Call("SuppressArsenalUpgrades", 1)
+
+ RunConsoleCommand("worthcheckout", unpack(tobuy))
+
+ if pWorth and pWorth:Valid() then
+ pWorth:Close()
+ end
+ else
+ surface.PlaySound("buttons/combine_button_locked.wav")
+ end
+end
+
+local function CheckoutDoClick(self)
+ local tobuy = {}
+ for _, btn in pairs(WorthButtons) do
+ if btn and btn.On and btn.ID then
+ table.insert(tobuy, btn.ID)
+ end
+ end
+
+ Checkout(tobuy)
+end
+
+local function RandDoClick(self)
+ gamemode.Call("SuppressArsenalUpgrades", 1)
+
+ RunConsoleCommand("worthrandom")
+
+ if pWorth and pWorth:Valid() then
+ pWorth:Close()
+ end
+end
+
+GM.SavedCarts = {}
+hook.Add("Initialize", "LoadCarts", function()
+ if file.Exists(GAMEMODE.CartFile, "DATA") then
+ GAMEMODE.SavedCarts = Deserialize(file.Read(GAMEMODE.CartFile)) or {}
+ end
+end)
+
+local function ClearCartDoClick()
+ for _, btn in ipairs(WorthButtons) do
+ if btn.On then
+ btn:DoClick(true, true)
+ end
+ end
+
+ surface.PlaySound("buttons/button11.wav")
+end
+
+local function LoadCart(cartid, silent)
+ if GAMEMODE.SavedCarts[cartid] then
+ MakepWorth()
+ for _, id in pairs(GAMEMODE.SavedCarts[cartid][2]) do
+ for __, btn in pairs(WorthButtons) do
+ if btn and (btn.ID == id or GAMEMODE.Items[id] and GAMEMODE.Items[id].Signature == btn.ID) then
+ btn:DoClick(true, true)
+ end
+ end
+ end
+ if not silent then
+ surface.PlaySound("buttons/combine_button1.wav")
+ end
+ end
+end
+
+local function LoadDoClick(self)
+ LoadCart(self.ID)
+end
+
+local function SaveCurrentCart(name)
+ local tobuy = {}
+ for _, btn in pairs(WorthButtons) do
+ if btn and btn.On and btn.ID then
+ table.insert(tobuy, btn.ID)
+ end
+ end
+ for i, cart in ipairs(GAMEMODE.SavedCarts) do
+ if string.lower(cart[1]) == string.lower(name) then
+ cart[1] = name
+ cart[2] = tobuy
+
+ file.Write(GAMEMODE.CartFile, Serialize(GAMEMODE.SavedCarts))
+ print("Saved cart "..tostring(name))
+
+ LoadCart(i, true)
+ return
+ end
+ end
+
+ GAMEMODE.SavedCarts[#GAMEMODE.SavedCarts + 1] = {name, tobuy}
+
+ file.Write(GAMEMODE.CartFile, Serialize(GAMEMODE.SavedCarts))
+ print("Saved cart "..tostring(name))
+
+ LoadCart(#GAMEMODE.SavedCarts, true)
+end
+
+local function SaveDoClick(self)
+ Derma_StringRequest("Save cart", "Enter a name for this cart.", "Name",
+ function(strTextOut) SaveCurrentCart(strTextOut) end,
+ function(strTextOut) end,
+ "OK", "Cancel")
+end
+
+local function DeleteDoClick(self)
+ if GAMEMODE.SavedCarts[self.ID] then
+ table.remove(GAMEMODE.SavedCarts, self.ID)
+ file.Write(GAMEMODE.CartFile, Serialize(GAMEMODE.SavedCarts))
+ surface.PlaySound("buttons/button19.wav")
+ MakepWorth()
+ end
+end
+
+local function QuickCheckDoClick(self)
+ if GAMEMODE.SavedCarts[self.ID] then
+ Checkout(GAMEMODE.SavedCarts[self.ID][2])
+ end
+end
+
+function MakepWorth()
+ if pWorth and pWorth:Valid() then
+ pWorth:Remove()
+ pWorth = nil
+ end
+
+ local maxworth = GAMEMODE.StartingWorth
+ WorthRemaining = maxworth
+
+ local wid, hei = math.min(ScrW(), 720), ScrH() * 0.7
+
+ local frame = vgui.Create("DFrame")
+ pWorth = frame
+ frame:SetSize(wid, hei)
+ frame:SetDeleteOnClose(true)
+ frame:SetKeyboardInputEnabled(false)
+ frame:SetTitle(" ")
+
+ local propertysheet = vgui.Create("DPropertySheet", frame)
+ propertysheet:StretchToParent(4, 24, 4, 50)
+ propertysheet.Paint = function() end
+
+ local list = vgui.Create("DPanelList", propertysheet)
+ propertysheet:AddSheet("Favorites", list, "icon16/heart.png", false, false)
+ list:EnableVerticalScrollbar(true)
+ list:SetWide(propertysheet:GetWide() - 16)
+ list:SetSpacing(2)
+ list:SetPadding(2)
+
+ local savebutton = EasyButton(nil, "Save the current cart", 0, 10)
+ savebutton.DoClick = SaveDoClick
+ list:AddItem(savebutton)
+
+ local panfont = "ZSHUDFontSmall"
+ local panhei = 40
+
+ local defaultcart = cvarDefaultCart:GetString()
+
+ for i, savetab in ipairs(GAMEMODE.SavedCarts) do
+ local cartpan = vgui.Create("DEXRoundedPanel")
+ cartpan:SetCursor("pointer")
+ cartpan:SetSize(list:GetWide(), panhei)
+
+ local cartname = savetab[1]
+
+ local x = 8
+
+ if defaultcart == cartname then
+ local defimage = vgui.Create("DImage", cartpan)
+ defimage:SetImage("icon16/heart.png")
+ defimage:SizeToContents()
+ defimage:SetMouseInputEnabled(true)
+ defimage:SetTooltip("This is your default cart.\nIf you join the game late then you'll spawn with this cart.")
+ defimage:SetPos(x, cartpan:GetTall() * 0.5 - defimage:GetTall() * 0.5)
+ x = x + defimage:GetWide() + 4
+ end
+
+ local cartnamelabel = EasyLabel(cartpan, cartname, panfont)
+ cartnamelabel:SetPos(x, cartpan:GetTall() * 0.5 - cartnamelabel:GetTall() * 0.5)
+
+ x = cartpan:GetWide() - 20
+
+ local checkbutton = vgui.Create("DImageButton", cartpan)
+ checkbutton:SetImage("icon16/accept.png")
+ checkbutton:SizeToContents()
+ checkbutton:SetTooltip("Purchase this saved cart.")
+ x = x - checkbutton:GetWide() - 8
+ checkbutton:SetPos(x, cartpan:GetTall() * 0.5 - checkbutton:GetTall() * 0.5)
+ checkbutton.ID = i
+ checkbutton.DoClick = QuickCheckDoClick
+
+ local loadbutton = vgui.Create("DImageButton", cartpan)
+ loadbutton:SetImage("icon16/folder_go.png")
+ loadbutton:SizeToContents()
+ loadbutton:SetTooltip("Load this saved cart.")
+ x = x - loadbutton:GetWide() - 8
+ loadbutton:SetPos(x, cartpan:GetTall() * 0.5 - loadbutton:GetTall() * 0.5)
+ loadbutton.ID = i
+ loadbutton.DoClick = LoadDoClick
+
+ local defaultbutton = vgui.Create("DImageButton", cartpan)
+ defaultbutton:SetImage("icon16/heart.png")
+ defaultbutton:SizeToContents()
+ if cartname == defaultcart then
+ defaultbutton:SetTooltip("Remove this cart as your default.")
+ else
+ defaultbutton:SetTooltip("Make this cart your default.")
+ end
+ x = x - defaultbutton:GetWide() - 8
+ defaultbutton:SetPos(x, cartpan:GetTall() * 0.5 - defaultbutton:GetTall() * 0.5)
+ defaultbutton.Name = cartname
+ defaultbutton.DoClick = DefaultDoClick
+
+ local deletebutton = vgui.Create("DImageButton", cartpan)
+ deletebutton:SetImage("icon16/bin.png")
+ deletebutton:SizeToContents()
+ deletebutton:SetTooltip("Delete this saved cart.")
+ x = x - deletebutton:GetWide() - 8
+ deletebutton:SetPos(x, cartpan:GetTall() * 0.5 - loadbutton:GetTall() * 0.5)
+ deletebutton.ID = i
+ deletebutton.DoClick = DeleteDoClick
+
+ list:AddItem(cartpan)
+ end
+
+ for catid, catname in ipairs(GAMEMODE.ItemCategories) do
+ local list = vgui.Create("DPanelList", propertysheet)
+ list:SetPaintBackground(false)
+ propertysheet:AddSheet(catname, list, GAMEMODE.ItemCategoryIcons[catid], false, false)
+ list:EnableVerticalScrollbar(true)
+ list:SetWide(propertysheet:GetWide() - 16)
+ list:SetSpacing(2)
+ list:SetPadding(2)
+
+ for i, tab in ipairs(GAMEMODE.Items) do
+ if tab.Category == catid and tab.WorthShop then
+ local button = vgui.Create("ZSWorthButton")
+ button:SetWorthID(i)
+ list:AddItem(button)
+ WorthButtons[i] = button
+ end
+ end
+ end
+
+ local worthlab = EasyLabel(frame, "Worth: "..tostring(WorthRemaining), "ZSHUDFontSmall", COLOR_LIMEGREEN)
+ worthlab:SetPos(8, frame:GetTall() - worthlab:GetTall() - 8)
+ frame.WorthLab = worthlab
+
+ local checkout = vgui.Create("DButton", frame)
+ checkout:SetFont("ZSHUDFontSmall")
+ checkout:SetText("Checkout")
+ checkout:SizeToContents()
+ checkout:SetSize(130, 30)
+ checkout:AlignBottom(8)
+ checkout:CenterHorizontal()
+ checkout.DoClick = CheckoutDoClick
+
+ local randombutton = vgui.Create("DButton", frame)
+ randombutton:SetText("Random")
+ randombutton:SetSize(64, 16)
+ randombutton:AlignBottom(8)
+ randombutton:AlignRight(8)
+ randombutton.DoClick = RandDoClick
+
+ local clearbutton = vgui.Create("DButton", frame)
+ clearbutton:SetText("Clear")
+ clearbutton:SetSize(64, 16)
+ clearbutton:AlignRight(8)
+ clearbutton:MoveAbove(randombutton, 8)
+ clearbutton.DoClick = ClearCartDoClick
+
+ if #GAMEMODE.SavedCarts == 0 then
+ propertysheet:SetActiveTab(propertysheet.Items[math.min(2, #propertysheet.Items)].Tab)
+ end
+
+ frame:Center()
+ frame:SetAlpha(0)
+ frame:AlphaTo(255, 0.5, 0)
+ frame:MakePopup()
+
+ return frame
+end
+
+local PANEL = {}
+PANEL.m_ItemID = 0
+PANEL.RefreshTime = 1
+PANEL.NextRefresh = 0
+
+function PANEL:Init()
+ self:SetFont("DefaultFontSmall")
+end
+
+function PANEL:Think()
+ if CurTime() >= self.NextRefresh then
+ self.NextRefresh = CurTime() + self.RefreshTime
+ self:Refresh()
+ end
+end
+
+function PANEL:Refresh()
+ local count = GAMEMODE:GetCurrentEquipmentCount(self:GetItemID())
+ if count == 0 then
+ self:SetText(" ")
+ else
+ self:SetText(count)
+ end
+
+ self:SizeToContents()
+end
+
+function PANEL:SetItemID(id) self.m_ItemID = id end
+function PANEL:GetItemID() return self.m_ItemID end
+
+vgui.Register("ItemAmountCounter", PANEL, "DLabel")
+
+PANEL = {}
+
+function PANEL:Init()
+ self:SetText("")
+
+ self:DockPadding(4, 4, 4, 4)
+ self:SetTall(48)
+
+ local mdlframe = vgui.Create("DEXRoundedPanel", self)
+ mdlframe:SetWide(self:GetTall() - 8)
+ mdlframe:Dock(LEFT)
+ mdlframe:DockMargin(0, 0, 20, 0)
+
+ self.ModelPanel = vgui.Create("DModelPanel", mdlframe)
+ self.ModelPanel:Dock(FILL)
+ self.ModelPanel:DockPadding(0, 0, 0, 0)
+ self.ModelPanel:DockMargin(0, 0, 0, 0)
+
+ self.NameLabel = EasyLabel(self, "", "ZSHUDFontSmall")
+ self.NameLabel:SetContentAlignment(4)
+ self.NameLabel:Dock(FILL)
+
+ self.PriceLabel = EasyLabel(self, "", "ZSHUDFontTiny")
+ self.PriceLabel:SetWide(80)
+ self.PriceLabel:SetContentAlignment(6)
+ self.PriceLabel:Dock(RIGHT)
+ self.PriceLabel:DockMargin(8, 0, 4, 0)
+
+ self.ItemCounter = vgui.Create("ItemAmountCounter", self)
+
+ self:SetWorthID(nil)
+end
+
+function PANEL:SetWorthID(id)
+ self.ID = id
+
+ local tab = FindStartingItem(id)
+
+ if not tab then
+ self.ModelPanel:SetVisible(false)
+ self.ItemCounter:SetVisible(false)
+ self.NameLabel:SetText("")
+ return
+ end
+
+ local mdl = tab.Model or (weapons.GetStored(tab.SWEP) or tab).WorldModel
+ if mdl then
+ self.ModelPanel:SetModel(mdl)
+ local mins, maxs = self.ModelPanel.Entity:GetRenderBounds()
+ self.ModelPanel:SetCamPos(mins:Distance(maxs) * Vector(0.75, 0.75, 0.5))
+ self.ModelPanel:SetLookAt((mins + maxs) / 2)
+ self.ModelPanel:SetVisible(true)
+ else
+ self.ModelPanel:SetVisible(false)
+ end
+
+ if tab.SWEP or tab.Countables then
+ self.ItemCounter:SetItemID(id)
+ self.ItemCounter:SetVisible(true)
+ else
+ self.ItemCounter:SetVisible(false)
+ end
+
+ if tab.Worth then
+ self.PriceLabel:SetText(tostring(tab.Worth).." Worth")
+ else
+ self.PriceLabel:SetText("")
+ end
+
+ self:SetTooltip(tab.Description)
+
+ if tab.NoClassicMode and GAMEMODE:IsClassicMode() or tab.NoZombieEscape and GAMEMODE.ZombieEscape then
+ self:SetAlpha(120)
+ else
+ self:SetAlpha(255)
+ end
+
+ self.NameLabel:SetText(tab.Name or "")
+end
+
+function PANEL:Paint(w, h)
+ local outline
+ if self.Hovered then
+ outline = self.On and COLOR_GREEN or COLOR_GRAY
+ else
+ outline = self.On and COLOR_DARKGREEN or COLOR_DARKGRAY
+ end
+
+ draw.RoundedBox(8, 0, 0, w, h, outline)
+ draw.RoundedBox(4, 4, 4, w - 8, h - 8, color_black)
+end
+
+function PANEL:DoClick(silent, force)
+ local id = self.ID
+ local tab = FindStartingItem(id)
+ if not tab then return end
+
+ if self.On then
+ self.On = nil
+ if not silent then
+ surface.PlaySound("buttons/button18.wav")
+ end
+ WorthRemaining = WorthRemaining + tab.Worth
+ else
+ if WorthRemaining < tab.Worth and not force then
+ surface.PlaySound("buttons/button8.wav")
+ return
+ end
+ self.On = true
+ if not silent then
+ surface.PlaySound("buttons/button17.wav")
+ end
+ WorthRemaining = WorthRemaining - tab.Worth
+ end
+
+ pWorth.WorthLab:SetText("Worth: ".. WorthRemaining)
+ if WorthRemaining <= 0 then
+ pWorth.WorthLab:SetTextColor(COLOR_RED)
+ elseif WorthRemaining <= GAMEMODE.StartingWorth * 0.25 then
+ pWorth.WorthLab:SetTextColor(COLOR_YELLOW)
+ else
+ pWorth.WorthLab:SetTextColor(COLOR_LIMEGREEN)
+ end
+ pWorth.WorthLab:SizeToContents()
+end
+
+vgui.Register("ZSWorthButton", PANEL, "DButton")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/zschanginglabel.lua b/gamemodes/zombiesurvival/gamemode/vgui/zschanginglabel.lua
new file mode 100644
index 0000000..35b8d9f
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/zschanginglabel.lua
@@ -0,0 +1,36 @@
+local PANEL = {}
+
+local function empty() end
+
+function PANEL:SetChangeFunction(func, autosize)
+ self.Think = function(me)
+ local val = func()
+ if self.LastValue ~= val and val ~= nil then
+ self.LastValue = val
+
+ self:SetText(val)
+
+ if autosize then
+ self:SizeToContents()
+ end
+
+ if self.OnChanged then
+ self:OnChanged(val)
+ end
+ end
+ end
+end
+
+function PANEL:RemoveChangeFunction()
+ self.Think = empty
+end
+
+function PANEL:SetChangedFunction(func)
+ self.OnChanged = func
+end
+
+function PANEL:RemoveChangedFunction()
+ self.OnChanged = empty
+end
+
+vgui.Register("DEXChangingLabel", PANEL, "DEXChangingLabel")
diff --git a/gamemodes/zombiesurvival/gamemode/vgui/zshealtharea.lua b/gamemodes/zombiesurvival/gamemode/vgui/zshealtharea.lua
new file mode 100644
index 0000000..1fa7726
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/vgui/zshealtharea.lua
@@ -0,0 +1,314 @@
+local PANEL = {}
+
+local colHealth = Color(0, 0, 0, 240)
+local function ContentsPaint(self)
+ local lp = LocalPlayer()
+ if lp:IsValid() then
+ local health = math.max(lp:Health(), 0)
+ local healthperc = math.Clamp(health / lp:GetMaxHealthEx(), 0, 1)
+
+ colHealth.r = (1 - healthperc) * 180
+ colHealth.g = healthperc * 180
+
+ draw.SimpleTextBlurry(health, "ZSHUDFont", 8, self:GetTall() - 8, colHealth, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
+ end
+end
+
+function PANEL:Init()
+ self:DockMargin(0, 0, 0, 0)
+ self:DockPadding(0, 0, 0, 0)
+
+ self.HealthModel = vgui.Create("ZSHealthModelPanel", self)
+ self.HealthModel:Dock(LEFT)
+
+ local contents = vgui.Create("Panel", self)
+ contents:Dock(FILL)
+ contents.Paint = ContentsPaint
+
+ local poisonstatus = vgui.Create("ZSHealthStatus", contents)
+ poisonstatus:SetTall(20)
+ poisonstatus:SetAlpha(200)
+ poisonstatus:SetColor(Color(180, 180, 0))
+ poisonstatus:SetMemberName("POISON!")
+ poisonstatus.GetMemberValue = function(me)
+ local lp = LocalPlayer()
+ if lp:IsValid() then
+ return lp:GetPoisonDamage()
+ end
+ end
+ poisonstatus.MemberMaxValue = 50
+ poisonstatus:Dock(TOP)
+
+ local bleedstatus = vgui.Create("ZSHealthStatus", contents)
+ bleedstatus:SetTall(20)
+ bleedstatus:SetAlpha(200)
+ bleedstatus:SetColor(Color(220, 0, 0))
+ bleedstatus:SetMemberName("BLEED!")
+ bleedstatus.GetMemberValue = function(me)
+ local lp = LocalPlayer()
+ if lp:IsValid() then
+ return lp:GetBleedDamage()
+ end
+ end
+ bleedstatus.MemberMaxValue = 20
+ bleedstatus:Dock(TOP)
+
+ self:ParentToHUD()
+ self:InvalidateLayout()
+end
+
+function PANEL:PerformLayout()
+ local screenscale = BetterScreenScale()
+
+ self:SetSize(screenscale * 350, screenscale * 128)
+
+ self.HealthModel:SetWide(self:GetTall())
+
+ self:AlignLeft(screenscale * 24)
+ self:AlignBottom(screenscale * 24)
+end
+
+function PANEL:Paint()
+end
+
+vgui.Register("ZSHealthArea", PANEL, "Panel")
+
+local PANEL = {}
+
+PANEL.ModelLow = 0
+PANEL.ModelHigh = 72
+PANEL.Health = 100
+PANEL.BarricadeGhosting = 0
+
+function PANEL:Init()
+ self:SetAnimSpeed(0)
+ self:SetFOV(55)
+end
+
+local function LowestAndHighest(ent)
+ local lowest
+ local highest
+
+ local basepos = ent:GetPos()
+ for i=0, ent:GetBoneCount() - 1 do
+ local bonepos, boneang = ent:GetBonePosition(i)
+ if bonepos and bonepos ~= basepos then
+ if lowest == nil then
+ lowest = bonepos.z
+ highest = bonepos.z
+ else
+ lowest = math.min(lowest, bonepos.z)
+ highest = math.max(highest, bonepos.z)
+ end
+ end
+ end
+
+ highest = (highest or 1) + ent:GetModelScale() * 8
+
+ return lowest or 0, highest
+end
+
+function PANEL:Think()
+ local lp = LocalPlayer()
+ if lp:IsValid() then
+ self.Health = math.Clamp(lp:Health() / lp:GetMaxHealthEx(), 0, 1)
+ self.BarricadeGhosting = math.Approach(self.BarricadeGhosting, lp:IsBarricadeGhosting() and 1 or 0, FrameTime() * 5)
+
+ local model = lp:GetModel()
+ local modelscale = lp:GetModelScale()
+ local ent = self.Entity
+ if not ent or not ent:IsValid() or model ~= ent:GetModel() or modelscale ~= ent:GetModelScale() then
+ if IsValid(self.OverrideEntity) then
+ self.OverrideEntity:Remove()
+ self.OverrideEntity = nil
+ end
+
+ self:SetModel(model)
+
+ if IsValid(self.Entity) then
+ local mins, maxs = lp:GetRenderBounds()
+ self:SetCamPos(mins:Distance(maxs) * Vector(0, -0.9, 0.4))
+ self:SetLookAt((mins + maxs) / 2)
+ self.Entity:SetModelScale(modelscale, 0)
+ end
+ end
+
+ local overridemodel = lp.status_overridemodel
+ if overridemodel and overridemodel:IsValid() then
+ if IsValid(self.Entity) and not IsValid(self.OverrideEntity) then
+ self.OverrideEntity = ClientsideModel(overridemodel:GetModel(), RENDER_GROUP_OPAQUE_ENTITY)
+ if IsValid(self.OverrideEntity) then
+ self.OverrideEntity:SetPos(self.Entity:GetPos())
+ self.OverrideEntity:SetParent(self.Entity)
+ self.OverrideEntity:AddEffects(bit.bor(EF_BONEMERGE, EF_BONEMERGE_FASTCULL))
+ self.OverrideEntity:SetNoDraw(true)
+ end
+ end
+ elseif self.OverrideEntity and self.OverrideEntity:IsValid() then
+ self.OverrideEntity:Remove()
+ self.OverrideEntity = nil
+ end
+
+ ent = self.Entity
+ if ent and ent:IsValid() then
+ ent:SetSequence(lp:GetSequence())
+
+ ent:SetPoseParameter("move_x", lp:GetPoseParameter("move_x") * 2 - 1)
+ ent:SetPoseParameter("move_y", lp:GetPoseParameter("move_y") * 2 - 1)
+ ent:SetCycle(lp:GetCycle())
+
+ local modellow, modelhigh = LowestAndHighest(ent)
+ self.ModelLow = math.Approach(self.ModelLow, modellow, FrameTime() * 256)
+ self.ModelHigh = math.Approach(self.ModelHigh, modelhigh, FrameTime() * 256)
+ self.ModelHigh = math.max(self.ModelLow + 1, self.ModelHigh)
+ end
+ end
+end
+
+function PANEL:OnRemove()
+ if IsValid(self.Entity) then
+ self.Entity:Remove()
+ end
+ if IsValid(self.OverrideEntity) then
+ self.OverrideEntity:Remove()
+ end
+end
+
+local matWhite = Material("models/debug/debugwhite")
+local matGlow = Material("sprites/glow04_noz")
+local matShadow = CreateMaterial("zshealthhudshadow", "UnlitGeneric", {["$basetexture"] = "decals/simpleshadow", ["$vertexalpha"] = "1", ["$vertexcolor"] = "1"})
+local colShadow = Color(20, 20, 20, 230)
+function PANEL:Paint()
+ local ent = self.OverrideEntity or self.Entity
+ if not ent or not ent:IsValid() then return end
+
+ local lp = LocalPlayer()
+ if not lp:IsValid() then return end
+
+ local x, y = self:LocalToScreen(0, 0)
+ local ang = self.aLookAngle
+ local w, h = self:GetSize()
+ local health = self.Health
+ local entpos = ent:GetPos()
+
+ self:LayoutEntity(ent)
+
+ if not ang then
+ ang = (self.vLookatPos - self.vCamPos):Angle()
+ end
+
+ render.ModelMaterialOverride(matWhite)
+ render.SuppressEngineLighting(true)
+ cam.IgnoreZ(true)
+
+ cam.Start3D(self.vCamPos - ang:Forward() * 16, ang, self.fFOV * 0.75, x, y, w, h, 5, 4096)
+ render.OverrideDepthEnable(true, false)
+ render.SetColorModulation(0, 0, self.BarricadeGhosting)
+ ent:DrawModel()
+ render.OverrideDepthEnable(false)
+ cam.End3D()
+
+ cam.Start3D(self.vCamPos, ang, self.fFOV, x, y, w, h, 5, 4096)
+
+ render.SetMaterial(matShadow)
+ render.DrawQuadEasy(entpos, Vector(0, 0, 1), 45, 90, colShadow)
+
+ render.SetLightingOrigin(entpos)
+ render.ResetModelLighting(0.2, 0.2, 0.2)
+ render.SetModelLighting(BOX_FRONT, 0.8, 0.8, 0.8)
+ render.SetModelLighting(BOX_TOP, 0.8, 0.8, 0.8)
+
+ if health == 1 then
+ render.SetColorModulation(0, 0.6, 0)
+ ent:DrawModel()
+ elseif health == 0 then
+ render.SetColorModulation(0, 0, 0)
+ ent:DrawModel()
+ else
+ local normal = Vector(0, 0, 1)
+ local pos = entpos + Vector(0, 0, self.ModelLow * (1 - health) + self.ModelHigh * health)
+
+ render.EnableClipping(true)
+
+ render.PushCustomClipPlane(normal, normal:Dot(pos))
+ render.SetColorModulation(health > 0.5 and 0.6 or (0.7 + math.sin(CurTime() * math.pi * 2) * 0.2), 0, 0)
+ ent:DrawModel()
+ render.PopCustomClipPlane()
+
+ normal = normal * -1
+ render.PushCustomClipPlane(normal, normal:Dot(pos))
+ render.SetColorModulation(0, 0.6, 0)
+ ent:DrawModel()
+ render.PopCustomClipPlane()
+
+ render.EnableClipping(false)
+ end
+
+ cam.End3D()
+
+ render.ModelMaterialOverride()
+ render.SuppressEngineLighting(false)
+ render.SetColorModulation(1, 1, 1)
+ cam.IgnoreZ(false)
+end
+
+function PANEL:LayoutEntity(ent)
+ self:RunAnimation()
+end
+
+vgui.Register("ZSHealthModelPanel", PANEL, "DModelPanel")
+
+local PANEL = {}
+
+PANEL.MemberValue = 0
+PANEL.LerpMemberValue = 0
+PANEL.MemberMaxValue = 100
+PANEL.MemberName = "Unnamed"
+
+function PANEL:SetColor(col) self.m_Color = col end
+function PANEL:GetColor() return self.m_Color end
+function PANEL:SetMemberName(n) self.MemberName = n end
+function PANEL:GetMemberName() return self.MemberName end
+
+function PANEL:Init()
+ self:SetColor(Color(255, 255, 255))
+end
+
+function PANEL:Think()
+ if self.GetMemberValue then
+ self.MemberValue = self:GetMemberValue() or self.MemberValue
+ end
+ if self.GetMemberMaxValue then
+ self.MemberMaxValue = self:GetMemberMaxValue() or self.MemberMaxValue
+ end
+
+ if self.MemberValue > self.LerpMemberValue then
+ self.LerpMemberValue = self.MemberValue
+ elseif self.MemberValue < self.LerpMemberValue then
+ self.LerpMemberValue = math.Approach(self.LerpMemberValue, self.MemberValue, FrameTime() * 10)
+ end
+end
+
+function PANEL:Paint()
+ local value = self.LerpMemberValue
+ if value <= 0 then return end
+
+ local col = self:GetColor()
+ local max = self.MemberMaxValue
+ local w, h = self:GetSize()
+
+ surface.SetDrawColor(0, 0, 0, 255)
+ surface.DrawRect(0, 0, w, h)
+
+ surface.SetDrawColor(col)
+ surface.DrawOutlinedRect(0, 0, w, h)
+ surface.DrawRect(3, 3, (w - 6) * math.Clamp(value / max, 0, 1), h - 6)
+
+ local t1 = math.ceil(value)
+ draw.SimpleText(t1, "ZSHUDFontTinyNS", w - 3, h / 2 + 1, color_black, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER)
+ draw.SimpleText(t1, "ZSHUDFontTinyNS", w - 4, h / 2, color_white, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER)
+ draw.SimpleText(self.MemberName, "ZSHUDFontTinyNS", 5, h / 2 + 1, color_black, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
+ draw.SimpleText(self.MemberName, "ZSHUDFontTinyNS", 4, h / 2, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
+end
+
+vgui.Register("ZSHealthStatus", PANEL, "Panel")
diff --git a/gamemodes/zombiesurvival/gamemode/workshopfix.lua b/gamemodes/zombiesurvival/gamemode/workshopfix.lua
new file mode 100644
index 0000000..1d55983
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/workshopfix.lua
@@ -0,0 +1,148 @@
+AddCSLuaFile()
+
+-- thanks for fixing this bug that's been there for months, garry!
+
+-- Change this to an entity to check for to determine if our entities didn't get loaded.
+local ENTITYCLASS = "prop_nail"
+
+hook.Add("Initialize", "workshop", function()
+
+if scripted_ents.GetStored(ENTITYCLASS) ~= nil then return end
+
+print("Workshop version...")
+
+local foldername = GAMEMODE.FolderName
+
+local entitiespath = foldername.."/entities/entities/"
+local effectspath = foldername.."/entities/effects/"
+local weaponspath = foldername.."/entities/weapons/"
+
+-- ENTITIES
+local files, folders = file.Find(entitiespath.."*", "LUA")
+
+for _, filename in pairs(files) do
+ ENT = {}
+ ENT.Folder = entitiespath
+ ENT.FolderName = filename
+
+ include(entitiespath..filename)
+
+ scripted_ents.Register(ENT, string.StripExtension(filename))
+end
+
+for _, foldername in pairs(folders) do
+ ENT = {}
+ ENT.Folder = entitiespath..foldername
+ ENT.FolderName = foldername
+
+ if SERVER then
+ if file.Exists(entitiespath..foldername.."/init.lua", "LUA") then
+ include(entitiespath..foldername.."/init.lua")
+ elseif file.Exists(entitiespath..foldername.."/shared.lua", "LUA") then
+ include(entitiespath..foldername.."/shared.lua")
+ end
+ end
+
+ if CLIENT then
+ if file.Exists(entitiespath..foldername.."/cl_init.lua", "LUA") then
+ include(entitiespath..foldername.."/cl_init.lua")
+ elseif file.Exists(entitiespath..foldername.."/shared.lua", "LUA") then
+ include(entitiespath..foldername.."/shared.lua")
+ end
+ end
+
+ scripted_ents.Register(ENT, foldername)
+end
+
+-- EFFECTS
+local files, folders = file.Find(effectspath.."*", "LUA")
+
+for _, filename in pairs(files) do
+ if SERVER then
+ AddCSLuaFile(effectspath..filename)
+ end
+ if CLIENT then
+ EFFECT = {}
+ EFFECT.Folder = effectspath
+ EFFECT.FolderName = filename
+
+ include(effectspath..filename)
+
+ effects.Register(EFFECT, string.StripExtension(filename))
+ end
+end
+
+for _, foldername in pairs(folders) do
+ if SERVER and file.Exists(effectspath..foldername.."/init.lua", "LUA") then
+ AddCSLuaFile(effectspath..foldername.."/init.lua")
+ end
+
+ if CLIENT and file.Exists(effectspath..foldername.."/init.lua", "LUA") then
+ EFFECT = {}
+ EFFECT.Folder = effectspath..foldername
+ EFFECT.FolderName = foldername
+
+ include(effectspath..foldername.."/init.lua")
+
+ effects.Register(EFFECT, foldername)
+ end
+end
+
+-- WEAPONS
+local files, folders = file.Find(weaponspath.."*", "LUA")
+
+for _, filename in pairs(files) do
+ SWEP = {}
+ SWEP.Folder = weaponspath
+ SWEP.FolderName = filename
+ SWEP.Base = "weapon_base"
+
+ SWEP.Primary = {}
+ SWEP.Secondary = {}
+ --[[SWEP.Primary.ClipSize = 8
+ SWEP.Primary.DefaultClip = 32
+ SWEP.Primary.Automatic = false
+ SWEP.Primary.Ammo = "Pistol"
+ SWEP.Secondary.ClipSize = 8
+ SWEP.Secondary.DefaultClip = 32
+ SWEP.Secondary.Automatic = false
+ SWEP.Secondary.Ammo = "Pistol"]]
+
+ include(weaponspath..filename)
+
+ weapons.Register(SWEP, string.StripExtension(filename))
+end
+
+for _, foldername in pairs(folders) do
+ SWEP = {}
+ SWEP.Folder = weaponspath..foldername
+ SWEP.FolderName = foldername
+ SWEP.Base = "weapon_base"
+
+ SWEP.Primary = {}
+ SWEP.Secondary = {}
+
+ if SERVER then
+ if file.Exists(weaponspath..foldername.."/init.lua", "LUA") then
+ include(weaponspath..foldername.."/init.lua")
+ elseif file.Exists(weaponspath..foldername.."/shared.lua", "LUA") then
+ include(weaponspath..foldername.."/shared.lua")
+ end
+ end
+
+ if CLIENT then
+ if file.Exists(weaponspath..foldername.."/cl_init.lua", "LUA") then
+ include(weaponspath..foldername.."/cl_init.lua")
+ elseif file.Exists(weaponspath..foldername.."/shared.lua", "LUA") then
+ include(weaponspath..foldername.."/shared.lua")
+ end
+ end
+
+ weapons.Register(SWEP, foldername)
+end
+
+ENT = nil
+EFFECT = nil
+SWEP = nil
+
+end)
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/bloated_zombie.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/bloated_zombie.lua
new file mode 100644
index 0000000..b254e93
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/bloated_zombie.lua
@@ -0,0 +1,190 @@
+CLASS.Name = "Bloated Zombie"
+CLASS.TranslationName = "class_bloated_zombie"
+CLASS.Description = "description_bloated_zombie"
+CLASS.Help = "controls_bloated_zombie"
+
+CLASS.Wave = 3 / 6
+
+CLASS.Health = 325
+CLASS.Speed = 120
+CLASS.JumpPower = 150
+CLASS.Mass = DEFAULT_MASS * 2
+
+CLASS.CanTaunt = true
+
+CLASS.Points = 6
+
+CLASS.SWEP = "weapon_zs_bloatedzombie"
+
+CLASS.Model = Model("models/player/fatty/fatty.mdl")
+
+CLASS.DeathSounds = {"npc/ichthyosaur/water_growl5.wav"}
+
+CLASS.VoicePitch = 0.6
+
+CLASS.CanFeignDeath = true
+
+sound.Add({
+ name = "fatty.footstep",
+ channel = CHAN_BODY,
+ volume = 0.8,
+ soundlevel = 65,
+ pitchstart = 75,
+ pitchend = 75,
+ sound = {"npc/zombie/foot1.wav", "npc/zombie/foot2.wav", "npc/zombie/foot3.wav"}
+})
+
+sound.Add({
+ name = "fatty.footscuff",
+ channel = CHAN_BODY,
+ volume = 0.8,
+ soundlevel = 65,
+ pitchstart = 75,
+ pitchend = 75,
+ sound = {"npc/zombie/foot_slide1.wav", "npc/zombie/foot_slide2.wav", "npc/zombie/foot_slide3.wav"}
+})
+
+local DIR_BACK = DIR_BACK
+local ACT_HL2MP_ZOMBIE_SLUMP_RISE = ACT_HL2MP_ZOMBIE_SLUMP_RISE
+local ACT_HL2MP_SWIM_PISTOL = ACT_HL2MP_SWIM_PISTOL
+local ACT_HL2MP_IDLE_CROUCH_ZOMBIE = ACT_HL2MP_IDLE_CROUCH_ZOMBIE
+local ACT_HL2MP_WALK_CROUCH_ZOMBIE_01 = ACT_HL2MP_WALK_CROUCH_ZOMBIE_01
+local ACT_HL2MP_RUN_ZOMBIE = ACT_HL2MP_RUN_ZOMBIE
+
+function CLASS:PlayPainSound(pl)
+ pl:EmitSound("npc/zombie_poison/pz_idle"..math.random(2, 3)..".wav", 72, math.Rand(75, 85))
+
+ return true
+end
+
+local mathrandom = math.random
+local StepSounds = {
+ "npc/zombie/foot1.wav",
+ "npc/zombie/foot2.wav",
+ "npc/zombie/foot3.wav"
+}
+local ScuffSounds = {
+ "npc/zombie/foot_slide1.wav",
+ "npc/zombie/foot_slide2.wav",
+ "npc/zombie/foot_slide3.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if mathrandom() < 0.15 then
+ pl:EmitSound(ScuffSounds[mathrandom(#ScuffSounds)], 70, 75)
+ else
+ pl:EmitSound(StepSounds[mathrandom(#StepSounds)], 70, 75)
+ end
+
+ return true
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ if feign:GetDirection() == DIR_BACK then
+ pl.CalcSeqOverride = pl:LookupSequence("zombie_slump_rise_02_fast")
+ else
+ pl.CalcIdeal = ACT_HL2MP_ZOMBIE_SLUMP_RISE
+ end
+
+ return true
+ end
+
+ if pl:WaterLevel() >= 3 then
+ pl.CalcIdeal = ACT_HL2MP_SWIM_PISTOL
+ elseif pl:Crouching() then
+ if velocity:Length2D() <= 0.5 then
+ pl.CalcIdeal = ACT_HL2MP_IDLE_CROUCH_ZOMBIE
+ else
+ pl.CalcIdeal = ACT_HL2MP_WALK_CROUCH_ZOMBIE_01 - 1 + math.ceil((CurTime() / 4 + pl:EntIndex()) % 3)
+ end
+ else
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ if feign:GetState() == 1 then
+ pl:SetCycle(1 - math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ else
+ pl:SetCycle(math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ end
+ pl:SetPlaybackRate(0)
+ return true
+ end
+
+ local len2d = velocity:Length2D()
+ if len2d > 0.5 then
+ pl:SetPlaybackRate(math.min(len2d / maxseqgroundspeed, 3))
+ else
+ pl:SetPlaybackRate(1)
+ end
+
+ return true
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_GMOD_GESTURE_RANGE_ZOMBIE, true)
+ return ACT_INVALID
+ end
+end
+
+function CLASS:DoesntGiveFear(pl)
+ return pl.FeignDeath and pl.FeignDeath:IsValid()
+end
+
+if SERVER then
+ function CLASS:AltUse(pl)
+ pl:StartFeignDeath()
+ end
+
+ local function Bomb(pl, pos, dir)
+ if not IsValid(pl) then return end
+
+ dir:RotateAroundAxis(dir:Right(), 30)
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(pos)
+ effectdata:SetNormal(dir:Forward())
+ util.Effect("fatexplosion", effectdata, true)
+
+ for i=1, 6 do
+ local ang = Angle()
+ ang:Set(dir)
+ ang:RotateAroundAxis(ang:Up(), math.Rand(-30, 30))
+ ang:RotateAroundAxis(ang:Right(), math.Rand(-30, 30))
+
+ local heading = ang:Forward()
+
+ local ent = ents.CreateLimited("projectile_poisonflesh")
+ if ent:IsValid() then
+ ent:SetPos(pos)
+ ent:SetOwner(pl)
+ ent:Spawn()
+ ent:SetTeamID(TEAM_UNDEAD)
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:SetVelocityInstantaneous(heading * math.Rand(120, 250))
+ end
+ end
+ end
+ end
+
+ function CLASS:OnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo, assister)
+ if attacker ~= pl and not suicide then
+ local pos = pl:LocalToWorld(pl:OBBCenter())
+ local ang = pl:SyncAngles()
+ timer.Simple(0, function() Bomb(pl, pos, ang) end)
+ end
+ end
+end
+
+if CLIENT then
+ CLASS.Icon = "zombiesurvival/killicons/zombie"
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_bonemesh.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_bonemesh.lua
new file mode 100644
index 0000000..89b9981
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_bonemesh.lua
@@ -0,0 +1,111 @@
+CLASS.Name = "Bonemesh"
+CLASS.TranslationName = "class_bonemesh"
+CLASS.Description = "description_bonemesh"
+CLASS.Help = "controls_bonemesh"
+
+CLASS.Wave = 0
+CLASS.Threshold = 0
+CLASS.Unlocked = true
+CLASS.Hidden = true
+CLASS.Boss = true
+
+CLASS.Health = 1000
+CLASS.Speed = 195
+
+CLASS.FearPerInstance = 1
+
+CLASS.Points = 30
+
+CLASS.SWEP = "weapon_zs_bonemesh"
+
+CLASS.Model = Model("models/player/zombie_fast.mdl")
+
+CLASS.VoicePitch = 0.8
+
+CLASS.Hull = {Vector(-16, -16, 0), Vector(16, 16, 58)}
+CLASS.HullDuck = {Vector(-16, -16, 0), Vector(16, 16, 32)}
+CLASS.ViewOffset = Vector(0, 0, 50)
+CLASS.ViewOffsetDucked = Vector(0, 0, 24)
+
+CLASS.PainSounds = {"npc/zombie/zombie_pain1.wav", "npc/zombie/zombie_pain2.wav", "npc/zombie/zombie_pain3.wav", "npc/zombie/zombie_pain4.wav", "npc/zombie/zombie_pain5.wav", "npc/zombie/zombie_pain6.wav"}
+CLASS.DeathSounds = {"npc/zombie/zombie_die1.wav", "npc/zombie/zombie_die2.wav", "npc/zombie/zombie_die3.wav"}
+
+local STEPSOUNDTIME_NORMAL = STEPSOUNDTIME_NORMAL
+local STEPSOUNDTIME_WATER_FOOT = STEPSOUNDTIME_WATER_FOOT
+local STEPSOUNDTIME_ON_LADDER = STEPSOUNDTIME_ON_LADDER
+local STEPSOUNDTIME_WATER_KNEE = STEPSOUNDTIME_WATER_KNEE
+local ACT_ZOMBIE_LEAPING = ACT_ZOMBIE_LEAPING
+local ACT_HL2MP_RUN_ZOMBIE_FAST = ACT_HL2MP_RUN_ZOMBIE_FAST
+
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if iFoot == 0 then
+ pl:EmitSound("npc/antlion_guard/foot_light1.wav", 70, math.random(115, 120))
+ else
+ pl:EmitSound("npc/antlion_guard/foot_light2.wav", 70, math.random(115, 120))
+ end
+
+ return true
+end
+
+function CLASS:PlayerStepSoundTime(pl, iType, bWalking)
+ if iType == STEPSOUNDTIME_NORMAL or iType == STEPSOUNDTIME_WATER_FOOT then
+ return 450 - pl:GetVelocity():Length()
+ elseif iType == STEPSOUNDTIME_ON_LADDER then
+ return 400
+ elseif iType == STEPSOUNDTIME_WATER_KNEE then
+ return 550
+ end
+
+ return 250
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ if not pl:OnGround() or pl:WaterLevel() >= 3 then
+ pl.CalcIdeal = ACT_ZOMBIE_LEAPING
+ else
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE_FAST
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ if not pl:OnGround() or pl:WaterLevel() >= 3 then
+ pl:SetPlaybackRate(1)
+
+ if pl:GetCycle() >= 1 then
+ pl:SetCycle(pl:GetCycle() - 1)
+ end
+
+ return true
+ end
+end
+
+function CLASS:Move(pl, mv)
+ if mv:GetForwardSpeed() <= 0 then
+ mv:SetMaxSpeed(mv:GetMaxSpeed() * 0.33)
+ mv:SetMaxClientSpeed(mv:GetMaxClientSpeed() * 0.33)
+ end
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_GMOD_GESTURE_RANGE_ZOMBIE_SPECIAL, true)
+ return ACT_INVALID
+ end
+end
+
+if SERVER then
+ function CLASS:OnSpawned(pl)
+ local status = pl:GiveStatus("overridemodel")
+ if status and status:IsValid() then
+ status:SetModel("models/Zombie/Poison.mdl")
+ end
+
+ pl:CreateAmbience("bonemeshambience")
+ end
+end
+
+if not CLIENT then return end
+
+--CLASS.Icon = "zombiesurvival/killicons/bonemesh"
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_butcher.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_butcher.lua
new file mode 100644
index 0000000..bd4cae2
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_butcher.lua
@@ -0,0 +1,148 @@
+CLASS.Name = "The Butcher"
+CLASS.TranslationName = "class_butcher"
+CLASS.Description = "description_butcher"
+CLASS.Help = "controls_butcher"
+
+CLASS.Wave = 0
+CLASS.Threshold = 0
+CLASS.Unlocked = true
+CLASS.Hidden = true
+CLASS.Boss = true
+
+CLASS.Health = 750
+CLASS.Speed = 190
+
+CLASS.CanTaunt = true
+
+CLASS.FearPerInstance = 1
+
+CLASS.Points = 30
+
+CLASS.SWEP = "weapon_zs_butcherknifez"
+
+CLASS.Model = Model("models/player/corpse1.mdl")
+
+CLASS.VoicePitch = 0.65
+
+CLASS.PainSounds = {"npc/zombie/zombie_pain1.wav", "npc/zombie/zombie_pain2.wav", "npc/zombie/zombie_pain3.wav", "npc/zombie/zombie_pain4.wav", "npc/zombie/zombie_pain5.wav", "npc/zombie/zombie_pain6.wav"}
+CLASS.DeathSounds = {"npc/zombie/zombie_die1.wav", "npc/zombie/zombie_die2.wav", "npc/zombie/zombie_die3.wav"}
+
+local ACT_HL2MP_SWIM_MELEE = ACT_HL2MP_SWIM_MELEE
+local ACT_HL2MP_IDLE_CROUCH_MELEE = ACT_HL2MP_IDLE_CROUCH_MELEE
+local ACT_HL2MP_WALK_CROUCH_MELEE = ACT_HL2MP_WALK_CROUCH_MELEE
+local ACT_HL2MP_IDLE_MELEE = ACT_HL2MP_IDLE_MELEE
+local ACT_HL2MP_RUN_ZOMBIE = ACT_HL2MP_RUN_ZOMBIE
+local ACT_HL2MP_RUN_MELEE = ACT_HL2MP_RUN_MELEE
+local ACT_HL2MP_RUN_ZOMBIE = ACT_HL2MP_RUN_ZOMBIE
+
+local mathrandom = math.random
+local StepLeftSounds = {
+ "npc/fast_zombie/foot1.wav",
+ "npc/fast_zombie/foot2.wav"
+}
+local StepRightSounds = {
+ "npc/fast_zombie/foot3.wav",
+ "npc/fast_zombie/foot4.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if iFoot == 0 then
+ pl:EmitSound(StepLeftSounds[mathrandom(#StepLeftSounds)], 70)
+ else
+ pl:EmitSound(StepRightSounds[mathrandom(#StepRightSounds)], 70)
+ end
+
+ return true
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ if pl:WaterLevel() >= 3 then
+ pl.CalcIdeal = ACT_HL2MP_SWIM_MELEE
+ return true
+ end
+
+ local swinging = false
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and CurTime() < wep:GetNextPrimaryFire() then
+ swinging = true
+ end
+
+ if pl:Crouching() then
+ if velocity:Length2D() <= 0.5 then
+ pl.CalcIdeal = ACT_HL2MP_IDLE_CROUCH_MELEE
+ else
+ pl.CalcIdeal = ACT_HL2MP_WALK_CROUCH_MELEE
+ end
+ elseif velocity:Length2D() <= 0.5 then
+ if swinging then
+ pl.CalcIdeal = ACT_HL2MP_IDLE_MELEE
+ else
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE
+ end
+ elseif swinging then
+ pl.CalcIdeal = ACT_HL2MP_RUN_MELEE
+ else
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local len2d = velocity:Length2D()
+ if len2d > 0.5 then
+ pl:SetPlaybackRate(math.min(len2d / maxseqgroundspeed, 3))
+ else
+ pl:SetPlaybackRate(1)
+ end
+
+ return true
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE, true)
+ return ACT_INVALID
+ end
+end
+
+if SERVER then
+ function CLASS:OnSpawned(pl)
+ pl:CreateAmbience("butcherambience")
+ end
+
+ local function MakeButcherKnife(pos)
+ local ent = ents.Create("prop_weapon")
+ if ent:IsValid() then
+ ent:SetPos(pos)
+ ent:SetAngles(AngleRand())
+ ent:SetWeaponType("weapon_zs_butcherknife")
+ ent:Spawn()
+
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:SetVelocityInstantaneous(VectorRand():GetNormalized() * math.Rand(24, 100))
+ phys:AddAngleVelocity(VectorRand() * 200)
+ end
+ end
+ end
+
+ function CLASS:OnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo, assister)
+ local pos = pl:LocalToWorld(pl:OBBCenter())
+ timer.Simple(0, function()
+ MakeButcherKnife(pos)
+ end)
+ end
+end
+
+if not CLIENT then return end
+
+--CLASS.Icon = "zombiesurvival/killicons/butcher"
+
+function CLASS:PrePlayerDraw(pl)
+ render.SetColorModulation(1, 0.5, 0.5)
+end
+
+function CLASS:PostPlayerDraw(pl)
+ render.SetColorModulation(1, 1, 1)
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_giga_gore_child.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_giga_gore_child.lua
new file mode 100644
index 0000000..6bf5773
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_giga_gore_child.lua
@@ -0,0 +1,193 @@
+CLASS.Name = "Giga Gore Child"
+CLASS.TranslationName = "class_giga_gore_child"
+CLASS.Description = "description_giga_gore_child"
+CLASS.Help = "controls_giga_gore_child"
+
+CLASS.Wave = 0
+CLASS.Threshold = 0
+CLASS.Unlocked = true
+CLASS.Hidden = true
+CLASS.Boss = true
+
+CLASS.Health = 2000
+CLASS.Speed = 170
+
+CLASS.Points = 30
+
+CLASS.CanTaunt = true
+
+CLASS.FearPerInstance = 1
+
+CLASS.SWEP = "weapon_zs_gigagorechild"
+
+CLASS.Model = Model("models/vinrax/player/doll_player.mdl")
+
+CLASS.VoicePitch = 1
+
+CLASS.ModelScale = 1.6
+
+CLASS.CanFeignDeath = true
+
+CLASS.Mass = 500
+CLASS.ViewOffset = DEFAULT_VIEW_OFFSET * CLASS.ModelScale
+CLASS.ViewOffsetDucked = DEFAULT_VIEW_OFFSET_DUCKED * CLASS.ModelScale
+CLASS.StepSize = 25
+CLASS.Hull = {Vector(-16, -16, 0) * CLASS.ModelScale, Vector(16, 16, 64) * CLASS.ModelScale}
+CLASS.HullDuck = {Vector(-16, -16, 0) * CLASS.ModelScale, Vector(16, 16, 32) * CLASS.ModelScale}
+
+CLASS.Hull[1].x = -16
+CLASS.Hull[2].x = 16
+CLASS.Hull[1].y = -16
+CLASS.Hull[2].y = 16
+CLASS.HullDuck[1].x = -16
+CLASS.HullDuck[2].x = 16
+CLASS.HullDuck[1].y = -16
+CLASS.HullDuck[2].y = 16
+
+local DIR_BACK = DIR_BACK
+local ACT_HL2MP_ZOMBIE_SLUMP_RISE = ACT_HL2MP_ZOMBIE_SLUMP_RISE
+local ACT_HL2MP_SWIM_PISTOL = ACT_HL2MP_SWIM_PISTOL
+local ACT_HL2MP_IDLE_CROUCH_ZOMBIE = ACT_HL2MP_IDLE_CROUCH_ZOMBIE
+local ACT_HL2MP_WALK_CROUCH_ZOMBIE_01 = ACT_HL2MP_WALK_CROUCH_ZOMBIE_01
+local ACT_HL2MP_RUN_ZOMBIE = ACT_HL2MP_RUN_ZOMBIE
+
+local mathrandom = math.random
+local StepLeftSounds = {
+ "npc/zombie/foot1.wav",
+ "npc/zombie/foot2.wav"
+}
+local StepRightSounds = {
+ "npc/zombie/foot2.wav",
+ "npc/zombie/foot3.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if iFoot == 0 then
+ pl:EmitSound(StepLeftSounds[mathrandom(#StepLeftSounds)], 77, 50)
+ pl:EmitSound("physics/concrete/concrete_break2.wav", 77, 70)
+ else
+ pl:EmitSound(StepRightSounds[mathrandom(#StepRightSounds)], 77, 50)
+ pl:EmitSound("physics/concrete/concrete_break3.wav", 77, 70)
+ end
+
+ if EyePos():Distance(vFootPos) <= 300 then
+ util.ScreenShake(vFootPos, 5, 5, 1, 300)
+ end
+
+ return true
+end
+
+function CLASS:PlayDeathSound(pl)
+ local pitch = math.random(60, 70)
+ for i=1, 2 do
+ pl:EmitSound("ambient/creatures/town_child_scream1.wav", 75, pitch)
+ end
+
+ return true
+end
+
+function CLASS:PlayPainSound(pl)
+ pl:EmitSound("ambient/voices/citizen_beaten"..math.random(5)..".wav", 70, math.random(50, 60))
+ pl.NextPainSound = CurTime() + 1.25
+
+ return true
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ if feign:GetDirection() == DIR_BACK then
+ pl.CalcSeqOverride = pl:LookupSequence("zombie_slump_rise_02_fast")
+ else
+ pl.CalcIdeal = ACT_HL2MP_ZOMBIE_SLUMP_RISE
+ end
+ return true
+ end
+
+ if pl:WaterLevel() >= 3 then
+ pl.CalcIdeal = ACT_HL2MP_SWIM_PISTOL
+ elseif pl:Crouching() then
+ if velocity:Length2D() <= 0.5 then
+ pl.CalcIdeal = ACT_HL2MP_IDLE_CROUCH_ZOMBIE
+ else
+ pl.CalcIdeal = ACT_HL2MP_WALK_CROUCH_ZOMBIE_01 - 1 + math.ceil((CurTime() / 4 + pl:EntIndex()) % 3)
+ end
+ else
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE
+ end
+
+ return true
+end
+
+function CLASS:Move(pl, move)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.IsSwinging and wep:IsSwinging() then
+ move:SetMaxSpeed(move:GetMaxSpeed() * 0.25)
+ move:SetMaxClientSpeed(move:GetMaxClientSpeed() * 0.25)
+
+ return true
+ end
+end
+
+function CLASS:PlayerStepSoundTime(pl, iType, bWalking)
+ return GAMEMODE.BaseClass.PlayerStepSoundTime(GAMEMODE.BaseClass, pl, iType, bWalking) * 1.8
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ if feign:GetState() == 1 then
+ pl:SetCycle(1 - math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ else
+ pl:SetCycle(math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ end
+ pl:SetPlaybackRate(0)
+ return true
+ end
+
+ local len2d = velocity:Length2D()
+ if len2d > 0.5 then
+ pl:SetPlaybackRate(math.min(len2d / maxseqgroundspeed, 3))
+ else
+ pl:SetPlaybackRate(1)
+ end
+
+ pl:SetPlaybackRate(pl:GetPlaybackRate() * 0.5)
+
+ return true
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_GMOD_GESTURE_RANGE_ZOMBIE, true)
+ return ACT_INVALID
+ elseif event == PLAYERANIMEVENT_RELOAD then
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_GMOD_GESTURE_ITEM_THROW, true)
+ return ACT_INVALID
+ end
+end
+
+function CLASS:DoesntGiveFear(pl)
+ return pl.FeignDeath and pl.FeignDeath:IsValid()
+end
+
+if SERVER then
+ function CLASS:OnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo)
+ pl:FakeDeath(pl:LookupSequence("death_0"..math.random(4)), self.ModelScale)
+
+ return true
+ end
+
+ function CLASS:PostOnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo)
+ pl:SetZombieClass(GAMEMODE.DefaultZombieClass)
+ end
+
+ function CLASS:AltUse(pl)
+ pl:StartFeignDeath()
+ end
+end
+
+if not CLIENT then return end
+
+function CLASS:ShouldDrawLocalPlayer()
+ return true
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_nightmare.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_nightmare.lua
new file mode 100644
index 0000000..8287731
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_nightmare.lua
@@ -0,0 +1,131 @@
+CLASS.Name = "Nightmare"
+CLASS.TranslationName = "class_nightmare"
+CLASS.Description = "description_nightmare"
+CLASS.Help = "controls_nightmare"
+
+CLASS.Wave = 0
+CLASS.Threshold = 0
+CLASS.Unlocked = true
+CLASS.Hidden = true
+CLASS.Boss = true
+
+CLASS.Health = 2000
+CLASS.Speed = 140
+
+CLASS.CanTaunt = true
+
+CLASS.FearPerInstance = 1
+
+CLASS.Points = 30
+
+CLASS.SWEP = "weapon_zs_nightmare"
+
+CLASS.Model = Model("models/player/skeleton.mdl")
+
+CLASS.VoicePitch = 0.65
+
+CLASS.PainSounds = {"npc/zombie/zombie_pain1.wav", "npc/zombie/zombie_pain2.wav", "npc/zombie/zombie_pain3.wav", "npc/zombie/zombie_pain4.wav", "npc/zombie/zombie_pain5.wav", "npc/zombie/zombie_pain6.wav"}
+CLASS.DeathSounds = {"npc/zombie/zombie_die1.wav", "npc/zombie/zombie_die2.wav", "npc/zombie/zombie_die3.wav"}
+
+local ACT_HL2MP_SWIM_PISTOL = ACT_HL2MP_SWIM_PISTOL
+local ACT_HL2MP_IDLE_CROUCH_ZOMBIE = ACT_HL2MP_IDLE_CROUCH_ZOMBIE
+local ACT_HL2MP_WALK_CROUCH_ZOMBIE_01 = ACT_HL2MP_WALK_CROUCH_ZOMBIE_01
+local ACT_HL2MP_RUN_ZOMBIE = ACT_HL2MP_RUN_ZOMBIE
+
+local mathrandom = math.random
+local StepSounds = {
+ "npc/zombie/foot1.wav",
+ "npc/zombie/foot2.wav",
+ "npc/zombie/foot3.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ pl:EmitSound(StepSounds[mathrandom(#StepSounds)], 70)
+
+ return true
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ if pl:WaterLevel() >= 3 then
+ pl.CalcIdeal = ACT_HL2MP_SWIM_PISTOL
+ elseif pl:Crouching() then
+ if velocity:Length2D() <= 0.5 then
+ pl.CalcIdeal = ACT_HL2MP_IDLE_CROUCH_ZOMBIE
+ else
+ pl.CalcIdeal = ACT_HL2MP_WALK_CROUCH_ZOMBIE_01 - 1 + math.ceil((CurTime() / 4 + pl:EntIndex()) % 3)
+ end
+ else
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local len2d = velocity:Length2D()
+ if len2d > 0.5 then
+ pl:SetPlaybackRate(math.min(len2d / maxseqgroundspeed, 3))
+ else
+ pl:SetPlaybackRate(1)
+ end
+
+ return true
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_GMOD_GESTURE_RANGE_ZOMBIE, true)
+ return ACT_INVALID
+ end
+end
+
+if SERVER then
+ function CLASS:OnSpawned(pl)
+ pl:CreateAmbience("nightmareambience")
+ end
+end
+
+if not CLIENT then return end
+
+CLASS.Icon = "zombiesurvival/killicons/nightmare"
+
+local function CreateBoneOffsets(pl)
+ pl.m_NightmareBoneOffsetsNext = CurTime() + math.Rand(0.02, 0.1)
+
+ local offsets = {}
+ local angs = {}
+ for i=1, pl:GetBoneCount() - 1 do
+ if math.random(3) == 3 then
+ offsets[i] = VectorRand():GetNormalized() * math.Rand(0.5, 3)
+ end
+ if math.random(5) == 5 then
+ angs[i] = Angle(math.Rand(-5, 5), math.Rand(-15, 15), math.Rand(-5, 5))
+ end
+ end
+ pl.m_NightmareBoneOffsets = offsets
+ pl.m_NightmareBoneAngles = angs
+end
+
+function CLASS:BuildBonePositions(pl)
+ if not pl.m_NightmareBoneOffsets or CurTime() >= pl.m_NightmareBoneOffsetsNext then
+ CreateBoneOffsets(pl)
+ end
+
+ local offsets = pl.m_NightmareBoneOffsets
+ local angs = pl.m_NightmareBoneAngles
+ for i=1, pl:GetBoneCount() - 1 do
+ if offsets[i] then
+ pl:ManipulateBonePosition(i, offsets[i])
+ end
+ if angs[i] then
+ pl:ManipulateBoneAngles(i, angs[i])
+ end
+ end
+end
+
+function CLASS:PrePlayerDraw(pl)
+ render.SetColorModulation(0.1, 0.1, 0.1)
+end
+
+function CLASS:PostPlayerDraw(pl)
+ render.SetColorModulation(1, 1, 1)
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_pukepus.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_pukepus.lua
new file mode 100644
index 0000000..4363f67
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_pukepus.lua
@@ -0,0 +1,147 @@
+CLASS.Name = "Puke Pus"
+CLASS.TranslationName = "class_pukepus"
+CLASS.Description = "description_pukepus"
+CLASS.Help = "controls_pukepus"
+
+CLASS.Wave = 0
+CLASS.Threshold = 0
+CLASS.Unlocked = true
+CLASS.Hidden = true
+CLASS.Boss = true
+
+CLASS.FearPerInstance = 1
+
+CLASS.Health = 2750
+CLASS.SWEP = "weapon_zs_pukepus"
+
+CLASS.Model = Model("models/Zombie/Poison.mdl")
+
+CLASS.Speed = 120
+CLASS.Points = 30
+
+CLASS.PainSounds = {"NPC_PoisonZombie.Pain"}
+CLASS.DeathSounds = {Sound("npc/zombie_poison/pz_call1.wav")}
+
+CLASS.VoicePitch = 0.5
+
+CLASS.ModelScale = 1.5
+CLASS.Mass = 200
+CLASS.ViewOffset = Vector(0, 0, 75)
+CLASS.ViewOffsetDucked = Vector(0, 0, 48)
+CLASS.StepSize = 25
+--[[CLASS.Hull = {Vector(-22, -22, 0), Vector(22, 22, 96)}
+CLASS.HullDuck = {Vector(-22, -22, 0), Vector(22, 22, 58)}]]
+
+CLASS.JumpPower = 225
+
+local ACT_IDLE = ACT_IDLE
+local STEPSOUNDTIME_NORMAL = STEPSOUNDTIME_NORMAL
+local STEPSOUNDTIME_WATER_FOOT = STEPSOUNDTIME_WATER_FOOT
+local STEPSOUNDTIME_ON_LADDER = STEPSOUNDTIME_ON_LADDER
+local STEPSOUNDTIME_WATER_KNEE = STEPSOUNDTIME_WATER_KNEE
+
+function CLASS:CalcMainActivity(pl, velocity)
+ if velocity:Length2D() <= 0.5 then
+ pl.CalcIdeal = ACT_IDLE
+ else
+ pl.CalcSeqOverride = 2
+ end
+
+ return true
+end
+
+local mathrandom = math.random
+local StepSounds = {
+ "npc/zombie_poison/pz_left_foot1.wav"
+}
+local ScuffSounds = {
+ "npc/zombie_poison/pz_right_foot1.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if iFoot == 0 and mathrandom() < 0.333 then
+ pl:EmitSound(ScuffSounds[mathrandom(#ScuffSounds)], 80, 90)
+ else
+ pl:EmitSound(StepSounds[mathrandom(#StepSounds)], 80, 90)
+ end
+
+ return true
+end
+
+function CLASS:PlayerStepSoundTime(pl, iType, bWalking)
+ if iType == STEPSOUNDTIME_NORMAL or iType == STEPSOUNDTIME_WATER_FOOT then
+ return (365 - pl:GetVelocity():Length()) * 1.5
+ elseif iType == STEPSOUNDTIME_ON_LADDER then
+ return 450
+ elseif iType == STEPSOUNDTIME_WATER_KNEE then
+ return 600
+ end
+
+ return 200
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ pl:FixModelAngles(velocity)
+
+ local len2d = velocity:Length2D()
+ if len2d > 0.5 then
+ pl:SetPlaybackRate(math.min(len2d / maxseqgroundspeed * 0.5, 3))
+ else
+ pl:SetPlaybackRate(0.5)
+ end
+
+ return true
+end
+
+if SERVER then
+ function CLASS:OnSpawned(pl)
+ pl:CreateAmbience("pukepusambience")
+ end
+end
+
+local BonesToZero = {
+ "ValveBiped.Bip01_L_UpperArm",
+ "ValveBiped.Bip01_L_Forearm",
+ "ValveBiped.Bip01_L_Hand",
+ "ValveBiped.Bip01_L_Finger1",
+ "ValveBiped.Bip01_L_Finger11",
+ "ValveBiped.Bip01_L_Finger12",
+ "ValveBiped.Bip01_L_Finger2",
+ "ValveBiped.Bip01_L_Finger21",
+ "ValveBiped.Bip01_L_Finger22",
+ "ValveBiped.Bip01_L_Finger3",
+ "ValveBiped.Bip01_L_Finger31",
+ "ValveBiped.Bip01_L_Finger32",
+ "ValveBiped.Bip01_R_UpperArm",
+ "ValveBiped.Bip01_R_Forearm",
+ "ValveBiped.Bip01_R_Hand",
+ "ValveBiped.Bip01_R_Finger1",
+ "ValveBiped.Bip01_R_Finger11",
+ "ValveBiped.Bip01_R_Finger12",
+ "ValveBiped.Bip01_R_Finger2",
+ "ValveBiped.Bip01_R_Finger21",
+ "ValveBiped.Bip01_R_Finger22",
+ "ValveBiped.Bip01_R_Finger3",
+ "ValveBiped.Bip01_R_Finger31",
+ "ValveBiped.Bip01_R_Finger32"
+}
+function CLASS:BuildBonePositions(pl)
+ for _, bone in pairs(BonesToZero) do
+ local boneid = pl:LookupBone(bone)
+ if boneid and boneid > 0 then
+ pl:ManipulateBoneScale(boneid, vector_tiny)
+ end
+ end
+end
+
+if not CLIENT then return end
+
+CLASS.Icon = "zombiesurvival/killicons/pukepus"
+
+local matSkin = Material("Models/Barnacle/barnacle_sheet")
+function CLASS:PrePlayerDraw(pl)
+ render.ModelMaterialOverride(matSkin)
+end
+
+function CLASS:PostPlayerDraw(pl)
+ render.ModelMaterialOverride()
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_shade.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_shade.lua
new file mode 100644
index 0000000..97c03b0
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_shade.lua
@@ -0,0 +1,189 @@
+CLASS.Name = "Shade"
+CLASS.TranslationName = "class_shade"
+CLASS.Description = "description_shade"
+CLASS.Help = "controls_shade"
+
+CLASS.Wave = 0
+CLASS.Threshold = 0
+CLASS.Unlocked = true
+CLASS.Hidden = true
+CLASS.Boss = true
+
+CLASS.NoGibs = true
+CLASS.NoFallDamage = true
+CLASS.NoFallSlowdown = true
+
+CLASS.NoShadow = true
+
+CLASS.Health = 1200
+CLASS.Speed = 125
+
+CLASS.FearPerInstance = 1
+
+CLASS.Points = 30
+
+CLASS.SWEP = "weapon_zs_shade"
+
+CLASS.Model = Model("models/player/zombie_fast.mdl")
+
+CLASS.VoicePitch = 0.8
+
+CLASS.PainSounds = {Sound("npc/barnacle/barnacle_pull1.wav"), Sound("npc/barnacle/barnacle_pull2.wav"), Sound("npc/barnacle/barnacle_pull3.wav"), Sound("npc/barnacle/barnacle_pull4.wav")}
+CLASS.DeathSounds = {Sound("zombiesurvival/wraithdeath1.ogg"), Sound("zombiesurvival/wraithdeath2.ogg"), Sound("zombiesurvival/wraithdeath3.ogg"), Sound("zombiesurvival/wraithdeath4.ogg")}
+
+local ACT_HL2MP_IDLE_MAGIC = ACT_HL2MP_IDLE_MAGIC
+local ACT_HL2MP_RUN_MAGIC = ACT_HL2MP_RUN_MAGIC
+local ACT_HL2MP_RUN_ZOMBIE = ACT_HL2MP_RUN_ZOMBIE
+
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ return true
+end
+
+function CLASS:PlayerStepSoundTime(pl, iType, bWalking)
+ return 1000
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ if pl.ShadeControl and pl.ShadeControl:IsValid() then
+ if velocity:Length2D() <= 0.5 then
+ pl.CalcIdeal = ACT_HL2MP_IDLE_MAGIC
+ else
+ pl.CalcIdeal = ACT_HL2MP_RUN_MAGIC
+ end
+
+ return true
+ end
+
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE
+
+ return true
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2, true)
+ return ACT_INVALID
+ end
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ pl:SetPlaybackRate(1)
+ pl:SetCycle(0.35 + math.abs(math.sin(CurTime() * 1.5)) * 0.3)
+
+ return true
+end
+
+function CLASS:ProcessDamage(pl, dmginfo)
+ local attacker = dmginfo:GetAttacker()
+ if not SHADEFLASHLIGHTDAMAGE and attacker:IsPlayer() and attacker:Team() == TEAM_HUMAN then
+ dmginfo:SetDamage(0)
+ dmginfo:ScaleDamage(0)
+
+ if SERVER then
+ local center = pl:LocalToWorld(pl:OBBCenter())
+ local hitpos = pl:NearestPoint(dmginfo:GetDamagePosition())
+ local effectdata = EffectData()
+ effectdata:SetOrigin(center)
+ effectdata:SetStart(pl:WorldToLocal(hitpos))
+ effectdata:SetAngles((center - hitpos):Angle())
+ effectdata:SetEntity(pl)
+ util.Effect("shadedeflect", effectdata, true, true)
+
+ local status = pl.status_shadeambience
+ if status and status:IsValid() then
+ status:SetLastReflect(CurTime())
+ end
+ end
+ end
+end
+
+function CLASS:OnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo, assister)
+ return true
+end
+
+if SERVER then
+ function CLASS:OnSpawned(pl)
+ pl:CreateAmbience("shadeambience")
+ pl:SetRenderMode(RENDERMODE_TRANSALPHA)
+ end
+
+ function CLASS:SwitchedAway(pl)
+ pl:SetRenderMode(RENDERMODE_NORMAL)
+ end
+end
+
+if not CLIENT then return end
+
+--CLASS.Icon = "zombiesurvival/killicons/shade"
+
+local ToZero = {"ValveBiped.Bip01_L_Thigh", "ValveBiped.Bip01_R_Thigh", "ValveBiped.Bip01_L_Calf", "ValveBiped.Bip01_R_Calf", "ValveBiped.Bip01_L_Foot", "ValveBiped.Bip01_R_Foot"}
+function CLASS:BuildBonePositions(pl)
+ for _, bonename in pairs(ToZero) do
+ local boneid = pl:LookupBone(bonename)
+ if boneid and boneid > 0 then
+ pl:ManipulateBoneScale(boneid, vector_tiny)
+ end
+ end
+end
+
+local nodraw = false
+local matWhite = Material("models/debug/debugwhite")
+local matRefract = Material("models/spawn_effect")
+function CLASS:PreRenderEffects(pl)
+ if render.SupportsVertexShaders_2_0() then
+ local normal = pl:GetUp()
+ render.EnableClipping(true)
+ render.PushCustomClipPlane(normal, normal:Dot(pl:GetPos() + normal * 16))
+ end
+
+ if nodraw then return end
+
+ local red = 0
+ local baseblend = 0.1
+ local status = pl.status_shadeambience
+ if status and status:IsValid() then
+ red = 1 - math.Clamp((CurTime() - status:GetLastDamaged()) * 3, 0, 1) ^ 3
+ baseblend = baseblend + (1 - math.Clamp((CurTime() - status:GetLastReflect()) * 2, 0, 1) ^ 0.5) * 0.75
+ end
+
+ render.SetColorModulation(red, 0.1, 1 - red)
+ render.SetBlend(baseblend + math.abs(math.cos(CurTime())) ^ 2 * 0.1)
+ render.SuppressEngineLighting(true)
+ render.ModelMaterialOverride(matWhite)
+end
+
+function CLASS:PostRenderEffects(pl)
+ if render.SupportsVertexShaders_2_0() then
+ render.PopCustomClipPlane()
+ render.EnableClipping(false)
+ end
+
+ if nodraw then return end
+
+ render.SetColorModulation(1, 1, 1)
+ render.SetBlend(1)
+ render.SuppressEngineLighting(false)
+ render.ModelMaterialOverride()
+
+ if render.SupportsPixelShaders_2_0() then
+ render.UpdateRefractTexture()
+
+ matRefract:SetFloat("$refractamount", 0.01)
+
+ render.ModelMaterialOverride(matRefract)
+ nodraw = true
+ pl:DrawModel()
+ nodraw = false
+ render.ModelMaterialOverride(0)
+ end
+end
+
+function CLASS:PrePlayerDraw(pl)
+ pl:RemoveAllDecals()
+
+ self:PreRenderEffects(pl)
+end
+
+function CLASS:PostPlayerDraw(pl)
+ self:PostRenderEffects(pl)
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_ticklemonster.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_ticklemonster.lua
new file mode 100644
index 0000000..2d8836b
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/boss_ticklemonster.lua
@@ -0,0 +1,150 @@
+CLASS.Name = "The Tickle Monster"
+CLASS.TranslationName = "class_the_tickle_monster"
+CLASS.Description = "description_the_tickle_monster"
+CLASS.Help = "controls_the_tickle_monster"
+
+CLASS.Wave = 0
+CLASS.Threshold = 0
+CLASS.Unlocked = true
+CLASS.Hidden = true
+CLASS.Boss = true
+
+CLASS.Health = 1200
+CLASS.Speed = 120
+
+CLASS.FearPerInstance = 1
+
+CLASS.CanTaunt = true
+
+CLASS.Points = 30
+
+CLASS.SWEP = "weapon_zs_ticklemonster"
+
+CLASS.Model = Model("models/player/zombie_fast.mdl")
+
+CLASS.VoicePitch = 0.8
+
+CLASS.PainSounds = {"npc/zombie/zombie_pain1.wav", "npc/zombie/zombie_pain2.wav", "npc/zombie/zombie_pain3.wav", "npc/zombie/zombie_pain4.wav", "npc/zombie/zombie_pain5.wav", "npc/zombie/zombie_pain6.wav"}
+CLASS.DeathSounds = {"npc/zombie/zombie_die1.wav", "npc/zombie/zombie_die2.wav", "npc/zombie/zombie_die3.wav"}
+
+CLASS.ViewOffset = Vector(0, 0, 80)
+CLASS.ViewOffsetDucked = Vector(0, 0, 50)
+CLASS.Hull = {Vector(-16, -16, 0), Vector(16, 16, 86)}
+CLASS.HullDuck = {Vector(-16, -16, 0), Vector(16, 16, 48)}
+
+local STEPSOUNDTIME_NORMAL = STEPSOUNDTIME_NORMAL
+local STEPSOUNDTIME_WATER_FOOT = STEPSOUNDTIME_WATER_FOOT
+local STEPSOUNDTIME_ON_LADDER = STEPSOUNDTIME_ON_LADDER
+local STEPSOUNDTIME_WATER_KNEE = STEPSOUNDTIME_WATER_KNEE
+local ACT_HL2MP_SWIM_PISTOL = ACT_HL2MP_SWIM_PISTOL
+local ACT_HL2MP_IDLE_CROUCH_ZOMBIE = ACT_HL2MP_IDLE_CROUCH_ZOMBIE
+local ACT_HL2MP_WALK_CROUCH_ZOMBIE_01 = ACT_HL2MP_WALK_CROUCH_ZOMBIE_01
+local ACT_HL2MP_RUN_ZOMBIE = ACT_HL2MP_RUN_ZOMBIE
+
+local mathrandom = math.random
+local StepSounds = {
+ "npc/zombie/foot1.wav",
+ "npc/zombie/foot2.wav",
+ "npc/zombie/foot3.wav"
+}
+local ScuffSounds = {
+ "npc/zombie/foot_slide1.wav",
+ "npc/zombie/foot_slide2.wav",
+ "npc/zombie/foot_slide3.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if mathrandom() < 0.15 then
+ pl:EmitSound(ScuffSounds[mathrandom(#ScuffSounds)], 70)
+ else
+ pl:EmitSound(StepSounds[mathrandom(#StepSounds)], 70)
+ end
+
+ return true
+end
+
+function CLASS:PlayerStepSoundTime(pl, iType, bWalking)
+ if iType == STEPSOUNDTIME_NORMAL or iType == STEPSOUNDTIME_WATER_FOOT then
+ return 625 - pl:GetVelocity():Length()
+ elseif iType == STEPSOUNDTIME_ON_LADDER then
+ return 600
+ elseif iType == STEPSOUNDTIME_WATER_KNEE then
+ return 750
+ end
+
+ return 450
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ if pl:WaterLevel() >= 3 then
+ pl.CalcIdeal = ACT_HL2MP_SWIM_PISTOL
+ elseif pl:Crouching() then
+ if velocity:Length2D() <= 0.5 then
+ pl.CalcIdeal = ACT_HL2MP_IDLE_CROUCH_ZOMBIE
+ else
+ pl.CalcIdeal = ACT_HL2MP_WALK_CROUCH_ZOMBIE_01 - 1 + math.ceil((CurTime() / 4 + pl:EntIndex()) % 3)
+ end
+ else
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local len2d = velocity:Length2D()
+ if len2d > 0.5 then
+ pl:SetPlaybackRate(math.min(len2d / maxseqgroundspeed, 3))
+ else
+ pl:SetPlaybackRate(1)
+ end
+
+ return true
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_GMOD_GESTURE_RANGE_ZOMBIE, true)
+ return ACT_INVALID
+ end
+end
+
+if SERVER then
+ function CLASS:OnSpawned(pl)
+ pl:CreateAmbience("ticklemonsterambience")
+ end
+end
+
+if not CLIENT then return end
+
+CLASS.Icon = "zombiesurvival/killicons/tickle"
+
+local vecSpineOffset = Vector(10, 0, 0)
+local SpineBones = {"ValveBiped.Bip01_Spine2", "ValveBiped.Bip01_Spine4", "ValveBiped.Bip01_Spine3"}
+function CLASS:BuildBonePositions(pl)
+ for _, bone in pairs(SpineBones) do
+ local spineid = pl:LookupBone(bone)
+ if spineid and spineid > 0 then
+ pl:ManipulateBonePosition(spineid, vecSpineOffset)
+ end
+ end
+
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.GetSwingEndTime then
+ local desiredscale
+ if wep:GetSwingEndTime() > 0 then
+ desiredscale = 2 + (1 - math.Clamp((wep:GetSwingEndTime() - CurTime()) / wep.MeleeDelay, 0, 1)) * 10
+ else
+ desiredscale = 2
+ end
+ pl.m_TMArmLength = math.Approach(pl.m_TMArmLength or 2, desiredscale, FrameTime() * 10)
+
+ local larmid = pl:LookupBone("ValveBiped.Bip01_L_Forearm")
+ if larmid and larmid > 0 then
+ pl:ManipulateBoneScale(larmid, Vector(pl.m_TMArmLength, 2, 2))
+ end
+ local rarmid = pl:LookupBone("ValveBiped.Bip01_R_Forearm")
+ if rarmid and rarmid > 0 then
+ pl:ManipulateBoneScale(rarmid, Vector(pl.m_TMArmLength, 2, 2))
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/burster.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/burster.lua
new file mode 100644
index 0000000..abe9bba
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/burster.lua
@@ -0,0 +1,192 @@
+CLASS.Hidden = true
+CLASS.Disabled = true
+CLASS.Unlocked = true
+
+CLASS.Name = "Burster"
+CLASS.TranslationName = "class_burster"
+CLASS.Description = "description_burster"
+CLASS.Help = "controls_burster"
+
+CLASS.Wave = 5 / 6
+
+CLASS.Health = 100
+CLASS.Speed = 160
+
+CLASS.Points = 3
+
+CLASS.CanTaunt = true
+
+CLASS.SWEP = "weapon_zs_burster"
+
+CLASS.Model = Model("models/player/zombie_fast.mdl")
+
+CLASS.VoicePitch = 0.7
+
+local STEPSOUNDTIME_NORMAL = STEPSOUNDTIME_NORMAL
+local STEPSOUNDTIME_WATER_FOOT = STEPSOUNDTIME_WATER_FOOT
+local STEPSOUNDTIME_ON_LADDER = STEPSOUNDTIME_ON_LADDER
+local STEPSOUNDTIME_WATER_KNEE = STEPSOUNDTIME_WATER_KNEE
+local ACT_HL2MP_SWIM_PISTOL = ACT_HL2MP_SWIM_PISTOL
+local ACT_HL2MP_IDLE_CROUCH_ZOMBIE = ACT_HL2MP_IDLE_CROUCH_ZOMBIE
+local ACT_HL2MP_RUN_ZOMBIE = ACT_HL2MP_RUN_ZOMBIE
+local ACT_HL2MP_WALK_CROUCH_ZOMBIE_01 = ACT_HL2MP_WALK_CROUCH_ZOMBIE_01
+local ACT_HL2MP_RUN_ZOMBIE = ACT_HL2MP_RUN_ZOMBIE
+
+function CLASS:PlayPainSound(pl)
+ pl:EmitSound("npc/zombie_poison/pz_warn"..math.random(2)..".wav", 75, math.Rand(137, 143))
+
+ return true
+end
+
+function CLASS:PlayDeathSound(pl)
+ pl:EmitSound("npc/zombie_poison/pz_die2.wav", 75, math.Rand(122, 128))
+
+ return true
+end
+
+local mathrandom = math.random
+local StepSounds = {
+ "npc/zombie/foot1.wav",
+ "npc/zombie/foot2.wav",
+ "npc/zombie/foot3.wav"
+}
+local ScuffSounds = {
+ "npc/zombie/foot_slide1.wav",
+ "npc/zombie/foot_slide2.wav",
+ "npc/zombie/foot_slide3.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if mathrandom() < 0.15 then
+ pl:EmitSound(ScuffSounds[mathrandom(#ScuffSounds)], 70)
+ else
+ pl:EmitSound(StepSounds[mathrandom(#StepSounds)], 70)
+ end
+
+ return true
+end
+
+function CLASS:PlayerStepSoundTime(pl, iType, bWalking)
+ if iType == STEPSOUNDTIME_NORMAL or iType == STEPSOUNDTIME_WATER_FOOT then
+ return 625 - pl:GetVelocity():Length()
+ elseif iType == STEPSOUNDTIME_ON_LADDER then
+ return 600
+ elseif iType == STEPSOUNDTIME_WATER_KNEE then
+ return 750
+ end
+
+ return 450
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.GetCharge then
+ local charge = wep:GetCharge()
+ if charge > 0 then
+ pl.CalcSeqOverride = pl:LookupSequence("taunt_zombie_original")
+ return true
+ end
+ end
+
+ if pl:WaterLevel() >= 3 then
+ pl.CalcIdeal = ACT_HL2MP_SWIM_PISTOL
+ return true
+ end
+
+ if velocity:Length2D() <= 0.5 then
+ if pl:Crouching() then
+ pl.CalcIdeal = ACT_HL2MP_IDLE_CROUCH_ZOMBIE
+ else
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE
+ end
+ elseif pl:Crouching() then
+ pl.CalcIdeal = ACT_HL2MP_WALK_CROUCH_ZOMBIE_01 - 1 + math.ceil((CurTime() / 4 + pl:EntIndex()) % 3)
+ else
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.GetCharge then
+ local charge = wep:GetCharge()
+ if charge > 0 then
+ pl:SetPlaybackRate(0)
+ pl:SetCycle(wep:GetCharge() ^ 2 * 0.8)
+ return true
+ end
+ end
+
+ local len2d = velocity:Length2D()
+ if len2d > 0.5 then
+ pl:SetPlaybackRate(math.min(len2d / maxseqgroundspeed * 0.666, 3))
+ else
+ pl:SetPlaybackRate(1)
+ end
+
+ return true
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_GMOD_GESTURE_RANGE_ZOMBIE, true)
+ return ACT_INVALID
+ end
+end
+
+function CLASS:Move(pl, mv)
+ local wep = pl:GetActiveWeapon()
+ if wep.Move and wep:Move(mv) then
+ return true
+ end
+end
+
+if SERVER then
+ function CLASS:CanPlayerSuicide(pl)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.GetCharge and wep:GetCharge() > 0 then return false end
+ end
+
+ local function DoExplode(pl, pos, magnitude)
+ local inflictor = pl:GetActiveWeapon()
+ if not inflictor:IsValid() then inflictor = pl end
+
+ local effectdata = EffectData()
+ effectdata:SetOrigin(pos)
+ effectdata:SetMagnitude(magnitude)
+ util.Effect("chemzombieexplode", effectdata, true)
+
+ util.PoisonBlastDamage(inflictor, pl, pos, magnitude * 128, magnitude * 85, true)
+
+ pl:CheckRedeem()
+ end
+
+ function CLASS:OnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo, assister)
+ local magnitude = 1
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.GetCharge then magnitude = wep:GetCharge() end
+
+ if magnitude == 0 then return end
+
+ local pos = pl:WorldSpaceCenter()
+
+ pl:Gib(dmginfo)
+ timer.Simple(0, function() DoExplode(pl, pos, magnitude) end)
+
+ return true
+ end
+
+ function CLASS:OnSpawned(pl)
+ local status = pl:GiveStatus("overridemodel")
+ if status and status:IsValid() then
+ status:SetModel("models/Zombie/Poison.mdl")
+ end
+
+ pl:CreateAmbience("bursterambience")
+ end
+end
+
+if not CLIENT then return end
+
+CLASS.Icon = "zombiesurvival/killicons/chemzombie"
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/chem_zombie.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/chem_zombie.lua
new file mode 100644
index 0000000..ff7d479
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/chem_zombie.lua
@@ -0,0 +1,112 @@
+CLASS.Hidden = true
+CLASS.Disabled = true
+CLASS.Unlocked = true
+
+CLASS.Name = "Chem Zombie"
+CLASS.TranslationName = "class_chem_zombie"
+CLASS.Description = "description_chem_zombie"
+CLASS.Help = "controls_chem_zombie"
+
+CLASS.Wave = 1
+CLASS.Health = 100
+CLASS.SWEP = "weapon_zs_chemzombie"
+CLASS.Model = Model("models/Zombie/Poison.mdl")
+CLASS.Speed = 160
+
+CLASS.Points = 3
+
+CLASS.PainSounds = {Sound("npc/metropolice/knockout2.wav"), Sound("npc/metropolice/pain1.wav"), Sound("npc/metropolice/pain2.wav"), Sound("npc/metropolice/pain3.wav"), Sound("npc/metropolice/pain4.wav")}
+CLASS.DeathSounds = {Sound("ambient/fire/gascan_ignite1.wav")}
+CLASS.VoicePitch = 0.65
+
+CLASS.ViewOffset = Vector(0, 0, 50)
+CLASS.Hull = {Vector(-16, -16, 0), Vector(16, 16, 64)}
+CLASS.HullDuck = {Vector(-16, -16, 0), Vector(16, 16, 35)}
+
+function CLASS:CanUse(pl)
+ return false
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ if velocity:Length2D() <= 0.5 then
+ pl.CalcIdeal = ACT_IDLE
+ else
+ pl.CalcSeqOverride = 2
+ end
+
+ return true
+end
+
+local StepSounds = {
+ "npc/zombie_poison/pz_left_foot1.wav"
+}
+local ScuffSounds = {
+ "npc/zombie_poison/pz_right_foot1.wav"
+}
+local mathrandom = math.random
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if iFoot == 0 and mathrandom() < 0.333 then
+ pl:EmitSound(ScuffSounds[mathrandom(#ScuffSounds)], 80, 90)
+ else
+ pl:EmitSound(StepSounds[mathrandom(#StepSounds)], 80, 90)
+ end
+
+ return true
+end
+
+function CLASS:PlayerStepSoundTime(pl, iType, bWalking)
+ if iType == STEPSOUNDTIME_NORMAL or iType == STEPSOUNDTIME_WATER_FOOT then
+ return 365 - pl:GetVelocity():Length()
+ elseif iType == STEPSOUNDTIME_ON_LADDER then
+ return 300
+ elseif iType == STEPSOUNDTIME_WATER_KNEE then
+ return 450
+ end
+
+ return 150
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ pl:FixModelAngles(velocity)
+end
+
+if SERVER then
+ function CLASS:OnSpawned(pl)
+ pl:CreateAmbience("chemzombieambience")
+ end
+
+ hook.Add("InitPostEntityMap", "MakeChemDummy", function()
+ DUMMY_CHEMZOMBIE = ents.Create("dummy_chemzombie")
+ if DUMMY_CHEMZOMBIE:IsValid() then
+ DUMMY_CHEMZOMBIE:Spawn()
+ end
+ end)
+
+ local function ChemBomb(pl, pos)
+ local effectdata = EffectData()
+ effectdata:SetOrigin(pos)
+ util.Effect("chemzombieexplode", effectdata, true)
+
+ if DUMMY_CHEMZOMBIE:IsValid() then
+ DUMMY_CHEMZOMBIE:SetPos(pos)
+ end
+ util.PoisonBlastDamage(DUMMY_CHEMZOMBIE, pl, pos, 128, 85, true)
+
+ pl:CheckRedeem()
+ end
+
+ function CLASS:OnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo, assister)
+ if attacker ~= pl and not suicide then
+ local pos = pl:LocalToWorld(pl:OBBCenter())
+
+ pl:Gib(dmginfo)
+ timer.Simple(0, function() ChemBomb(pl, pos) end)
+
+ return true
+ end
+ end
+end
+
+if not CLIENT then return end
+
+CLASS.Icon = "zombiesurvival/killicons/chemzombie"
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/classic_zombie.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/classic_zombie.lua
new file mode 100644
index 0000000..55dc414
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/classic_zombie.lua
@@ -0,0 +1,66 @@
+-- This is a special class which is essentially just Fresh Dead made to be a bit stronger so people can put it in their maps.
+-- It also has a climbing function although not as good as the Fast Zombie. Only so you don't have people exploiting high places.
+
+CLASS.Name = "Classic Zombie"
+CLASS.TranslationName = "class_classic_zombie"
+CLASS.Base = "freshdead"
+
+CLASS.Health = 150
+CLASS.Speed = 200
+CLASS.Points = 4
+
+CLASS.SWEP = "weapon_zs_classiczombie"
+
+CLASS.UsePlayerModel = true
+CLASS.UsePreviousModel = false
+CLASS.NoFallDamage = true
+
+if SERVER then
+ function CLASS:OnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo) end
+end
+
+function CLASS:Move(pl, mv)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.Move and wep:Move(mv) then
+ return true
+ end
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.GetClimbing and wep:GetClimbing() then
+ pl.CalcIdeal = ACT_ZOMBIE_CLIMB_UP
+ return true
+ end
+
+ return self.BaseClass.CalcMainActivity(self, pl, velocity)
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.GetClimbing and wep:GetClimbing() then
+ local vel = pl:GetVelocity()
+ local speed = vel:Length()
+ if speed > 8 then
+ pl:SetPlaybackRate(math.Clamp(speed / 60, 0, 1) * (vel.z < 0 and -1 or 1) * 0.25)
+ else
+ pl:SetPlaybackRate(0)
+ end
+
+ return true
+ end
+
+ return self.BaseClass.UpdateAnimation(self, pl, velocity, maxseqgroundspeed)
+end
+
+--[[if SERVER then return end
+
+function CLASS:CreateMove(pl, cmd)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.IsClimbing and wep:IsClimbing() then
+ local buttons = cmd:GetButtons()
+ if bit.band(buttons, IN_DUCK) ~= 0 then
+ cmd:SetButtons(buttons - IN_DUCK)
+ end
+ end
+end]]
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/crow.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/crow.lua
new file mode 100644
index 0000000..b3bec1c
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/crow.lua
@@ -0,0 +1,150 @@
+CLASS.Name = "Crow"
+CLASS.TranslationName = "class_crow"
+CLASS.Description = "description_crow"
+
+CLASS.Health = 5
+CLASS.Wave = 0
+CLASS.Threshold = 0
+CLASS.SWEP = "weapon_zs_crow"
+CLASS.Model = Model("models/crow.mdl")
+CLASS.Speed = 90
+CLASS.JumpPower = 230
+
+CLASS.PainSounds = {"NPC_Crow.Pain"}
+CLASS.DeathSounds = {"NPC_Crow.Die"}
+
+CLASS.Unlocked = true
+CLASS.Hidden = true
+
+CLASS.Hull = {Vector(-4, -4, 0), Vector(4, 4, 9)}
+CLASS.HullDuck = {Vector(-4, -4, 0), Vector(4, 4, 9)}
+CLASS.ViewOffset = Vector(0,0,8)
+CLASS.ViewOffsetDucked = Vector(0,0,8)
+CLASS.CrouchedWalkSpeed = 1
+CLASS.StepSize = 8
+CLASS.Mass = 2
+
+CLASS.NoUse = true
+CLASS.NoGibs = true
+CLASS.NoCollideAll = true
+CLASS.NoFallDamage = true
+CLASS.NoFallSlowdown = true
+CLASS.NeverAlive = true
+CLASS.AllowTeamDamage = true
+CLASS.NoDeaths = true
+CLASS.Points = 0
+
+function CLASS:NoDeathMessage(pl, attacker, dmginfo)
+ return true
+end
+
+function CLASS:DoesntGiveFear()
+ return true
+end
+
+function CLASS:ScalePlayerDamage(pl, hitgroup, dmginfo)
+ return true
+end
+
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ return true
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ if pl:OnGround() then
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.IsPecking and wep:IsPecking() then
+ pl.CalcSeqOverride = 5
+ elseif velocity:Length2D() > 0.5 then
+ pl.CalcIdeal = ACT_RUN
+ else
+ pl.CalcIdeal = ACT_IDLE
+ end
+ elseif velocity:Length() > 350 then
+ pl.CalcIdeal = ACT_FLY
+ else
+ pl.CalcSeqOverride = 7
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ pl:FixModelAngles(velocity)
+ pl:SetPlaybackRate(1)
+ return true
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MELEE_ATTACK1, true)
+ return ACT_INVALID
+ end
+end
+
+function CLASS:Move(pl, mv)
+ if not pl:GetActiveWeapon().IsCrow then return end
+
+ if not pl:IsOnGround() and pl:KeyDown(IN_JUMP) then
+ local dir = pl:EyeAngles()
+ if pl:KeyDown(IN_MOVELEFT) then
+ dir:RotateAroundAxis(dir:Up(), 20)
+ elseif pl:KeyDown(IN_MOVERIGHT) then
+ dir:RotateAroundAxis(dir:Up(), -20)
+ end
+
+ if pl:KeyDown(IN_FORWARD) then
+ mv:SetVelocity(dir:Forward() * 450)
+ else
+ mv:SetVelocity(dir:Forward() * 300)
+ end
+
+ return true
+ end
+end
+
+if SERVER then
+
+function CLASS:SwitchedAway(pl)
+ pl:SetAllowFullRotation(false)
+end
+
+function CLASS:OnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo)
+ pl:SetAllowFullRotation(false)
+
+ if attacker:IsPlayer() and attacker ~= pl then
+ if attacker:Team() == TEAM_HUMAN then
+ attacker.CrowKills = attacker.CrowKills + 1
+ elseif attacker:GetZombieClassTable().Name == "Crow" then
+ attacker.CrowVsCrowKills = attacker.CrowVsCrowKills + 1
+
+ net.Start("zs_crow_kill_crow")
+ net.WriteString(pl:Name())
+ net.WriteString(attacker:Name())
+ net.Broadcast()
+ end
+ end
+
+ if pl:Health() < -45 then
+ local amount = pl:OBBMaxs():Length()
+ local vel = pl:GetVelocity()
+ util.Blood(pl:LocalToWorld(pl:OBBCenter()), math.Rand(amount * 0.25, amount * 0.5), vel:GetNormalized(), vel:Length() * 0.75)
+
+ return true
+ elseif not pl.KnockedDown then
+ pl:CreateRagdoll()
+ end
+
+ pl:SetHealth(pl:GetMaxHealth())
+ pl:StripWeapons()
+ pl:Spectate(OBS_MODE_ROAMING)
+end
+end
+
+if not CLIENT then return end
+
+function CLASS:ShouldDrawLocalPlayer(pl)
+ return true
+end
+
+CLASS.Icon = "zombiesurvival/killicons/crow"
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/fast_headcrab.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/fast_headcrab.lua
new file mode 100644
index 0000000..9e90569
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/fast_headcrab.lua
@@ -0,0 +1,106 @@
+CLASS.Name = "Fast Headcrab"
+CLASS.TranslationName = "class_fast_headcrab"
+CLASS.Description = "description_fast_headcrab"
+CLASS.Help = "controls_fast_headcrab"
+
+CLASS.Model = Model("models/headcrab.mdl")
+
+CLASS.Wave = 1 / 3
+
+CLASS.SWEP = "weapon_zs_fastheadcrab"
+
+CLASS.Health = 30
+CLASS.Speed = 230
+CLASS.JumpPower = 100
+
+CLASS.NoFallDamage = true
+CLASS.NoFallSlowdown = true
+
+CLASS.Points = 2
+
+CLASS.Hull = {Vector(-12, -12, 0), Vector(12, 12, 18.1)}
+CLASS.HullDuck = {Vector(-12, -12, 0), Vector(12, 12, 18.1)}
+CLASS.ViewOffset = Vector(0, 0, 10)
+CLASS.ViewOffsetDucked = Vector(0, 0, 10)
+CLASS.StepSize = 8
+CLASS.CrouchedWalkSpeed = 1
+CLASS.Mass = 16
+
+CLASS.CantDuck = true
+
+CLASS.IsHeadcrab = true
+
+CLASS.PainSounds = {"NPC_FastHeadcrab.Pain"}
+CLASS.DeathSounds = {"NPC_FastHeadcrab.Die"}
+
+function CLASS:Move(pl, mv)
+ local wep = pl:GetActiveWeapon()
+ if wep.Move and wep:Move(mv) then
+ return true
+ end
+end
+
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ return true
+end
+
+function CLASS:ScalePlayerDamage(pl, hitgroup, dmginfo)
+ return true
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ if pl:OnGround() then
+ if velocity:Length2D() > 0.5 then
+ pl.CalcIdeal = ACT_RUN
+ else
+ pl.CalcSeqOverride = 1
+ end
+ elseif pl:WaterLevel() >= 3 then
+ pl.CalcSeqOverride = 6
+ else
+ pl.CalcSeqOverride = 3
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ pl:FixModelAngles(velocity)
+
+ local seq = pl:GetSequence()
+ if seq == 3 then
+ if not pl.m_PrevFrameCycle then
+ pl.m_PrevFrameCycle = true
+ pl:SetCycle(0)
+ end
+
+ pl:SetPlaybackRate(1)
+
+ return true
+ elseif pl.m_PrevFrameCycle then
+ pl.m_PrevFrameCycle = nil
+ end
+end
+
+if not CLIENT then return end
+
+CLASS.Icon = "zombiesurvival/killicons/fastheadcrab"
+
+function CLASS:CreateMove(pl, cmd)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.m_ViewAngles and wep.IsPouncing and wep:IsPouncing() then
+ local maxdiff = FrameTime() * 15
+ local mindiff = -maxdiff
+ local originalangles = wep.m_ViewAngles
+ local viewangles = cmd:GetViewAngles()
+
+ local diff = math.AngleDifference(viewangles.yaw, originalangles.yaw)
+ if diff > maxdiff or diff < mindiff then
+ viewangles.yaw = math.NormalizeAngle(originalangles.yaw + math.Clamp(diff, mindiff, maxdiff))
+ end
+
+ wep.m_ViewAngles = viewangles
+
+ cmd:SetViewAngles(viewangles)
+ end
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/fast_zombie.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/fast_zombie.lua
new file mode 100644
index 0000000..3bb271b
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/fast_zombie.lua
@@ -0,0 +1,228 @@
+CLASS.Name = "Fast Zombie"
+CLASS.TranslationName = "class_fast_zombie"
+CLASS.Description = "description_fast_zombie"
+CLASS.Help = "controls_fast_zombie"
+
+CLASS.Model = Model("models/player/zombie_fast.mdl") --Model("models/Zombie/Fast.mdl")
+
+CLASS.Wave = 1 / 2
+CLASS.Revives = true
+CLASS.Infliction = 0.5 -- We auto-unlock this class if 50% of humans are dead regardless of what wave it is.
+
+CLASS.Health = 125
+CLASS.Speed = 260
+CLASS.SWEP = "weapon_zs_fastzombie"
+
+CLASS.Points = 4
+
+CLASS.Hull = {Vector(-16, -16, 0), Vector(16, 16, 58)}
+CLASS.HullDuck = {Vector(-16, -16, 0), Vector(16, 16, 32)}
+CLASS.ViewOffset = Vector(0, 0, 50)
+CLASS.ViewOffsetDucked = Vector(0, 0, 24)
+
+CLASS.PainSounds = {"NPC_FastZombie.Pain"}
+CLASS.DeathSounds = {"NPC_FastZombie.Die"}
+
+CLASS.VoicePitch = 0.75
+
+CLASS.NoFallDamage = true
+CLASS.NoFallSlowdown = true
+
+function CLASS:Move(pl, mv)
+ local wep = pl:GetActiveWeapon()
+ if wep.Move and wep:Move(mv) then
+ return true
+ end
+
+ if mv:GetForwardSpeed() <= 0 then
+ mv:SetMaxSpeed(math.min(mv:GetMaxSpeed(), 90))
+ mv:SetMaxClientSpeed(math.min(mv:GetMaxClientSpeed(), 90))
+ end
+end
+
+local mathrandom = math.random
+local StepLeftSounds = {
+ "npc/fast_zombie/foot1.wav",
+ "npc/fast_zombie/foot2.wav"
+}
+local StepRightSounds = {
+ "npc/fast_zombie/foot3.wav",
+ "npc/fast_zombie/foot4.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if iFoot == 0 then
+ pl:EmitSound(StepLeftSounds[mathrandom(#StepLeftSounds)], 70)
+ else
+ pl:EmitSound(StepRightSounds[mathrandom(#StepRightSounds)], 70)
+ end
+
+ return true
+end
+--[[function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if iFoot == 0 then
+ pl:EmitSound("NPC_FastZombie.GallopLeft")
+ else
+ pl:EmitSound("NPC_FastZombie.GallopRight")
+ end
+
+ return true
+end]]
+
+function CLASS:PlayerStepSoundTime(pl, iType, bWalking)
+ if iType == STEPSOUNDTIME_NORMAL or iType == STEPSOUNDTIME_WATER_FOOT then
+ return 450 - pl:GetVelocity():Length()
+ elseif iType == STEPSOUNDTIME_ON_LADDER then
+ return 400
+ elseif iType == STEPSOUNDTIME_WATER_KNEE then
+ return 550
+ end
+
+ return 250
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local wep = pl:GetActiveWeapon()
+ if not wep:IsValid() or not wep.GetClimbing then return end
+
+ if wep:GetClimbing() then
+ pl.CalcIdeal = ACT_ZOMBIE_CLIMB_UP
+ return true
+ elseif wep:GetPounceTime() > 0 then
+ pl.CalcIdeal = ACT_ZOMBIE_LEAP_START
+ return true
+ end
+
+ local speed = velocity:Length2D()
+ if not pl:OnGround() or pl:WaterLevel() >= 3 then
+ pl.CalcIdeal = ACT_ZOMBIE_LEAPING
+ elseif speed <= 0.5 and wep:IsRoaring() then
+ pl.CalcSeqOverride = pl:LookupSequence("menu_zombie_01")
+ else
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE_FAST
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local wep = pl:GetActiveWeapon()
+ if not wep:IsValid() or not wep.GetClimbing then return end
+
+ if wep:GetSwinging() then
+ if not pl.PlayingFZSwing then
+ pl.PlayingFZSwing = true
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_GMOD_GESTURE_RANGE_FRENZY)
+ end
+ elseif pl.PlayingFZSwing then
+ pl.PlayingFZSwing = false
+ pl:AnimResetGestureSlot(GESTURE_SLOT_ATTACK_AND_RELOAD) --pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_GMOD_GESTURE_RANGE_FRENZY, true)
+ end
+
+ if wep:GetClimbing() then
+ local vel = pl:GetVelocity()
+ local speed = vel:Length()
+ if speed > 8 then
+ pl:SetPlaybackRate(math.Clamp(speed / 160, 0, 1) * (vel.z < 0 and -1 or 1))
+ else
+ pl:SetPlaybackRate(0)
+ end
+
+ return true
+ end
+
+ if wep:GetPounceTime() > 0 then
+ pl:SetPlaybackRate(0.25)
+
+ if not pl.m_PrevFrameCycle then
+ pl.m_PrevFrameCycle = true
+ pl:SetCycle(0)
+ end
+
+ return true
+ elseif pl.m_PrevFrameCycle then
+ pl.m_PrevFrameCycle = nil
+ end
+
+ local speed = velocity:Length2D()
+ if not pl:OnGround() or pl:WaterLevel() >= 3 then
+ pl:SetPlaybackRate(1)
+
+ if pl:GetCycle() >= 1 then
+ pl:SetCycle(pl:GetCycle() - 1)
+ end
+
+ return true
+ end
+ if speed <= 0.5 and wep:IsRoaring() then
+ pl:SetPlaybackRate(0)
+ pl:SetCycle(math.Clamp(1 - (wep:GetRoarEndTime() - CurTime()) / wep.RoarTime, 0, 1) * 0.9)
+
+ return true
+ end
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ return ACT_INVALID
+ end
+end
+
+if SERVER then
+ function CLASS:ReviveCallback(pl, attacker, dmginfo)
+ if not pl.Revive and not dmginfo:GetInflictor().IsMelee and dmginfo:GetDamageType() ~= DMG_BLAST and dmginfo:GetDamageType() ~= DMG_BURN and (pl:LastHitGroup() == HITGROUP_LEFTLEG or pl:LastHitGroup() == HITGROUP_RIGHTLEG) and math.random(3) == 1 then
+ local classtable = GAMEMODE.ZombieClasses["Fast Zombie Legs"]
+ if classtable then
+ pl:RemoveStatus("overridemodel", false, true)
+ local deathclass = pl.DeathClass or pl:GetZombieClass()
+ pl:SetZombieClass(classtable.Index)
+ pl:DoHulls(classtable.Index, TEAM_UNDEAD)
+ pl.DeathClass = deathclass
+
+ pl:EmitSound("physics/flesh/flesh_bloody_break.wav", 100, 75)
+
+ pl:Gib()
+ pl.Gibbed = nil
+
+ timer.Simple(0, function()
+ if IsValid(pl) then
+ pl:SecondWind()
+ end
+ end)
+
+ return true
+ end
+ end
+
+ return false
+ end
+end
+
+if SERVER then return end
+
+CLASS.Icon = "zombiesurvival/killicons/fastzombie"
+
+function CLASS:CreateMove(pl, cmd)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.IsPouncing then
+ if wep.m_ViewAngles and wep:IsPouncing() then
+ local maxdiff = FrameTime() * 20
+ local mindiff = -maxdiff
+ local originalangles = wep.m_ViewAngles
+ local viewangles = cmd:GetViewAngles()
+
+ local diff = math.AngleDifference(viewangles.yaw, originalangles.yaw)
+ if diff > maxdiff or diff < mindiff then
+ viewangles.yaw = math.NormalizeAngle(originalangles.yaw + math.Clamp(diff, mindiff, maxdiff))
+ end
+
+ wep.m_ViewAngles = viewangles
+
+ cmd:SetViewAngles(viewangles)
+ --[[elseif wep:IsClimbing() then
+ local buttons = cmd:GetButtons()
+ if bit.band(buttons, IN_DUCK) ~= 0 then
+ cmd:SetButtons(buttons - IN_DUCK)
+ end]]
+ end
+ end
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/fast_zombie_legs.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/fast_zombie_legs.lua
new file mode 100644
index 0000000..528ff62
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/fast_zombie_legs.lua
@@ -0,0 +1,210 @@
+CLASS.Name = "Fast Zombie Legs"
+CLASS.TranslationName = "class_fast_zombie_legs"
+CLASS.Description = "description_fast_zombie_legs"
+
+CLASS.Model = Model("models/player/zombie_fast.mdl")
+CLASS.NoHead = true
+
+CLASS.Wave = 0
+CLASS.Threshold = 0
+CLASS.Unlocked = true
+CLASS.Hidden = true
+
+CLASS.Health = 75
+CLASS.Speed = 200
+CLASS.JumpPower = 250
+
+CLASS.Points = 2
+
+CLASS.Hull = {Vector(-16, -16, 0), Vector(16, 16, 32)}
+CLASS.HullDuck = {Vector(-16, -16, 0), Vector(16, 16, 32)}
+CLASS.ViewOffset = Vector(0, 0, 32)
+CLASS.ViewOffsetDucked = Vector(0, 0, 32)
+CLASS.Mass = DEFAULT_MASS * 0.5
+CLASS.CrouchedWalkSpeed = 1
+
+CLASS.CantDuck = true
+CLASS.CanFeignDeath = false
+
+CLASS.VoicePitch = 0.65
+
+CLASS.SWEP = "weapon_zs_fastzombielegs"
+
+if SERVER then
+ function CLASS:OnSpawned(pl)
+ local status = pl:GiveStatus("overridemodel")
+ if status and status:IsValid() then
+ status:SetModel("models/Gibs/Fast_Zombie_Legs.mdl")
+ end
+ end
+
+ function CLASS:AltUse(pl)
+ local feigndeath = pl.FeignDeath
+ if feigndeath and feigndeath:IsValid() then
+ if CurTime() >= feigndeath:GetStateEndTime() then
+ feigndeath:SetState(1)
+ feigndeath:SetStateEndTime(CurTime() + 1.5)
+ end
+ elseif pl:IsOnGround() and not pl:KeyDown(IN_FORWARD) and not pl:KeyDown(IN_MOVERIGHT) and not pl:KeyDown(IN_MOVELEFT) and not pl:KeyDown(IN_BACK) then
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and not wep:IsSwinging() and CurTime() > wep:GetNextPrimaryFire() then
+ local status = pl:GiveStatus("feigndeath")
+ if status and status:IsValid() then
+ status:SetStateEndTime(CurTime() + 1.5)
+ end
+ end
+ end
+ end
+end
+
+--[[function CLASS:ScalePlayerDamage(pl, hitgroup, dmginfo)
+ if hitgroup ~= HITGROUP_LEFTLEG and hitgroup ~= HITGROUP_RIGHTLEG and hitgroup ~= HITGROUP_GEAR and hitgroup ~= HITGROUP_GENERIC then
+ dmginfo:SetDamage(0)
+ dmginfo:ScaleDamage(0)
+ end
+
+ return true
+end]]
+
+function CLASS:Move(pl, mv)
+ local wep = pl:GetActiveWeapon()
+ if wep.Move and wep:Move(mv) then
+ return true
+ end
+end
+
+function CLASS:ShouldDrawLocalPlayer(pl)
+ return true
+end
+
+local mathrandom = math.random
+local StepLeftSounds = {
+ "npc/fast_zombie/foot1.wav",
+ "npc/fast_zombie/foot2.wav"
+}
+local StepRightSounds = {
+ "npc/fast_zombie/foot3.wav",
+ "npc/fast_zombie/foot4.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if iFoot == 0 then
+ pl:EmitSound(StepLeftSounds[mathrandom(#StepLeftSounds)], 70)
+ else
+ pl:EmitSound(StepRightSounds[mathrandom(#StepRightSounds)], 70)
+ end
+
+ return true
+end
+--[[function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if iFoot == 0 then
+ pl:EmitSound("NPC_FastZombie.GallopLeft")
+ else
+ pl:EmitSound("NPC_FastZombie.GallopRight")
+ end
+
+ return true
+end]]
+
+function CLASS:PlayerStepSoundTime(pl, iType, bWalking)
+ if iType == STEPSOUNDTIME_NORMAL or iType == STEPSOUNDTIME_WATER_FOOT then
+ return 625 - pl:GetVelocity():Length()
+ elseif iType == STEPSOUNDTIME_ON_LADDER then
+ return 600
+ elseif iType == STEPSOUNDTIME_WATER_KNEE then
+ return 750
+ end
+
+ return 450
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ pl.CalcSeqOverride = pl:LookupSequence("zombie_slump_rise_02_fast")
+ elseif velocity:Length2D() <= 0.5 then
+ pl.CalcIdeal = ACT_HL2MP_IDLE_ZOMBIE
+ else
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ if feign:GetState() == 1 then
+ pl:SetCycle(1 - math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ else
+ pl:SetCycle(math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ end
+ pl:SetPlaybackRate(0)
+
+ return true
+ end
+
+ local len2d = velocity:Length2D()
+ if len2d > 0.5 then
+ pl:SetPlaybackRate(math.min(len2d / maxseqgroundspeed * 0.75, 3))
+ else
+ pl:SetPlaybackRate(1)
+ end
+
+ return true
+end
+
+if not CLIENT then return end
+
+CLASS.Icon = "zombiesurvival/killicons/legs"
+
+-- This whole point of this is to stop drawing decals on the upper part of the model. It doesn't actually do anything to the visible model.
+local undo = false
+function CLASS:PrePlayerDraw(pl)
+ local boneid = pl:LookupBone("ValveBiped.Bip01_Spine")
+ if boneid and boneid > 0 then
+ local pos, ang = pl:GetBonePosition(boneid)
+ if pos then
+ local normal = ang:Forward() * -1
+ render.EnableClipping(true)
+ render.PushCustomClipPlane(normal, normal:Dot(pos))
+ undo = true
+ end
+ end
+end
+
+function CLASS:PostPlayerDraw(pl)
+ if undo then
+ render.PopCustomClipPlane()
+ render.EnableClipping(false)
+ end
+end
+
+function CLASS:BuildBonePositions(pl)
+ local desired
+
+ local bone = "ValveBiped.Bip01_L_Thigh"
+
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() then
+ if wep.GetSwingEndTime and wep:GetSwingEndTime() > 0 then
+ desired = 1 - math.Clamp((wep:GetSwingEndTime() - CurTime()) / wep.MeleeDelay, 0, 1)
+ end
+
+ if wep:GetDTBool(3) then
+ bone = "ValveBiped.Bip01_R_Thigh"
+ end
+ end
+
+ desired = desired or 0
+
+ if desired > 0 then
+ pl.m_KickDelta = CosineInterpolation(0, 1, desired)
+ else
+ pl.m_KickDelta = math.Approach(pl.m_KickDelta or 0, desired, FrameTime() * 4)
+ end
+
+ local boneid = pl:LookupBone(bone)
+ if boneid and boneid > 0 then
+ pl:ManipulateBoneAngles(boneid, pl.m_KickDelta * Angle(bone == "ValveBiped.Bip01_L_Thigh" and 0 or 20, -110, 30))
+ end
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/flesh_creeper.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/flesh_creeper.lua
new file mode 100644
index 0000000..48dd7a4
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/flesh_creeper.lua
@@ -0,0 +1,197 @@
+CLASS.Name = "Flesh Creeper"
+CLASS.TranslationName = "class_flesh_creeper"
+CLASS.Description = "description_flesh_creeper"
+CLASS.Help = "controls_flesh_creeper"
+
+CLASS.Wave = 0
+CLASS.Hidden = true
+CLASS.Unlocked = true
+CLASS.Health = 100
+CLASS.SWEP = "weapon_zs_fleshcreeper"
+CLASS.Model = Model("models/antlion.mdl")
+CLASS.Speed = 175
+
+CLASS.Points = 4
+
+CLASS.VoicePitch = 0.55
+
+CLASS.PainSounds = {Sound("npc/barnacle/barnacle_pull1.wav"), Sound("npc/barnacle/barnacle_pull2.wav"), Sound("npc/barnacle/barnacle_pull3.wav"), Sound("npc/barnacle/barnacle_pull4.wav")}
+CLASS.DeathSounds = {Sound("npc/barnacle/barnacle_die1.wav"), Sound("npc/barnacle/barnacle_die2.wav")}
+
+CLASS.ModelScale = 0.65
+--[[CLASS.ModelScale = 0.6324555
+CLASS.ClientsideModelScale = 0.4 / CLASS.ModelScale]]
+
+CLASS.Hull = {Vector(-16, -16, 0), Vector(16, 16, 48)}
+CLASS.HullDuck = {Vector(-16, -16, 0), Vector(16, 16, 48)}
+
+CLASS.Hull[1].x = -16
+CLASS.Hull[2].x = 16
+CLASS.Hull[1].y = -16
+CLASS.Hull[2].y = 16
+CLASS.HullDuck[1].x = -16
+CLASS.HullDuck[2].x = 16
+CLASS.HullDuck[1].y = -16
+CLASS.HullDuck[2].y = 16
+
+CLASS.ViewOffset = Vector(0, 0, 40)
+CLASS.ViewOffsetDucked = Vector(0, 0, 10)
+
+function CLASS:CanUse(pl)
+ return GAMEMODE:GetDynamicSpawning() and not GAMEMODE.ZombieEscape
+end
+
+function CLASS:Move(pl, mv)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.IsInAttackAnim and (wep:IsInAttackAnim() or wep:GetHoldingRightClick()) then
+ mv:SetMaxSpeed(0)
+ mv:SetMaxClientSpeed(0)
+
+ return true
+ end
+
+ if mv:GetForwardSpeed() <= 0 then
+ mv:SetMaxSpeed(mv:GetMaxSpeed() * 0.45)
+ mv:SetMaxClientSpeed(mv:GetMaxClientSpeed() * 0.45)
+ end
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.IsInAttackAnim then
+ if wep:IsInAttackAnim() then
+ pl.CalcSeqOverride = 14
+ return true
+ elseif wep:GetHoldingRightClick() then
+ pl.CalcSeqOverride = 21
+ return true
+ end
+ end
+
+ if velocity:Length2D() > 0.5 then
+ --[[if pl:Crouching() and pl:OnGround() then
+ pl.CalcSeqOverride = 17
+ else]]
+ pl.CalcSeqOverride = 4
+ --[[end
+ elseif pl:Crouching() and pl:OnGround() then
+ pl.CalcSeqOverride = 40]]
+ else
+ pl.CalcSeqOverride = 2
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ pl:FixModelAngles(velocity)
+
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.IsInAttackAnim then
+ if wep:IsInAttackAnim() then
+ pl:SetPlaybackRate(0)
+ pl:SetCycle((1 - (wep:GetAttackAnimTime() - CurTime()) / wep.Primary.Delay))
+
+ return true
+ elseif wep:GetHoldingRightClick() then
+ pl:SetPlaybackRate(0)
+
+ local delta = CurTime() - wep:GetRightClickStart()
+ if delta > 1 then
+ --pl:SetCycle(0.333 + (delta * 3 % 1) * 0.2)
+ pl:SetCycle(0.5 + math.sin(delta * 12) * 0.05)
+ else
+ --pl:SetCycle(delta / 3)
+ pl:SetCycle(delta / 2)
+ end
+
+ return true
+ end
+ end
+
+ if velocity:Length2D() >= 16 then
+ GAMEMODE.BaseClass.UpdateAnimation(GAMEMODE.BaseClass, pl, velocity, maxseqgroundspeed)
+
+ --[[local dir = Vector()
+ dir:Set(velocity)
+ dir.z = 0
+ dir:Normalize()
+ local aimdir = pl:GetAimVector()
+ aimdir.z = 0
+ aimdir:Normalize()
+
+ if dir:Dot(aimdir) >= 0.5 then
+ pl:SetPlaybackRate(pl:GetPlaybackRate() / self.ModelScale / 2)
+ else]]
+ pl:SetPlaybackRate(pl:GetPlaybackRate() / self.ModelScale)
+ --end
+
+ --[[if pl:Crouching() then
+ pl:SetPoseParameter("move_yaw", 0)
+ end]]
+
+ return true
+ end
+
+ --[[if pl:Crouching() then
+ pl:SetCycle(0.5 + math.sin(CurTime() * 2) * 0.025)
+ pl:SetPlaybackRate(0)
+
+ return true
+ end]]
+
+ return true
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ return ACT_INVALID
+ end
+end
+
+function CLASS:CreateMove(pl, cmd)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.IsSwinging and wep:IsSwinging() and bit.band(cmd:GetButtons(), IN_JUMP) ~= 0 then
+ cmd:SetButtons(cmd:GetButtons() - IN_JUMP)
+ end
+end
+
+local FootSounds = {
+ "npc/zombie/foot1.wav",
+ "npc/zombie/foot2.wav",
+ "npc/zombie/foot3.wav"
+}
+local mathrandom = math.random
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ pl:EmitSound(FootSounds[mathrandom(#FootSounds)], 65, math.random(105, 115))
+
+ return true
+end
+
+if SERVER then
+ function CLASS:OnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo)
+ local ent = pl:FakeDeath(pl:LookupSequence("Flip1"), self.ModelScale, math.Rand(0.45, 0.5))
+ if ent:IsValid() then
+ ent:SetMaterial("models/flesh")
+ end
+
+ return true
+ end
+end
+
+if not CLIENT then return end
+
+--CLASS.Icon = "zombiesurvival/killicons/flesh_creeper"
+
+local matFlesh = Material("models/flesh")
+function CLASS:PrePlayerDraw(pl)
+ render.ModelMaterialOverride(matFlesh)
+end
+
+function CLASS:PostPlayerDraw(pl)
+ render.ModelMaterialOverride()
+end
+
+function CLASS:ShouldDrawLocalPlayer()
+ return true
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/freshdead.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/freshdead.lua
new file mode 100644
index 0000000..17f98b3
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/freshdead.lua
@@ -0,0 +1,148 @@
+CLASS.Name = "Fresh Dead"
+CLASS.TranslationName = "class_fresh_dead"
+CLASS.Description = ""
+CLASS.Help = ""
+
+CLASS.Wave = 0
+CLASS.Unlocked = true
+CLASS.Hidden = true
+
+CLASS.Health = 125
+CLASS.Speed = 200
+
+CLASS.Points = 3
+
+CLASS.CanTaunt = true
+
+CLASS.UsePreviousModel = true
+
+CLASS.SWEP = "weapon_zs_freshdead"
+
+CLASS.PainSounds = {"npc/zombie/zombie_pain1.wav", "npc/zombie/zombie_pain2.wav", "npc/zombie/zombie_pain3.wav", "npc/zombie/zombie_pain4.wav", "npc/zombie/zombie_pain5.wav", "npc/zombie/zombie_pain6.wav"}
+CLASS.DeathSounds = {"npc/zombie/zombie_die1.wav", "npc/zombie/zombie_die2.wav", "npc/zombie/zombie_die3.wav"}
+
+CLASS.VoicePitch = 0.65
+
+CLASS.CanFeignDeath = true
+
+local mathrandom = math.random
+local StepLeftSounds = {
+ "npc/zombie/foot1.wav",
+ "npc/zombie/foot2.wav"
+}
+local StepRightSounds = {
+ "npc/zombie/foot2.wav",
+ "npc/zombie/foot3.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if iFoot == 0 then
+ pl:EmitSound(StepLeftSounds[mathrandom(#StepLeftSounds)], 70)
+ else
+ pl:EmitSound(StepRightSounds[mathrandom(#StepRightSounds)], 70)
+ end
+
+ return true
+end
+--[[function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if iFoot == 0 then
+ pl:EmitSound("Zombie.FootstepLeft")
+ else
+ pl:EmitSound("Zombie.FootstepRight")
+ end
+
+ return true
+end]]
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local revive = pl.Revive
+ if revive and revive:IsValid() then
+ pl.CalcIdeal = ACT_HL2MP_ZOMBIE_SLUMP_RISE
+ return true
+ end
+
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ if feign:GetDirection() == DIR_BACK then
+ pl.CalcSeqOverride = pl:LookupSequence("zombie_slump_rise_02_fast")
+ else
+ pl.CalcIdeal = ACT_HL2MP_ZOMBIE_SLUMP_RISE
+ end
+ return true
+ end
+
+ if pl:WaterLevel() >= 3 then
+ pl.CalcIdeal = ACT_HL2MP_SWIM_PISTOL
+ elseif pl:Crouching() then
+ if velocity:Length2D() <= 0.5 then
+ pl.CalcIdeal = ACT_HL2MP_IDLE_CROUCH_ZOMBIE
+ else
+ pl.CalcIdeal = ACT_HL2MP_WALK_CROUCH_ZOMBIE_01 - 1 + math.ceil((CurTime() / 4 + pl:EntIndex()) % 3)
+ end
+ else
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local revive = pl.Revive
+ if revive and revive:IsValid() then
+ pl:SetCycle(0.4 + (1 - math.Clamp((revive:GetReviveTime() - CurTime()) / revive.AnimTime, 0, 1)) * 0.6)
+ pl:SetPlaybackRate(0)
+ return true
+ end
+
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ if feign:GetState() == 1 then
+ pl:SetCycle(1 - math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ else
+ pl:SetCycle(math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ end
+ pl:SetPlaybackRate(0)
+ return true
+ end
+
+ local len2d = velocity:Length2D()
+ if len2d > 0.5 then
+ pl:SetPlaybackRate(math.min(len2d / maxseqgroundspeed, 3))
+ else
+ pl:SetPlaybackRate(1)
+ end
+
+ return true
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_GMOD_GESTURE_RANGE_ZOMBIE, true)
+ return ACT_INVALID
+ end
+end
+
+function CLASS:DoesntGiveFear(pl)
+ return pl.FeignDeath and pl.FeignDeath:IsValid()
+end
+
+if SERVER then
+ function CLASS:OnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo)
+ pl:SetZombieClass(GAMEMODE.DefaultZombieClass)
+ end
+
+ function CLASS:AltUse(pl)
+ pl:StartFeignDeath()
+ end
+end
+
+if not CLIENT then return end
+
+CLASS.Icon = "zombiesurvival/killicons/zombie"
+
+function CLASS:PrePlayerDraw(pl)
+ render.SetColorModulation(0.5, 0.9, 0.5)
+end
+
+function CLASS:PostPlayerDraw(pl)
+ render.SetColorModulation(1, 1, 1)
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/ghoul.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/ghoul.lua
new file mode 100644
index 0000000..6425650
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/ghoul.lua
@@ -0,0 +1,199 @@
+CLASS.Name = "Ghoul"
+CLASS.TranslationName = "class_ghoul"
+CLASS.Description = "description_ghoul"
+CLASS.Help = "controls_ghoul"
+
+CLASS.Wave = 0
+CLASS.Unlocked = true
+
+CLASS.Health = 150
+CLASS.Speed = 170
+
+CLASS.Points = 4
+
+CLASS.CanTaunt = true
+
+CLASS.SWEP = "weapon_zs_ghoul"
+
+CLASS.Model = Model("models/player/corpse1.mdl")
+
+CLASS.VoicePitch = 0.7
+
+CLASS.CanFeignDeath = true
+
+function CLASS:PlayPainSound(pl)
+ pl:EmitSound("npc/zombie_poison/pz_warn"..math.random(2)..".wav", 75, math.Rand(137, 143))
+
+ return true
+end
+
+function CLASS:PlayDeathSound(pl)
+ pl:EmitSound("npc/zombie_poison/pz_die2.wav", 75, math.Rand(122, 128))
+
+ return true
+end
+
+local mathrandom = math.random
+local StepSounds = {
+ "npc/zombie/foot1.wav",
+ "npc/zombie/foot2.wav",
+ "npc/zombie/foot3.wav"
+}
+local ScuffSounds = {
+ "npc/zombie/foot_slide1.wav",
+ "npc/zombie/foot_slide2.wav",
+ "npc/zombie/foot_slide3.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if mathrandom() < 0.15 then
+ pl:EmitSound(ScuffSounds[mathrandom(#ScuffSounds)], 70)
+ else
+ pl:EmitSound(StepSounds[mathrandom(#StepSounds)], 70)
+ end
+
+ return true
+end
+
+function CLASS:PlayerStepSoundTime(pl, iType, bWalking)
+ if iType == STEPSOUNDTIME_NORMAL or iType == STEPSOUNDTIME_WATER_FOOT then
+ return 625 - pl:GetVelocity():Length()
+ elseif iType == STEPSOUNDTIME_ON_LADDER then
+ return 600
+ elseif iType == STEPSOUNDTIME_WATER_KNEE then
+ return 750
+ end
+
+ return 450
+end
+
+function CLASS:KnockedDown(pl, status, exists)
+ pl:AnimResetGestureSlot(GESTURE_SLOT_ATTACK_AND_RELOAD)
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ if feign:GetDirection() == DIR_BACK then
+ pl.CalcSeqOverride = pl:LookupSequence("zombie_slump_rise_02_fast")
+ else
+ pl.CalcIdeal = ACT_HL2MP_ZOMBIE_SLUMP_RISE
+ end
+ return true
+ end
+
+ if pl:WaterLevel() >= 3 then
+ pl.CalcIdeal = ACT_HL2MP_SWIM_PISTOL
+ return true
+ end
+
+ if velocity:Length2D() <= 0.5 then
+ if pl:Crouching() then
+ pl.CalcIdeal = ACT_HL2MP_IDLE_CROUCH_ZOMBIE
+ else
+ pl.CalcIdeal = ACT_HL2MP_IDLE_ZOMBIE
+ end
+ elseif pl:Crouching() then
+ pl.CalcIdeal = ACT_HL2MP_WALK_CROUCH_ZOMBIE_01 - 1 + math.ceil((CurTime() / 4 + pl:EntIndex()) % 3)
+ else
+ pl.CalcIdeal = ACT_HL2MP_WALK_ZOMBIE_01 - 1 + math.ceil((CurTime() / 4 + pl:EntIndex()) % 3)
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ if feign:GetState() == 1 then
+ pl:SetCycle(1 - math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ else
+ pl:SetCycle(math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ end
+ pl:SetPlaybackRate(0)
+ return true
+ end
+
+ local len2d = velocity:Length2D()
+ if len2d > 0.5 then
+ pl:SetPlaybackRate(math.min(len2d / maxseqgroundspeed * 0.666, 3))
+ else
+ pl:SetPlaybackRate(1)
+ end
+
+ return true
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_GMOD_GESTURE_RANGE_ZOMBIE, true)
+ return ACT_INVALID
+ end
+end
+
+function CLASS:DoesntGiveFear(pl)
+ return pl.FeignDeath and pl.FeignDeath:IsValid()
+end
+
+--[[local function CreateFlesh(pl, damage, damagepos, damagedir)
+ damage = math.min(damage, 100)
+
+ pl:EmitSound("physics/body/body_medium_break"..math.random(2, 4)..".wav", 74, 125 - damage * 0.50)
+
+ if SERVER then
+ local damagepos = pl:LocalToWorld(damagepos)
+
+ for i=1, math.max(1, math.floor(damage / 15)) do
+ local ent = ents.Create("projectile_poisonflesh")
+ if ent:IsValid() then
+ local heading = (damagedir + VectorRand() * 0.3):GetNormalized()
+ ent:SetPos(damagepos + heading)
+ ent:SetOwner(pl)
+ ent:Spawn()
+ ent:SetTeamID(TEAM_UNDEAD)
+ local phys = ent:GetPhysicsObject()
+ if phys:IsValid() then
+ phys:Wake()
+ phys:SetVelocityInstantaneous(math.min(350, 16 + damage ^ math.Rand(1.15, 1.25)) * heading)
+ end
+ end
+ end
+ end
+end
+
+function CLASS:ProcessDamage(pl, dmginfo)
+ local attacker, damage = dmginfo:GetAttacker(), dmginfo:GetDamage()
+ if attacker ~= pl and damage >= 5 and damage < pl:Health() and CurTime() >= (pl.m_NextGhoulEmit or 0) then
+ pl.m_NextGhoulEmit = CurTime() + 0.25
+
+ local pos = pl:WorldToLocal(dmginfo:GetDamagePosition())
+ local norm = dmginfo:GetDamageForce():GetNormalized() * -1
+ timer.Simple(0, function()
+ if pl:IsValid() then
+ CreateFlesh(pl, damage, pos, norm)
+ end
+ end)
+ end
+end]]
+
+if SERVER then
+ function CLASS:AltUse(pl)
+ pl:StartFeignDeath()
+ end
+
+ --[[function CLASS:OnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo, assister)
+ local damage = dmginfo:GetDamage()
+ if damage >= 5 then
+ local pos = pl:WorldToLocal(dmginfo:GetDamagePosition())
+ local norm = dmginfo:GetDamageForce():GetNormalized() * -1
+ timer.Simple(0, function()
+ if pl:IsValid() then
+ CreateFlesh(pl, math.max(30, damage * 2), pos, norm)
+ end
+ end)
+ end
+ end]]
+end
+
+if not CLIENT then return end
+
+CLASS.Icon = "zombiesurvival/killicons/ghoul"
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/gore_child.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/gore_child.lua
new file mode 100644
index 0000000..6efe04e
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/gore_child.lua
@@ -0,0 +1,180 @@
+CLASS.Name = "Gore Child"
+CLASS.TranslationName = "class_gore_child"
+CLASS.Description = "description_gore_child"
+CLASS.Help = "controls_gore_child"
+
+CLASS.Wave = 0
+CLASS.Unlocked = true
+CLASS.Hidden = true
+
+CLASS.Health = 15
+CLASS.Speed = 120
+
+CLASS.Points = 0.5
+
+CLASS.CanTaunt = true
+
+CLASS.SWEP = "weapon_zs_gorechild"
+
+CLASS.Model = Model("models/vinrax/player/doll_player.mdl")
+
+CLASS.VoicePitch = 1.5
+
+CLASS.ModelScale = 0.4
+
+CLASS.Mass = 30
+CLASS.ViewOffset = DEFAULT_VIEW_OFFSET * CLASS.ModelScale
+CLASS.ViewOffsetDucked = DEFAULT_VIEW_OFFSET_DUCKED * CLASS.ModelScale
+CLASS.StepSize = 8
+CLASS.Hull = {Vector(-16, -16, 0) * CLASS.ModelScale, Vector(16, 16, 100) * CLASS.ModelScale}
+CLASS.HullDuck = {Vector(-16, -16, 0) * CLASS.ModelScale, Vector(16, 16, 60) * CLASS.ModelScale}
+
+CLASS.CanFeignDeath = true
+
+local mathrandom = math.random
+local StepLeftSounds = {
+ "npc/zombie/foot1.wav",
+ "npc/zombie/foot2.wav"
+}
+local StepRightSounds = {
+ "npc/zombie/foot2.wav",
+ "npc/zombie/foot3.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if iFoot == 0 then
+ pl:EmitSound(StepLeftSounds[mathrandom(#StepLeftSounds)], 55, 150)
+ else
+ pl:EmitSound(StepRightSounds[mathrandom(#StepRightSounds)], 55, 150)
+ end
+
+ return true
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ if feign:GetDirection() == DIR_BACK then
+ pl.CalcSeqOverride = pl:LookupSequence("zombie_slump_rise_02_fast")
+ else
+ pl.CalcIdeal = ACT_HL2MP_ZOMBIE_SLUMP_RISE
+ end
+ return true
+ end
+
+ if pl:WaterLevel() >= 3 then
+ pl.CalcIdeal = ACT_HL2MP_SWIM_PISTOL
+ elseif pl:Crouching() then
+ if velocity:Length2D() <= 0.5 then
+ pl.CalcIdeal = ACT_HL2MP_IDLE_CROUCH_ZOMBIE
+ else
+ pl.CalcIdeal = ACT_HL2MP_WALK_CROUCH_ZOMBIE_01 - 1 + math.ceil((CurTime() / 4 + pl:EntIndex()) % 3)
+ end
+ else
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local wep = pl:GetActiveWeapon()
+ if not wep:IsValid() or not wep.GetSwinging then return end
+
+ if wep:GetSwinging() then
+ if not pl.PlayingFZSwing then
+ pl.PlayingFZSwing = true
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_GMOD_GESTURE_RANGE_FRENZY)
+ end
+ elseif pl.PlayingFZSwing then
+ pl.PlayingFZSwing = false
+ pl:AnimResetGestureSlot(GESTURE_SLOT_ATTACK_AND_RELOAD)
+ end
+
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ if feign:GetState() == 1 then
+ pl:SetCycle(1 - math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ else
+ pl:SetCycle(math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ end
+ pl:SetPlaybackRate(0)
+ return true
+ end
+
+ local len2d = velocity:Length2D()
+ if len2d > 0.5 then
+ pl:SetPlaybackRate(math.min(len2d / maxseqgroundspeed, 3))
+ else
+ pl:SetPlaybackRate(1)
+ end
+
+ if velocity:Length2D() >= 16 then
+ pl:SetPlaybackRate(pl:GetPlaybackRate() * 1.5)
+ end
+
+ return true
+end
+
+function CLASS:PlayerStepSoundTime(pl, iType, bWalking)
+ return GAMEMODE.BaseClass.PlayerStepSoundTime(GAMEMODE.BaseClass, pl, iType, bWalking) * 0.5
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ return ACT_INVALID
+ end
+end
+
+function CLASS:DoesntGiveFear(pl)
+ return pl.FeignDeath and pl.FeignDeath:IsValid()
+end
+
+function CLASS:PlayPainSound(pl)
+ pl:EmitSound("ambient/creatures/teddy.wav", 65, math.random(140, 150))
+ pl.NextPainSound = CurTime() + 0.6
+
+ return true
+end
+
+function CLASS:PlayDeathSound(pl)
+ pl:EmitSound("ambient/voices/citizen_beaten"..math.random(5)..".wav", 70, math.random(140, 150))
+
+ return true
+end
+
+if SERVER then
+ function CLASS:OnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo)
+ pl:FakeDeath(pl:LookupSequence("death_0"..math.random(4)), self.ModelScale)
+
+ return true
+ end
+
+ function CLASS:PostOnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo)
+ pl:SetZombieClass(GAMEMODE.DefaultZombieClass)
+ end
+
+ function CLASS:AltUse(pl)
+ pl:StartFeignDeath()
+ end
+end
+
+--[[function CLASS:Move(pl, move)
+ local mypos = move:GetOrigin()
+
+ for _, ent in pairs(team.GetPlayers(TEAM_HUMAN)) do
+ local pos = ent:GetPos()
+ local dist = mypos:Distance(pos)
+ if dist <= 16 then
+ local dir = mypos - pos
+ dir.z = 0
+ dir:Normalize()
+ move:SetVelocity(move:GetVelocity() + FrameTime() * 400 * (1 - dist / 16) * dir)
+ end
+ end
+end]]
+
+if not CLIENT then return end
+
+function CLASS:ShouldDrawLocalPlayer(pl)
+ return true
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/headcrab.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/headcrab.lua
new file mode 100644
index 0000000..06c7d1c
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/headcrab.lua
@@ -0,0 +1,165 @@
+CLASS.Name = "Headcrab"
+CLASS.TranslationName = "class_headcrab"
+CLASS.Description = "description_headcrab"
+CLASS.Help = "controls_headcrab"
+
+CLASS.Model = Model("models/headcrabclassic.mdl")
+
+CLASS.Wave = 0
+CLASS.Unlocked = true
+
+CLASS.SWEP = "weapon_zs_headcrab"
+
+CLASS.Health = 40
+CLASS.Speed = 160
+CLASS.JumpPower = 100
+
+CLASS.NoFallDamage = true
+CLASS.NoFallSlowdown = true
+
+CLASS.Points = 2
+
+CLASS.Hull = {Vector(-12, -12, 0), Vector(12, 12, 18.1)}
+CLASS.HullDuck = {Vector(-12, -12, 0), Vector(12, 12, 18.1)}
+CLASS.ViewOffset = Vector(0, 0, 10)
+CLASS.ViewOffsetDucked = Vector(0, 0, 10)
+CLASS.StepSize = 8
+CLASS.CrouchedWalkSpeed = 1
+CLASS.Mass = 25
+
+CLASS.CantDuck = true
+
+CLASS.IsHeadcrab = true
+
+CLASS.PainSounds = {"NPC_HeadCrab.Pain"}
+CLASS.DeathSounds = {"NPC_HeadCrab.Die"}
+
+function CLASS:Move(pl, mv)
+ local wep = pl:GetActiveWeapon()
+ if wep.Move and wep:Move(mv) then
+ return true
+ end
+end
+
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ return true
+end
+
+function CLASS:ScalePlayerDamage(pl, hitgroup, dmginfo)
+ return true
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.GetBurrowTime then
+ local time = wep:GetBurrowTime()
+ if time > 0 then
+ pl.CalcSeqOverride = 11
+ return true
+ elseif time < 0 then
+ pl.CalcSeqOverride = 10
+ return true
+ end
+ end
+
+ if pl:OnGround() then
+ if velocity:Length2D() > 0.5 then
+ pl.CalcIdeal = ACT_RUN
+ else
+ pl.CalcSeqOverride = 1
+ end
+ elseif pl:WaterLevel() >= 3 then
+ pl.CalcSeqOverride = 6
+ else
+ pl.CalcSeqOverride = 5
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ pl:FixModelAngles(velocity)
+
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.GetBurrowTime then
+ local time = wep:GetBurrowTime()
+ if time ~= 0 then
+ pl:SetCycle(math.Clamp((math.abs(time) - CurTime()) / wep.BurrowTime, 0, 1))
+ pl:SetPlaybackRate(0)
+ return true
+ end
+ end
+
+ local seq = pl:GetSequence()
+ if seq == 5 then
+ if not pl.m_PrevFrameCycle then
+ pl.m_PrevFrameCycle = true
+ pl:SetCycle(0)
+ end
+
+ pl:SetPlaybackRate(1)
+
+ return true
+ elseif pl.m_PrevFrameCycle then
+ pl.m_PrevFrameCycle = nil
+ end
+
+ local len2d = velocity:Length2D()
+ if len2d > 0.5 then
+ pl:SetPlaybackRate(math.min(len2d / maxseqgroundspeed * 0.5, 2))
+ else
+ pl:SetPlaybackRate(1)
+ end
+
+ return true
+end
+
+function CLASS:DoesntGiveFear(pl)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.GetBurrowTime then
+ return wep:GetBurrowTime() > 0 and CurTime() > math.abs(wep:GetBurrowTime())
+ end
+end
+CLASS.NoDraw = CLASS.DoesntGiveFear
+
+function CLASS:ShouldDrawLocalPlayer(pl)
+ local wep = pl:GetActiveWeapon()
+ return wep:IsValid() and wep.GetBurrowTime and wep:GetBurrowTime() ~= 0
+end
+
+if SERVER then
+ function CLASS:AltUse(pl)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() then wep:Reload() end
+ end
+end
+
+if not CLIENT then return end
+
+CLASS.Icon = "zombiesurvival/killicons/headcrab"
+
+function CLASS:PrePlayerDraw(pl)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.GetBurrowTime and wep:GetBurrowTime() ~= 0 and CurTime() >= math.abs(wep:GetBurrowTime()) then
+ return true
+ end
+end
+
+function CLASS:CreateMove(pl, cmd)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.m_ViewAngles and wep.IsPouncing and wep:IsPouncing() then
+ local maxdiff = FrameTime() * 15
+ local mindiff = -maxdiff
+ local originalangles = wep.m_ViewAngles
+ local viewangles = cmd:GetViewAngles()
+
+ local diff = math.AngleDifference(viewangles.yaw, originalangles.yaw)
+ if diff > maxdiff or diff < mindiff then
+ viewangles.yaw = math.NormalizeAngle(originalangles.yaw + math.Clamp(diff, mindiff, maxdiff))
+ end
+
+ wep.m_ViewAngles = viewangles
+
+ cmd:SetViewAngles(viewangles)
+ end
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/poison_headcrab.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/poison_headcrab.lua
new file mode 100644
index 0000000..ffd7f56
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/poison_headcrab.lua
@@ -0,0 +1,142 @@
+CLASS.Name = "Poison Headcrab"
+CLASS.TranslationName = "class_poison_headcrab"
+CLASS.Description = "description_poison_headcrab"
+CLASS.Help = "controls_poison_headcrab"
+
+CLASS.Model = Model("models/headcrabblack.mdl")
+
+CLASS.Wave = 2 / 3
+CLASS.Threshold = 0.6
+
+CLASS.SWEP = "weapon_zs_poisonheadcrab"
+
+CLASS.Health = 70
+CLASS.Speed = 145
+CLASS.JumpPower = 100
+
+CLASS.NoFallDamage = true
+CLASS.NoFallSlowdown = true
+
+CLASS.IsHeadcrab = true
+
+CLASS.Points = 4
+
+CLASS.Hull = {Vector(-12, -12, 0), Vector(12, 12, 18.1)}
+CLASS.HullDuck = {Vector(-12, -12, 0), Vector(12, 12, 18.1)}
+CLASS.ViewOffset = Vector(0, 0, 10)
+CLASS.ViewOffsetDucked = Vector(0, 0, 10)
+CLASS.StepSize = 8
+CLASS.CrouchedWalkSpeed = 1
+CLASS.Mass = 40
+
+CLASS.CantDuck = true
+
+CLASS.PainSounds = {"NPC_BlackHeadcrab.Pain"}
+CLASS.DeathSounds = {"NPC_BlackHeadcrab.Die"}
+
+function CLASS:Move(pl, mv)
+ local wep = pl:GetActiveWeapon()
+ if wep.Move and wep:Move(mv) then
+ return true
+ end
+end
+
+function CLASS:ScalePlayerDamage(pl, hitgroup, dmginfo)
+ return true
+end
+
+local mathrandom = math.random
+local StepSounds = {
+ "npc/headcrab_poison/ph_step1.wav",
+ "npc/headcrab_poison/ph_step2.wav",
+ "npc/headcrab_poison/ph_step3.wav",
+ "npc/headcrab_poison/ph_step4.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ pl:EmitSound(StepSounds[mathrandom(#StepSounds)], 60)
+
+ return true
+end
+--[[function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ pl:EmitSound("NPC_BlackHeadcrab.Footstep")
+
+ return true
+end]]
+
+function CLASS:PlayerStepSoundTime(pl, iType, bWalking)
+ if iType == STEPSOUNDTIME_NORMAL or iType == STEPSOUNDTIME_WATER_FOOT then
+ return 285 - pl:GetVelocity():Length()
+ elseif iType == STEPSOUNDTIME_ON_LADDER then
+ return 200
+ elseif iType == STEPSOUNDTIME_WATER_KNEE then
+ return 280
+ end
+
+ return 175
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() then
+ if wep.ShouldPlayLeapAnimation and wep:ShouldPlayLeapAnimation() then
+ pl.CalcSeqOverride = 7
+ return true
+ elseif wep.IsGoingToSpit and wep:IsGoingToSpit() then
+ pl.CalcSeqOverride = 2
+ return true
+ end
+ end
+
+ if pl:OnGround() then
+ if velocity:Length2D() > 0.5 then
+ pl.CalcIdeal = ACT_RUN
+ else
+ pl.CalcSeqOverride = 4
+ end
+ else
+ pl.CalcSeqOverride = 6
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ pl:FixModelAngles(velocity)
+
+ local seq = pl:GetSequence()
+ if seq == 2 or seq == 7 then
+ pl:SetPlaybackRate(1)
+
+ if not pl.m_PrevFrameCycle then
+ pl.m_PrevFrameCycle = true
+ pl:SetCycle(0)
+ end
+
+ return true
+ elseif pl.m_PrevFrameCycle then
+ pl.m_PrevFrameCycle = nil
+ end
+end
+
+if not CLIENT then return end
+
+CLASS.Icon = "zombiesurvival/killicons/poisonheadcrab"
+
+function CLASS:CreateMove(pl, cmd)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.m_ViewAngles and (wep.IsLeaping and wep:IsLeaping() or wep.IsGoingToLeap and wep:IsGoingToLeap()) then
+ local maxdiff = FrameTime() * 15
+ local mindiff = -maxdiff
+ local originalangles = wep.m_ViewAngles
+ local viewangles = cmd:GetViewAngles()
+
+ local diff = math.AngleDifference(viewangles.yaw, originalangles.yaw)
+ if diff > maxdiff or diff < mindiff then
+ viewangles.yaw = math.NormalizeAngle(originalangles.yaw + math.Clamp(diff, mindiff, maxdiff))
+ end
+
+ wep.m_ViewAngles = viewangles
+
+ cmd:SetViewAngles(viewangles)
+ end
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/poison_zombie.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/poison_zombie.lua
new file mode 100644
index 0000000..8224162
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/poison_zombie.lua
@@ -0,0 +1,72 @@
+CLASS.Name = "Poison Zombie"
+CLASS.TranslationName = "class_poison_zombie"
+CLASS.Description = "description_poison_zombie"
+CLASS.Help = "controls_poison_zombie"
+
+CLASS.Model = Model("models/Zombie/Poison.mdl")
+
+CLASS.Wave = 2 / 3
+
+CLASS.Health = 400
+CLASS.Speed = 150
+CLASS.SWEP = "weapon_zs_poisonzombie"
+
+CLASS.Mass = DEFAULT_MASS * 1.5
+
+CLASS.Points = 7
+
+CLASS.PainSounds = {"NPC_PoisonZombie.Pain"}
+CLASS.DeathSounds = {"NPC_PoisonZombie.Die"}
+CLASS.VoicePitch = 0.6
+
+CLASS.ViewOffset = Vector(0, 0, 50)
+CLASS.Hull = {Vector(-16, -16, 0), Vector(16, 16, 64)}
+CLASS.HullDuck = {Vector(-16, -16, 0), Vector(16, 16, 35)}
+
+function CLASS:CalcMainActivity(pl, velocity)
+ if velocity:Length2D() <= 0.5 then
+ pl.CalcIdeal = ACT_IDLE
+ else
+ pl.CalcIdeal = ACT_WALK
+ end
+
+ return true
+end
+
+local mathrandom = math.random
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if iFoot == 0 and mathrandom(3) < 3 then
+ pl:EmitSound("NPC_PoisonZombie.FootstepRight")
+ else
+ pl:EmitSound("NPC_PoisonZombie.FootstepLeft")
+ end
+
+ return true
+end
+
+function CLASS:PlayerStepSoundTime(pl, iType, bWalking)
+ if iType == STEPSOUNDTIME_NORMAL or iType == STEPSOUNDTIME_WATER_FOOT then
+ return 365 - pl:GetVelocity():Length()
+ elseif iType == STEPSOUNDTIME_ON_LADDER then
+ return 300
+ elseif iType == STEPSOUNDTIME_WATER_KNEE then
+ return 450
+ end
+
+ return 150
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MELEE_ATTACK1, true)
+ return ACT_INVALID
+ end
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ pl:FixModelAngles(velocity)
+end
+
+if not CLIENT then return end
+
+CLASS.Icon = "zombiesurvival/killicons/poisonzombie"
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/special_willowisp.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/special_willowisp.lua
new file mode 100644
index 0000000..c0c03f9
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/special_willowisp.lua
@@ -0,0 +1,113 @@
+CLASS.Name = "Will O' Wisp"
+CLASS.TranslationName = "class_wilowisp"
+CLASS.Description = "description_wilowisp"
+
+CLASS.Health = 10000
+CLASS.Wave = 0
+CLASS.Threshold = 0
+CLASS.Model = Model("models/error.mdl")
+CLASS.Speed = 260
+CLASS.JumpPower = 0
+
+CLASS.PainSounds = {Sound("npc/scanner/photo1.wav")}
+CLASS.DeathSounds = {Sound("zombiesurvival/wraithdeath1.ogg"), Sound("zombiesurvival/wraithdeath2.ogg"), Sound("zombiesurvival/wraithdeath3.ogg"), Sound("zombiesurvival/wraithdeath4.ogg")}
+
+CLASS.Unlocked = true
+CLASS.Hidden = true
+
+CLASS.SWEP = "weapon_zs_special_wow"
+
+CLASS.Hull = {Vector(-3, -3, 0), Vector(3, 3, 6)}
+CLASS.HullDuck = {Vector(-3, -3, 0), Vector(3, 3, 6)}
+CLASS.ViewOffset = Vector(0, 0, 3)
+CLASS.ViewOffsetDucked = Vector(0, 0, 3)
+CLASS.CrouchedWalkSpeed = 1
+CLASS.Mass = 2
+CLASS.MoveType = MOVETYPE_FLY
+
+CLASS.NoGibs = true
+CLASS.NoCollideAll = true
+CLASS.NoFallDamage = true
+CLASS.NoFallSlowdown = true
+CLASS.Points = 0
+
+CLASS.CameraDistance = 64
+
+function CLASS:CanUse(pl)
+ return pl:SteamID() == "STEAM_0:1:3307510" or pl:SteamID() == "STEAM_0:0:4187062"
+end
+
+function CLASS:NoDeathMessage(pl, attacker, dmginfo)
+ return true
+end
+
+function CLASS:DoesntGiveFear()
+ return true
+end
+
+function CLASS:ScalePlayerDamage(pl, hitgroup, dmginfo)
+ dmginfo:SetDamage(0)
+ dmginfo:ScaleDamage(0)
+ return true
+end
+
+function CLASS:ShouldDrawLocalPlayer(pl)
+ return true
+end
+
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ return true
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ pl.CalcIdeal = ACT_IDLE
+ pl.CalcSeqOverride = -1
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ return true
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ return ACT_INVALID
+end
+
+function CLASS:Move(pl, mv)
+ pl:SetGroundEntity(NULL)
+
+ mv:SetForwardSpeed(0)
+ mv:SetSideSpeed(0)
+
+ local vel = mv:GetVelocity()
+
+ if pl:KeyDown(IN_FORWARD) then
+ vel = vel + 180 * FrameTime() * pl:GetAimVector()
+ elseif pl:KeyDown(IN_BACK) then
+ vel = vel - 180 * FrameTime() * pl:GetAimVector()
+ else
+ vel = vel * math.max(1 - FrameTime() * 0.5, 0)
+ end
+
+ if vel:Length() >= self.Speed then
+ vel:Normalize()
+ vel = vel * self.Speed
+ end
+
+ mv:SetVelocity(vel)
+
+ return true
+end
+
+function CLASS:OnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo)
+ return true
+end
+
+if not CLIENT then return end
+
+CLASS.Icon = "sprites/glow04_noz"
+
+function CLASS:PrePlayerDraw(pl)
+ return true
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/super_zombie.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/super_zombie.lua
new file mode 100644
index 0000000..fc6f81f
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/super_zombie.lua
@@ -0,0 +1,51 @@
+CLASS.Name = "Super Zombie"
+CLASS.TranslationName = "class_super_zombie"
+CLASS.Base = "freshdead"
+
+CLASS.Health = 1500
+CLASS.Speed = SPEED_ZOMBIEESCAPE_ZOMBIE
+CLASS.Points = 5
+
+CLASS.SWEP = "weapon_zs_superzombie"
+
+CLASS.UsePlayerModel = true
+CLASS.UsePreviousModel = false
+CLASS.NoFallDamage = true
+
+if SERVER then
+ function CLASS:OnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo) end
+end
+
+function CLASS:Move(pl, mv)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.Move and wep:Move(mv) then
+ return true
+ end
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.GetClimbing and wep:GetClimbing() then
+ pl.CalcIdeal = ACT_ZOMBIE_CLIMB_UP
+ return true
+ end
+
+ return self.BaseClass.CalcMainActivity(self, pl, velocity)
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.GetClimbing and wep:GetClimbing() then
+ local vel = pl:GetVelocity()
+ local speed = vel:Length()
+ if speed > 8 then
+ pl:SetPlaybackRate(math.Clamp(speed / 60, 0, 1) * (vel.z < 0 and -1 or 1) * 0.25)
+ else
+ pl:SetPlaybackRate(0)
+ end
+
+ return true
+ end
+
+ return self.BaseClass.UpdateAnimation(self, pl, velocity, maxseqgroundspeed)
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/wraith.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/wraith.lua
new file mode 100644
index 0000000..9a8ad79
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/wraith.lua
@@ -0,0 +1,132 @@
+CLASS.Name = "Wraith"
+CLASS.TranslationName = "class_wraith"
+CLASS.Description = "description_wraith"
+CLASS.Help = "controls_wraith"
+
+CLASS.Wave = 1 / 3
+CLASS.Health = 100
+CLASS.SWEP = "weapon_zs_wraith"
+CLASS.Model = Model("models/wraith_zsv1.mdl")
+CLASS.Speed = 190
+
+CLASS.Points = 4
+
+CLASS.VoicePitch = 0.65
+
+CLASS.PainSounds = {Sound("npc/barnacle/barnacle_pull1.wav"), Sound("npc/barnacle/barnacle_pull2.wav"), Sound("npc/barnacle/barnacle_pull3.wav"), Sound("npc/barnacle/barnacle_pull4.wav")}
+CLASS.DeathSounds = {Sound("zombiesurvival/wraithdeath1.ogg"), Sound("zombiesurvival/wraithdeath2.ogg"), Sound("zombiesurvival/wraithdeath3.ogg"), Sound("zombiesurvival/wraithdeath4.ogg")}
+
+CLASS.NoShadow = true
+
+--CLASS.GhostSpeed = 35
+
+function CLASS:Move(pl, move)
+ --[[if pl:GetBarricadeGhosting() then
+ move:SetMaxSpeed(self.GhostSpeed)
+ move:SetMaxClientSpeed(self.GhostSpeed)
+ end]]
+
+ if pl:KeyDown(IN_SPEED) then
+ move:SetMaxSpeed(50)
+ move:SetMaxClientSpeed(50)
+ end
+end
+
+--[[function CLASS:GetJumpPower(pl)
+ return pl:IsBarricadeGhosting() and 0 or DEFAULT_JUMP_POWER
+end
+
+function CLASS:SwitchedAway(pl)
+ pl:SetBarricadeGhosting(false)
+end]]
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.IsAttacking and wep:IsAttacking() then
+ pl.CalcSeqOverride = 10
+ elseif velocity:Length2D() > 0.5 then
+ pl.CalcSeqOverride = 3
+ else
+ pl.CalcSeqOverride = 1
+ end
+
+ return true
+end
+
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ return true
+end
+
+function CLASS:ScalePlayerDamage(pl, hitgroup, dmginfo)
+ --[[if pl:IsBarricadeGhosting() then
+ dmginfo:SetDamage(dmginfo:GetDamage() * 1.5)
+ end]]
+
+ -- The Wraith model doesn't have hitboxes.
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ pl:FixModelAngles(velocity)
+
+ local seq = pl:GetSequence()
+ if seq == 10 then
+ if not pl.m_PrevFrameCycle then
+ pl.m_PrevFrameCycle = true
+ pl:SetCycle(0)
+ end
+ elseif pl.m_PrevFrameCycle then
+ pl.m_PrevFrameCycle = nil
+ end
+end
+
+function CLASS:GetAlpha(pl)
+ local wep = pl:GetActiveWeapon()
+ if not wep.IsAttacking then wep = NULL end
+
+ if wep:IsValid() and wep:IsAttacking() then
+ return 0.7
+ elseif MySelf:IsValid() and MySelf:Team() == TEAM_UNDEAD then
+ local eyepos = EyePos()
+ return math.Clamp(pl:GetVelocity():Length() - pl:NearestPoint(eyepos):Distance(eyepos) * 0.5, 35, 180) / 255
+ else
+ local eyepos = EyePos()
+ return math.Clamp(pl:GetVelocity():Length() - pl:NearestPoint(eyepos):Distance(eyepos) * 0.5, 0, 180) / 255
+ end
+end
+
+function CLASS:OnKilled(pl, attacker, inflictor, suicide, headshot, dmginfo, assister)
+ if SERVER then
+ local effectdata = EffectData()
+ effectdata:SetOrigin(pl:GetPos())
+ effectdata:SetNormal(pl:GetForward())
+ effectdata:SetEntity(pl)
+ util.Effect("wraithdeath", effectdata, nil, true)
+ end
+
+ return true
+end
+
+if not CLIENT then return end
+
+CLASS.Icon = "zombiesurvival/killicons/wraithv2"
+
+function CLASS:PrePlayerDraw(pl)
+ pl:RemoveAllDecals()
+
+ --[[if pl:GetBarricadeGhosting() then
+ render.SetBlend(0.7)
+ render.SetColorModulation(1, 1, 5)
+ else]]
+ local alpha = self:GetAlpha(pl)
+ if alpha == 0 then return true end
+
+ render.SetBlend(alpha)
+ render.SetColorModulation(0.3, 0.3, 0.3)
+ --end
+end
+
+function CLASS:PostPlayerDraw(pl)
+ render.SetColorModulation(1, 1, 1)
+ render.SetBlend(1)
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/zombie.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/zombie.lua
new file mode 100644
index 0000000..5e7b4c8
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/zombie.lua
@@ -0,0 +1,239 @@
+CLASS.Name = "Zombie"
+CLASS.TranslationName = "class_zombie"
+CLASS.Description = "description_zombie"
+CLASS.Help = "controls_zombie"
+
+CLASS.Wave = 0
+CLASS.Unlocked = true
+CLASS.IsDefault = true
+CLASS.Order = 0
+
+CLASS.Health = 200
+CLASS.Speed = 140
+CLASS.Revives = true
+
+CLASS.CanTaunt = true
+
+CLASS.Points = 5
+
+CLASS.SWEP = "weapon_zs_zombie"
+
+CLASS.Model = Model("models/player/zombie_classic.mdl")
+
+CLASS.PainSounds = {"npc/zombie/zombie_pain1.wav", "npc/zombie/zombie_pain2.wav", "npc/zombie/zombie_pain3.wav", "npc/zombie/zombie_pain4.wav", "npc/zombie/zombie_pain5.wav", "npc/zombie/zombie_pain6.wav"}
+CLASS.DeathSounds = {"npc/zombie/zombie_die1.wav", "npc/zombie/zombie_die2.wav", "npc/zombie/zombie_die3.wav"}
+
+CLASS.VoicePitch = 0.65
+
+CLASS.CanFeignDeath = true
+
+function CLASS:KnockedDown(pl, status, exists)
+ pl:AnimResetGestureSlot(GESTURE_SLOT_ATTACK_AND_RELOAD)
+end
+
+local mathrandom = math.random
+local StepSounds = {
+ "npc/zombie/foot1.wav",
+ "npc/zombie/foot2.wav",
+ "npc/zombie/foot3.wav"
+}
+local ScuffSounds = {
+ "npc/zombie/foot_slide1.wav",
+ "npc/zombie/foot_slide2.wav",
+ "npc/zombie/foot_slide3.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if mathrandom() < 0.15 then
+ pl:EmitSound(ScuffSounds[mathrandom(#ScuffSounds)], 70)
+ else
+ pl:EmitSound(StepSounds[mathrandom(#StepSounds)], 70)
+ end
+
+ return true
+end
+
+-- Sound scripts are LITERALLY 100x slower than raw file input. Test it yourself if you don't believe me.
+--[[function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if iFoot == 0 then
+ if mathrandom() < 0.15 then
+ pl:EmitSound("Zombie.ScuffLeft")
+ else
+ pl:EmitSound("Zombie.FootstepLeft")
+ end
+ else
+ if mathrandom() < 0.15 then
+ pl:EmitSound("Zombie.ScuffRight")
+ else
+ pl:EmitSound("Zombie.FootstepRight")
+ end
+ end
+
+ return true
+end]]
+
+function CLASS:PlayerStepSoundTime(pl, iType, bWalking)
+ if iType == STEPSOUNDTIME_NORMAL or iType == STEPSOUNDTIME_WATER_FOOT then
+ return 625 - pl:GetVelocity():Length()
+ elseif iType == STEPSOUNDTIME_ON_LADDER then
+ return 600
+ elseif iType == STEPSOUNDTIME_WATER_KNEE then
+ return 750
+ end
+
+ return 450
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local revive = pl.Revive
+ if revive and revive:IsValid() then
+ pl.CalcIdeal = ACT_HL2MP_ZOMBIE_SLUMP_RISE
+ return true
+ end
+
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ if feign:GetDirection() == DIR_BACK then
+ pl.CalcSeqOverride = pl:LookupSequence("zombie_slump_rise_02_fast")
+ else
+ pl.CalcIdeal = ACT_HL2MP_ZOMBIE_SLUMP_RISE
+ end
+ return true
+ end
+
+ if pl:WaterLevel() >= 3 then
+ pl.CalcIdeal = ACT_HL2MP_SWIM_PISTOL
+ return true
+ end
+
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.IsMoaning and wep:IsMoaning() then
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE
+ elseif velocity:Length2D() <= 0.5 then
+ if pl:Crouching() then
+ pl.CalcIdeal = ACT_HL2MP_IDLE_CROUCH_ZOMBIE
+ else
+ pl.CalcIdeal = ACT_HL2MP_IDLE_ZOMBIE
+ end
+ elseif pl:Crouching() then
+ pl.CalcIdeal = ACT_HL2MP_WALK_CROUCH_ZOMBIE_01 - 1 + math.ceil((CurTime() / 4 + pl:EntIndex()) % 3)
+ else
+ pl.CalcIdeal = ACT_HL2MP_WALK_ZOMBIE_01 - 1 + math.ceil((CurTime() / 4 + pl:EntIndex()) % 3)
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local revive = pl.Revive
+ if revive and revive:IsValid() then
+ pl:SetCycle(0.4 + (1 - math.Clamp((revive:GetReviveTime() - CurTime()) / revive.AnimTime, 0, 1)) * 0.6)
+ pl:SetPlaybackRate(0)
+ return true
+ end
+
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ if feign:GetState() == 1 then
+ pl:SetCycle(1 - math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ else
+ pl:SetCycle(math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ end
+ pl:SetPlaybackRate(0)
+ return true
+ end
+
+ local len2d = velocity:Length2D()
+ if len2d > 0.5 then
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and wep.IsMoaning and wep:IsMoaning() then
+ pl:SetPlaybackRate(math.min(len2d / maxseqgroundspeed, 3))
+ else
+ pl:SetPlaybackRate(math.min(len2d / maxseqgroundspeed * 0.666, 3))
+ end
+ else
+ pl:SetPlaybackRate(1)
+ end
+
+ return true
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_GMOD_GESTURE_RANGE_ZOMBIE, true)
+ return ACT_INVALID
+ end
+end
+
+function CLASS:DoesntGiveFear(pl)
+ return pl.FeignDeath and pl.FeignDeath:IsValid()
+end
+
+if SERVER then
+ function CLASS:AltUse(pl)
+ pl:StartFeignDeath()
+ end
+
+ function CLASS:ProcessDamage(pl, dmginfo)
+ local attacker, inflictor, damage = dmginfo:GetAttacker(), dmginfo:GetInflictor(), dmginfo:GetDamage()
+ if attacker ~= pl and damage >= pl:Health() and pl:LastHitGroup() ~= HITGROUP_HEAD and damage < 70 and not inflictor.IsMelee and not inflictor.NoReviveFromKills and dmginfo:GetDamageType() ~= DMG_BLAST and dmginfo:GetDamageType() ~= DMG_BURN and dmginfo:GetDamageType() ~= DMG_CRUSH and (pl.NextZombieRevive or 0) <= CurTime() and pl:LastHitGroup() ~= HITGROUP_LEFTLEG and pl:LastHitGroup() ~= HITGROUP_RIGHTLEG then
+ pl.NextZombieRevive = CurTime() + 3
+
+ dmginfo:SetDamage(0)
+ pl:SetHealth(10)
+
+ local status = pl:GiveStatus("revive_slump")
+ if status then
+ status:SetReviveTime(CurTime() + 2.25)
+ end
+
+ return true
+ end
+ end
+
+ function CLASS:ReviveCallback(pl, attacker, dmginfo)
+ if not pl.Revive and not dmginfo:GetInflictor().IsMelee and not dmginfo:GetInflictor().NoReviveFromKills and dmginfo:GetDamageType() ~= DMG_BLAST and dmginfo:GetDamageType() ~= DMG_BURN and (pl:LastHitGroup() == HITGROUP_LEFTLEG or pl:LastHitGroup() == HITGROUP_RIGHTLEG) then
+ local classtable = math.random(1) == 3 and GAMEMODE.ZombieClasses["Zombie Legs"] or GAMEMODE.ZombieClasses["Zombie Torso"]
+ if classtable then
+ pl:RemoveStatus("overridemodel", false, true)
+ local deathclass = pl.DeathClass or pl:GetZombieClass()
+ pl:SetZombieClass(classtable.Index)
+ pl:DoHulls(classtable.Index, TEAM_UNDEAD)
+ pl.DeathClass = deathclass
+
+ pl:EmitSound("physics/flesh/flesh_bloody_break.wav", 100, 75)
+
+ if classtable == GAMEMODE.ZombieClasses["Zombie Torso"] then
+ local ent = ents.Create("prop_dynamic_override")
+ if ent:IsValid() then
+ ent:SetModel(Model("models/Zombie/Classic_legs.mdl"))
+ ent:SetPos(pl:GetPos())
+ ent:SetAngles(pl:GetAngles())
+ ent:Spawn()
+ ent:Fire("kill", "", 1.5)
+ end
+ end
+
+ pl:Gib()
+ pl.Gibbed = nil
+
+ timer.Simple(0, function()
+ if pl:IsValid() then
+ pl:SecondWind()
+ end
+ end)
+
+ return true
+ end
+ end
+
+ return false
+ end
+
+ function CLASS:OnSecondWind(pl)
+ pl:EmitSound("npc/zombie/zombie_voice_idle"..math.random(1, 14)..".wav", 100, 85)
+ end
+end
+
+if CLIENT then
+ CLASS.Icon = "zombiesurvival/killicons/zombie"
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/zombie_legs.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/zombie_legs.lua
new file mode 100644
index 0000000..45855b1
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/zombie_legs.lua
@@ -0,0 +1,222 @@
+CLASS.Name = "Zombie Legs"
+CLASS.TranslationName = "class_zombie_legs"
+CLASS.Description = "description_zombie_legs"
+
+CLASS.Model = Model("models/player/zombie_classic.mdl")
+CLASS.NoHead = true
+
+CLASS.Wave = 0
+CLASS.Threshold = 0
+CLASS.Unlocked = true
+CLASS.Hidden = true
+
+CLASS.Health = 100
+CLASS.Speed = 170
+CLASS.JumpPower = 250
+
+CLASS.Points = 1
+
+CLASS.Hull = {Vector(-16, -16, 0), Vector(16, 16, 32)}
+CLASS.HullDuck = {Vector(-16, -16, 0), Vector(16, 16, 32)}
+CLASS.ViewOffset = Vector(0, 0, 32)
+CLASS.ViewOffsetDucked = Vector(0, 0, 32)
+CLASS.Mass = DEFAULT_MASS * 0.5
+CLASS.CrouchedWalkSpeed = 1
+
+CLASS.CantDuck = true
+
+CLASS.CanFeignDeath = true
+
+CLASS.VoicePitch = 0.65
+
+CLASS.SWEP = "weapon_zs_zombielegs"
+
+if SERVER then
+ function CLASS:OnSpawned(pl)
+ local status = pl:GiveStatus("overridemodel")
+ if status and status:IsValid() then
+ status:SetModel("models/Zombie/Classic_legs.mdl")
+ end
+ end
+
+ function CLASS:AltUse(pl)
+ local feigndeath = pl.FeignDeath
+ if feigndeath and feigndeath:IsValid() then
+ if CurTime() >= feigndeath:GetStateEndTime() then
+ feigndeath:SetState(1)
+ feigndeath:SetStateEndTime(CurTime() + 1.5)
+ end
+ elseif pl:IsOnGround() and not pl:KeyDown(IN_FORWARD) and not pl:KeyDown(IN_MOVERIGHT) and not pl:KeyDown(IN_MOVELEFT) and not pl:KeyDown(IN_BACK) then
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() and not wep:IsSwinging() and CurTime() > wep:GetNextPrimaryFire() then
+ local status = pl:GiveStatus("feigndeath")
+ if status and status:IsValid() then
+ status:SetStateEndTime(CurTime() + 1.5)
+ end
+ end
+ end
+ end
+end
+
+--[[function CLASS:ScalePlayerDamage(pl, hitgroup, dmginfo)
+ --if hitgroup ~= HITGROUP_LEFTLEG and hitgroup ~= HITGROUP_RIGHTLEG and hitgroup ~= HITGROUP_GEAR and hitgroup ~= HITGROUP_GENERIC then
+ if dmginfo:GetDamagePosition().z > pl:GetPos().z + 48 then
+ dmginfo:SetDamage(0)
+ dmginfo:ScaleDamage(0)
+ end
+
+ return true
+end]]
+
+function CLASS:Move(pl, mv)
+ local wep = pl:GetActiveWeapon()
+ if wep.Move and wep:Move(mv) then
+ return true
+ end
+end
+
+function CLASS:ShouldDrawLocalPlayer(pl)
+ return true
+end
+
+local mathrandom = math.random
+local StepSounds = {
+ "npc/zombie/foot1.wav",
+ "npc/zombie/foot2.wav",
+ "npc/zombie/foot3.wav"
+}
+local ScuffSounds = {
+ "npc/zombie/foot_slide1.wav",
+ "npc/zombie/foot_slide2.wav",
+ "npc/zombie/foot_slide3.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if mathrandom() < 0.15 then
+ pl:EmitSound(ScuffSounds[mathrandom(#ScuffSounds)], 70)
+ else
+ pl:EmitSound(StepSounds[mathrandom(#StepSounds)], 70)
+ end
+
+ return true
+end
+--[[function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if iFoot == 0 then
+ if mathrandom() < 0.15 then
+ pl:EmitSound("Zombie.ScuffLeft")
+ else
+ pl:EmitSound("Zombie.FootstepLeft")
+ end
+ else
+ if mathrandom() < 0.15 then
+ pl:EmitSound("Zombie.ScuffRight")
+ else
+ pl:EmitSound("Zombie.FootstepRight")
+ end
+ end
+
+ return true
+end]]
+
+function CLASS:PlayerStepSoundTime(pl, iType, bWalking)
+ if iType == STEPSOUNDTIME_NORMAL or iType == STEPSOUNDTIME_WATER_FOOT then
+ return 625 - pl:GetVelocity():Length()
+ elseif iType == STEPSOUNDTIME_ON_LADDER then
+ return 600
+ elseif iType == STEPSOUNDTIME_WATER_KNEE then
+ return 750
+ end
+
+ return 450
+end
+
+function CLASS:CalcMainActivity(pl, velocity)
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ pl.CalcSeqOverride = pl:LookupSequence("zombie_slump_rise_02_fast")
+ elseif velocity:Length2D() <= 0.5 then
+ pl.CalcIdeal = ACT_HL2MP_IDLE_ZOMBIE
+ else
+ pl.CalcIdeal = ACT_HL2MP_RUN_ZOMBIE
+ end
+
+ return true
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ local feign = pl.FeignDeath
+ if feign and feign:IsValid() then
+ if feign:GetState() == 1 then
+ pl:SetCycle(1 - math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ else
+ pl:SetCycle(math.max(feign:GetStateEndTime() - CurTime(), 0) * 0.666)
+ end
+ pl:SetPlaybackRate(0)
+
+ return true
+ end
+
+ local len2d = velocity:Length2D()
+ if len2d > 0.5 then
+ pl:SetPlaybackRate(math.min(len2d / maxseqgroundspeed * 0.75, 3))
+ else
+ pl:SetPlaybackRate(1)
+ end
+
+ return true
+end
+
+if not CLIENT then return end
+
+CLASS.Icon = "zombiesurvival/killicons/legs"
+
+-- This whole point of this is to stop drawing decals on the upper part of the model. It doesn't actually do anything to the visible model.
+local undo = false
+function CLASS:PrePlayerDraw(pl)
+ local boneid = pl:LookupBone("ValveBiped.Bip01_Spine")
+ if boneid and boneid > 0 then
+ local pos, ang = pl:GetBonePosition(boneid)
+ if pos then
+ local normal = ang:Forward() * -1
+ render.EnableClipping(true)
+ render.PushCustomClipPlane(normal, normal:Dot(pos))
+ undo = true
+ end
+ end
+end
+
+function CLASS:PostPlayerDraw(pl)
+ if undo then
+ render.PopCustomClipPlane()
+ render.EnableClipping(false)
+ end
+end
+
+function CLASS:BuildBonePositions(pl)
+ local desired
+
+ local bone = "ValveBiped.Bip01_L_Thigh"
+
+ local wep = pl:GetActiveWeapon()
+ if wep:IsValid() then
+ if wep.GetSwingEndTime and wep:GetSwingEndTime() > 0 then
+ desired = 1 - math.Clamp((wep:GetSwingEndTime() - CurTime()) / wep.MeleeDelay, 0, 1)
+ end
+
+ if wep:GetDTBool(3) then
+ bone = "ValveBiped.Bip01_R_Thigh"
+ end
+ end
+
+ desired = desired or 0
+
+ if desired > 0 then
+ pl.m_KickDelta = CosineInterpolation(0, 1, desired)
+ else
+ pl.m_KickDelta = math.Approach(pl.m_KickDelta or 0, desired, FrameTime() * 4)
+ end
+
+ local boneid = pl:LookupBone(bone)
+ if boneid and boneid > 0 then
+ pl:ManipulateBoneAngles(boneid, pl.m_KickDelta * Angle(bone == "ValveBiped.Bip01_L_Thigh" and 0 or 20, -110, 30))
+ end
+end
diff --git a/gamemodes/zombiesurvival/gamemode/zombieclasses/zombie_torso.lua b/gamemodes/zombiesurvival/gamemode/zombieclasses/zombie_torso.lua
new file mode 100644
index 0000000..f2f580e
--- /dev/null
+++ b/gamemodes/zombiesurvival/gamemode/zombieclasses/zombie_torso.lua
@@ -0,0 +1,78 @@
+CLASS.Name = "Zombie Torso"
+CLASS.TranslationName = "class_zombie_torso"
+CLASS.Description = "description_zombie_torso"
+
+CLASS.Model = Model("models/Zombie/Classic_torso.mdl")
+
+CLASS.SWEP = "weapon_zs_zombietorso"
+
+CLASS.Wave = 0
+CLASS.Threshold = 0
+CLASS.Unlocked = true
+CLASS.Hidden = true
+
+CLASS.Health = 100
+CLASS.Speed = 130
+CLASS.JumpPower = 120
+
+CLASS.Points = 1
+
+CLASS.Hull = {Vector(-16, -16, 0), Vector(16, 16, 20)}
+CLASS.HullDuck = {Vector(-16, -16, 0), Vector(16, 16, 20)}
+CLASS.ViewOffset = Vector(0, 0, 14)
+CLASS.ViewOffsetDucked = Vector(0, 0, 14)
+CLASS.Mass = DEFAULT_MASS * 0.5
+CLASS.CrouchedWalkSpeed = 1
+CLASS.StepSize = 12
+
+CLASS.CantDuck = true
+
+CLASS.PainSounds = {"npc/zombie/zombie_pain1.wav", "npc/zombie/zombie_pain2.wav", "npc/zombie/zombie_pain3.wav", "npc/zombie/zombie_pain4.wav", "npc/zombie/zombie_pain5.wav", "npc/zombie/zombie_pain6.wav"}
+CLASS.DeathSounds = {"npc/zombie/zombie_die1.wav", "npc/zombie/zombie_die2.wav", "npc/zombie/zombie_die3.wav"}
+
+CLASS.VoicePitch = 0.65
+
+function CLASS:CalcMainActivity(pl, velocity)
+ if velocity:Length2D() <= 0.5 then
+ pl.CalcSeqOverride = 1
+ else
+ pl.CalcIdeal = ACT_WALK
+ end
+
+ return true
+end
+
+local mathrandom = math.random
+local ScuffSounds = {
+ "npc/zombie/foot_slide1.wav",
+ "npc/zombie/foot_slide2.wav",
+ "npc/zombie/foot_slide3.wav"
+}
+function CLASS:PlayerFootstep(pl, vFootPos, iFoot, strSoundName, fVolume, pFilter)
+ if mathrandom() < 0.07 then
+ pl:EmitSound(ScuffSounds[mathrandom(#ScuffSounds)], 70, 90)
+ end
+
+ return true
+end
+
+function CLASS:DoAnimationEvent(pl, event, data)
+ if event == PLAYERANIMEVENT_ATTACK_PRIMARY then
+ pl:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MELEE_ATTACK1, true)
+ return ACT_INVALID
+ end
+end
+
+function CLASS:UpdateAnimation(pl, velocity, maxseqgroundspeed)
+ pl:FixModelAngles(velocity)
+end
+
+if SERVER then
+ function CLASS:OnSecondWind(pl)
+ pl:EmitSound("npc/zombie/zombie_voice_idle"..math.random(1, 14)..".wav", 100, 85)
+ end
+end
+
+if CLIENT then
+ CLASS.Icon = "zombiesurvival/killicons/torso"
+end
diff --git a/gamemodes/zombiesurvival/icon24.png b/gamemodes/zombiesurvival/icon24.png
new file mode 100644
index 0000000..1feebe6
Binary files /dev/null and b/gamemodes/zombiesurvival/icon24.png differ
diff --git a/gamemodes/zombiesurvival/license.txt b/gamemodes/zombiesurvival/license.txt
new file mode 100644
index 0000000..550a88b
--- /dev/null
+++ b/gamemodes/zombiesurvival/license.txt
@@ -0,0 +1,50 @@
+JBGM LICENSE
+
+VERSION Xx420xX2, 5 January 2014
+
+Copyright © 2013 William Moodhe
+
+Anyone is allowed to copy, upload, or distribute copies of this license, but changing it is not allowed.
+
+Preamble
+
+The GNU license was garbage so I made my own. If you don't like it then feel free to delete the gamemode.
+A good portion of people have seen fit to modify stuff I've made, make it so people can "donate" for premium features, and subsequently generate revenue using things that I and others have created without permission. Then they ban members of my Steam groups, DDoS my own servers, openly insult me despite never having talked to me, and be jerks in general.
+
+So I will be issuing DMCA take down notices to server hosts and others who think that I'm joking. Server hosts have typically sided with me during the few times I've needed to do this. I don't plan on being 'that guy' and going after gmod servers trying to stay alive but I do plan on weeding out a few of the bigger jerks out there.
+
+tl;dr - I won't screw with you if you don't screw with me.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+TERMS AND CONDITIONS
+
+0. Definitions
+
+"License" refers to this file. An updated version is available at . The version at is always correct and up-to-date.
+
+"Author" refers to the person William Moodhe
+
+"Content" refers to all files and folders that the license came with as well as the intellectual property and all derivitive works.
+
+"Copyright" refers to the laws on intellectual property and the legal rights automatically granted to the Author during the creation of the Content.
+
+"Modify" refers to editing the Content as well as creating programs or code which depends on the Content to run. For the purpose of this license, deleting things without deleting the entire Content is ALSO considered editing.
+
+1. For any conditions not outlined in the License, refer to your country or state laws for Copyright.
+[Host your server in Russia.]
+
+2. You may freely copy, distribute, create derivitive works and distribute derivitive works of the Content as long as you obey the License and the License is not Modified.
+[Feel free to make edits.]
+
+3. You will not Modify the Content in such a way that it will, directly or indirectly, generate revenue without explicit, written permission from the Author.
+[For example: making it so you can pay to have extra health, points, speed, etc.]
+
+4. You will not deny access to the Author to anything in such a way that it would not allow the Author to see if the Gamemode was Modified.
+[For example: banning my Steam groups from your server.]
+
+5. You will not host, distribute, Modify, or otherwise copy the Content if you are affiliated with HeLLsGamers .
+
+6. If you do not agree to any of the above conditions you must delete the Content in its entirety as well as all copies of the Content and derivitive works of the Content that you have made.
+
+END TERMS AND CONDITIONS
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/mapping and new entities.txt b/gamemodes/zombiesurvival/mapping and new entities.txt
new file mode 100644
index 0000000..923649b
--- /dev/null
+++ b/gamemodes/zombiesurvival/mapping and new entities.txt
@@ -0,0 +1,206 @@
+Zombie Survival also sports powerful new entities that let you change the game around. Check out some of the zs_obj_ maps for examples.
+This might not be updated so it's always best to check this: http://www.noxiousnet.com/forums/index.php?topic=2373.0 since this is basically a copy-paste.
+
+ ====================
+ = IMPORTANT THINGS =
+ ====================
+
+* The filter by team ID's for filter_team are: Zombie: 3 and Human: 4.
+* Non-ZS weapons are removed from the map when it starts.
+* prop_door_rotating is breakable and can be torn off their hinges. Locked doors are invulnerable!
+* func_door_rotating is breakable as long as the brush is as small as a door is.
+* func_physbox are BREAKABLE no matter what.
+* item_ammo_crate is removed from the map when it starts.
+* People on the same team do not collide with each other.
+* Having _obj_ or objective in the map name automatically turns off dynamic zombie spawning. You can use logic_dynamicspawning to manually turn it back on.
+* The game automatically chooses the spawn point closest to the average position of all humans.
+
+ =======================
+ = TIPS AND GUIDELINES =
+ =======================
+
+* Never add secret rooms to your map. This isn't Zombie-Strike: Fullbright and you will only degrade the impression of your maps.
+* Props play a BIG part in ZS! Humans can pick them up, pull them, drag them, throw them, arrange them, and even build with them. Make sure props are PHYSICAL PROPS, NOT STATIC! Humans will want to use those props!
+* Zombies have the ability to see in pitch black areas with their dark to light vision.
+* Zombie spawns have noxious gases around them that damage humans and heal zombies. Place spawns intelligently.
+* Zombie spawn areas should be hazardous to humans. High up ledges or places to backpedal in to are a no-no. In an ideal ZS map, humans should never want to even step foot in or near the zombie spawn.
+* Bottlenecks are obvious camping spots.
+* Humans will only spawn when their client is ready or 30 seconds after joining on the server.
+* If there is a spot that is safer than another, you can bet that the humans will go there right when the game begins. Make sure to have multiple holding areas and make it so each of the areas have disadvantages!
+ A classic example of what not to do is to have a big main house and one or two small houses. The small houses will never get used because the big one is almost always more secure!
+ Another example is the three-story house. You have your first floor, second floor, and an attic.
+ The greatest mistake a mapper can make is to make it so the upper floors are safer than the bottom ones instead of having it so the upper ones are last-ditch spots.
+ This can EASILY be avoided by adding windows, holes in walls, and other environmental things.
+ Your map could be the best looking thing in the world but if there's one room that's safer than the rest, the humans will always go there and you might as well just delete the rest of the map.
+* Humans have an oxygen meter before they start to drown. Zombies don't.
+* Humans may have flashlights but they still can't see across a long, dark hallway or across a dark field (without graphics card setting changes or flashlight hacks). Zombies can.
+* Humans will find ways to exploit the map, weather it be jumping off the map bounds, jamming an elevator, or finding an extremely exploitable camping spot.
+ Make sure to test your map for these spots and always TRY and exploit your own map.
+* Not everyone has Counter-Strike: Source or Episode 2. Use HL2 models, materials, and sounds unless you plan on pakratting the content.
+* zs_somethinghouse is a completely unoriginal name.
+
+ ===============
+ = ENTITY LIST =
+ ===============
+
+info_player_human - Humans can spawn here.
+info_player_zombie - Zombies can spawn here.
+info_player_undead - Zombies can also spawn here.
+info_player_redeemed - Redeemed players can spawn here. Use of this is optional.
+Spawnpoints have a keyvalue "disabled" 1/0 and an input "disable" and "enable" to make it so players can't spawn at them dynamically.
+
+logic_beats - Allows you to turn beats (the ambient music) on or off.
+Keyvalues:
+ enabled <0/1> - Should beats be on or off.
+Inputs:
+ enable - Enables beats.
+ disable - Disables beats.
+
+logic_dynamicspawning - Allows you to control dynamic spawning.
+Dynamic spawning is a new feature where zombies will spawn on top of each other if no humans can see it and the zombie is not too close to any humans.
+This is on by default except in maps with _obj_ or objective in their names.
+Keyvalues:
+ enabled <0/1> - Should dynamic spawning be on?
+Inputs:
+ enable - Enables dynamic spawning.
+ disable - Disables dynamic spawning.
+
+logic_points - Allows you to control and call outputs based on points.
+Keyvalues: None
+Inputs:
+ addtoactivator - Adds to the activator.
+ addtocaller - Adds to the caller.
+ takefromactivator - Takes from the activator.
+ takefromcaller - Takes from the caller.
+ setactivatoramount - Sets the amount that activator has to .
+ setcalleramount - Same as above but with the caller.
+ callifactivatorhave - If the activator has this amount then OnConditionPassed is thrown, otherwise OnConditionFailed.
+ callifactivatornothave - Same as above but logic is reversed.
+ callifcallerhave - Same as above but with caller.
+ callifcallernothave - Same as above but with caller.
+Outputs:
+ OnConditionPassed - Thrown by ourselves when a condition is passed. The activator is always the player in question. The arguments are the amount that was checked against.
+ OnConditionFailed - Thrown by ourselves when a condition is failed. Same as above.
+
+logic_startingloadout - Allows you to control what people start with.
+Keyvalues:
+ startingloadout (see below)
+Inputs:
+ setstartingoadout - Sets the starting load out for all new humans. This is a comma-separated list of entity classes which is then separated by colons. For example: "weapon_zs_peashooter:1,weapon_zs_axe:1,item_ammo_pistol:2" would give everyone a peashooter, an axe, and spawn two boxes of pistol ammo on them. It also accepts "none" for absolutely no starting items and "worth" for using the worth menu (default).
+
+logic_brains - All inputs and outputs are the same as logic_points but this works for brains (kills as a zombie). Two new inputs are added.
+Keyvalues: None
+Inputs:
+ redeemactivator - Instantly redeems the activator.
+ redeemcaller - Instantly redeems the caller.
+ setredeembrains - Sets the amount of brains required for a zombie to automatically redeem. Setting it to 0 means no automatic redemptions.
+
+logic_worth - Allows you to control Worth.
+Keyvalues:
+ startingworth - The amount of Worth to start with. Use 0 to disable Worth.
+Inputs:
+ setstartingworth - Sets the amount of worth to start with.
+
+logic_pickups - Allows you to control how much stuff people can pickup in the map. Only things placed by the mapper work with this system. Stuff from dead humans doesn't count.
+Keyvalues:
+ maxweaponpickups - How many weapons a player can pickup from the map.
+ maxammopickups - How many ammo boxes a player can pickup from the map.
+ maxflashlightpickups - How many flashlight batteries a player can pickup from the map.
+ weaponrequiredforammo <0 or 1> - If 1 then players must have a weapon that takes the ammo before being able to pick up an ammo box.
+Inputs:
+ setmaxweaponpickups - Same as above.
+ setmaxammopickups - Same as above.
+ setmaxflashlightpickups - Same as above.
+ setweaponrequiredforammo <0 or 1> - Same as above.
+
+logic_classunlock - Allows you to control class unlocks.
+Keyvalues:
+ class - Sets the name of the class to watch for any outputs.
+Outputs:
+ OnClassUnlocked - Called when the class we're watching's class is unlocked by the game. This output isn't called if the class is unlocked by any logic_classunlock entities, only by the game.
+Inputs:
+ unlockclass - Forces a class to be unlocked.
+ lockclass - Forces a class to be locked.
+
+point_worldhint - Allows you to create 3D hints and information tags.
+Keyvalues:
+ hint - The hint to display.
+ viewer - The team that can view us. Use 0 for everyone, -1 for no one (inactive), 3 for zombie, and 4 for human.
+ range - The range from the player's camera we must be in to see this hint. It can also be 0 for infinite which is the default.
+Inputs:
+ sethint - Same as the hint key value.
+ setviewer - Same as the viewer key value.
+ setrange - Same as the range key value.
+
+zombiegasses - Manually place a point for the zombies' noxious gases.
+To get these new entities, just make a info_player_start entity and rename the entity class to one of those. Don't worry about obsolete, it doesn't matter.
+
+logic_winlose
+Inputs:
+ win: Humans win the game, map over.
+ lose: Humans lose the game, map over.
+Outputs:
+ OnWin: Called when humans win even if not by this entity.
+ OnLose: Vice versa.
+
+logic_pickupdrop
+Keyvalues:
+ EntityToWatch - targetname of the entity to watch for the below OUTPUTS.
+Outputs:
+ OnPickedUp - Activator is the player, caller is the entity that was picked up.
+ OnDropped - Activator is the player, caller is the entity that was picked up.
+Inputs:
+ ForceDrop - arguments is the targetname of what you want to use. Forces the dropping of something that's picked up by a human.
+ DisablePickup - arguments is the targetname of what you want to use. Disables human pickups. Does not force dropping if currently carried, use the above input.
+ EnablePickup - arguments is the targetname of what you want to use. Enables human pickups.
+
+logic_waves
+Keyvalues:
+ wave - any On* outputs will watch for this wave. Use -1 for all waves.
+Outputs:
+ OnWaveEnd - Called when the wave ends.
+ OnWaveStart - Called when the wave starts.
+Inputs:
+ AdvanceWave - Advances to the next wave and sets the wave to active.
+ EndWave - Sets the time that the wave ends to this very moment.
+ StartWave - Sets the time that the wave begins to this very moment.
+ SetWave - Sets the wave to . This does not change the wave state between active and inactive.
+ SetWaves - Sets the total amount of waves to . Don't worry about class unlocks, the gamemode does not use the max waves value directly.
+ SetWaveStart - Sets the time that the wave will start to TimeNow + . You should use this instead of delayed entity inputs.
+ SetWaveEnd - Same as above but for the time that the wave ends.
+
+logic_barricade
+Inputs:
+ disablethese - Takes the arguments in the form of a comma-separated array and disables any entities with that name. For example, disablethese objective1,somethingimportant,somethingelse. This would disable nailing of those entities.
+ enablethese - Same as above but enables instead of disables.
+
+prop_nail - Allows you to manually place nails.
+Keyvalues:
+ healthoverride - Sets the nail's maximum health to a specific number.
+ healthmultiplier - Multiply the nail's default maximum health by this number.
+ unremovable <1/0> - Set to 1 to make this nail unremovable by players.
+Inputs:
+ sethealth - Sets the nail's remaining health.
+ attachto - Parent to this entity.
+ nailto - Nail to this entity. Use attachto first and then this to weld the two. Use "worldspawn" here to weld to the world.
+ setname - Display this text as the owner name.
+ setunremovable <1/0> - Set if this nail is unremovable.
+ toggleunmovable - Toggle unremovable state.
+
+prop_playergib - Allows you to manually place gibs.
+Keyvalues:
+ lifetime - Overrides how long for this gib should live. 0 for never automatically remove.
+ gibtype - Overrides the gib's type (skull, spine, etc. This is a number not a model or name).
+
+logic_infliction
+Keyvalues:
+ infliction: Defines infliction to watch for (float between 0.0 - 1.0).
+Outputs:
+ OnInflictionReached: Called when the above value is reached.
+ OnLastHuman: Called when there is one person alive. !caller and !activator are both the last human's entity.
+
+point_zsmessage
+Keyvalues:
+ team ("zombie", "human", "private", or "all"): Filter which team gets the message. You can use private if you only want the activator to get the message or all for every player on the server.
+Inputs:
+ message ("msg"): What to display. Supports the markup library. http://wiki.garrysmod.com/?title=Markup.Parse
diff --git a/gamemodes/zombiesurvival/readme.txt b/gamemodes/zombiesurvival/readme.txt
new file mode 100644
index 0000000..699dd88
--- /dev/null
+++ b/gamemodes/zombiesurvival/readme.txt
@@ -0,0 +1,55 @@
+ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
+ZZZ ZZZ
+ZZZ ZOMBIE SURVIVAL ZZZ
+ZZZ THE DEFINITIVE ZOMBIE EXPERIENCE ZZZ
+ZZZ A GAMEMODE FOR GMOD ZZZ
+ZZZ ZZZ
+ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
+
+Created and programmed by William "JetBoom" Moodhe
+E-mail: williammoodhe@gmail.com
+Alternate e-mail: jetboom@noxiousnet.com
+Web: http://www.noxiousnet.com
+
+Additional credits:
+Zombie view models 11k (tjd113@gmail.com)
+Zombie kill icons Eisiger (k2deseve@gmail.com)
+Some HUD textures Typhon (lukas-tinel@hotmail.com)
+Ambient beat sounds Austin "Little Nemo" Killey (austin_odyssey@yahoo.com)
+Melee weapon models Zombie Panic: Source (http://www.zombiepanic.org/)
+Board Kit model Samuel (samuel_games@hotmail.com)
+
+
+ ZZZZZZZZZZZZZZZZZZZZZZZZZ
+ZZ ZZ
+ZZ INSTALL ZZ
+ZZ ZZ
+ ZZZZZZZZZZZZZZZZZZZZZZZZZ
+
+1. Put the zombiesurvival folder in garrysmod/gamemodes with all the other gamemode folders.
+2. In console: gamemode zombiesurvival
+3. Run a zs_ map.
+
+
+ ZZZZZZZZZZZZZZZZZZZZZZZZZ
+ZZ ZZ
+ZZ RUNNING SERVERS ZZ
+ZZ ZZ
+ ZZZZZZZZZZZZZZZZZZZZZZZZZ
+
+1. Get srcds and configure it for garrysmod (requires steamcmd).
+2. Put the zombiesurvival folder in garrysmod/gamemodes with all the other gamemode folders.
+3. Get some maps. ZS_ maps are plentiful on the Internet and the game also supports many other map types: CS:S, Zombie Mod, Zombie Horde, Zombie Panic! Source
+4. Either setup a custom voting script or use mapcycle_zombiesurvival.txt. Make a file called mapcycle_zombiesurvival.txt in base garrysmod folder. Put in names of maps without the .bsp ending. One per line.
+5. Make your auto-start batch file or whatever you use. The line should look like this:
+srcds.exe -port 27015 -console -game garrysmod -secure +ip 24.102.103.104 +hostport 27015 +gamemode zombiesurvival +maxplayers 32 +map zs_oldhouse +hostname "Your ZS Server"
+6. Run it. You now have a server. See other guides on the web for setting up sv_downloadurl.
+
+
+ ZZZZZZZZZZZZZZZZZZZZZZZZ
+ZZ ZZ
+ZZ LEGAL JARGON ZZ
+ZZ ZZ
+ ZZZZZZZZZZZZZZZZZZZZZZZZZ
+
+See license file
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/scripting and addons.txt b/gamemodes/zombiesurvival/scripting and addons.txt
new file mode 100644
index 0000000..7c893c6
--- /dev/null
+++ b/gamemodes/zombiesurvival/scripting and addons.txt
@@ -0,0 +1,151 @@
+Zombie Survival now sports the following custom hooks and stuff.
+If you're adding new game features then you would probably want to use hooks instead of overwriting files that may be updated.
+You're a big boy, you know how to make hooks and use autorun so I won't go in to that. Just use them as if they were any other hook.
+Returning anything besides nil in a hook will override the gamemode's stuff.
+
+If you're going to be calling gamemode functions then use gamemode.Call so hooks are called and everything works properly.
+gamemode.Call("EndRound", TEAM_HUMAN) instead of GAMEMODE:EndRound(TEAM_HUMAN)
+MOST OF THE TIME THERE IS A HOOK CALLED AFTER THE FIRST ONE CALLED PostHookName
+
+=SHARED=
+
+Hook. Can a player purchase something from a crate? Return false to explicitly not allow, true to explicitly allow.
+GM:PlayerCanPurchase(Player ply)
+
+Hook. Can a player checkout their worth loadout?
+GM:PlayerCanCheckout(Player ply)
+
+Hook. Called when a weapon is succesfully deployed. Used for setting player walk speeds.
+GM:WeaponDeployed(Player ply, Weapon wep)
+
+Hook. Can a player be healed?
+GM:PlayerCanBeHealed(Player pl)
+
+Hook. Is a class unlocked?
+GM:IsClassUnlocked(Integer class)
+
+=SERVER SIDE=
+
+Hook. Called when the game wants to turn waves on or off.
+GM:SetWaveActive(Bool active)
+
+Hook. Called when the game wants to set the time that a wave will start.
+GM:SetWaveStart(Float time)
+
+Hook. Called when the game wants to set the time that a wave will end.
+GM:SetWaveEnd(Float time)
+
+Hook. Called when the game wants to set the wave to something.
+GM:SetWave(Integer wave)
+
+Hook and function. End a round with a team as the winner. Bit of a complication here: zombies don't actually win ZS. The point is to survive so if you die you must redeem to have a shot at winning.
+GM:EndRound(Integer team)
+
+Hook. Called when a player repairs an object. Usually a nail.
+GM:PlayerRepairedObject(Player ply, Entity object, Float repaired, Weapon wep)
+
+Hook. Called when a nail is created. ent1 and ent2 are the two entities. ent2 may be the world.
+GM:OnNailCreated(Entity ent1, Entity ent2, Entity nail)
+
+Hook. Called when someone heals a team member (NOT THEMSELF).
+GM:PlayerHealedTeamMember(Player healer, Player target, Float health, Weapon wep)
+
+Hook. Called when there is one human left.
+GM:LastHuman(Player pl)
+
+Hook. Called when a zombie kills the last human.
+GM:LastBite(Player victim, Player attacker)
+
+Hook and function. Gives a player their default equipment or a random loadout if they have none.
+GM:GiveDefaultOrRandomEquipment(Player pl)
+
+Hook and function. Gives a player random equipment without checking their favorites.
+GM:GiveRandomEquipment(Player pl)
+
+Hook and function. Loads the next map. HERE IS WHERE YOU PUT YOUR MAP VOTING AND STUFF. RETURN TRUE TO OVERRIDE.
+GM:LoadNextMap()
+
+Hook. Called when a player has told the server that GM:HookGetLocal (client-side hook below) has been called. DO NOT TRUST THE CLIENT ON THIS, SHOULD ONLY BE USED FOR COSMETICS AND SENDING NETWORKED STUFF.
+GM:PlayerReady(Player pl)
+
+Function. Recalculates if a prop should be frozen or not due to being nailed and such. Use true as a second argument to check all props that have a constraint to this one as well.
+GM:EvaluatePropFreeze(Entity ent, Bool usehierarchy)
+
+Hook. Human kills a zombie.
+GM:HumanKilledZombie(Player victim, Player attacker, DamageInfo dmginfo, Bool headshot, Bool wassuicide)
+
+Hook. Zombie kills a human.
+GM:HumanKilledZombie(Player victim, Player attacker, DamageInfo dmginfo, Bool headshot, Bool wassuicide)
+
+SELF-EXPLANATORY HOOKS AND FUNCTIONS
+GM:LoadMapEditorFile()
+GM:SetupSpawnPoints()
+GM:RemoveUnusedEntities()
+GM:ReplaceMapWeapons()
+GM:ReplaceMapAmmo()
+GM:ReplaceMapBatteries()
+GM:CreateZombieGas()
+GM:SetupProps()
+GM:DoHonorableMentions()
+GM:PostDoHonorableMentions(filter)
+GM:PostEndRound(winner)
+GM:CalculateInfliction()
+GM:RemoveDuplicateAmmo(pl)
+GM:ShouldAntiGrief(ent, attacker, dmginfo, health)
+GM:PostHumanKilledZombie(ply, attacker, dmginfo, assister, assistfrags, headshot)
+GM:PostZombieKilledHuman(ply, attacker, dmginfo, headshot, wassuicide)
+GM:CanDamageNail(nail, attacker, inflictor, damage, dmginfo)
+GM:OnNailDamaged(nail, attacker, inflictor, damage, dmginfo)
+GM:OnNailDestroyed(nail, attacker, inflictor, damage, dmginfo)
+GM:OnNailRemoved(nail, ent1, ent2, remover)
+GM:OnPlayerChangedTeam(ply, oldteam, newteam)
+GM:PlayerPointsAdded(ply, points)
+GM:PlayerRedeemed(ply)
+GM:WaveStateChanged(active)
+
+=CLIENT SIDE=
+
+Function. Adds a death notice.
+GM:AddDeathNotice(String attackername, Integer attackerteam, String inflictor, String victimname, Integer victimteam, Bool headshot)
+
+Called when the player sees LocalPlayer() as a valid entity and MySelf is available to be called.
+GM:HookGetLocal(Player pl)
+
+Hook. Called when the player dies as a human. attackername is the player's name. Note, this is only called when killed by another player and while a human.
+GM:LocalPlayerDied(String attackername)
+
+Function. Adds a floating score number in the world.
+GM:FloatingScore(Entity ent, [String type, Integer score, Integer flags])
+
+Hook. Called when the player gets profits from a crate they own.
+GM:ReceivedCommission(Entity crate, Player buyer, Integer points)
+
+Hook. Called when the player heals another player.
+GM:HealedOtherPlayer(Player other, Integer points)
+
+Hook. Called when the player repairs an object.
+GM:RepairedObject(Entity object, Integer pointsreceived)
+
+Function. Suppresses the Arsenal Upgrade message for provided number of seconds.
+GM:SuppressArsenalUpgrades(Float time)
+
+Function. Add an honorable mention to the end board.
+GM:AddHonorableMention(Player ply, Integer mention, Integer data)
+
+Hook. Called when opening the human context menu.
+GM:HumanMenu()
+
+Hook and function. Toggles zombie dark to light vision.
+GM:ToggleZombieVision()
+
+Hook. Called when you click a person's name in the scoreboard.
+GM:ClickedPlayerButton(Player ply, Panel panel)
+
+Hook. Called when you click a person's name in the honorable mentions.
+GM:ClickedEndBoardPlayer(Player ply, Panel panel)
+
+Hook. Called when building the help menu. Use this to add new sheets.
+GM:BuildHelpMenu(Panel helpwindow, Panel propertysheet)
+
+Hook. Called when building the options menu. Use this to add extra options.
+GM:AddExtraOptions(Panel panellist, Panel optionsmenu)
diff --git a/gamemodes/zombiesurvival/workshop512.jpg b/gamemodes/zombiesurvival/workshop512.jpg
new file mode 100644
index 0000000..8d013d4
Binary files /dev/null and b/gamemodes/zombiesurvival/workshop512.jpg differ
diff --git a/gamemodes/zombiesurvival/workshopdesc.txt b/gamemodes/zombiesurvival/workshopdesc.txt
new file mode 100644
index 0000000..0cfb9e1
--- /dev/null
+++ b/gamemodes/zombiesurvival/workshopdesc.txt
@@ -0,0 +1,9 @@
+A massive gamemode where humans are pit against a zombie horde. All zombies are controlled by actual players instead of NPCs. When a human dies, they become part of the Undead!
+
+Comes with tons of weapons, multiple classes for zombies, boss zombies, an in-depth barricading system, and the new Classic Mode.
+
+WARNING: THIS GAMEMODE WILL NOT WORK PROPERLY FROM THE WORKSHOP. AN UPCOMING GMOD UPDATE IS REQUIRED BEFORE GAMEMODES WORK ON THE STEAM WORKSHOP. IF YOU ARE PLANNING TO HOST A SERVER THEN DOWNLOAD FROM THE SVN. THIS IS ONLY FOR DOWNLOADING CONTENT.
+
+SVN: svn://noxiousnet.com/trunk/public/gmod13/zombiesurvival
+Forum: http://www.noxiousnet.com/forums/index.php?board=43.0
+FP Thread: http://facepunch.com/showthread.php?t=1160198
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/zombiesurvival.fgd b/gamemodes/zombiesurvival/zombiesurvival.fgd
new file mode 100644
index 0000000..2a49895
--- /dev/null
+++ b/gamemodes/zombiesurvival/zombiesurvival.fgd
@@ -0,0 +1,386 @@
+//////////////////////////////////////////////////////////////////////////////////
+// NoXiousNet Zombie Survival FGD //
+// If there are any bugs with this file, or any additions that need to be made //
+// make a post at: http://www.noxiousnet.com/forums/index.php?topic=14910 //
+//////////////////////////////////////////////////////////////////////////////////
+
+@BaseClass base(Targetname) = ZSSpawn
+[
+ disabled(choices) : "Disabled" : 0 : "If disabled, players cannot spawn here." =
+ [
+ 1 : "Yes"
+ 0 : "No"
+ ]
+ input enable(void) : "Enable the spawn point."
+ input disable(void) : "Disable the spawn point."
+ input toggle(void) : "Toggle the spawn point."
+]
+@PointClass base(PlayerClass, Angles, ZSSpawn) studio("models/editor/playerstart.mdl") = info_player_human : "ZS: Humans can spawn here."
+[
+]
+@PointClass base(PlayerClass, Angles, ZSSpawn) studio("models/editor/playerstart.mdl") = info_player_zombie : "ZS: Zombies can spawn here."
+[
+]
+@PointClass base(PlayerClass, Angles, ZSSpawn) studio("models/editor/playerstart.mdl") = info_player_undead : "ZS: Zombies can spawn here. Alias of info_player_zombie."
+[
+]
+@PointClass base(PlayerClass, Angles, ZSSpawn) studio("models/editor/playerstart.mdl") = info_player_redeemed : "ZS: Redeemed players can spawn here. Use of this is optional."
+[
+]
+@PointClass base(Targetname) = logic_beats : "ZS: Allows you to turn beats (the ambient music) on or off."
+[
+ enabled(choices) : "Enabled" : 1 : "Allows ZS beats" =
+ [
+ 1 : "Yes"
+ 0 : "No"
+ ]
+ // Inputs
+ input enable(void) : "Enables beats."
+ input disable(void) : "Disables beats."
+ // Outputs
+]
+@PointClass base(Targetname) = logic_dynamicspawning : "ZS: Allows you to control dynamic spawning."
+[
+ enabled(choices) : "Enabled" : 1 : "Should dynamic spawning be on?" =
+ [
+ 1 : "Yes"
+ 0 : "No"
+ ]
+ // Inputs
+ input enable(void) : "Enable dynamic spawning."
+ input disable(void) : "Disable dynamic spawning."
+]
+@PointClass base(Origin) iconsprite("particles/smokey") sphere( radius ) = zombiegasses : "ZS: Manually place a point for the zombies' noxious gases."
+[
+ radius(integer) : "Radius" : 250 : "Radius that this can damage humans/heal zombies."
+]
+@PointClass base(Targetname) = logic_pickupdrop : "ZS: Controls events when players pickup or drop things."
+[
+ EntityToWatch(target_destination) : "Entity to Watch" : " " : "Name of the entity to watch (for outputs)."
+ // Inputs
+ input ForceDrop(string) : "Forces the dropping of something that's picked up by a human."
+ input DisablePickup(string) : "Disables human pickups for the specified entity. Does not force dropping if currently carried, use the above input."
+ input EnablePickup(string) : "Enables human pickups for the specified entity."
+
+ // Outputs
+ output OnPickedUp(void) : "Activator is the player, caller is the entity that was picked up."
+ output OnDropped(void) : "Activator is the player, caller is the entity that was picked up."
+
+]
+@PointClass base(Targetname) = logic_points : "ZS: Allows you to control and call outputs based on points."
+[
+ // Inputs
+ input addtoactivator(integer) : "Adds to the activator."
+ input addtocaller(integer) : "Adds to the caller."
+ input takefromactivator(integer) : "Takes from the activator."
+ input takefromcaller(integer) : "Takes from the caller."
+ input setactivatoramount(integer) : "Sets the amount that activator has to ."
+ input setcalleramount(integer) : "Sets the amount that caller has to ."
+ input callifactivatorhave(integer) : "If the activator has this amount then OnConditionPassed is thrown, otherwise OnConditionFailed."
+ input callifactivatornothave(integer) : "If the activator does bot have this amount then OnConditionPassed is thrown, otherwise OnConditionFailed."
+ input callifcallerhave(integer) : "If the caller has this amount then OnConditionPassed is thrown, otherwise OnConditionFailed."
+ input callifcallernothave(integer) : "If the call does not have this amount then OnConditionPassed is thrown, otherwise OnConditionFailed."
+
+ // Outputs
+ output OnConditionPassed(void) : "Thrown by ourselves when a condition is passed. The activator is always the player in question. The arguments are the amount that was checked against."
+ output OnConditionFailed(void) : "Thrown by ourselves when a condition is failed. The activator is always the player in question. The arguments are the amount that was checked against."
+]
+@PointClass base(Targetname) = logic_brains : "ZS: Allows you to control and call outputs based on brains."
+[
+ // Inputs
+ input addtoactivator(integer) : "Adds to the activator."
+ input addtocaller(integer) : "Adds to the caller."
+ input takefromactivator(integer) : "Takes from the activator."
+ input takefromcaller(integer) : "Takes from the caller."
+ input setactivatoramount(integer) : "Sets the amount that activator has to ."
+ input setcalleramount(integer) : "Sets the amount that caller has to ."
+ input callifactivatorhave(integer) : "If the activator has this amount then OnConditionPassed is thrown, otherwise OnConditionFailed."
+ input callifactivatornothave(integer) : "If the activator does bot have this amount then OnConditionPassed is thrown, otherwise OnConditionFailed."
+ input callifcallerhave(integer) : "If the caller has this amount then OnConditionPassed is thrown, otherwise OnConditionFailed."
+ input callifcallernothave(integer) : "If the call does not have this amount then OnConditionPassed is thrown, otherwise OnConditionFailed."
+ input redeemactivator(void) : "Instantly redeems the activator."
+ input redeemcaller(void) : "Instantly redeems the caller."
+ input setredeembrains(integer) : "Sets the amount of brains required for a zombie to automatically redeem. Setting it to 0 means no automatic redemptions."
+
+ // Outputs
+ output OnConditionPassed(void) : "Thrown by ourselves when a condition is passed. The activator is always the player in question. The arguments are the amount that was checked against."
+ output OnConditionFailed(void) : "Thrown by ourselves when a condition is failed. The activator is always the player in question. The arguments are the amount that was checked against."
+]
+@PointClass base(Targetname) = logic_startingloadout : "ZS: Allows you to control what people start with."
+[
+ setstartingoadout(string) : "Starting Loadout" : " " : "Sets the starting load out for all new humans. This is a comma-separated list of entity classes which is then separated by colons. For example: weapon_zs_peashooter:1,weapon_zs_axe:1,item_ammo_pistol:2 would give everyone a peashooter, an axe, and spawn two boxes of pistol ammo on them. It also accepts none for absolutely no starting items and worth for using the worth menu (default)."
+]
+@PointClass base(Targetname) = logic_worth : "ZS: Allows you to control Worth."
+[
+ startingworth(integer) : "Starting Worth" : 100 : "The amount of Worth to start with. Use 0 to disable Worth."
+ // Inputs
+ setstartingworth(integer) : "Sets the amount of worth to start with."
+]
+@PointClass base(Targetname) = logic_barricade : "ZS: Allows or disallows specific entities from being nailed."
+[
+ // Inputs
+ input disablethese(string) : "Takes the arguments in the form of a comma-separated array and disables any entities with that name. For example, disablethese objective1,somethingimportant,somethingelse. This would disable nailing of those entities."
+ input enablethese(string) : "Takes the arguments in the form of a comma-separated array and enables any entities with that name. For example, enablethese objective1,somethingimportant,somethingelse. This would enable nailing of those entities."
+]
+@PointClass base(Targetname) = logic_difficulty : "ZS: Adjusts the difficulty of the game."
+[
+ // Inputs
+ input setzombiespeedmultiplier(float) : "Multiplyer for Zombie speed."
+ input setzombiedamagemultiplier(float) : "Multiplyer for Zombie damage."
+]
+@PointClass base(Targetname) = logic_pickups : "ZS: Allows you to control how much stuff people can pickup in the map. Only things placed by the mapper work with this system. Stuff from dead humans doesn't count."
+[
+ maxweaponpickups(integer) : "Max Weapon Pickups" : 5 : "How many weapons a player can pickup from the map."
+ maxammopickups(integer) : "Max Ammo Pickups" : 5 : "How many ammo boxes a player can pickup from the map."
+ maxflashlightpickups(integer) : "Max Flashlight Pickups" : 5 : "How many flashlight batteries a player can pickup from the map."
+ weaponrequiredforammo(choices) : "Correct Weapon Required" : 0 : "If 1 then players must have a weapon that takes the ammo before being able to pick up an ammo box." =
+ [
+ 1 : "Yes"
+ 0 : "No"
+ ]
+ // Inputs
+ input setmaxweaponpickups(integer) : "Set the number of weapons a player can pickup from the map."
+ input setmaxammopickups(integer) : "Set the number of ammo boxes a player can pickup from the map."
+ input setmaxflashlightpickups(integer) : "Set the number of flashlight batteries a player can pickup from the map."
+ input setweaponrequiredforammo(integer) : "If 1 then players must have a weapon that takes the ammo before being able to pick up an ammo box."
+]
+@PointClass base(Targetname) = logic_classunlock : "ZS: Allows you to control class unlocks."
+[
+ class(string) : "Class" : "zombie" : "Sets the name of the class to watch for any outputs."
+ // Inputs
+ input unlockclass(string) : "Forces a class to be unlocked."
+ input lockclass(string) : "Forces a class to be locked."
+ // Outputs
+ output OnClassUnlocked(void) : "Called when the class we're watching's class is unlocked by the game. This output isn't called if the class is unlocked by any logic_classunlock entities, only by the game."
+]
+@PointClass studio("models/crossbow_bolt.mdl") base(Targetname) = prop_nail : "ZS: Allows you to manually place nails."
+[
+ healthoverride(integer) : "Health Override" : 210 : "Sets the nail's maximum health to a specific number."
+ healthmultiplier(float) : "Health Multiply" : 1 : "Multiply the nail's default maximum health by this number."
+ unremovable(choices) : "Unremovable" : 0 : "Set to yes to make this nail unremovable by players." =
+ [
+ 1 : "Yes"
+ 0 : "No"
+ ]
+ input sethealth(integer) : "Sets the nail's remaining health."
+ input attachto(string) : "Parent to this entity."
+ input nailto(string) : "Nail to this entity. Use attachto first and then this to weld the two. Use 'worldspawn' here to weld to the world."
+ input setname(string) : "Display this text as the owner name."
+ input setunremovable(integer) : "Set if this nail is unremovable."
+ input toggleunremovable(integer) : "Toggle unremovable state."
+]
+
+@PointClass base(Targetname) sphere( range ) = point_worldhint : "ZS: Allows you to create 3D hints and information tags."
+[
+ hint(string) : "Hint" : " " : "The hint to display."
+ viewer(choices) : "Seen By" : 0 : "The team that can view us." =
+ [
+ "-1" : "Disabled"
+ "0" : "Everyone"
+ "3" : "Zombies"
+ "4" : "Humans"
+ ]
+ range(integer) : "Range" : 0 : "The range from the player's camera we must be in to see this hint. It can also be 0 for infinite."
+ // Inputs
+ input sethint(string) : "Sets the hint to display."
+ input setviewer(integer) : "Sets the team that can view us. Use 0 for everyone, -1 for no one (inactive), 3 for zombie, and 4 for human."
+ input setrange(float) : "Sets the range from the player's camera we must be in to see this hint. It can also be 0 for infinite which is the default."
+]
+
+@PointClass base(Targetname) = prop_playergib : "ZS: Allows you to manually place gibs."
+[
+// "models/gibs/HGIBS.mdl"
+// "models/gibs/HGIBS_spine.mdl"
+// "models/gibs/HGIBS_rib.mdl"
+// "models/gibs/HGIBS_scapula.mdl"
+// "models/gibs/antlion_gib_medium_2.mdl"
+// "models/gibs/Antlion_gib_Large_1.mdl"
+// "models/gibs/Strider_Gib4.mdl"
+ gibtype(choices) : "Gib Type" : 1 : "Overrides the gib's type." =
+ [
+ 1 : "Skull"
+ 2 : "Spine"
+ 3 : "Rib"
+ 4 : "Scapula"
+ 7 : "Small Chunk"
+ 5 : "Medium Chunk"
+ 6 : "Large Chunk"
+ ]
+ lifetime(integer) : "Lifetime" : 0 : "Overrides how long for this gib should live. 0 for never automatically remove."
+]
+
+@PointClass base(Targetname) = logic_winlose : "ZS: When activated, this will end the round immediately, with the specified outcome."
+[
+ // Inputs
+ input win(void) : "Humans win the game, map over."
+ input lose(void) : "Humans lose the game, map over."
+ // Outputs
+ output onwin(void) : "Called when humans win even if not by this entity."
+ output onlose(void) : "Called when humans lose even if not by this entity."
+]
+@PointClass base(Targetname) = logic_infliction : "ZS: Watches for the specified infliction level."
+[
+ infliction(float) : "Infliction" : "0.5" : "Defines infliction to watch for (float between 0.0 - 1.0)."
+ // Outputs
+ output OnInflictionReached(void) : "Called when the specified infliction level has been reached."
+ output OnLastHuman(void) : "Called when there is one person alive. !caller and !activator are both the last human's entity."
+]
+@PointClass base(Targetname) = logic_waves : "ZS: Watches for the start of the specified wave."
+[
+ wave(integer) : "Wave" : 1 : "Any On* outputs will watch for this wave. Use -1 for all waves."
+ // Inputs
+ input AdvanceWave(void) : "Advances to the next wave and sets the wave to active."
+ input EndWave(void) : "Sets the time that the wave ends to this very moment."
+ input StartWave(void) : "Sets the time that the wave begins to this very moment."
+ input SetWave(integer) : "Sets the wave to the number specified. This does not change the wave state between active and inactive."
+ input SetWaves(integer) : "Sets the total amount of waves to the number specified. Don't worry about class unlocks, the gamemode does not use the max waves value directly."
+ input SetWaveStart(integer) : "Sets the time that the wave will start to TimeNow + . You should use this instead of delayed entity inputs."
+ input SetWaveEnd(integer) : "Sets the time that the wave will end to TimeNow + . You should use this instead of delayed entity inputs."
+ // Outputs
+ output OnWaveStart(void) : "Called when the specified wave has started."
+ output OnWaveEnd(void) : "Called when the specified wave has ended."
+]
+
+@PointClass base(Targetname) = point_zsmessage : "ZS: Custom message that is displayed with the specified message."
+[
+ team(choices) : "Team" : "all" : "Filter which team gets the message." =
+ [
+ "zombie" : "Zombies"
+ "human" : "Humans"
+ "private" : "Activator Only"
+ "all" : "All"
+ ]
+ input message(string) : "What to display. Supports the markup library."
+]
+
+
+
+// Starting Weapons
+
+@PointClass base(Weapon) studio("models/weapons/w_pistol.mdl") = weapon_zs_owens : "Worth: 45, clip size: 12, ammo type: pistol.\n"+
+"The latest starting pistol to be added to the game, has the highest damage potential of a starting pistol. It shoots 2 shots which together deal 16 damage. Its primary downside is that it has a lower accuracy than the peashooter and that crouching and using iron sights doesn't improve its accuracy unlike the battleaxe. Since its addition into the game it has been the favorite starting pistol among players up until the ammo nerf and updates of autumn 2009." []
+
+@PointClass base(Weapon) studio("models/weapons/w_pist_p228.mdl") = weapon_zs_peashooter : "Worth: 35, clip size: 18, ammo type: pistol\n"+
+"Its bullet damage is 9 making it the weakest in firepower. To compensate for this, it has a high firing rate, a large clip of 18 bullets, and a crouching accuracy almost on par with the slug rifle. Since the ammo nerf of autumn 2009 it has become the favorite starter for players due to its large amount of starting ammo and the fact that other items in the loadout menu can be used to give the player a 25 points pistol without having to use the peashooters ammo with. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_pist_usp.mdl") = weapon_zs_battleaxe : "Worth: 35, clip size: 12, ammo type: pistol\n"+
+"The classic starting pistol with the highest damage per bullet. Despite shooting only one bullet, it is the least accurate starting weapon when crouching. Its iron sight accuracies are much higher however than that of the owens. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_supershorty.mdl") = weapon_zs_blaster : "Worth: 60, clip size: 6, ammo type: shotgun\n"+
+"The blaster is the most powerful starting weapon in terms of the total damage that it can deal for one shot. At point blank this shotgun can take out a normal zombie with just 2 shots to the head. It comes with 36 shotgun shells. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_smg1.mdl") = weapon_zs_tosser : "Worth: 60, clip size: 25, ammo type: SMG\n"+
+"The tosser is the SMG starter weapon of the game. It is basically a bulletstorm with a smaller clip size, a smaller firing rate, and much more accuracy. Choosing it is a gamble since you could get lots of points with few bullets spend, or you could end up using up all your starting ammo without making it to 25 points. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_snip_scout.mdl") = weapon_zs_stubber : "Worth: 60, clip size: 5, ammo type: rifle\n"+
+"The stubber is the most powerful starting weapon in terms of single bullet power. It is a fairly accurate sniper that deals 35 damage per bullet. As there are few other weapons in the game that can deal nearly as much damage per bullet it is an excellent weapon for claiming kills with. It's biggest downside is that it is highly inefficient at close range. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_rif_famas.mdl") = weapon_zs_crackler : "Worth: 55, Clips size: 22, Ammo Type: Assault Rfifle\n"+
+"The Crackler is the same as the Tosser except with a lower walking speed, a lower firing rate, and assault rifle ammunition instead of SMG ammunition. " []
+
+// Tools + Weapons
+
+@PointClass base(Weapon) studio("models/weapons/w_hammer.mdl") = weapon_zs_hammer : "Worth: 45, Ammo type: n/a\n"+
+"The hammer and its nails can be used for building barricades, making it a very important tool for surviving the zombie horde. The hammer can also be used as a melee weapon. " []
+
+@PointClass base(Weapon) studio("models/items/healthkit.mdl") = weapon_zs_medicalkit : "Worth: 50, Ammo type: hp\n"+
+"The Medical Kit, though expensive, is a very useful tool. With it, players can heal teammates for 10hp every second and heal themselves themselves for 5hp every 16 seconds. A point is awarded for every 5 hp that is used to heal teammates. It is especially useful for getting a 25 point gun quickly on slow maps with exposed zombie spawn points. " []
+
+@PointClass base(Weapon) studio("models/props_debris/wood_board05a.mdl") = weapon_zs_boardpack : "Worth: 20, Ammo type: wood\n"+
+"The board pack gives players 6 boards that they can use along with the hammer and nails to help in building barricade(s). Is very useful on maps with few props, especially the CSS based ones. It can also be used with an aegis. " []
+
+@PointClass base(Weapon) studio("models/combine_turrets/floor_turret.mdl") = weapon_zs_gunturret : "Worth: 60, Ammo Limit: 1000, Ammo Type: SMG\n"+
+"This is a stationary turret that is placed similarly to aegis boards. Once placed, they will seek zombies and fire when one crosses its laser sight, focusing on the head. However, turrets can be extremely vulnerable to zombies as its firing power isn't good enough to take down zombies on its own and doesn't have much health. " []
+
+@PointClass base(Weapon) studio("models/items/item_item_crate.mdl") = weapon_zs_arsenalcrate : "Worth: 50, Ammo Type: n/a\n"+
+"The Arsenal Crate is a major part of the humans' survival. At wave break, this allows humans to purchase other weapons at 20% off. When a player purchases an item from this, the owner gets paid 10% commission price. Arsenal Crates can be destroyed by zombie attacks. " []
+
+@PointClass base(Weapon) studio("models/props_combine/combine_mine01.mdl") = weapon_zs_messagebeacon : "Worth: 25, Ammo Type: n/a\n"+
+"These display messages that can be seen by fellow human players. They can be useful to help newer players get to where they need to go and communicate what needs to be done. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_knife_ct.mdl") = weapon_zs_swissarmyknife : "Worth: 10\n"+
+"The classic melee weapon. It deals 16 damage and it is essential for getting assassin awards. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_plank.mdl") = weapon_zs_plank : "Worth: 5\n"+
+"The plank is the weakest melee weapon, but it has a high fire rate. Due to its cheap price, it is usually the melee weapon of choice for those wishing to focus on guns." []
+
+@PointClass base(Weapon) studio("models/Weapons/w_axe.mdl") = weapon_zs_axe : "Worth: 30\n"+
+"Reliable and strong, all its statistics are near average. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_sledgehammer.mdl") = weapon_zs_sledgehammer : "Worth: 50\n"+
+"The most powerful melee weapon in the game. However, it has a very low firing rate and it greatly slows down the walking speed of the player. It is useful for defensive purposes, or for killing weakened zombies." []
+
+@PointClass base(Weapon) studio("models/weapons/w_shovel.mdl") = weapon_zs_shovel : "Worth: 45\n"+
+"Basically a lighter version of the sledgehammer. Unlike the sledgehammer this weapon doesn't slow down the player so it can be useful for attacking purposes as well as defensive ones. It has the largest range over any of the other melee weapons in the game. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_fryingpan.mdl") = weapon_zs_fryingpan : "Worth: 20\n"+
+"Slightly more powerful than the knife, the player can move faster with this than he/she can with the knife. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_pot.mdl") = weapon_zs_pot : "Worth: 20\n"+
+"Almost exactly like the pan, except it has a much larger range. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_crowbar.mdl") = weapon_zs_crowbar : "Worth: 30\n"+
+"The crowbar is weak and slows the player down, but it comes with a high attack rate. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_crowbar.mdl") = weapon_zs_stunbaton : "Worth: 45 \n"+
+"Very weak, but it comes with an ability to slow down zombies. " []
+
+@PointClass base(Weapon) studio("models/props_c17/computer01_keyboard.mdl") = weapon_zs_keyboard : "Worth: n/a\n"+
+"Can only be picked up from maps with this entity. It is similar to the pot and pan in terms of hitting power. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_357.mdl") = weapon_zs_magnum : "Points to acquire: 25, Clip size: 6, ammo type: pistol\n"+
+"The latest weapon to be added to the 25 points level, this weapon shoots one bullet which deals a large amount of damage. This weapon is ammo efficient, allowing you to use your pistol ammo to its fullest potential. Another useful trait that this pistol possesses, is the ability for fired bullets to bounce off of walls, allowing you to hit from around corners and deal more damage. It is the most effective pistol against Poison Headcrabs, Poison Zombies, and normal Zombies. It has the lowest firing rate of any pistol in the game. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_pist_glock18.mdl") = weapon_zs_glock3 : "Points to acquire: 25, Clip size: 7, ammo type: pistol\n"+
+"This pistol is the perfect close range, on the move, combat weapon in the game, it shoots 3 bullets per shot each dealing a good amount of damage. This pistol offers excellent protection against targets which are fast and have low health. It is pretty much the exact opposite of the magnum and the most effective pistol against Fast Zombies, Wraiths, and Headcrabs. Its primary disadvantages include huge ammo expenditure and the fact that it can only be used effectively in medium close range combat. !" []
+
+@PointClass base(Weapon) studio("models/weapons/w_pist_deagle.mdl") = weapon_zs_deagle : "Points to acquire: 25, Clip size: 7, ammo type: pistol\n"+
+"The desert eagle is the first ever gun upgrade added to Zombie Survival. It was originally one of the most favored weapons in the game until ZS 2.0 came out. Its primary advantage is that it has the highest accuracies of all three pistols. It deals the least damage of any tier 2 pistol but its accuracy and decent firing rate makes up for it." []
+
+@PointClass base(Weapon) studio("models/weapons/w_smg_ump45.mdl") = weapon_zs_reaper : "Points to acquire: 75, Clip size: 28, ammo type: SMG\n"+
+"This Submachine Gun is a favorite amongst Human 1st enthusiasts due to its ammo friendly nature and its high bullet damage, thus killing zombies faster than the other Submachine Guns. Its single disadvantage is the clip size, which is only 28 bullets giving it the least amount of ammo out of all of the other SMGs. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_smg_p90.mdl") = weapon_zs_bulletstorm : "Points to acquire: 75, Clip size: 50, ammo type: SMG\n"+
+"One of the newer Submachine Guns added to Zombie Survival, its bullets deal the least amount of damage of any SMG. It also has the highest firing rate, the largest clip size (50), and the highest starting ammo amongst all the other submachine guns (300). " []
+
+@PointClass base(Weapon) studio("models/weapons/w_smg_mp5.mdl") = weapon_zs_smg : "Points to acquire: 75, Clip size: 30, ammo type: SMG\n"+
+"This Submachine Gun was formerly the favorite one amongst humans until the Reaper was introduced. Many people still favor it over other weapons, however due to its powerful bullet damage, faster firing rate, higher clip size of 30, and short reload time. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_smg_mac10.mdl") = weapon_zs_uzi : "Points to acquire: 75, Clip size: 40, ammo type: SMG\n"+
+"The first Submachine Gun added to Zombie Survival and the second gun upgrade ever added. It is weaker than the Shredder and the Reaper, but it has a large enough clip size to pack quite a punch to groups of Fast Zombies. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_rif_ak47.mdl") = weapon_zs_akbar : "Points to acquire: 80, Clip size: 25 Ammo type: Assault Rifle\n"+
+"The disadvantages of the Akbar include a low clip size, and the fact that it uses assault rifle ammo instead of SMG ammo. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_rif_galil.mdl") = weapon_zs_ender : "Points to acquire: 75, Clip size: 8 Ammo type: Shotgun\n"+
+"The Ender is a mid tier shotgun that is automatic. It is very useful against clearing a horde of zombies. Keep in mind that this weapon will go through ammo at a very fast rate. Besides this minor setback, the ender is a decent choice for a mid tier weapon. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_rocket_launcher.mdl") = weapon_zs_barricadekit : "Points to acquire: 100, Clip size: 1, ammo type: wood\n"+
+"The Barricade Kit allows players to place a large plank of wood to block zombies from reaching an area. It adjusts itself to the surface it is placed on and comes with 5 boards. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_grenade.mdl") = weapon_zs_grenade : "Points to acquire: 100, Clip size: 1, ammo type: grenade\n"+
+"A standard Half-Life 2 grenade that can be acquired at 100 points. In the right situations, this weapon can potentially produce huge amounts of kills. This weapon is especially good in maps that involve zombies struggling to get through a narrow entrance to reach the humans. It is also a good way of getting rid of Poison Headcrabs. However, if used wrong, these can do drastic damage to a barricade, so use with caution. Comes in a set of 3. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_annabelle.mdl") = weapon_zs_annabelle : "Points to acquire: 125, Clip size: 4, ammo type: rifle\n"+
+"A replica of the same shotgun that Father Grigori used in Half-Life 2. It is a rifle based weapon and uses the same type of ammunition as the stubber and the slug rifle. it is more accurate than the stubber (except when crouching and using iron sights at the same time) and deals 2 times more damage than the stubber does. it is a perfect weapon for sniping wraiths, fasties, chems, and poison headcrabs. Compared to the crossbow it is less powerful and as such it has 36 bullets while the crossbow has only 24 bolts. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_crossbow.mdl") = weapon_zs_crossbow : "Points to acquire: 125, Clip size: 1, ammo type: xbowbolt\n"+
+"A more realistic version of the Half-Life 2 crossbow, this weapon is extremely effective in hallways and clusterfucks. It is the only weapon in the game with a 100% accuracy at all times and it has the ability to penetrate through multiple zombies dealing serious collateral damage. A zoom view can be activated using the secondary mouse button. This weapon is very effective in a bottleneck situation. Its primary disadvantage is that it is exceedingly difficult to use, in fact it is the most difficult weapon to handle in Zombie Survival. Additionally, its bullet is physical and is affected strongly by gravity. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_rif_aug.mdl") = weapon_zs_inferno : "Points to acquire: 150, Clip size: 30, ammo type: Assault rifle\n"+
+"The inferno is basically a Shredder with greater accuracy. It's accuracy has made it a favorite amongst players. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_rif_m4a1.mdl") = weapon_zs_m4 : "Points to acquire: 150, Clip size: 30, ammo type: Assault rifle\n"+
+"The stalker is the most powerful automatic gun in the game in terms of hitting power. However, it is highly lacking in terms of accuracy. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_shot_xm1014.mdl") = weapon_zs_slugrifle : "Points to acquire: 200, Clip size: 2, ammo type: rifle\n"+
+"The Slug Rifle shoots one bullet that deals a tremendous amount of damage and upon crouching and using ironsights, the accuracy becomes 99% accurate, thus making it a perfect sniper-like weapon in the game. The sound it creates is also of epic proportions. The weapon is ammo friendly. Its only limitation is that it is completely useless at close range and that you need to use the other weapons you have to dispose of a zombie that gets very close to you. It's also ineffective against packs of zombies. It comes with a low amount of ammo but remaining ammo from an annabelle or a stubber can be used in the slug rifle. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_shotgun.mdl") = weapon_zs_boomstick : "Points to acquire: 200, Clip size: 2(1), ammo type: shotgun\n"+
+"The Boom Stick deals more damage than any other weapon in the game. It fires 12 shots that do 25 damage each. The maximum damage is 600 if you include the head shot damage bonus. It has a low firing rate since it has to reload after firing just once. This weapon has the unique ability of consuming two shots per attack. If one hasn't picked up shotgun ammo from somewhere, they will only be able to fire the boomstick 18 times before running out of ammo. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_shot_m3super90.mdl") = weapon_zs_sweepershotgun : "Points to acquire: 200, Clip size: 6, ammo type: shotgun\n"+
+"Although this shotgun deals a much lower amount of damage per attack compared to the Boomstick, is is much more versatile since it has a 6 bullet clip and a fast reloading speed. The sweeper is also the first shotgun to be introduced into Zombie Survival. " []
+
+@PointClass base(Weapon) studio("models/weapons/w_IRifle.mdl") = weapon_zs_pulserifle : "Points to acquire: 225, Clip size: 20, ammo type: Assault rifle\n"+
+"The Adonis is a 120 point assault rifle that combines high bullet power with the accuracy of the inferno. It comes with a low clip size and a very low firing rate however. This is the perfect weapon to use against chems from a distance. It comes with the ability to slow zombies it hits. Shooting 4 times at the feet of an approaching zombie is a very good way to help the others take out the zombies. " []
\ No newline at end of file
diff --git a/gamemodes/zombiesurvival/zombiesurvival.txt b/gamemodes/zombiesurvival/zombiesurvival.txt
new file mode 100644
index 0000000..00ec1e4
--- /dev/null
+++ b/gamemodes/zombiesurvival/zombiesurvival.txt
@@ -0,0 +1,16 @@
+"zombiesurvival"
+{
+ "base" "base"
+ "title" "Zombie Survival"
+ "maps" "^zs_|^zm_|^zh_|^zps_|^zr_|^ze_"
+ "menusystem" "1"
+ "workshopid" "105462463"
+
+ "author_name" "William 'JetBoom' Moodhe"
+ "author_email" "williammoodhe@gmail.com"
+ "author_url" "http://www.noxiousnet.com/"
+
+ "settings"
+ {
+ }
+}