86 Commits

Author SHA1 Message Date
Michael Fabian 'Xaymar' Dirks 8a99ae2abf client: Unify layout 2020-12-21 03:08:50 +01:00
Michael Fabian 'Xaymar' Dirks 4f7543541c server/states: Fully remove "The Dead Hunt" 2020-12-21 02:20:04 +01:00
Michael Fabian 'Xaymar' Dirks 5562311505 shared/defines: Add shared definitions 2020-12-21 02:02:08 +01:00
Michael Fabian 'Xaymar' Dirks cdd9153f8d shared/config: Remove unsupported gametype option 2020-12-21 02:02:05 +01:00
Michael Fabian 'Xaymar' Dirks 677f35ec4a shared/config: Add Friendly Fire option 2020-12-21 02:01:59 +01:00
Michael Fabian 'Xaymar' Dirks 819c1bfd7d gamemode: Remove rarely used options 2020-12-21 01:58:11 +01:00
Michael Fabian 'Xaymar' Dirks 9b97f44f35 project: Switch to FreeBSD 3-Clause from MIT/X11 2020-12-21 01:39:19 +01:00
Michael Fabian 'Xaymar' Dirks c49e802b01 project: Add Visual Studio Code workspace 2020-12-21 01:39:04 +01:00
Michael Fabian 'Xaymar' Dirks ee89cbc05b init: Update to new RoundManager and UI 2019-08-15 15:46:32 +02:00
Michael Fabian 'Xaymar' Dirks eafb71c5bb server/states: Adjust to new RoundManager 2019-08-15 15:46:14 +02:00
Michael Fabian 'Xaymar' Dirks f31244432e client/hud/gamestatedisplay: Redesign with DPI awareness
This redesign drastically improves the early design, while also relying more on the new RoundManager available to clients.
2019-08-15 15:45:56 +02:00
Michael Fabian 'Xaymar' Dirks 15dd65be46 roundmanager: Update to have Client and Server implementations
The client code now no longer has to rely on the GAMEMODE object to handle synchronization, and instead can use the actual RoundManager for it.
2019-08-15 15:44:29 +02:00
Michael Fabian 'Xaymar' Dirks 8c5b037a68 sh_init: Add info_player_spawn to Spectators 2019-08-15 15:43:14 +02:00
Michael Fabian 'Xaymar' Dirks 61f1e9a0cc vgui: Adjust DFrameDPI and DLabelDPI to use CreateFontData 2019-08-15 15:42:40 +02:00
Michael Fabian 'Xaymar' Dirks 81638d3db1 vgui/uimanager: Fix log spam and reduce duplicated logic 2019-08-15 15:42:14 +02:00
Michael Fabian 'Xaymar' Dirks 68ee7e31d8 vgui/fontamanger: Fix existing font logic 2019-08-15 15:41:56 +02:00
Michael Fabian 'Xaymar' Dirks 89704044e8 gamemode: Update init files 2019-08-15 00:39:01 +02:00
Michael Fabian 'Xaymar' Dirks cc0c9c411f client/ui: Rename scoreboard file 2019-08-15 00:38:42 +02:00
Michael Fabian 'Xaymar' Dirks 1c1592a840 client/ui: New Help and Settings UI (partially DPI Aware) 2019-08-15 00:38:05 +02:00
Michael Fabian 'Xaymar' Dirks 8a97adade3 vgui: DPI Aware DFrame 2019-08-15 00:37:31 +02:00
Michael Fabian 'Xaymar' Dirks 484d38c1b6 vgui: DPI Aware DLabel 2019-08-15 00:37:20 +02:00
Michael Fabian 'Xaymar' Dirks b217582757 vgui: Global UI and Font managers
Drastically simplifies the logic required to use these and no longer relies on the GAMEMODE/GM object.
2019-08-15 00:36:42 +02:00
Michael Fabian 'Xaymar' Dirks a754f2cbce tools: Improve logic slightly 2019-08-14 21:03:54 +02:00
Michael Fabian 'Xaymar' Dirks 3cfa2a8d9e Add github issue templates and sponsorship information 2019-07-20 23:03:45 +02:00
Michael Fabian 'Xaymar' Dirks 629b921341 client/hud/gamestatedisplay: Improved HUD Game State Display
This is a Derma version of the manually drawn Default Player Class HUD Element which is now gone. It integrates with the UIManager and FontManager and scales with the ScreenSize instead of being a fixed small size.
2019-01-12 21:19:11 +01:00
Michael Fabian 'Xaymar' Dirks 4a8b95bdb4 Modify time logic to split RoundTime and StateTime
Adds two new functions:
- GM:GetRoundStateTime (Shared)
- GM:SetRoundStateTime (Server)
2019-01-12 21:17:49 +01:00
Michael Fabian 'Xaymar' Dirks 882cb5d9bb cl_init: Load and initialize new UI classes 2019-01-12 20:34:08 +01:00
Michael Fabian 'Xaymar' Dirks 0d1320a49b init: Add fontmanager and uimanager 2019-01-12 20:27:32 +01:00
Michael Fabian 'Xaymar' Dirks c8a4d63fda uimanager: Basic UI Manager for DPI and similar 2019-01-12 20:26:41 +01:00
Michael Fabian 'Xaymar' Dirks 7ce9df68ec fontmanager: Manager class for Fonts
Ensures that each font is only allocated once.
2019-01-12 20:26:09 +01:00
Michael Fabian 'Xaymar' Dirks 873e5410c1 media: Add transparent version of wide logo 2018-12-02 08:01:21 +01:00
Michael Fabian 'Xaymar' Dirks 9e6637679f gamemode: Fix scoreboard logo from 4da22f2f0e 2018-12-02 08:01:03 +01:00
Michael Fabian 'Xaymar' Dirks e951ae2b18 tools: Add Auto-Install script
This scripts goal is to attempt to install the addons into the /garrysmod/addons/ directory of the installed Garry's Mod. This should make it massively simpler to quickly get started with modifying and creating your own version of the gamemode.
2018-12-02 07:41:01 +01:00
Michael Fabian 'Xaymar' Dirks 004f89bd0a gamemode: Add support for directly installing into addons 2018-12-02 07:39:01 +01:00
Michael Fabian 'Xaymar' Dirks 27a44edaa1 gamemode: Fix logo size (GMod doesn't set a limit) 2018-12-02 07:38:41 +01:00
Michael Fabian 'Xaymar' Dirks 4da22f2f0e gamemode: Update logo and icon 2018-12-02 07:28:14 +01:00
Michael Fabian 'Xaymar' Dirks 333c7e3de7 media: Convert icon to SVG 2018-12-02 07:26:16 +01:00
Michael Fabian 'Xaymar' Dirks dd0de1aad1 tools, media: Update release tools 2018-12-02 07:25:44 +01:00
Michael Fabian 'Xaymar' Dirks 5452c69c8c media: Remove old files 2018-12-02 07:05:39 +01:00
Michael Fabian 'Xaymar' Dirks 13d91b20a1 gamemode/server/states/state_postround: Minor formatting 2018-12-02 06:40:13 +01:00
Michael Fabian 'Xaymar' Dirks 78f9596023 media: Add higher quality SVG files (compatible with Inkscape and text Diff) 2018-12-02 06:39:45 +01:00
Michael Fabian 'Xaymar' Dirks 8e6a557941 media: Remove old files 2018-12-02 06:39:00 +01:00
Michael Fabian 'Xaymar' Dirks a715cff408 project: Remove steam:// links in README.md 2018-12-02 06:38:25 +01:00
Michael Fabian 'Xaymar' Dirks 6d808c4272 git: More ignored files and merge/diff attributes for binary files 2018-12-02 06:36:00 +01:00
Michael Fabian 'Xaymar' Dirks a2b2c33475 tools: Simplify release tools 2018-12-02 05:38:55 +01:00
Michael Fabian 'Xaymar' Dirks 2ef4e82bbf media: Move media content 2018-12-02 03:39:21 +01:00
Michael Fabian 'Xaymar' Dirks 1565f956f9 tools: Move tools into separate directory 2018-12-02 03:38:09 +01:00
Michael Fabian 'Xaymar' Dirks 1a092fdf4d project: Rename and rewrite README file 2018-12-02 03:20:08 +01:00
Michael Fabian 'Xaymar' Dirks a1590c70a4 gamemode/player_class/class_hider: Log interaction with entities 2018-08-07 02:39:12 +02:00
Michael Fabian 'Xaymar' Dirks c56d0cee3e gamemode/player_class/class_default: Ignore players and increase use time
Players should be ignored for use commands, since it does not actually change things. Also increase the abuse cooldown to 0.5 seconds for non-blacklisted items.
2018-08-07 02:38:39 +02:00
Michael Fabian 'Xaymar' Dirks 69d22a0a20 Version 1.4.0 2018-08-07 02:35:48 +02:00
Michael Fabian 'Xaymar' Dirks 87be085030 gamemode/player_class/class_seeker: Log killed players in the debug log 2018-08-07 00:17:00 +02:00
Michael Fabian 'Xaymar' Dirks 4169000b22 gamemode/player_class/class_hider: Add seeker bonus health on kill and log the kill
Fixes #7
2018-08-07 00:15:54 +02:00
Michael Fabian 'Xaymar' Dirks 2bace089e9 entities/weapons/weapon_ph_smg: Fix weapon refire time and damage
Fixes #8
2018-08-07 00:14:22 +02:00
Michael Fabian 'Xaymar' Dirks 6a6b8da999 gamemode/server: Fix prop rotation messages appearing without debug log
Also adds the intended angle and player initiating the action
2018-07-05 06:56:44 +02:00
Michael Fabian 'Xaymar' Dirks 45925f2029 gamemode/server/roundmanager: Switch to generated implementation
Like with states, allows reuse and prevents missing elements and uses the Lua engine to do the lookup instead of the Lua parser. Slightly faster, but may not be directly obvious in use.
2018-07-05 06:55:46 +02:00
Michael Fabian 'Xaymar' Dirks bf0673914b gamemode/server/states: Switch to generated implementation
This has the benefit that all base info is present as meta info and setting a member to nil simply uses the meta member instead.
2018-07-05 06:54:05 +02:00
Michael Fabian 'Xaymar' Dirks 8e92eeef70 proxy: Add proxy gamemode
This gamemode is a simple proxy to allow the servers to be listed as "Prop Hunt" (using 'gamemode prop_hunt') while in reality playing "Prop Hunt Extended". This is primarily intended for servers where the barebone Prop Hunt configuration is active.
2018-07-05 03:49:24 +02:00
Michael Fabian 'Xaymar' Dirks b4379e94e6 project: ReadMe and workshop.txt 2018-07-05 02:20:50 +02:00
Michael Fabian 'Xaymar' Dirks 3d91f969c9 Version 1.3.1 2018-03-04 22:09:10 +01:00
Michael Fabian 'Xaymar' Dirks 05cf316c58 Shared: Use correct ConVar for Config::Teams::SeekerPercentage() 2018-03-04 21:57:43 +01:00
Michael Fabian 'Xaymar' Dirks 3a78c97742 media: Add normal logo 2017-11-26 16:21:59 +01:00
Michael Fabian 'Xaymar' Dirks 6b2ff0b55f gamemode: Implement a fully featured Scoreboard
The original game mode had a Scoreboard and now Prop Hunt Extended also has one. As usual, it has separation by team (Spectator, Hider, Seeker) and has the game mode logo in the top left. This score board is kept very simple and is non-interactive.

Media: https://drive.google.com/uc?id=12uVh2-BSC3p_aPgRSWNRdz3M0zbBj2BZ
2017-11-26 14:44:26 +01:00
Michael Fabian 'Xaymar' Dirks f5dacddd8c gamemode: Remove dmultilinelabel.lua (See Panel:SetWrap) 2017-11-26 13:50:27 +01:00
Michael Fabian 'Xaymar' Dirks dfdd8f82a3 gamemode: Allow infinite rounds to be played 2017-11-26 13:49:59 +01:00
Michael Fabian 'Xaymar' Dirks 7f3ba60b40 gamemode: Fix Suicide and Team Killing increasing Frags 2017-11-26 13:49:20 +01:00
Michael Fabian 'Xaymar' Dirks 863f099f31 gamemode: Implement Scoreboard support
The game mode will now assign points to teams as well as increment frags and deaths. This paves the way for a proper scoreboard to be added.
2017-11-26 12:54:57 +01:00
Michael Fabian 'Xaymar' Dirks 73a587085c gamemode: Remove the NoCollide constraint on player death 2017-11-26 12:46:02 +01:00
Michael Fabian 'Xaymar' Dirks 20dc523045 media: Add transparent version of the wide logo 2017-11-26 12:41:38 +01:00
Michael Fabian 'Xaymar' Dirks 47b768ffbd content: Rename content directory to prophuntextended 2017-11-26 12:41:06 +01:00
Michael Fabian 'Xaymar' Dirks 7349a96603 gamemode: Implement Alive() function in player classes
This allows checking if the player is actually alive according to the current player class. Some classes are alive to the game, but not to the actual game mode, for example Spectators are alive, but not really.
2017-11-26 12:40:28 +01:00
Michael Fabian 'Xaymar' Dirks be456dc323 gamemode: Fix client load order causing missing files.
Garry's Mod registers lua files in the order they appear, and will immediately run cl_init.lua once it is registered. This occasionally caused includes to error.
2017-11-26 12:38:23 +01:00
Michael Fabian 'Xaymar' Dirks f83464c10b gamemode: Create a few extra fonts 2017-11-26 12:36:33 +01:00
Michael Fabian 'Xaymar' Dirks be017d3d55 gamemode: Fix Hiders getting stuck on themselves
It seems that the physics engine allows the parent to collide with childs, but childs not with the parent. This doesn't make any sense at all.
2017-11-26 09:30:15 +01:00
Michael Fabian 'Xaymar' Dirks 6fbd73b217 gamemode: Remove unused lua code
These are mostly now in sh_config.lua, so there's no need to keep them around.
2017-11-26 08:21:04 +01:00
Michael Fabian 'Xaymar' Dirks ceb9ed1513 data: Remove unused files 2017-11-26 08:11:17 +01:00
Michael Fabian 'Xaymar' Dirks 677ff7b529 gamemode: Only show the selection halo for Hiders
The selection halo was previously visible to everyone in approximate mode, which caused more issues than it should have.
2017-11-26 04:26:23 +01:00
Michael Fabian 'Xaymar' Dirks 624fc3968e gamemode: Fix wrong id for settings
This caused some of these to overwrite each other.
2017-11-25 13:53:10 +01:00
Michael Fabian 'Xaymar' Dirks eb3b7f3aef gamemode: Add new 'Selection Halo' feature
This feature allows Hiders to easily tell which prop they will turn into if they press Use. As always, it can be fully configured and even turned off. By default it is enabled and set to Approximate mode.

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

In Accurate mode, the server is responsible for exactly knowing the best match to the Use key and sending this to the user. This has a server performance impact that scales with the player base and the rate at which these updates are performed can be configured. This mode is affected by lag and packet loss, so only really useful for high performance LAN servers or testing.
2017-11-25 13:25:29 +01:00
Michael Fabian 'Xaymar' Dirks 785f55a017 gamemode: Add Player meta extension
The meta object is extended by some commonly used functionality that Garry's Mod does not expose directly. Some of these are Server only and will produce wrong results on the Client, also due to Garry's Mod not exposing things properly.
2017-11-25 13:14:57 +01:00
Michael Fabian 'Xaymar' Dirks 2691ca4e46 gamemode/compat: Remove old compatibility code 2017-11-25 09:21:59 +01:00
Michael Fabian 'Xaymar' Dirks 8413d8e08e gamemode: Add support for FindUseEntity hook 2017-11-25 09:18:59 +01:00
Michael Fabian 'Xaymar' Dirks 5a4791a097 gamemode/sh_player: Add proper license header 2017-11-25 09:16:20 +01:00
Michael Fabian 'Xaymar' Dirks cc820a89d3 gamemode: Add new and update existing cvars with help text
The command 'cvarlist ph_' should now actually be much more descriptive than before.
2017-11-25 01:30:06 +01:00
Michael Fabian 'Xaymar' Dirks e8f5fc4b92 compat/tauntpackloader: Fix support for third party taunt packs 2017-11-25 00:16:52 +01:00
Michael Fabian 'Xaymar' Dirks 0091281e90 media: Add wider version of the logo 2017-11-25 00:16:33 +01:00
89 changed files with 6587 additions and 1621 deletions
+7
View File
@@ -0,0 +1,7 @@
*.jpg merge=binary -diff
*.png merge=bianry -diff
*.gif merge=binary -diff
*.tiff merge=bianry -diff
*.tga merge=binary -diff
*.psd merge=binary -diff
*.psb merge=binary -diff
+3
View File
@@ -0,0 +1,3 @@
issuehunt: xaymar
patreon: xaymar
custom: https://www.paypal.me/xaymar
+20
View File
@@ -0,0 +1,20 @@
---
name: Feature request
about: Want a new feature implemented?
---
<!--- Please fill out the following template, which will help other contributors review your Issue. -->
<!--- Make sure youve read the contribution guidelines -->
### Description
<!-- Describe the feature (and behavior) in as much detail as possible (yes, that means write an essay if you have to) -->
<!-- Include images of what you expect from the feature -->
### Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] I have read the contribution guidelines.
- [ ] This feature is necessary and can't be done through other means.
- [ ] This feature does not break existing functionality.
- [ ] I am willing to hire/pay someone to implement this.
+27
View File
@@ -0,0 +1,27 @@
---
name: Question/Feedback
about: Submit a question or some feedback! (Not for bugs, issues or crashes!)
---
<!--- Please fill out the following template, which will help other contributors review your Issue. -->
<!--- Make sure youve read the contribution guidelines -->
### Description
<!-- Describe the feature (and behavior) in as much detail as possible (yes, that means write an essay if you have to) -->
<!-- Include images of what you expect from the feature -->
### System Information
<!-- Include as much information about the system you're using as possible. -->
- Software Version: [e. g. 1.0.0, 1.2.1, ... - NEVER LATEST]
- Operating System: [e. g. Windows, Debian, Ubuntu, RedHat, FreeBSD, ...]
- Kernel Version: [e. g. 1903/1809 (Windows), 4.12 (Linux), ...]
- CPU: [e. g. Intel i7, AMD Zen2, Qualcomm, ...]
- GPU: [e. g. Nvidia RTX 2xxx Series, AMD Radeone 5xxx Series, ...]
- RAM: [e. g. 16GB, 32GB, 64GB, ...]
### Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] I have read the contribution guidelines.
- [ ] This is not a bug, crash or generic issue.
+38
View File
@@ -0,0 +1,38 @@
---
name: Issue/Bug report
about: Encountered a problem, a bug or a crash?
---
<!--- Please fill out the following template, which will help other contributors review your Issue. -->
<!--- Make sure youve read the contribution guidelines -->
### Description
<!-- Describe the bug (and behavior) in as much detail as necessary -->
<!-- Include screenshots and attach (crash) logs if possible -->
### Expected Behavior
<!-- What is the expected behavior in this case? -->
### Reproduction Steps
<!-- Describe the steps required to get this to happen from a cleanly installed obs-studio -->
<!-- Leave out detail that is not relevant to -->
1. Open a portal to the Infinite Void
2. Summon an ancient God
3. Realize your mistake
### System Information
<!-- Include as much information about the system you're using as possible. -->
- Software Version: [e. g. 1.0.0, 1.2.1, ... - NEVER LATEST]
- Operating System: [e. g. Windows, Debian, Ubuntu, RedHat, FreeBSD, ...]
- Kernel Version: [e. g. 1903/1809 (Windows), 4.12 (Linux), ...]
- CPU: [e. g. Intel i7, AMD Zen2, Qualcomm, ...]
- GPU: [e. g. Nvidia RTX 2xxx Series, AMD Radeone 5xxx Series, ...]
- RAM: [e. g. 16GB, 32GB, 64GB, ...]
### Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] I have read the contribution guidelines.
- [ ] I can reproduce the issue with the exact reproduction steps I have provided.
- [ ] The issue appears on all of my systems that can run this software.
+35
View File
@@ -0,0 +1,35 @@
<!--- Please fill out the following template, which will help other contributors review your Pull Request. -->
<!--- Make sure youve read the contribution guidelines -->
### Description
<!--- Describe your changes in detail. -->
<!--- If this change includes UI elements, please include screenshots. -->
### Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open Mantis issue, or implements feature request -->
<!--- from the Ideas page, please link to the issue here. -->
### How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment (hardware, OS version, etc.),-->
<!--- and the tests you ran, including how it may affect other areas of code. -->
### Types of changes
<!--- What types of changes does your PR introduce? Uncomment all that apply -->
<!--- - Bug fix (non-breaking change which fixes an issue) -->
<!--- - New feature (non-breaking change which adds functionality) -->
<!--- - Performance enhancement (non-breaking change which improves efficiency) -->
<!--- - Code cleanup (non-breaking change which makes code smaller or more readable) -->
<!--- - Breaking change (fix or feature that would cause existing functionality to change) -->
<!--- - Documentation (a change to documentation pages) -->
### Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] My code has been run through [clang-format](https://github.com/obsproject/obs-studio/blob/master/.clang-format).
- [ ] I have read the [**contributing** document](https://github.com/obsproject/obs-studio/blob/master/CONTRIBUTING.rst).
- [ ] My code is not on the master branch.
- [ ] The code has been tested.
- [ ] All commit messages are properly formatted and commits squashed where appropriate.
+3 -4
View File
@@ -1,4 +1,3 @@
Pack.gma /media/rendered/*
Changelog.txt *.gma
Description.txt desktop.ini
/*.gma
+6 -17
View File
@@ -1,22 +1,11 @@
The MIT License (MIT) Copyright 2015-2020 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
Copyright (c) 2016 Michael Fabian Dirks Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Permission is hereby granted, free of charge, to any person obtaining a copy 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+58
View File
@@ -0,0 +1,58 @@
# Prop Hunt Extended
Hide n Seek with a twist - Hiders can turn into anything on the map! From bottles, to vending machines and all the way to huge cars - what you become depends on how you want to play. Do you want to blend in with your surroundings, or do you want to make a fool of the Seekers? And how will you deal with finding (and killing) all hiders as a Seeker?
## Features and Improvements
* **Prop Rotation**: Rotate your prop into the correct orientation to fool Seekers even more.
* **Correct Hitboxes**: All hitboxes now compensate for lag, making shots that should have hit actually hit.
* **Better Camera**: First- & Third-Person modes, world collision, proper world origin to support small hiding spaces without making the world disappear.
* **Custom Player Models**: Customize yourself to the best of your abilities.
* **Taunt Packs**: All taunt packs compatible with Tsukasas Taunt Pack Loader will work and load.
* **Name Plates and Selection Halo**: Know who is what, and what you're going to select!
* **Proper Scoreboard**: The gamemode comes with a proper Scoreboard instead of the default one.
* **Better Configuration**: Everything can be configured during gameplay using CVars.
* **Improved Networking Performance**: Only necessary information is shared.
## Compatibility with other Addons
* **[MapVote](https://steamcommunity.com/sharedfiles/filedetails/?id=151583504)**: Full support
* **Tsukasas Taunt Pack Loader**: Compatibility layer included, not compatible due to this.
* **LiteGibs**: Breaks literally everything somehow.
# How To Play
## Seekers
Your primary goal is to find hiders by any means possible. But watch out, you might lose health if you shoot an object that isn't actually a hider! Pick things up before shooting them, or simply remember the layout of the maps you are playing on. And remember: You lose if only a single hider is still alive at the end of the round.
## Hiders
Stay alive as long as possible and make Seekers look like a fool. Dance around their feet, hide in plain sight or be that huge car that nobody though you could become! What you do is entirely up to you.
## Spectators
You get to watch the whole thing go down live! Sit back, grab some popcorn or any other snack and relax.
## Controls
* ShowHelp (Default F1): Show Help and client Settings menu.
* ShowTeam (Default F2): Show Team Selection menu.
* ShowSpare1 (Default F3): Taunt everything and everyone.
* ShowContextMenu (Default C): Toggle between First- and Thirdperson camera.
* ShowSpawnMenu (Default Q): (Hider only) Hold to enable prop rotation, let go to disable prop rotation.
* Prop Hunt SMG Reload (Default R): If ammo is full switches between single and burst fire.
# Other Stuff
## Help and Community
All help is provided through [Discord (preferred, channel #gmod-prop-hunt-extended)](https://discord.gg/tbqhAxr) and [Steam Workshop Discussions](https://steamcommunity.com/sharedfiles/filedetails/discussions/468149739). Please read the [FAQ](https://steamcommunity.com/workshop/filedetails/discussion/468149739/358415206095321277/) as it can often answer your question.
## Spread the Word
It is always appreciated to see the word about this Gamemode being spread, especially to content creators that are still uploading Prop Hunt content. If you want to tag me, my Twitter username is [@Xaymar](https://twitter.com/Xaymar), my Twitch username is [Xaymar](https://twitch.tv/Xaymar), my YouTube custom url is [Xaymar](https://youtube.com/c/Xaymar) and my Patreon is also [Xaymar](https://patreon.com/Xaymar).
## Donations to help the cause
The development of this and other projects is funded through [Patreon](https://www.patreon.com/Xaymar). My dream is to eventually be able to do this full time without requiring a full-time job, perhaps even streaming this to YouTube and Twitch.
## Official Servers
### Central Europe
* Primary: steam://connect/xaymar.com:27015
* Secondary: steam://connect/xaymar.com:27016
## Links
* [Workshop page](https://steamcommunity.com/sharedfiles/filedetails/?id=468149739)
* [Facepunch Thread](https://forum.facepunch.com/f/gmodgames/osvi/Prop-Hunt-Extended/1/)
# License
For the license, see the file `LICENSE`. This file overrides any headers written in files.
-4
View File
@@ -1,4 +0,0 @@
@ECHO OFF
call env.win.bat
"%GARRYSMODPATH%\bin\gmpublish.exe" update -id 468149739 -icon "media\gamemode_workshop.jpg" -addon "pack.gma" -changes ""
PAUSE
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 KiB

+11
View File
@@ -0,0 +1,11 @@
[h1]Version: 1.4.0[/h1]
The round manager has been rewritten to improve code quality and reusability and is now using meta-classes, which slightly improves overall performance. For addons that hook into the gamemode, this means that GAMEMODE.RoundManager is only valid after GM:Initialize() has been run.
Additionally the Prop Hunt SMG has been slightly changed and now fires at a rate of 0.075 (from 0.1), but deals only 4 damage (from 5), which makes it near identical to the standard Half Life 2 SMG. It will now deal 53.33 DPS instead of 50 DPS like before, while keeping the accuracy and extra features as is.
[b]Changelog:[/b]
[list][*]Changed Prop Hunt SMD Refire Time from 0.1 to 0.075.
[*]Fixed Seekers not gaining health back after killing a Hider.
[*]Fixed some debug log messages by Prop Rotation appearing without debug log being enabled.
[*]Rewrote the round manager to use a class based system.
[list]
Binary file not shown.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.
Binary file not shown.
+102
View File
@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="32"
viewBox="0 0 8.4666667 8.4666667"
version="1.1"
id="svg8"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
sodipodi:docname="icon.svg"
inkscape:export-filename="D:\Projects\GarrysMod\PropHuntExtended\media\rendered\icon.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="32"
inkscape:cx="22.42927"
inkscape:cy="16.716875"
inkscape:document-units="mm"
inkscape:current-layer="layer3"
showgrid="false"
units="px"
inkscape:window-width="2880"
inkscape:window-height="1620"
inkscape:window-x="4068"
inkscape:window-y="228"
inkscape:window-maximized="0" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-288.53332)">
<rect
style="display:inline;fill:#433a35;fill-opacity:1;stroke-width:0.0073266"
id="rect4532"
width="8.4666662"
height="8.4666662"
x="0"
y="288.53333" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Layer 2"
style="display:inline">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:9.64581013px;line-height:1.25;font-family:Impact;-inkscape-font-specification:Impact;letter-spacing:0px;word-spacing:0px;fill:#f2722b;fill-opacity:1;stroke:none;stroke-width:1.80858934"
x="-0.39562893"
y="267.48511"
id="text817"
transform="matrix(0.90062328,0,0,1.1103422,0,-288.53331)"><tspan
sodipodi:role="line"
id="tspan815"
x="-0.39562893"
y="267.48511"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Impact;-inkscape-font-specification:Impact;fill:#f2722b;fill-opacity:1;stroke-width:1.80858934">PH</tspan></text>
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Layer 3">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.02445936px;line-height:1.25;font-family:Impact;-inkscape-font-specification:Impact;letter-spacing:0px;word-spacing:0px;fill:#fffff7;fill-opacity:1;stroke:none;stroke-width:1.12958598"
x="1.3681852"
y="8.4666901"
id="text821"><tspan
sodipodi:role="line"
id="tspan819"
x="1.3681852"
y="8.4666901"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Impact;-inkscape-font-specification:Impact;fill:#fffff7;fill-opacity:1;stroke-width:1.12958598">EX</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

+213
View File
@@ -0,0 +1,213 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="8192"
height="1024"
viewBox="0 0 2167.4666 270.93334"
version="1.1"
id="svg4530"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
sodipodi:docname="logo-wide-transparent.svg"
style="enable-background:new"
inkscape:export-filename="D:\Projects\GarrysMod\PropHuntExtended\source\gamemodes\prophuntextended\logo.png"
inkscape:export-xdpi="24"
inkscape:export-ydpi="24">
<defs
id="defs4524">
<marker
inkscape:stockid="Arrow1Sstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Sstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path6765"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt"
transform="matrix(0.2,0,0,0.2,1.2,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path6753"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
<linearGradient
id="linearGradient6153"
osb:paint="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop6151" />
</linearGradient>
<filter
style="color-interpolation-filters:sRGB"
id="filter7370"
inkscape:label="text-extended-filter"
x="-0.02"
width="1.04">
<feGaussianBlur
stdDeviation="1"
id="feGaussianBlur7374"
result="result4" />
<feGaussianBlur
stdDeviation="2"
id="feGaussianBlur7376"
in="SourceGraphic"
result="result2" />
<feGaussianBlur
stdDeviation="4"
id="feGaussianBlur7378"
in="SourceGraphic"
result="result1" />
<feBlend
mode="screen"
in2="result2"
id="feBlend7380"
result="result3"
in="result1" />
<feBlend
mode="screen"
in2="result4"
id="feBlend7382"
result="result5" />
<feBlend
mode="screen"
in2="SourceGraphic"
id="feBlend7384"
result="result7" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.27854414"
inkscape:cx="4871.459"
inkscape:cy="1967.7857"
inkscape:document-units="mm"
inkscape:current-layer="layer3"
showgrid="false"
showborder="true"
inkscape:pagecheckerboard="true"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2080"
inkscape:window-x="3829"
inkscape:window-y="-11"
inkscape:window-maximized="1"
showguides="true"
inkscape:guide-bbox="true">
<sodipodi:guide
position="541.86667,270.93333"
orientation="0,1"
id="guide4543"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
<sodipodi:guide
position="541.86667,270.93334"
orientation="1,0"
id="guide4545"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
<sodipodi:guide
position="541.86667,406.4"
orientation="0,1"
id="guide4547"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
</sodipodi:namedview>
<metadata
id="metadata4527">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Text EXTENDED"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-26.066643)"
style="display:inline">
<g
style="display:inline;stroke:#f2722b;stroke-width:14.74307919;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;filter:url(#filter7370)"
transform="matrix(0.82040111,0,0,0.82040111,1119.0696,23.456852)"
inkscape:label="Layer 1"
id="g7255">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:316.34109497px;line-height:1.25;font-family:Impact;-inkscape-font-specification:Impact;letter-spacing:0px;word-spacing:0px;fill:none;fill-opacity:1;stroke:#f2722b;stroke-width:14.57606602;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="-10.334827"
y="293.34174"
id="text7253"><tspan
dx="0"
sodipodi:role="line"
id="tspan7251"
x="-10.334827"
y="293.34174"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:273.42272949px;font-family:Impact;-inkscape-font-specification:Impact;letter-spacing:4.85868835px;fill:none;fill-opacity:1;stroke:#f2722b;stroke-width:14.57606602;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal">EXTENDED</tspan></text>
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Text PROP HUNT"
style="display:inline"
transform="translate(0,-270.93333)">
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Background"
style="display:inline" />
<g
transform="matrix(0.95541658,0,0,0.99515462,383.45565,251.14939)"
id="layer1-9"
inkscape:label="Ebene 1"
style="fill:#f2722b;fill-opacity:1;fill-rule:nonzero">
<text
id="text3715"
y="255.2442"
x="-387.08383"
style="font-style:normal;font-weight:normal;font-size:251.06704712px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#f2722b;fill-opacity:1;fill-rule:nonzero"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Impact;-inkscape-font-specification:Impact;fill:#f2722b;fill-opacity:1;fill-rule:nonzero"
y="255.2442"
x="-387.08383"
id="tspan3713"
sodipodi:role="line">PROP HUNT</tspan></text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.2 KiB

+221
View File
@@ -0,0 +1,221 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="8192"
height="1024"
viewBox="0 0 2167.4666 270.93334"
version="1.1"
id="svg4530"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
sodipodi:docname="logo-wide.svg"
style="enable-background:new"
inkscape:export-filename="D:\Projects\GarrysMod\PropHuntExtended\media\rendered\logo-wide.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs4524">
<marker
inkscape:stockid="Arrow1Sstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Sstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path6765"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt"
transform="matrix(0.2,0,0,0.2,1.2,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path6753"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
<linearGradient
id="linearGradient6153"
osb:paint="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop6151" />
</linearGradient>
<filter
style="color-interpolation-filters:sRGB"
id="filter7370"
inkscape:label="text-extended-filter"
x="-0.02"
width="1.04">
<feGaussianBlur
stdDeviation="1"
id="feGaussianBlur7374"
result="result4" />
<feGaussianBlur
stdDeviation="2"
id="feGaussianBlur7376"
in="SourceGraphic"
result="result2" />
<feGaussianBlur
stdDeviation="4"
id="feGaussianBlur7378"
in="SourceGraphic"
result="result1" />
<feBlend
mode="screen"
in2="result2"
id="feBlend7380"
result="result3"
in="result1" />
<feBlend
mode="screen"
in2="result4"
id="feBlend7382"
result="result5" />
<feBlend
mode="screen"
in2="SourceGraphic"
id="feBlend7384"
result="result7" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.27854414"
inkscape:cx="5596.6582"
inkscape:cy="1967.7857"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
showborder="true"
inkscape:pagecheckerboard="true"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2080"
inkscape:window-x="3829"
inkscape:window-y="-11"
inkscape:window-maximized="1"
showguides="true"
inkscape:guide-bbox="true">
<sodipodi:guide
position="541.86667,270.93333"
orientation="0,1"
id="guide4543"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
<sodipodi:guide
position="541.86667,270.93334"
orientation="1,0"
id="guide4545"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
<sodipodi:guide
position="541.86667,406.4"
orientation="0,1"
id="guide4547"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
</sodipodi:namedview>
<metadata
id="metadata4527">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Text EXTENDED"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-26.066643)"
style="display:inline">
<g
style="display:inline;stroke:#f2722b;stroke-width:14.74307919;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;filter:url(#filter7370)"
transform="matrix(0.82040111,0,0,0.82040111,1119.0696,23.456852)"
inkscape:label="Layer 1"
id="g7255">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:316.34109497px;line-height:1.25;font-family:Impact;-inkscape-font-specification:Impact;letter-spacing:0px;word-spacing:0px;fill:none;fill-opacity:1;stroke:#f2722b;stroke-width:14.57606602;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="-10.334827"
y="293.34174"
id="text7253"><tspan
dx="0"
sodipodi:role="line"
id="tspan7251"
x="-10.334827"
y="293.34174"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:273.42272949px;font-family:Impact;-inkscape-font-specification:Impact;letter-spacing:4.85868835px;fill:none;fill-opacity:1;stroke:#f2722b;stroke-width:14.57606602;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal">EXTENDED</tspan></text>
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Text PROP HUNT"
style="display:inline"
transform="translate(0,-270.93333)">
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Background"
style="display:inline">
<rect
style="display:inline;fill:#433a35;fill-opacity:1;stroke-width:0.46890202"
id="rect4532"
width="1083.7333"
height="270.93332"
x="1.110223e-016"
y="270.93335" />
</g>
<g
transform="matrix(0.95541658,0,0,0.99515462,383.45565,251.14939)"
id="layer1-9"
inkscape:label="Ebene 1"
style="fill:#f2722b;fill-opacity:1;fill-rule:nonzero">
<text
id="text3715"
y="255.2442"
x="-387.08383"
style="font-style:normal;font-weight:normal;font-size:251.06704712px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#f2722b;fill-opacity:1;fill-rule:nonzero"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Impact;-inkscape-font-specification:Impact;fill:#f2722b;fill-opacity:1;fill-rule:nonzero"
y="255.2442"
x="-387.08383"
id="tspan3713"
sodipodi:role="line">PROP HUNT</tspan></text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

+219
View File
@@ -0,0 +1,219 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="4096"
height="2048"
viewBox="0 0 1083.7333 541.86668"
version="1.1"
id="svg4530"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
sodipodi:docname="logo.svg"
enable-background="new"
inkscape:export-filename="D:\Projects\GarrysMod\PropHuntExtended\media\rendered\logo.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs4524">
<marker
inkscape:stockid="Arrow1Sstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Sstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path6765"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
transform="scale(0.2) translate(6,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path6753"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
transform="scale(0.8) translate(12.5,0)" />
</marker>
<linearGradient
id="linearGradient6153"
osb:paint="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop6151" />
</linearGradient>
<filter
style="color-interpolation-filters:sRGB"
id="filter7370"
inkscape:label="text-extended-filter"
x="-0.02"
width="1.04">
<feGaussianBlur
stdDeviation="1"
id="feGaussianBlur7374"
result="result4" />
<feGaussianBlur
stdDeviation="2"
id="feGaussianBlur7376"
in="SourceGraphic"
result="result2" />
<feGaussianBlur
stdDeviation="4"
id="feGaussianBlur7378"
in="SourceGraphic"
result="result1" />
<feBlend
mode="screen"
in2="result2"
id="feBlend7380"
result="result3"
in="result1" />
<feBlend
mode="screen"
in2="result4"
id="feBlend7382"
result="result5" />
<feBlend
mode="screen"
in2="SourceGraphic"
id="feBlend7384"
result="result7" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.7878418"
inkscape:cx="1533.9593"
inkscape:cy="1030.2533"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
showborder="true"
inkscape:pagecheckerboard="true"
units="px"
inkscape:window-width="3840"
inkscape:window-height="2080"
inkscape:window-x="3829"
inkscape:window-y="-11"
inkscape:window-maximized="1"
showguides="true"
inkscape:guide-bbox="true">
<sodipodi:guide
position="541.86667,270.93333"
orientation="0,1"
id="guide4543"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
<sodipodi:guide
position="541.86667,270.93334"
orientation="1,0"
id="guide4545"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
<sodipodi:guide
position="541.86667,406.4"
orientation="0,1"
id="guide4547"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" />
</sodipodi:namedview>
<metadata
id="metadata4527">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Text EXTENDED"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,244.86669)"
style="display:inline;">
<g
style="display:inline;stroke:#f2722b;stroke-width:14.74307919;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;filter:url(#filter7370)"
transform="matrix(0.82040111,0,0,0.82040111,37.679834,22.343453)"
inkscape:label="Layer 1"
id="g7255">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:316.34109497px;line-height:1.25;font-family:Impact;-inkscape-font-specification:Impact;letter-spacing:0px;word-spacing:0px;fill:none;fill-opacity:1;stroke:#f2722b;stroke-width:14.57606602;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="-10.334827"
y="293.34174"
id="text7253"><tspan
dx="0"
sodipodi:role="line"
id="tspan7251"
x="-10.334827"
y="293.34174"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:273.42272949px;font-family:Impact;-inkscape-font-specification:Impact;letter-spacing:4.85868835px;fill:none;fill-opacity:1;stroke:#f2722b;stroke-width:14.57606602;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal">EXTENDED</tspan></text>
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Text PROP HUNT"
style="display:inline">
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Background"
style="display:inline">
<rect
transform="translate(0,244.86669)"
style="display:inline;fill:#433a35;fill-opacity:1;stroke-width:0.46890202"
id="rect4532"
width="1083.7333"
height="270.93332"
x="1.110223e-016"
y="-244.86668" />
</g>
<g
transform="matrix(0.95541658,0,0,0.99515462,383.45565,-19.78395)"
id="layer1-9"
inkscape:label="Ebene 1"
style="fill:#f2722b;fill-opacity:1;fill-rule:nonzero">
<text
id="text3715"
y="255.2442"
x="-387.08383"
style="font-style:normal;font-weight:normal;font-size:251.06704712px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#f2722b;fill-opacity:1;fill-rule:nonzero"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Impact;-inkscape-font-specification:Impact;fill:#f2722b;fill-opacity:1;fill-rule:nonzero"
y="255.2442"
x="-387.08383"
id="tspan3713"
sodipodi:role="line">PROP HUNT</tspan></text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

+110
View File
@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 210 297"
version="1.1"
id="svg6163"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
sodipodi:docname="title-extended.svg">
<defs
id="defs6157">
<filter
style="color-interpolation-filters:sRGB"
id="filter7370"
inkscape:label="text-extended-filter">
<feGaussianBlur
stdDeviation="1"
id="feGaussianBlur7374"
result="result4" />
<feGaussianBlur
stdDeviation="2"
id="feGaussianBlur7376"
in="SourceGraphic"
result="result2" />
<feGaussianBlur
stdDeviation="4"
id="feGaussianBlur7378"
in="SourceGraphic"
result="result1" />
<feBlend
mode="screen"
in2="result2"
id="feBlend7380"
result="result3"
in="result1" />
<feBlend
mode="screen"
in2="result4"
id="feBlend7382"
result="result5" />
<feBlend
mode="screen"
in2="SourceGraphic"
id="feBlend7384"
result="result7" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="-77.142857"
inkscape:cy="560"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="3840"
inkscape:window-height="2080"
inkscape:window-x="3829"
inkscape:window-y="-11"
inkscape:window-maximized="1" />
<metadata
id="metadata6160">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g
style="display:inline;stroke:#f2722b;stroke-width:14.74307919;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;filter:url(#filter7370)"
transform="matrix(0.82040111,0,0,0.82040111,98.238237,35.82582)"
inkscape:label="Layer 1"
id="g7255">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:316.34109497px;line-height:1.25;font-family:Impact;-inkscape-font-specification:Impact;letter-spacing:0px;word-spacing:0px;fill:none;fill-opacity:1;stroke:#f2722b;stroke-width:14.57606602;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="-10.334827"
y="293.34174"
id="text7253"><tspan
dx="0"
sodipodi:role="line"
id="tspan7251"
x="-10.334827"
y="293.34174"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:273.42272949px;font-family:Impact;-inkscape-font-specification:Impact;letter-spacing:4.85868835px;fill:none;fill-opacity:1;stroke:#f2722b;stroke-width:14.57606602;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal">EXTENDED</tspan></text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

+88
View File
@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="4101.4619"
height="781.65002"
viewBox="0 0 1085.1785 206.81157"
version="1.1"
id="svg8"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
sodipodi:docname="title-text.svg">
<title
id="title3717">Prop Hunt Title Text</title>
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="1186.9308"
inkscape:cy="417.93638"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:pagecheckerboard="true"
showborder="false"
units="px"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="3840"
inkscape:window-height="2080"
inkscape:window-x="3829"
inkscape:window-y="-11"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Prop Hunt Title Text</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Michael Fabian Dirks &lt;info@xaymar.com&gt;</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title></dc:title>
</cc:Agent>
</dc:rights>
<dc:language>English</dc:language>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(376.78616,-52.600731)">
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:251.06704712px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#f2722b;fill-opacity:1;stroke:none;stroke-width:6.27667618;"
x="-387.08383"
y="255.2442"
id="text3715"><tspan
sodipodi:role="line"
id="tspan3713"
x="-387.08383"
y="255.2442"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Impact;-inkscape-font-specification:Impact;stroke-width:6.27667618;fill:#f2722b;fill-opacity:1;">PROP HUNT</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 177 KiB

+31
View File
@@ -0,0 +1,31 @@
Hide n Seek with a twist - Hiders can turn into anything on the map! From bottles, to vending machines and all the way to huge cars - what you become depends on how you want to play. Do you want to blend in with your surroundings, or do you want to make a fool of the Seekers? And how will you deal with finding (and killing) all hiders as a Seeker?
The Gamemode comes with out of the box support for console configuration (ph_*), custom taunt support, prop rotation, an improved code base for modders and better integration and some other fixes. Support for [url=https://steamcommunity.com/sharedfiles/filedetails/?id=151583504]MapVote[/url] is also built in, so as long as you have a compatible addon installed you will get a map voting menu at the end of a match.
[h1]How To Play[/h1]
[b]Seekers[/b]
Your primary goal is to find hiders by any means possible. But watch out, you might lose health if you shoot an object that isn't actually a hider! Pick things up before shooting them, or simply remember the layout of the maps you are playing on. And remember: You lose if only a single hider is still alive at the end of the round.
[b]Hiders[/b]
Stay alive as long as possible and make Seekers look like a fool. Dance around their feet, hide in plain sight or be that huge car that nobody though you could become! What you do is entirely up to you.
[b]Spectators[/b]
You get to watch the whole thing go down live! Sit back, grab some popcorn or any other snack and relax.
[h1]Controls[/h1]
[list][*]F2 (ShowTeam): Select A Team or Change Current Team.
[*]F3 (ShowSpare1): Play a Taunt.
[*]C (ShowContextMenu): Toggle between first and third person camera.
[*]Q (ShowSpawnMenu): Hold to rotate your object (Hider only).
[*]Ctrl (Duck, Crouch): Interact with objects instead of turning into them, allowing you to pick things up (Hiders only, Seekers always interact with things).
[*]R with the Prop Hunt SMG (Reload): On full magazine, switch between auto and burst fire.
[/list]
[h1]Support the Gamemode[/h1]
Spreading the word that Prop Hunt Extended exists, work together with others on the gamemode or just play it on your favourite server. Every single thing helps! You can also join our [url=https://discord.gg/tbqhAxr]Discord[/url] and perhaps find additional people to play with that way.
[h1]Need support?[/h1]
Please consider reading the [url=http://steamcommunity.com/workshop/filedetails/discussion/468149739/358415206095321277/]Frequently Asked Questions[/url] first. If nothing of that helped, either write a comment below or try asking your question in #gmod-prop-hunt-extended on [url=https://discord.gg/tbqhAxr]Discord[/url].
[h1]Want to join development?[/h1]
The entire source code is available under the MIT License [url=https://github.com/Xaymar/PropHuntExtended]on GitHub[/url].
-4
View File
@@ -1,4 +0,0 @@
@ECHO OFF
call env.win.bat
"%GARRYSMODPATH%\bin\gmad.exe" create -folder "%CD%\source" -out "%CD%\pack.gma"
PAUSE
+8
View File
@@ -0,0 +1,8 @@
{
"title" : "Prop Hunt Extended (Proxy Gamemode)",
"type" : "gamemode",
"tags" : [ ],
"ignore" : [
"addon.txt"
]
}
+9
View File
@@ -0,0 +1,9 @@
"AddonInfo"
{
"name" "Prop Hunt"
"version" "1.0.0"
"up_date" "00/00/00"
"author_name" "Xaymar"
"author_email" "info@xaymar.com"
"author_url" "https://xaymar.com/"
}
@@ -22,9 +22,4 @@
SOFTWARE. SOFTWARE.
--]] --]]
local ELEMENT = {} include("sh_init.lua")
function ELEMENT:Paint()
end
vgui.Register("DMultilineLabel", ELEMENT, "Panel")
@@ -0,0 +1,27 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
AddCSLuaFile("sh_init.lua")
AddCSLuaFile("cl_init.lua")
include "sh_init.lua"
@@ -0,0 +1,37 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
-- ------------------------------------------------------------------------- --
--! Gamemode Information
-- ------------------------------------------------------------------------- --
GM.Name = "Prop Hunt Extended"
GM.Author = "Michael Fabian 'Xaymar' Dirks"
GM.Email = "info@xaymar.com"
GM.Website = "http://xaymar.com/"
GM.TeamBased = true
GM.AllowAutoTeam = true
GM.SecondsBetweenTeamSwitches = 10
DeriveGamemode("prophuntextended")
+401
View File
@@ -0,0 +1,401 @@
"prop_hunt"
{
"base" "prophuntextended"
"title" "Prop Hunt Extended"
"maps" "^ph_"
"menusystem" "1"
"workshopid" "468149739"
"settings"
{
// Debug Settings
1
{
"name" "ph_debug"
"text" "Enable Debug Mode"
"type" "CheckBox"
"default" "0"
"help" "Prop Hunt: Enable Debug Mode"
}
2
{
"name" "ph_debug_log"
"text" "Enable Debug Logging"
"type" "CheckBox"
"default" "1"
"help" "Prop Hunt: Enable Debug Logging"
}
// Basic Settings
100
{
"name" "ph_gametype"
"text" "Game Type to use"
"type" "Numeric"
"default" "0"
"help" "Prop Hunt: Which Game Type should be played?"
}
101
{
"name" "mp_timelimit"
"text" "Map Time Limit"
"type" "Numeric"
"default" "0"
"help" "Map Time Limit (in Minutes)"
}
102
{
"name" "mp_friendlyfire"
"text" "Friendly fire"
"type" "Numeric"
"default" "0"
"help" "Allow friendly fire? (0 = No, 1 = Yes, 2 = Reflect)"
}
// Round Settings
200
{
"name" "ph_round_limit"
"text" "Maximum Rounds Played"
"type" "Numeric"
"default" "10"
"help" "Round Manager: Maximum Rounds to Play on a single Map"
}
201
{
"name" "ph_round_timelimit"
"text" "Time Limit per Round"
"type" "Numeric"
"default" "180"
"help" "Round Manager: Time Limit per Round (in Seconds)"
}
202
{
"name" "ph_round_blindtime"
"text" "Seeker Blind time per Round"
"type" "Numeric"
"default" "-30"
"help" "Round Manager: Blind Time for Seekers (in Seconds, positive takes away from ph_round_timelimit, negative adds extra time to ph_round_timelimit)"
}
// Team Settings
300
{
"name" "ph_teams_randomize"
"text" "Randomize Teams"
"type" "CheckBox"
"default" "1"
"help" "Teams: Randomize Teams instead of swapping each round"
}
301
{
"name" "ph_teams_weighted"
"text" "Randomize with weighted Score"
"type" "CheckBox"
"default" "1"
"help" "Teams: Use Weighted Randomization"
}
302
{
"name" "ph_teams_seekerpct"
"text" "Pct of Pl. becoming Seeker"
"type" "Numeric"
"default" "25"
"help" "Teams: Initial percentage of Seekers in Dead Hunt Game Type"
}
// Seeker Settings
400
{
"name" "ph_seeker_health"
"text" "Seeker Health"
"type" "Numeric"
"default" "100"
"help" "Seekers: Initial Health"
}
401
{
"name" "ph_seeker_health_max"
"text" "Seeker Max Health"
"type" "Numeric"
"default" "100"
"help" "Seekers: Maximum Health"
}
402
{
"name" "ph_seeker_health_bonus"
"text" "Seeker Health Kill-Bonus"
"type" "Numeric"
"default" "20"
"help" "Seekers: Health Bonus per Kill"
}
403
{
"name" "ph_seeker_health_penalty"
"text" "Seeker Health Penalty"
"type" "Numeric"
"default" "5"
"help" "Seekers: Health Penalty per wrong Shot"
}
404
{
"name" "ph_seeker_weapons"
"text" "Seeker Weapons"
"type" "Text"
"default" "weapon_crowbar,weapon_pistol,weapon_ph_smg,weapon_shotgun"
"help" "Seekers: Initial Weapons (Weapon,Weapon,...)"
}
405
{
"name" "ph_seeker_ammo"
"text" "Seeker Ammo"
"type" "Text"
"default" "Pistol:100,SMG1:300,SMG1_Grenade:1,Buckshot:64"
"help" "Seekers: Initial Ammo (Ammo:Amount,Ammo:Amount,...)"
}
406
{
"name" "ph_seeker_walk_speed"
"text" "Seeker Walk Speed"
"type" "Numeric"
"default" "250"
"help" "Seekers: Walk Speed"
}
407
{
"name" "ph_seeker_sprint"
"text" "Seeker Sprint Allowed"
"type" "CheckBox"
"default" "1"
"help" "Seekers: Allow Sprinting"
}
408
{
"name" "ph_seeker_sprint_speed"
"text" "Seeker Sprint Speed"
"type" "Numeric"
"default" "500"
"help" "Seekers: Sprint Speed"
}
409
{
"name" "ph_seeker_jump_power"
"text" "Seeker Jump Power"
"type" "Numeric"
"default" "200"
"help" "Seekers: Jump Power"
}
// Hider Settings
500
{
"name" "ph_hider_health"
"text" "Hider Health"
"type" "Numeric"
"default" "100"
"help" "Hiders: Initial Health"
}
501
{
"name" "ph_hider_health_max"
"text" "Hider Max Health"
"type" "Numeric"
"default" "100"
"help" "Hiders: Maximum Health"
}
502
{
"name" "ph_hider_health_scaling"
"text" "Hider Enable Health Scaling"
"type" "CheckBox"
"default" "1"
"help" "Hiders: Enable Health Scaling"
}
503
{
"name" "ph_hider_health_scaling_max"
"text" "Hider Scaled Max Health"
"type" "Numeric"
"default" "200"
"help" "Hiders: Maximum scaled Health"
}
504
{
"name" "ph_hider_allow_full_rotation"
"text" "Hider 3-Dimensional Rotation"
"type" "CheckBox"
"default" "0"
"help" "Hiders: Enable full 3D Rotation"
}
505
{
"name" "ph_hider_walk_speed"
"text" "Hider Walk Speed"
"type" "Numeric"
"default" "250"
"help" "Hiders: Walk Speed"
}
506
{
"name" "ph_hider_sprint"
"text" "Hider Sprint Allowed"
"type" "CheckBox"
"default" "0"
"help" "Hiders: Allow Sprinting"
}
507
{
"name" "ph_hider_sprint_speed"
"text" "Hider Sprint Speed"
"type" "Numeric"
"default" "500"
"help" "Hiders: Sprint Speed"
}
507
{
"name" "ph_hider_jump_power"
"text" "Hider Jump Power"
"type" "Numeric"
"default" "200"
"help" "Hiders: Jump Power"
}
// Whitelist & Blacklist
600
{
"name" "ph_list_class_whitelist"
"text" "Allowed Entity Classes"
"type" "Text"
"default" "ph_prop,prop_physics,prop_physics_multiplayer,prop_physics_respawnable"
"help" "Anti-Cheat: Whitelisted Hider Classes"
}
601
{
"name" "ph_list_abuse_blacklist"
"text" "Abuse Blacklist"
"type" "Text"
"default" "func_button,func_door,func_door_rotation,prop_door_rotation,func_tracktrain,func_tanktrain,func_breakable"
"help" "Anti-Cheat: Entity Abuse Blacklist"
}
602
{
"name" "ph_list_model_blacklist"
"text" "Model Blacklist"
"type" "Text"
"default" "models/props/cs_assault/dollar.mdl,models/props/cs_assault/money.mdl,models/props/cs_office/snowman_arm.mdl,models/props/cs_office/projector_remote.mdl"
"help" "Anti-Cheat: Model Abuse Blacklist"
}
// Taunts
700
{
"name" "ph_taunt_cooldown"
"text" "Cooldown for Taunts"
"type" "Numeric"
"default" "5"
"help" "Prop Hunt: Cooldown between Taunts"
}
701
{
"name" "ph_taunt_seekers"
"text" "Seeker Taunts"
"type" "Text"
"default" "bot/a_bunch_of_them.wav,bot/come_out_and_fight_like_a_man.wav,bot/come_out_wherever_you_are.wav,bot/come_to_papa.wav,bot/dont_worry_hell_get_it.wav,bot/hang_on_i_heard_something.wav,bot/hang_on_im_coming.wav,bot/i_dont_think_so.wav,bot/i_have_the_hostages.wav,bot/i_see_our_target.wav,bot/im_waiting_here.wav,bot/keeping_an_eye_on_the_hostages.wav,bot/nnno_sir.wav,bot/spotted_the_delivery_boy.wav,bot/target_acquired.wav,bot/target_spotted.wav,bot/you_heard_the_man_lets_go.wav"
"help" "Prop Hunt: Seeker Taunts"
}
702
{
"name" "ph_taunt_hiders"
"text" "Hider Taunts"
"type" "Text"
"default" "ambient/alarms/apc_alarm_pass1.wav,ambient/alarms/manhack_alert_pass1.wav,ambient/alarms/razortrain_horn1.wav,ambient/alarms/scanner_alert_pass1.wav,ambient/alarms/train_horn2.wav,ambient/alarms/train_horn_distant1.wav,ambient/alarms/warningbell1.wav,ambient/energy/whiteflash.wav,ambient/intro/alyxremove.wav,ambient/intro/logosfx.wav,ambient/levels/launch/1stfiringwarning.wav,ambient/levels/launch/rockettakeoffblast.wav,ambient/misc/ambulance1.wav,ambient/misc/carhonk1.wav,ambient/misc/carhonk2.wav,ambient/misc/carhonk3.wav,ambient/outro/gunshipcrash.wav,ambient/3dmeagle.wav,beams/beamstart5.wav,buttons/bell1.wav,buttons/weapon_cant_buy.wav,common/bass.wav,common/bugreporter_failed.wav,common/warning.wav,doors/door_squeek1.wav,friends/friend_join.wav,friends/friend_online.wav,friends/message.wav,hostage/hunuse/comeback.wav,hostage/hunuse/dontleaveme.wav,hostage/hunuse/yeahillstay.wav,items/gift_drop.wav,music/radio1.mp3,phx/eggcrack.wav,plats/elevbell1.wav,player/headshot1.wav,player/headshot2.wav,player/sprayer.wav,radio/enemydown.wav,radio/go.wav,radio/locknload.wav,radio/negative.wav,radio/rounddraw.wav,radio/takepoint.wav,resource/warning.wav,ui/achievement_earned.wav,ui/freeze_cam.wav,vehicles/junker/radar_ping_friendly1.wav,weapons/c4/c4_beep1.wav,weapons/c4/c4_click.wav,weapons/awp/awp1.wav,vo/canals/female01/gunboat_giveemhell.wav,vo/canals/female01/gunboat_justintime.wav,vo/canals/female01/stn6_incoming.wav,vo/canals/male01/gunboat_giveemhell.wav,vo/canals/male01/gunboat_justintime.wav,vo/canals/male01/stn6_incoming.wav,vo/canals/al_radio_stn6.wav,vo/canals/arrest_getgoing.wav,vo/canals/arrest_helpme.wav,vo/canals/arrest_lookingforyou.wav,vo/canals/boxcar_lethimhelp.wav,vo/canals/matt_closecall.wav,vo/canals/premassacre.wav,vo/ravenholm/aimforhead.wav,vo/ravenholm/bucket_patience.wav,vo/ravenholm/madlaugh01.wav,vo/ravenholm/madlaugh02.wav,vo/ravenholm/madlaugh03.wav,vo/ravenholm/madlaugh04.wav,weapons/strider_buster/ol12_stickybombcreator.wav,weapons/c4/c4_explode1.wav,weapons/357/357_fire2.wav,weapons/357/357_fire3.wav,weapons/scout/scout_fire-1.wav,weapons/smokegrenade/sg_explode.wav,weapons/grenade_launcher1.wav,weapons/explode3.wav,weapons/underwater_explode3.wav,items/nvg_on.wav,hostage/huse/letsdoit.wav,hostage/huse/illfollow.wav,hostage/huse/getouttahere.wav,doors/door_screen_move1.wav,doors/heavy_metal_stop1.wav,doors/default_move.wav,common/stuck2.wav,ambient/water_splash1.wav,ambient/water_splash2.wav,ambient/water_splash3.wav,ambient/weather/thunder1.wav,ambient/weather/thunder2.wav,ambient/weather/thunder3.wav,ambient/weather/thunder4.wav,ambient/weather/thunder5.wav,ambient/weather/thunder6.wav,ambient/outro/thunder7.wav,ambient/voices/crying_loop1.wav,ambient/voices/playground_memory.wav,ambient/voices/f_scream1.wav,ambient/voices/m_scream1.wav,ambient/voices/cough1.wav,ambient/voices/cough2.wav,ambient/voices/cough3.wav,ambient/voices/cough4.wav,ambient/overhead/plane1.wav,ambient/overhead/plane2.wav,ambient/overhead/plane3.wav,ambient/overhead/hel1.wav,ambient/overhead/hel2.wav,ambient/misc/truck_backup1.wav,ambient/misc/truck_drive1.wav,ambient/misc/truck_drive2.wav,ambient/machines/pneumatic_drill_1.wav,ambient/machines/pneumatic_drill_2.wav,ambient/machines/pneumatic_drill_3.wav,ambient/machines/pneumatic_drill_4.wav,ambient/machines/station_train_squeel.wav,ambient/machines/ticktock.wav,ambient/creatures/teddy.wav,ambient/creatures/town_child_scream1.wav,ambient/creatures/town_moan1.wav,ambient/creatures/town_muffled_cry1.wav,ambient/creatures/town_scared_breathing1.wav,ambient/creatures/town_scared_breathing2.wav,ambient/creatures/town_scared_sob1.wav,ambient/creatures/town_scared_sob2.wav,ambient/creatures/town_zombie_call1.wav"
"help" "Prop Hunt: Hider Taunts"
}
// Camera
800
{
"name" "ph_camera_allow_noclip"
"text" "Camera Noclip Allowed"
"type" "CheckBox"
"default" "0"
"help" "Camera: Allow clients to disable camera collision"
}
801
{
"name" "ph_camera_distance_max"
"text" "Camera Distance Max."
"type" "Numeric"
"default" "150"
"help" "Camera: Maximum allowed distance to player."
}
802
{
"name" "ph_camera_distance_min"
"text" "Camera Distance Min."
"type" "Numeric"
"default" "30"
"help" "Camera: Minimum allowed distance to player."
}
803
{
"name" "ph_camera_distance_right_range"
"text" "Camera Horizontal Offset Range"
"type" "Numeric"
"default" "20"
"help" "Camera: Horizontal allowed camera distance range."
}
804
{
"name" "ph_camera_distance_up_range"
"text" "Camera Vertical Offset Range"
"type" "Numeric"
"default" "20"
"help" "Camera: Vertical allowed camera distance range."
}
805
{
"name" "ph_camera_lag_min"
"text" "Camera Lag Min."
"type" "Numeric"
"default" "0"
"help" "Camera: Minimum Camera Lag."
}
806
{
"name" "ph_camera_lag_max"
"text" "Camera Lag Max."
"type" "Numeric"
"default" "0.95"
"help" "Camera: Maximum Camera Lag."
}
// Selection Halo
900
{
"name" "ph_selectionhalo_allow"
"text" "Selection Halo Allowed"
"type" "CheckBox"
"default" "1"
"help" "Selection Halo: Allow clients to enable halo around the currently looked at prop?"
}
901
{
"name" "ph_selectionhalo_approximate"
"text" "Selection Approximate Mode"
"type" "CheckBox"
"default" "1"
"help" "Selection Halo: Enable approximate selection halo, which only checks the forward vector on the client."
}
902
{
"name" "ph_selectionhalo_interval"
"text" "Selection Halo Allowed"
"type" "Numeric"
"default" "0.05"
"help" "Selection Halo: Interval for updates of the accuracte selection halo in seconds."
}
}
}
+1
View File
@@ -3,5 +3,6 @@
"type" : "gamemode", "type" : "gamemode",
"tags" : [ "fun" ], "tags" : [ "fun" ],
"ignore" : [ "ignore" : [
"addon.txt"
] ]
} }
+9
View File
@@ -0,0 +1,9 @@
"AddonInfo"
{
"name" "Prop Hunt Extended"
"version" "1.4.0"
"up_date" "00/00/00"
"author_name" "Xaymar"
"author_email" "info@xaymar.com"
"author_url" "https://xaymar.com/"
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1003 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Before

Width:  |  Height:  |  Size: 1003 KiB

After

Width:  |  Height:  |  Size: 1003 KiB

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

@@ -1,8 +0,0 @@
"TableToKeyValues"
{
"1" "models/props/cs_assault/dollar.mdl"
"2" "models/props/cs_assault/money.mdl"
"3" "models/props/cs_office/snowman_arm.mdl"
"4" "models/props_junk/garbage_plasticbottle001a.mdl"
"5" "models/props/cs_office/projector_remote.mdl"
}
@@ -1,8 +0,0 @@
"TableToKeyValues"
{
"TAUNT_DELAY" "0.1"
"ROUNDS_PER_MAP" "20"
"ROUND_TIME" "240"
"SWAP_TEAM_EVERY_ROUND" "1"
"GAME_TIME" "20"
}
@@ -1,26 +0,0 @@
"TableToKeyValues"
{
"1" "bot/aw_hell.wav"
"2" "bot/aww_man.wav"
"3" "bot/anyone_see_anything.wav"
"4" "bot/anyone_see_them.wav"
"5" "bot/come_out_and_fight_like_a_man.wav"
"6" "bot/come_out_wherever_you_are.wav"
"7" "bot/he_got_away.wav"
"8" "bot/he_got_away2.wav"
"9" "bot/i_dont_know_where_he_went.wav"
"10" "bot/i_got_nothing.wav"
"11" "bot/nothing_happening_over_here.wav"
"12" "bot/nothing_here.wav"
"13" "bot/nothing_moving_over_here.wav"
"14" "bot/thats_not_good.wav"
"15" "bot/theres_too_many.wav"
"16" "bot/theres_too_many_of_them.wav"
"17" "bot/theyre_all_over_the_place2.wav"
"18" "bot/theyre_everywhere2.wav"
"19" "bot/too_many2.wav"
"20" "bot/what_happened.wav"
"21" "bot/what_have_you_done.wav"
"22" "bot/where_are_they.wav"
"23" "bot/where_are_you_hiding.wav"
}
@@ -1,20 +0,0 @@
"TableToKeyValues"
{
"1" "bot/a_bunch_of_them.wav"
"2" "bot/come_out_and_fight_like_a_man.wav"
"3" "bot/come_out_wherever_you_are.wav"
"4" "bot/come_to_papa.wav"
"5" "bot/dont_worry_hell_get_it.wav"
"6" "bot/hang_on_i_heard_something.wav"
"7" "bot/hang_on_im_coming.wav"
"8" "bot/i_dont_think_so.wav"
"9" "bot/i_have_the_hostages.wav"
"10" "bot/i_see_our_target.wav"
"11" "bot/im_waiting_here.wav"
"12" "bot/keeping_an_eye_on_the_hostages.wav"
"13" "bot/nnno_sir.wav"
"14" "bot/spotted_the_delivery_boy.wav"
"15" "bot/target_acquired.wav"
"16" "bot/target_spotted.wav"
"17" "bot/you_heard_the_man_lets_go.wav"
}
@@ -1,131 +0,0 @@
"TableToKeyValues"
{
"1" "ambient/alarms/apc_alarm_pass1.wav"
"2" "ambient/alarms/manhack_alert_pass1.wav"
"3" "ambient/alarms/razortrain_horn1.wav"
"4" "ambient/alarms/scanner_alert_pass1.wav"
"5" "ambient/alarms/train_horn2.wav"
"6" "ambient/alarms/train_horn_distant1.wav"
"7" "ambient/alarms/warningbell1.wav"
"8" "ambient/energy/whiteflash.wav"
"9" "ambient/intro/alyxremove.wav"
"10" "ambient/intro/logosfx.wav"
"11" "ambient/levels/launch/1stfiringwarning.wav"
"12" "ambient/levels/launch/rockettakeoffblast.wav"
"13" "ambient/misc/ambulance1.wav"
"14" "ambient/misc/carhonk1.wav"
"15" "ambient/misc/carhonk2.wav"
"16" "ambient/misc/carhonk3.wav"
"17" "ambient/outro/gunshipcrash.wav"
"18" "ambient/3dmeagle.wav"
"19" "beams/beamstart5.wav"
"20" "buttons/bell1.wav"
"21" "buttons/weapon_cant_buy.wav"
"22" "common/bass.wav"
"23" "common/bugreporter_failed.wav"
"24" "common/warning.wav"
"25" "doors/door_squeek1.wav"
"26" "friends/friend_join.wav"
"27" "friends/friend_online.wav"
"28" "friends/message.wav"
"29" "hostage/hunuse/comeback.wav"
"30" "hostage/hunuse/dontleaveme.wav"
"31" "hostage/hunuse/yeahillstay.wav"
"32" "items/gift_drop.wav"
"33" "music/radio1.mp3"
"34" "phx/eggcrack.wav"
"35" "plats/elevbell1.wav"
"36" "player/headshot1.wav"
"37" "player/headshot2.wav"
"38" "player/sprayer.wav"
"39" "radio/enemydown.wav"
"40" "radio/go.wav"
"41" "radio/locknload.wav"
"42" "radio/negative.wav"
"43" "radio/rounddraw.wav"
"44" "radio/takepoint.wav"
"45" "resource/warning.wav"
"46" "ui/achievement_earned.wav"
"47" "ui/freeze_cam.wav"
"48" "vehicles/junker/radar_ping_friendly1.wav"
"49" "weapons/c4/c4_beep1.wav"
"50" "weapons/c4/c4_click.wav"
"51" "weapons/awp/awp1.wav"
"52" "vo/canals/female01/gunboat_giveemhell.wav"
"53" "vo/canals/female01/gunboat_justintime.wav"
"54" "vo/canals/female01/stn6_incoming.wav"
"55" "vo/canals/male01/gunboat_giveemhell.wav"
"56" "vo/canals/male01/gunboat_justintime.wav"
"57" "vo/canals/male01/stn6_incoming.wav"
"58" "vo/canals/al_radio_stn6.wav"
"59" "vo/canals/arrest_getgoing.wav"
"60" "vo/canals/arrest_helpme.wav"
"61" "vo/canals/arrest_lookingforyou.wav"
"62" "vo/canals/boxcar_lethimhelp.wav"
"63" "vo/canals/matt_closecall.wav"
"64" "vo/canals/premassacre.wav"
"65" "vo/ravenholm/aimforhead.wav"
"66" "vo/ravenholm/bucket_patience.wav"
"67" "vo/ravenholm/madlaugh01.wav"
"68" "vo/ravenholm/madlaugh02.wav"
"69" "vo/ravenholm/madlaugh03.wav"
"70" "vo/ravenholm/madlaugh04.wav"
"71" "weapons/strider_buster/ol12_stickybombcreator.wav"
"72" "weapons/c4/c4_explode1.wav"
"73" "weapons/357/357_fire2.wav"
"74" "weapons/357/357_fire3.wav"
"75" "weapons/scout/scout_fire-1.wav"
"76" "weapons/smokegrenade/sg_explode.wav"
"77" "weapons/grenade_launcher1.wav"
"78" "weapons/explode3.wav"
"79" "weapons/underwater_explode3.wav"
"80" "items/nvg_on.wav"
"81" "hostage/huse/letsdoit.wav"
"82" "hostage/huse/illfollow.wav"
"83" "hostage/huse/getouttahere.wav"
"84" "doors/door_screen_move1.wav"
"85" "doors/heavy_metal_stop1.wav"
"86" "doors/default_move.wav"
"87" "common/stuck2.wav"
"88" "ambient/water_splash1.wav"
"89" "ambient/water_splash2.wav"
"90" "ambient/water_splash3.wav"
"91" "ambient/weather/thunder1.wav"
"92" "ambient/weather/thunder2.wav"
"93" "ambient/weather/thunder3.wav"
"94" "ambient/weather/thunder4.wav"
"95" "ambient/weather/thunder5.wav"
"96" "ambient/weather/thunder6.wav"
"97" "ambient/outro/thunder7.wav"
"98" "ambient/voices/crying_loop1.wav"
"99" "ambient/voices/playground_memory.wav"
"100" "ambient/voices/f_scream1.wav"
"101" "ambient/voices/m_scream1.wav"
"102" "ambient/voices/cough1.wav"
"103" "ambient/voices/cough2.wav"
"104" "ambient/voices/cough3.wav"
"105" "ambient/voices/cough4.wav"
"106" "ambient/overhead/plane1.wav"
"107" "ambient/overhead/plane2.wav"
"108" "ambient/overhead/plane3.wav"
"109" "ambient/overhead/hel1.wav"
"110" "ambient/overhead/hel2.wav"
"111" "ambient/misc/truck_backup1.wav"
"112" "ambient/misc/truck_drive1.wav"
"113" "ambient/misc/truck_drive2.wav"
"114" "ambient/machines/pneumatic_drill_1.wav"
"115" "ambient/machines/pneumatic_drill_2.wav"
"116" "ambient/machines/pneumatic_drill_3.wav"
"117" "ambient/machines/pneumatic_drill_4.wav"
"118" "ambient/machines/station_train_squeel.wav"
"119" "ambient/machines/ticktock.wav"
"120" "ambient/creatures/teddy.wav"
"121" "ambient/creatures/town_child_scream1.wav"
"122" "ambient/creatures/town_moan1.wav"
"123" "ambient/creatures/town_muffled_cry1.wav"
"124" "ambient/creatures/town_scared_breathing1.wav"
"125" "ambient/creatures/town_scared_breathing2.wav"
"126" "ambient/creatures/town_scared_sob1.wav"
"127" "ambient/creatures/town_scared_sob2.wav"
"128" "ambient/creatures/town_zombie_call1.wav"
}
@@ -1,52 +0,0 @@
"TableToKeyValues"
{
"1" "bot/and_thats_how_its_done.wav"
"2" "bot/come_to_papa.wav"
"3" "bot/do_not_mess_with_me.wav"
"4" "bot/dropped_him.wav"
"5" "bot/enemy_down.wav"
"6" "bot/enemy_down2.wav"
"7" "bot/good_job_team.wav"
"8" "bot/got_him.wav"
"9" "bot/hes_broken.wav"
"10" "bot/hes_dead.wav"
"11" "bot/hes_done.wav"
"12" "bot/hes_down.wav"
"13" "bot/its_a_party.wav"
"14" "bot/i_am_dangerous.wav"
"15" "bot/i_am_on_fire.wav"
"16" "bot/i_got_more_where_that_came_from.wav"
"17" "bot/i_wasnt_worried_for_a_minute.wav"
"18" "bot/killed_him.wav"
"19" "bot/look_out_brag.wav"
"20" "bot/made_him_cry.wav"
"21" "bot/oh_yea.wav"
"22" "bot/oh_yea2.wav"
"23" "bot/owned.wav"
"24" "bot/ruined_his_day.wav"
"25" "bot/tag_them_and_bag_them.wav"
"26" "bot/thats_the_way_this_is_done.wav"
"27" "bot/that_was_a_close_one.wav"
"28" "bot/that_was_it.wav"
"29" "bot/that_was_the_last_guy.wav"
"30" "bot/that_was_the_last_one.wav"
"31" "bot/they_never_knew_what_hit_them.wav"
"32" "bot/they_will_not_escape.wav"
"33" "bot/they_wont_get_away.wav"
"34" "bot/they_wont_get_away2.wav"
"35" "bot/this_is_my_house.wav"
"36" "bot/took_him_down.wav"
"37" "bot/took_him_out.wav"
"38" "bot/took_him_out2.wav"
"39" "bot/wasted_him.wav"
"40" "bot/way_to_be_team.wav"
"41" "bot/well_done.wav"
"42" "bot/we_owned_them.wav"
"43" "bot/whew_that_was_close.wav"
"44" "bot/whoo.wav"
"45" "bot/whoo2.wav"
"46" "bot/whos_the_man.wav"
"47" "bot/who_wants_some_more.wav"
"48" "bot/yesss.wav"
"49" "bot/yesss2.wav"
}
@@ -1,6 +1,6 @@
-- SWEP Information -- SWEP Information
SWEP.Author = "Michael 'Xaymar' Dirks" SWEP.Author = "Michael 'Xaymar' Dirks"
SWEP.Contact = "info@project-kube.de" SWEP.Contact = "info@xaymar.com"
SWEP.PrintName = "PH Submachine Gun" SWEP.PrintName = "PH Submachine Gun"
SWEP.Purpose = "More accurate SMG for Prop Hunt." SWEP.Purpose = "More accurate SMG for Prop Hunt."
SWEP.Instructions = "Fire away! Alternative fire to fire a grenade." SWEP.Instructions = "Fire away! Alternative fire to fire a grenade."
@@ -30,8 +30,8 @@ SWEP.Primary.ClipSize = 45
SWEP.Primary.DefaultClip = 45 SWEP.Primary.DefaultClip = 45
SWEP.Primary.Automatic = true SWEP.Primary.Automatic = true
SWEP.Primary.Ammo = "SMG1" SWEP.Primary.Ammo = "SMG1"
SWEP.Primary.Damage = 5 SWEP.Primary.Damage = 4
SWEP.Primary.RefireTime = 0.1 SWEP.Primary.RefireTime = 0.075
-- Secondary Ammunition: SMG Grenades -- Secondary Ammunition: SMG Grenades
SWEP.Secondary.ClipSize = 1 SWEP.Secondary.ClipSize = 1
@@ -1,259 +0,0 @@
-- Sounds played by members of the losing team at the end of the round.
LOSS_SOUNDS = {
"bot/aw_hell.wav",
"bot/aww_man.wav",
"bot/anyone_see_anything.wav",
"bot/anyone_see_them.wav",
"bot/come_out_and_fight_like_a_man.wav",
"bot/come_out_wherever_you_are.wav",
"bot/he_got_away.wav",
"bot/he_got_away2.wav",
"bot/i_dont_know_where_he_went.wav",
"bot/i_got_nothing.wav",
"bot/nothing_happening_over_here.wav",
"bot/nothing_here.wav",
"bot/nothing_moving_over_here.wav",
"bot/thats_not_good.wav",
"bot/theres_too_many.wav",
"bot/theres_too_many_of_them.wav",
"bot/theyre_all_over_the_place2.wav",
"bot/theyre_everywhere2.wav",
"bot/too_many2.wav",
"bot/what_happened.wav",
"bot/what_have_you_done.wav",
"bot/where_are_they.wav",
"bot/where_are_you_hiding.wav"
}
-- Sounds played by members of the winning team at the end of the round.
VICTORY_SOUNDS = {
"bot/and_thats_how_its_done.wav",
"bot/come_to_papa.wav",
"bot/do_not_mess_with_me.wav",
"bot/dropped_him.wav",
"bot/enemy_down.wav",
"bot/enemy_down2.wav",
"bot/good_job_team.wav",
"bot/got_him.wav",
"bot/hes_broken.wav",
"bot/hes_dead.wav",
"bot/hes_done.wav",
"bot/hes_down.wav",
"bot/its_a_party.wav",
"bot/i_am_dangerous.wav",
"bot/i_am_on_fire.wav",
"bot/i_got_more_where_that_came_from.wav",
"bot/i_wasnt_worried_for_a_minute.wav",
"bot/killed_him.wav",
"bot/look_out_brag.wav",
"bot/made_him_cry.wav",
"bot/oh_yea.wav",
"bot/oh_yea2.wav",
"bot/owned.wav",
"bot/ruined_his_day.wav",
"bot/tag_them_and_bag_them.wav",
"bot/thats_the_way_this_is_done.wav",
"bot/that_was_a_close_one.wav",
"bot/that_was_it.wav",
"bot/that_was_the_last_guy.wav",
"bot/that_was_the_last_one.wav",
"bot/they_never_knew_what_hit_them.wav",
"bot/they_will_not_escape.wav",
"bot/they_wont_get_away.wav",
"bot/they_wont_get_away2.wav",
"bot/this_is_my_house.wav",
"bot/took_him_down.wav",
"bot/took_him_out.wav",
"bot/took_him_out2.wav",
"bot/wasted_him.wav",
"bot/way_to_be_team.wav",
"bot/well_done.wav",
"bot/we_owned_them.wav",
"bot/whew_that_was_close.wav",
"bot/whoo.wav",
"bot/whoo2.wav",
"bot/whos_the_man.wav",
"bot/who_wants_some_more.wav",
"bot/yesss.wav",
"bot/yesss2.wav"
}
-- Taunts played when Hunters hit their Spare1 binding.
HUNTER_TAUNTS = {
"bot/a_bunch_of_them.wav",
"bot/come_out_and_fight_like_a_man.wav",
"bot/come_out_wherever_you_are.wav",
"bot/come_to_papa.wav",
"bot/dont_worry_hell_get_it.wav",
"bot/hang_on_i_heard_something.wav",
"bot/hang_on_im_coming.wav",
"bot/i_dont_think_so.wav",
"bot/i_have_the_hostages.wav",
"bot/i_see_our_target.wav",
"bot/im_waiting_here.wav",
"bot/keeping_an_eye_on_the_hostages.wav",
"bot/nnno_sir.wav",
"bot/spotted_the_delivery_boy.wav",
"bot/target_acquired.wav",
"bot/target_spotted.wav",
"bot/you_heard_the_man_lets_go.wav"
}
-- Taunts played when Props hit their Spare1 binding.
PROP_TAUNTS = {
-- "ambient/alarms/apc_alarm_loop1.wav",
"ambient/alarms/apc_alarm_pass1.wav",
-- "ambient/alarms/citadel_alert_loop2.wav",
-- "ambient/alarms/city_firebell_loop1.wav",
-- "ambient/alarms/city_siren_loop2.wav",
-- "ambient/alarms/combine_bank_alarm_loop1.wav",
-- "ambient/alarms/combine_bank_alarm_loop4.wav",
-- "ambient/alarms/klaxon1.wav",
"ambient/alarms/manhack_alert_pass1.wav",
"ambient/alarms/razortrain_horn1.wav",
"ambient/alarms/scanner_alert_pass1.wav",
-- "ambient/alarms/siren.wav",
-- "ambient/alarms/train_crossing_bell_loop1.wav",
"ambient/alarms/train_horn2.wav",
"ambient/alarms/train_horn_distant1.wav",
"ambient/alarms/warningbell1.wav",
-- "ambient/chatter/cb_radio_chatter_1.wav",
-- "ambient/chatter/cb_radio_chatter_2.wav",
-- "ambient/chatter/cb_radio_chatter_3.wav",
"ambient/energy/whiteflash.wav",
"ambient/intro/alyxremove.wav",
"ambient/intro/logosfx.wav",
-- "ambient/levels/labs/teleport_alarm_loop1.wav",
"ambient/levels/launch/1stfiringwarning.wav",
"ambient/levels/launch/rockettakeoffblast.wav",
-- "ambient/levels/outland/basealarmloop.wav",
-- "ambient/machines/60hzhum.wav",
"ambient/misc/ambulance1.wav",
"ambient/misc/carhonk1.wav",
"ambient/misc/carhonk2.wav",
"ambient/misc/carhonk3.wav",
-- "ambient/music/bongo.wav",
-- "ambient/music/country_rock_am_radio_loop.wav",
-- "ambient/music/cubanmusic1.wav",
-- "ambient/music/dustmusic1.wav",
-- "ambient/music/dustmusic2.wav",
-- "ambient/music/dustmusic3.wav",
-- "ambient/music/flamenco.wav",
-- "ambient/music/latin.wav",
-- "ambient/music/mirame_radio_thru_wall.wav",
-- "ambient/music/piano1.wav",
-- "ambient/music/piano2.wav",
"ambient/outro/gunshipcrash.wav",
"ambient/3dmeagle.wav",
-- "ambient/guit1.wav",
-- "ambient/opera.wav",
-- "ambient/sheep.wav",
"beams/beamstart5.wav",
"buttons/bell1.wav",
"buttons/weapon_cant_buy.wav",
"common/bass.wav",
"common/bugreporter_failed.wav",
"common/warning.wav",
"doors/door_squeek1.wav",
"friends/friend_join.wav",
"friends/friend_online.wav",
"friends/message.wav",
"hostage/hunuse/comeback.wav",
"hostage/hunuse/dontleaveme.wav",
"hostage/hunuse/yeahillstay.wav",
"items/gift_drop.wav",
"music/radio1.mp3",
"phx/eggcrack.wav",
"plats/elevbell1.wav",
"player/headshot1.wav",
"player/headshot2.wav",
"player/sprayer.wav",
"radio/enemydown.wav",
"radio/go.wav",
"radio/locknload.wav",
"radio/negative.wav",
"radio/rounddraw.wav",
"radio/takepoint.wav",
"resource/warning.wav",
-- "test/temp/soundscape_test/tv_music.wav",
"ui/achievement_earned.wav",
"ui/freeze_cam.wav",
"vehicles/junker/radar_ping_friendly1.wav",
"weapons/c4/c4_beep1.wav",
"weapons/c4/c4_click.wav",
"weapons/awp/awp1.wav",
"vo/canals/female01/gunboat_giveemhell.wav",
"vo/canals/female01/gunboat_justintime.wav",
"vo/canals/female01/stn6_incoming.wav",
"vo/canals/male01/gunboat_giveemhell.wav",
"vo/canals/male01/gunboat_justintime.wav",
"vo/canals/male01/stn6_incoming.wav",
"vo/canals/al_radio_stn6.wav",
"vo/canals/arrest_getgoing.wav",
"vo/canals/arrest_helpme.wav",
"vo/canals/arrest_lookingforyou.wav",
"vo/canals/boxcar_lethimhelp.wav",
"vo/canals/matt_closecall.wav",
"vo/canals/premassacre.wav",
"vo/ravenholm/aimforhead.wav",
"vo/ravenholm/bucket_patience.wav",
"vo/ravenholm/madlaugh01.wav",
"vo/ravenholm/madlaugh02.wav",
"vo/ravenholm/madlaugh03.wav",
"vo/ravenholm/madlaugh04.wav",
"weapons/strider_buster/ol12_stickybombcreator.wav",
"weapons/c4/c4_explode1.wav",
"weapons/357/357_fire2.wav",
"weapons/357/357_fire3.wav",
"weapons/scout/scout_fire-1.wav",
"weapons/smokegrenade/sg_explode.wav",
"weapons/grenade_launcher1.wav",
"weapons/explode3.wav",
"weapons/underwater_explode3.wav",
"items/nvg_on.wav",
"hostage/huse/letsdoit.wav",
"hostage/huse/illfollow.wav",
"hostage/huse/getouttahere.wav",
"doors/door_screen_move1.wav",
"doors/heavy_metal_stop1.wav",
"doors/default_move.wav",
"common/stuck2.wav",
"ambient/water_splash1.wav",
"ambient/water_splash2.wav",
"ambient/water_splash3.wav",
"ambient/weather/thunder1.wav",
"ambient/weather/thunder2.wav",
"ambient/weather/thunder3.wav",
"ambient/weather/thunder4.wav",
"ambient/weather/thunder5.wav",
"ambient/weather/thunder6.wav",
"ambient/outro/thunder7.wav",
"ambient/voices/crying_loop1.wav",
"ambient/voices/playground_memory.wav",
"ambient/voices/f_scream1.wav",
"ambient/voices/m_scream1.wav",
"ambient/voices/cough1.wav",
"ambient/voices/cough2.wav",
"ambient/voices/cough3.wav",
"ambient/voices/cough4.wav",
"ambient/overhead/plane1.wav",
"ambient/overhead/plane2.wav",
"ambient/overhead/plane3.wav",
"ambient/overhead/hel1.wav",
"ambient/overhead/hel2.wav",
"ambient/misc/truck_backup1.wav",
"ambient/misc/truck_drive1.wav",
"ambient/misc/truck_drive2.wav",
"ambient/machines/pneumatic_drill_1.wav",
"ambient/machines/pneumatic_drill_2.wav",
"ambient/machines/pneumatic_drill_3.wav",
"ambient/machines/pneumatic_drill_4.wav",
"ambient/machines/station_train_squeel.wav",
"ambient/machines/ticktock.wav",
"ambient/creatures/teddy.wav",
"ambient/creatures/town_child_scream1.wav",
"ambient/creatures/town_moan1.wav",
"ambient/creatures/town_muffled_cry1.wav",
"ambient/creatures/town_scared_breathing1.wav",
"ambient/creatures/town_scared_breathing2.wav",
"ambient/creatures/town_scared_sob1.wav",
"ambient/creatures/town_scared_sob2.wav",
"ambient/creatures/town_zombie_call1.wav"
}
@@ -25,11 +25,21 @@
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
--! Includes --! Includes
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
-- Early Init
include("sh_init.lua") include("sh_init.lua")
include("vgui/dlabeldpi.lua")
include("vgui/dframedpi.lua")
include("vgui/fontmanager.lua")
include("vgui/uimanager.lua")
include("client/roundmanager.lua")
GM.UI = {} -- Late Init
include("client/cl_ui_help.lua") include("client/cl_ui_help.lua")
include("client/cl_ui_teamselection.lua") include("client/cl_ui_teamselection.lua")
include("client/hud/gamestatedisplay.lua")
include("client/ui/scoreboard.lua")
include("client/ui/help.lua")
include("client/ui/settings.lua")
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
--! Code --! Code
@@ -38,17 +48,24 @@ function GM:Initialize()
print("-------------------------------------------------------------------------") print("-------------------------------------------------------------------------")
print("Prop Hunt CL: Initializing...") print("Prop Hunt CL: Initializing...")
print("Prop Hunt CL: Initializing Gamemode Data...") print("Prop Hunt CL: Preparing data...")
self.Data = {} self.Data = {}
print("Prop Hunt CL: Creating Fonts...") print("Prop Hunt CL: Creating User Interface...")
surface.CreateFont("RobotoBoldCondensed160", {font="Roboto Bold Condensed", extended=true, size=160, weight=800, antialias=true}) FontManager:Request("RobotoBoldCondensed160", {font="Roboto Bold Condensed", extended=true, size=160, weight=800, antialias=true})
self.UI = {}
self.UI.Help = vgui.Create("PHE_HelpUI")
self.UI.Scoreboard = vgui.Create("DScoreBoard")
self.UI.GameStateDisplay = vgui.Create("PHE_GameState")
self.UI.GameStateDisplay:Show()
print("Prop Hunt CL: Complete.") print("Prop Hunt CL: Complete.")
print("-------------------------------------------------------------------------") print("-------------------------------------------------------------------------")
end end
function GM:Think() end function GM:Think()
UIManager:Tick()
end
function GM:InitialPlayerSpawn() function GM:InitialPlayerSpawn()
if GAMEMODE.Config:DebugLog() then print("Prop Hunt CL: InitialPlayerSpawn") end if GAMEMODE.Config:DebugLog() then print("Prop Hunt CL: InitialPlayerSpawn") end
@@ -167,6 +184,14 @@ function GM:OnSpawnMenuClose()
net.SendToServer() net.SendToServer()
end end
function GM:ScoreboardShow()
self.UI.Scoreboard:Show()
end
function GM:ScoreboardHide()
self.UI.Scoreboard:Hide()
end
function GM:ShowHelpUI() function GM:ShowHelpUI()
self.UI.Help:Show() self.UI.Help:Show()
end end
@@ -230,26 +255,57 @@ function DrawNamePlates(bDrawingDepth, bDrawingSkybox)
end end
hook.Add("PostDrawTranslucentRenderables", "PHDrawNamePlates", DrawNamePlates) hook.Add("PostDrawTranslucentRenderables", "PHDrawNamePlates", DrawNamePlates)
function DrawSelectionHalo(bDrawingDepth, bDrawingSkybox)
if (!GAMEMODE.Config.SelectionHalo:Enabled()) then return end
if ((LocalPlayer():Team() == GAMEMODE.Teams.Hiders)
&& (player_manager.GetPlayerClass(LocalPlayer()) == "Hider")) then
local ent = nil
if (GAMEMODE.Config.SelectionHalo:Approximate()) then
local trace = {
start = LocalPlayer():EyePos(),
endpos = LocalPlayer():EyePos() + LocalPlayer():EyeAngles():Forward() * 80,
mins = Vector(-16, -16, -16),
maxs = Vector( 16, 16, 16),
mask = MASK_SOLID + CONTENTS_DEBRIS + CONTENTS_PLAYERCLIP,
filter = function(ent)
-- Ensure that we don't actually hit ourselves by accident, or our "hands" model.
if (!IsValid(ent)
|| (ent == LocalPlayer())
|| (ent == LocalPlayer():GetHands())) then
return false
end
if table.HasValue(GAMEMODE.Config.Lists:ClassWhitelist(), ent:GetClass()) then return true end
return false
end,
output = {}
}
util.TraceLine(trace)
if !IsValid(trace.output.Entity) then util.TraceHull(trace) end
if IsValid(trace.output.Entity) then
if (!table.HasValue(GAMEMODE.Config.Lists:ModelBlacklist(), trace.output.Entity:GetModel())) then
ent = trace.output.Entity
end
end
else
ent = LocalPlayer():GetNWEntity("SelectionHalo")
end
if IsValid(ent) then
local color = HSVToColor(
GAMEMODE.Config.SelectionHalo:TintHue(),
GAMEMODE.Config.SelectionHalo:TintSaturation(),
GAMEMODE.Config.SelectionHalo:TintValue()
)
halo.Add({ ent }, color,
GAMEMODE.Config.SelectionHalo:BlurX(), GAMEMODE.Config.SelectionHalo:BlurY(), GAMEMODE.Config.SelectionHalo:Passes(),
GAMEMODE.Config.SelectionHalo:Additive(), GAMEMODE.Config.SelectionHalo:IgnoreZ())
end
end
end
hook.Add("PostDrawEffects", "PHDrawSelectionHalo", DrawSelectionHalo)
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
--! Old Code --! Old Code
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
--[[ --[[
function DrawPlayerHalos(bDrawingDepth, bDrawingSkybox)
for i,v in ipairs(player.GetAll()) do
if v:Alive() then
local pos = v:GetPos() + Vector(0, 0, 1) * (v:OBBMaxs().z - v:OBBMins().z + 5)
local ang = Angle(0, LocalPlayer():EyeAngles().y - 90, 90 - LocalPlayer():EyeAngles().x)
local healthPrc = v:Health() / v:GetMaxHealth()
local healthCol = HSVToColor(120 * healthPrc, 1.0, 1.0)
if v:Team() == TEAM_HUNTERS || LocalPlayer():Team() == TEAM_PROPS then
local ent = v
if v.ph_prop && v.ph_prop:IsValid() then ent = v.ph_prop end
halo.Add({ent}, healthCol, 2, 2, 1)
end
end
end
end
--hook.Add("PostDrawEffects", "PH_DrawPlayerHalos", DrawPlayerHalos)
]] ]]
@@ -22,61 +22,58 @@
SOFTWARE. SOFTWARE.
--]] --]]
local PANEL = vgui.Create("DFrame") local UI = {}
PANEL:SetSize(640, 480)
PANEL:SetTitle("Help")
PANEL:SetDraggable(true)
PANEL:SetVisible(false)
PANEL:SetDraggable(true)
PANEL:SetSizable(true)
PANEL:ShowCloseButton(true)
PANEL:SetDeleteOnClose(false)
function PANEL:Show() function UI:Init()
--self:SetSize(ScrW(), ScrH()) -- Initialize
self:SetVisible(false)
self:SetSize(1280, 720)
self:SetScreenLock(true)
self:SetTitle("Help & Settings")
self:SetDraggable(true)
self:SetSizable(true)
self:ShowCloseButton(true)
self:SetDeleteOnClose(false)
self.scale = 1.0
self.psh = vgui.Create("DPropertySheet", self)
self.psh:Dock(FILL)
self.psh:AddSheet("Help", vgui.Create("PHE_HelpUI_Help", self.psh))
self.psh:AddSheet("Settings", vgui.Create("PHE_HelpUI_Settings", self.psh))
-- Listen to DPI Updates
UIManager:Listen("UpdateDPI", self, function(dpi) self:UpdateDPI(dpi) end)
self:UpdateDPI(UIManager:GetDPIScale())
end
function UI:OnRemove()
UIManager:Silence("UpdateDPI", self)
self.psh:Remove()
end
function UI:Show()
self:Center() self:Center()
self:SetVisible(true) self:SetVisible(true)
self:SetFocusTopLevel(true) self:SetFocusTopLevel(true)
self:SlideDown(.5)
self:MakePopup() self:MakePopup()
end end
function PANEL:Hide()
self:Close()
self:SetVisible(false)
end
function PANEL:Paint(w, h) function UI:Paint(w, h)
draw.RoundedBox(0, 0, 0, w, h, Color(0,0,0,240)) draw.RoundedBox(0, 0, 0, w, h, Color(0,0,0,240))
end end
-- Sheets function UI:UpdateDPI(dpi)
local Element = vgui.Create("DPropertySheet", PANEL) local mult = dpi / self.scale
function Element:PAINT(w,h) self.scale = dpi
draw.RoundedBox(0, 0, 0, w, h, Color(0,0,0,240))
local x, y = self:GetPos()
local w, h = self:GetSize()
local nw, nh = w * mult, h * mult
local ox, oy = (nw - w) / 2, (nh - h) / 2
self:SetSize(w * mult, h * mult)
self:SetPos(x - ox, y - oy)
end end
Element:Dock(FILL)
PANEL.Sheets = Element
PANEL.Sheet = {}
-- Basic Info derma.DefineControl("PHE_HelpUI", "Show Help UI Element", UI, "DFrameDPI");
local Element = vgui.Create("DPanel", PANEL.Sheets)
function Element:Paint(w,h) end
PANEL.Sheets:AddSheet("The Gamemode", Element)
PANEL.Sheet.TheGamemode = Element
local Element = vgui.Create("DLabel", PANEL.Sheet.TheGamemode)
Element:Dock(TOP)
Element:SetMultiline(true)
Element:SetText([[
Prop Hunt Extended is a Gamemode based on the original Prop Hunt Gamemode. It changes many gameplay elements and features, adding the ability to easily integrate Taunt Packs, Configure Game parameters, rotate your prop and much more.
]])
-- Settings
PANEL.SettingsSheet = vgui.Create("DPanel", PANEL.Sheets)
PANEL.Sheets:AddSheet("Settings", PANEL.SettingsSheet)
GM.UI.Help = PANEL
@@ -0,0 +1,235 @@
--[[
The MIT License (MIT)
Copyright (c) 2015-2018 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
local UI = {}
function UI:Init()
self.time = CurTime() - 0.5
self.padding = 3
self.size = Vector(320, 30 + self.padding * 2)
self.size2 = Vector(60, self.size.y)
self.colors = {}
self.colors.background = Color(0, 0, 0, 204)
self.colors.title = Color(204, 204, 204, 255)
self.colors.text = Color(255, 255, 255, 255)
self.state = {}
self.state.name = ""
self.ui = {}
self:DockPadding(self.padding, self.padding, self.padding, self.padding)
self.ui.bar = vgui.Create("DShape", self)
self.ui.bar:SetType("Rect")
self.ui.bar:SetSize(0, 5)
self.ui.bar:Dock(BOTTOM)
self.ui.round = vgui.Create("Panel", self)
self.ui.round:Dock(LEFT)
self.ui.round:SetSize(100, self.size.y)
self.ui.round_title = vgui.Create("DLabelDPI", self.ui.round)
self.ui.round_title:SetFontEx({ size = 10 })
self.ui.round_title:SetText("Round")
self.ui.round_title:SetColor(self.colors.title)
self.ui.round_title:SetContentAlignment(2)
self.ui.round_title:SizeToContents()
self.ui.round_title:Dock(TOP)
self.ui.round_text = vgui.Create("DLabelDPI", self.ui.round)
self.ui.round_text:SetFontEx({ size = 14 })
self.ui.round_text:SetText("0 / 10")
self.ui.round_text:SetColor(self.colors.text)
self.ui.round_text:SetContentAlignment(8)
self.ui.round_text:Dock(FILL)
self.ui.time = vgui.Create("Panel", self)
self.ui.time:Dock(RIGHT)
self.ui.time:SetSize(100, self.size.y)
self.ui.time_title = vgui.Create("DLabelDPI", self.ui.time)
self.ui.time_title:SetFontEx({ size = 10 })
self.ui.time_title:SetText("Time")
self.ui.time_title:SetColor(self.colors.title)
self.ui.time_title:SetContentAlignment(2)
self.ui.time_title:SizeToContents()
self.ui.time_title:Dock(TOP)
self.ui.time_text = vgui.Create("DLabelDPI", self.ui.time)
self.ui.time_text:SetFontEx({ size = 14 })
self.ui.time_text:SetText("00:00")
self.ui.time_text:SetColor(self.colors.text)
self.ui.time_text:SetContentAlignment(8)
self.ui.time_text:Dock(FILL)
self.ui.state = vgui.Create("Panel", self)
self.ui.state:Dock(FILL)
self.ui.state_title = vgui.Create("DLabelDPI", self.ui.state)
self.ui.state_title:SetFontEx({ size = 14 })
self.ui.state_title:SetText("Waiting for Server...")
self.ui.state_title:SetColor(self.colors.title)
self.ui.state_title:SetContentAlignment(2)
self.ui.state_title:SizeToContents()
self.ui.state_title:Dock(TOP)
self.ui.state_text = vgui.Create("DLabelDPI", self.ui.state)
self.ui.state_text:SetFontEx({ size = 10 })
self.ui.state_text:SetText("Waiting for Server...")
self.ui.state_text:SetColor(self.colors.text)
self.ui.state_text:SetContentAlignment(8)
self.ui.state_text:Dock(FILL)
hook.Add("RoundManagerEnterState", self, self.HandleEnterState);
UIManager:Listen("UpdateDPI", self, function(dpi) self:UpdateDPI(dpi) end)
self:UpdateDPI(UIManager:GetDPIScale())
end
function UI:OnRemove()
UIManager:Silence("UpdateDPI", self)
end
function UI:Think()
-- Only update once every 1/20th of a second.
if ((CurTime() - self.time) < 0.05) then
return
end
self.time = CurTime()
-- Update Time
self.ui.time_text:SetText(string.format("%02d:%02d",
math.floor(GAMEMODE:GetRoundTime() / 60),
math.floor(GAMEMODE:GetRoundTime() % 60)))
-- Update State Text
local round_time = GAMEMODE:GetRoundStateTime()
local team_id = GAMEMODE.Teams.Spectator
if (LocalPlayer() && LocalPlayer():IsPlayer()) then
team_id = LocalPlayer():Team()
end
if (self.state.name == "Hide") then
if (team_id == GAMEMODE.Teams.Seekers) then
self.ui.state_text:SetText(string.format("You will be unblinded in %02d:%02d",
math.floor(round_time / 60), math.floor(round_time % 60)))
else
self.ui.state_text:SetText(string.format("Seekers unblinded in %02d:%02d...",
math.floor(round_time / 60), math.floor(round_time % 60)))
end
elseif (self.state.name == "Seek") then
if (team_id == GAMEMODE.Teams.Seekers) then
self.ui.state_text:SetText(string.format("You have %02d:%02d left to kill all Hiders.",
math.floor(round_time / 60), math.floor(round_time % 60)))
else
self.ui.state_text:SetText(string.format("You have %02d:%02d left to annoy all Seekers.",
math.floor(round_time / 60), math.floor(round_time % 60)))
end
end
end
function UI:Paint()
local w,h = self:GetSize()
draw.RoundedBox(0, 0, 0, w, h, self.colors.background)
end
function UI:PerformLayout(w, h)
end
function UI:UpdateDPI(dpi)
local w, h = self.size.x * dpi, self.size.y * dpi
local w2, h2 = self.size2.x * dpi, self.size2.y * dpi
self.ui.round:SetSize(w2, h2)
self.ui.time:SetSize(w2, h2)
self:DockPadding(self.padding * dpi, self.padding * dpi, self.padding * dpi, self.padding * dpi)
self:SetSize(w, h)
self:CenterHorizontal()
self:AlignTop(20 * dpi)
self.ui.round:InvalidateLayout()
self.ui.time:InvalidateLayout()
self:InvalidateLayout()
end
function UI:UpdateStateDisplay()
local team_id = GAMEMODE.Teams.Spectator
if (LocalPlayer() && LocalPlayer():IsPlayer()) then
team_id = LocalPlayer():Team()
end
-- Update Team Color
self.ui.bar:SetColor(team.GetColor(team_id))
-- Update State itself
if (self.state.name == "PreMatch") then
self.ui.state_title:SetText(team.GetName(team_id))
self.ui.state_text:SetText(string.format("Waiting for players..."))
elseif (self.state.name == "PreRound") then
self.ui.state_title:SetText(team.GetName(team_id))
self.ui.state_text:SetText(string.format("Round starts soon..."))
elseif (self.state.name == "Hide") then
local round_time = GAMEMODE:GetRoundStateTime()
if (team_id == GAMEMODE.Teams.Seekers) then
self.ui.state_title:SetText("Blinded! Get ready to seek.")
else
self.ui.state_title:SetText("Hiding Time!")
end
elseif (self.state.name == "Seek") then
local round_time = GAMEMODE:GetRoundStateTime()
if (team_id == GAMEMODE.Teams.Seekers) then
self.ui.state_title:SetText("Seek & Destroy!")
else
self.ui.state_title:SetText("Hide & Avoid!")
end
elseif (self.state.name == "PostRound") then
self.ui.state_text:SetText("Next Round starting soon...")
local winner = GAMEMODE:GetRoundWinner()
if (winner == GAMEMODE.Teams.Spectators) then
self.ui.state_title:SetText("Draw! Everybody lost.")
elseif (winner == GAMEMODE.Teams.Seekers) then
self.ui.state_title:SetText("Seekers Win!")
elseif (winner == GAMEMODE.Teams.Hiders) then
self.ui.state_title:SetText("Hiders Win!")
end
elseif (self.state.name == "PostMatch") then
self.ui.state_title:SetText(team.GetName(team_id))
end
end
function UI:HandleEnterState(id, name)
self.state.name = name
-- Update Round
if (GAMEMODE.Config.Round:Limit() > 0) then
self.ui.round_text:SetText(string.format("%d / %d", GAMEMODE:GetRound(), GAMEMODE.Config.Round:Limit()))
else
self.ui.round_text:SetText(string.format("%d / ∞", GAMEMODE:GetRound()))
end
self:UpdateStateDisplay()
end
vgui.Register("PHE_GameState", UI, "Panel")
@@ -0,0 +1,75 @@
--[[
The MIT License (MIT)
Copyright (c) 2019 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
local CLASS = {}
CLASS.__index = CLASS
local netmsg = { -- Keep in sync with server table.
refresh = "RoundManagerUpdate",
winner = "RoundManagerWinner"
}
function CLASS:__construct()
self.state = nil
self.state_name = ""
net.Receive(netmsg.refresh, function(len, pl) self:__netRefresh(len, pl) end)
net.Receive(netmsg.winner, function(len, pl) self:__netWinner(len, pl) end)
end
function CLASS:GetStateId()
return self.state
end
function CLASS:GetStateName()
return self.state_name
end
function CLASS:CanJoinTeam(team)
if (LocalPlayer():Team() == team) then
return false
end
end
function CLASS:__netRefresh(len, pl)
local data = net.ReadTable()
if (self.state != data.state) then
hook.Run("RoundManagerLeaveState", self.state, self.state_name)
self.state = data.state
self.state_name = data.state_name
hook.Run("RoundManagerEnterState", self.state, self.state_name)
end
end
function CreateRoundManager()
local obj = {}
obj.__index = obj
setmetatable(obj, CLASS)
obj:__construct()
return obj
end
_G["RoundManager"] = CreateRoundManager()
@@ -0,0 +1,107 @@
--[[
The MIT License (MIT)
Copyright (c) 2015-2018 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
local FontManagerMeta = {}
FontManagerMeta.__index = FontManagerMeta
-- Global Constructor
function FontManager()
local obj = {}
obj.__index = obj
setmetatable(obj, FontManagerMeta)
obj:__construct()
return obj
end
-- Constructor
function FontManagerMeta:__construct()
self.fonts = {}
end
function FontManagerMeta:Exists(name)
if (self.fonts[name] != nil) then
return true
end
return false
end
function FontManagerMeta:CreateFontData(settings)
local base = {}
base.font = "Roboto"
base.extended = true
base.size = 13
base.weight = 500
base.blursize = 0
base.scanlines = 0
base.antialias = true
base.underline = false
base.italic = false
base.strikeout = false
base.symbol = false
base.rotary = false
base.shadow = false
base.additive = false
base.outline = false
local final = table.Merge(base, settings)
return final
end
function FontManagerMeta:CreateFont(settings)
local final = self:CreateFontData(settings)
local name = self:ToName(final)
return self:Request(name, final)
end
function FontManagerMeta:ToName(settings)
local name = settings.font
name = name .. "[S" .. settings.size
name = name .. "W" .. settings.weight
if (settings.blursize > 0) then name = name .. "B" .. settings.blursize end
if (settings.scanlines > 0) then name = name .. "L" .. settings.scanlines end
if (settings.antialias) then name = name .. "A" end
if (settings.extended) then name = name .. "E" end
if (settings.underline) then name = name .. "U" end
if (settings.italic) then name = name .. "I" end
if (settings.strikeout) then name = name .. "-" end
if (settings.shadow) then name = name .. "S" end
if (settings.outline) then name = name .. "O" end
if (settings.additive) then name = name .. "+" end
if (settings.rotary) then name = name .. "R" end
if (settings.symbol) then name = name .. "#" end
name = name .. "]"
return name
end
function FontManagerMeta:Request(name, settings)
if (self.fonts[name] != nil) then
--print("[Prop Hunt Font Manager] Request for font '"..name.."' received and cached.")
return name
end
print("[Font Manager] Creating new Font '"..name.."'...")
self.fonts[name] = surface.CreateFont(name, settings)
return name
end
_G["FontManager"] = FontManager()
@@ -0,0 +1,148 @@
--[[
The MIT License (MIT)
Copyright (c) 2015-2019 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
-- Help Panel
local UI = {}
local HTML = [[
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: Roboto;
font-size: 18pt;
color: rgba(255, 255, 255, 1.0);
background: rgba(51, 51, 51, 1.0);
}
div, p {
margin: 0;
padding: 0;
}
p + p {
margin-top: 10pt;
}
</style>
</head>
<body>
<div id="about">
<h1>About Prop Hunt Extended</h1>
<p>
Hide n Seek with a twist: Hiders can turn into anything on the map! From bottles, to vending machines and all the way to huge cars, what you become depends on how you want to play. Do you want to blend in with your surroundings, or do you want to make a fool of the Seekers? And how will you deal with finding (and killing) all hiders as a Seeker?
</p>
<p>
The Gamemode comes with out of the box support for console configuration (ph_*), custom taunt support, prop rotation, an improved code base for modders and better integration and some other fixes. Support for MapVote is also built in, so as long as you have a compatible addon installed you will get a map voting menu at the end of a match.
</p>
<p>
<h2>Help Develop:</h2>
The Gamemode is Open Source under the MIT License <a href="https://github.com/xaymar/prophuntextended" target="_blank">on Github</a>.
</p>
</div>
<div id="howto">
<h2>How To Play</h2>
<p>
<h3>Seekers</h3>
Your primary goal is to find hiders by any means possible. But watch out, you might lose health if you shoot an object that isn't actually a hider! Pick things up before shooting them, or simply remember the layout of the maps you are playing on. And remember: You lose if only a single hider is still alive at the end of the round.
</p>
<p>
<h3>Hiders</h3>
Stay alive as long as possible and make Seekers look like a fool. Dance around their feet, hide in plain sight or be that huge car that nobody though you could become! What you do is entirely up to you.
</p>
<p>
<h3>Spectators</h3>
You get to watch the whole thing go down live! Sit back, grab some popcorn or any other snack and relax.
</p>
</div>
<div id="controls">
<h2>Controls</h2>
<table>
<tr>
<th>Key/Button</th>
<th>Control Name</th>
<th>Description</th>
</tr>
<tr>
<td>F1</td>
<td>ShowHelp</td>
<td>Opens the Help and Settings window for this gamemode.</td>
</tr>
<tr>
<td>F2</td>
<td>ShowTeam</td>
<td>Change the team.</td>
</tr>
<tr>
<td>F3</td>
<td>ShowSpare1</td>
<td>Play a random Taunt, if it is not currently on cooldown.</td>
</tr>
<tr>
<td>C</td>
<td>ShowContextMenu</td>
<td>Toggle between 1st and 3rd Person Camera.</td>
</tr>
<tr>
<td>Q</td>
<td>ShowSpawnMenu</td>
<td>Tap to rotate the prop towards your current view angle, hold to continue rotating.</td>
</tr>
<tr>
<td>Ctrl + E</td>
<td>Duck + Use</td>
<td>Interact with objects, such as picking them up, opening doors, or pushing buttons, instead of turning into the object you are targeting.</td>
</tr>
</table>
</div>
</body>
</html>
]]
function UI:Init()
self.content = vgui.Create("DHTML", self)
self.content:Dock(FILL)
self.content:SetHTML(HTML)
self.content.OnChildViewCreated = function(source, target, isPopup)
gui.OpenURL(target)
print(source)
print(target)
print(isPopup)
end
self.content.OnChangeTargetURL = function(url)
print(url)
end
-- GAMEMODE.UIManager:Listen("UpdateDPI", self, function(dpi) self:UpdateDPI(dpi) end)
-- self:UpdateDPI(GAMEMODE.UIManager:GetDPIScale())
end
function UI:OnRemove()
self.content:Remove()
-- GAMEMODE.UIManager:Silence("UpdateDPI", self)
end
derma.DefineControl("PHE_HelpUI_Help", "Help Page for Prop Hunt Extended", UI, "DPanel");
@@ -0,0 +1,340 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
local DPlayerEntry = {}
function DPlayerEntry:Init()
self.Data = {}
self.Data.Margin = {
left = 0,
top = 0,
right = 0,
bottom = 0
}
self.Data.LastUpdate = CurTime() - 10
self.Data.Player = nil
self:SetMinimumSize(100, 40)
self.Container = vgui.Create("DPanel", self)
self.Container:SetBackgroundColor(Color(127,127,127,255))
self.Container:SetPaintBackground(true)
self.Container:Dock(FILL)
self.Container:DockMargin(0, 0, 0, 0)
self.Avatar = vgui.Create("AvatarImage", self.Container)
self.Avatar:Dock(LEFT)
self.Name = vgui.Create("DLabel", self.Container)
self.Name:SetText("Unknown")
self.Name:SetFont("Roboto24")
self.Name:SetContentAlignment(4)
self.Name:Dock(FILL)
self.Name:DockMargin(10, 5, 10, 5)
self.Deaths = vgui.Create("DLabel", self.Container)
self.Deaths:SetSize(80, 30)
self.Deaths:SetText("N/A")
self.Deaths:SetFont("Roboto24")
self.Deaths:SetContentAlignment(6)
self.Deaths:Dock(RIGHT)
self.Deaths:DockMargin(10, 5, 10, 5)
self.Kills = vgui.Create("DLabel", self.Container)
self.Kills:SetSize(80, 30)
self.Kills:SetText("N/A")
self.Kills:SetFont("Roboto24")
self.Kills:SetContentAlignment(6)
self.Kills:Dock(RIGHT)
self.Kills:DockMargin(10, 5, 10, 5)
end
function DPlayerEntry:PerformLayout(w, h)
self:SetMinimumSize(
100 + self.Data.Margin.left + self.Data.Margin.right,
40 + self.Data.Margin.top + self.Data.Margin.bottom
)
-- Docked Content
local containerX, containerY, containerW, containerH = self.Container:GetBounds()
self.Avatar:SetSize(containerH, containerH)
self.Kills:SetSize(80, containerH - 10)
self.Deaths:SetSize(80, containerH - 10)
end
function DPlayerEntry:Think()
if (CurTime() - self.Data.LastUpdate) < 0.25 then return end
if IsValid(self.Data.Player) then
self.Avatar:SetPlayer(self.Data.Player, 184)
self.Name:SetText(self.Data.Player:GetName())
self.Kills:SetText(self.Data.Player:Frags())
self.Deaths:SetText(self.Data.Player:Deaths())
end
end
function DPlayerEntry:SetMargin(left, top, right, bottom)
local uleft = left or 0
local utop = top or uleft
local uright = right or uleft
local ubottom = bottom or utop
self.Container:DockMargin(uleft, utop, uright, ubottom)
self:InvalidateLayout()
end
function DPlayerEntry:SetBackgroundColor(clr)
self.Container:SetBackgroundColor(clr)
end
function DPlayerEntry:SetForegroundColor(clr)
self.Name:SetColor(clr)
self.Kills:SetColor(clr)
self.Deaths:SetColor(clr)
end
function DPlayerEntry:SetPlayer(ply)
self.Data.Player = ply
end
function DPlayerEntry:ShowFlags(kills, deaths)
self.Kills:SetVisible(kills)
self.Deaths:SetVisible(deaths)
self.Container:InvalidateLayout()
end
vgui.Register("DPlayerEntry", DPlayerEntry, "Panel")
local DPlayerList = {}
function DPlayerList:Init()
self.Data = {}
self.Data.Time = CurTime() - 1
self.Data.Team = nil
self.Data.Players = {}
self.Data.ShowKills = true
self.Data.ShowDeaths = true
self.Container = vgui.Create("DPanel", self)
self.Container:SetPaintBackground(true)
self.Container:SetBackgroundColor(Color(51, 51, 51, 102))
self.Container:Dock(FILL)
self.Title = vgui.Create("DPanel", self.Container)
self.Title:SetSize(1, 40)
self.Title:Dock(TOP)
self.Title:DockMargin(0, 0, 0, 5)
self.Title.Name = vgui.Create("DLabel", self.Title)
self.Title.Name:SetText("Unknown")
self.Title.Name:SetFont("Roboto32Bold")
self.Title.Name:SetContentAlignment(5)
self.Title.Name:Dock(FILL)
self.Title.Name:DockMargin(10, 5, 10, 5)
self.Title.Deaths = vgui.Create("DLabel", self.Title)
self.Title.Deaths:SetText("Deaths")
self.Title.Deaths:SetFont("Roboto24")
self.Title.Deaths:SetContentAlignment(6)
self.Title.Deaths:SetSize(80, 40)
self.Title.Deaths:Dock(RIGHT)
self.Title.Deaths:DockMargin(10, 5, 10, 5)
self.Title.Kills = vgui.Create("DLabel", self.Title)
self.Title.Kills:SetText("Kills")
self.Title.Kills:SetFont("Roboto24")
self.Title.Kills:SetContentAlignment(6)
self.Title.Kills:SetSize(80, 40)
self.Title.Kills:Dock(RIGHT)
self.Title.Kills:DockMargin(10, 5, 10, 5)
self.Scroll = vgui.Create("DScrollPanel", self.Container)
self.Scroll:Dock(FILL)
self.Layout = vgui.Create("DListLayout", self.Scroll)
self.Layout:Dock(FILL)
end
function DPlayerList:PerformLayout(w, h)
--self.Container:SetSize(w, h)
end
function DPlayerList:Think()
if (self.Data.Team == -1) then return end
if ((CurTime() - self.Data.Time) < 0.1) then return end
self.Data.Time = CurTime()
-- Update Team Information
if (self.Data.Team != nil) then
self.Title:SetBackgroundColor(team.GetColor(self.Data.Team))
-- Name
self.Title.Name:SetText(team.GetName(self.Data.Team))
-- Text Color
local hue,sat,val = ColorToHSV(team.GetColor(self.Data.Team))
sat = sat * 0.1
val = val * 0.1
local col = HSVToColor(hue,sat,val)
self.Title.Name:SetColor(col)
self.Title.Kills:SetColor(col)
self.Title.Deaths:SetColor(col)
end
-- Update living players
local pls = team.GetPlayers(self.Data.Team)
for i,v in ipairs(pls) do
local alive = player_manager.RunClass(v, "Alive")
local gui = self.Data.Players[v]
if (gui == nil) then
gui = vgui.Create("DPlayerEntry")
gui:SetPlayer(v)
gui:SetMargin(0, 0, 0, 5)
gui:Stop()
gui:SetAlpha(0)
gui:AlphaTo(255, 1)
self.Data.Players[v] = gui
self.Layout:Add(gui)
end
if (alive) then
local hue,sat,val = ColorToHSV(team.GetColor(self.Data.Team))
local sat2,val2 = sat * 0.8, val * 0.8
gui:SetBackgroundColor(HSVToColor(hue, sat2, val2))
local sat3,val3 = sat * 0.1, val
gui:SetForegroundColor(HSVToColor(hue, sat3, val3))
else
local hue,sat,val = ColorToHSV(team.GetColor(self.Data.Team))
local sat2,val2 = sat * 0.8, val * 0.1
gui:SetBackgroundColor(HSVToColor(hue, sat2, val2))
local sat3,val3 = sat * 0.1, val
gui:SetForegroundColor(HSVToColor(hue, sat3, val3))
end
gui:ShowFlags(self.Data.ShowKills, self.Data.ShowDeaths)
end
-- Find dead players
for ply,gui in pairs(self.Data.Players) do
if (!table.HasValue(pls, ply)) then
self.Data.Players[ply] = nil
gui:Stop()
gui:AlphaTo(0, 1)
gui:SetTerm(1)
end
end
self.Layout:InvalidateLayout()
self.Scroll:InvalidateLayout()
end
function DPlayerList:SetTeam(team)
self.Data.Team = team
end
function DPlayerList:ShowFlags(kills, deaths)
self.Data.ShowKills = kills
self.Data.ShowDeaths = deaths
self.Title.Kills:SetVisible(self.Data.ShowKills)
self.Title.Deaths:SetVisible(self.Data.ShowDeaths)
self.Title:InvalidateLayout()
end
vgui.Register("DPlayerList", DPlayerList, "Panel")
local DScoreBoard = {}
function DScoreBoard:Init()
self.Container = vgui.Create("DPanel", self)
self.Container:SetPaintBackground(true)
self.Container:SetBackgroundColor(Color(0, 0, 0, 240))
self.Container:Dock(FILL)
self.Container:DockMargin(0, 35, 0, 0)
self.Logo = vgui.Create("DImage", self)
self.Logo:SetImage("prophuntextended/scoreboard_logo.png")
self.Logo:SetKeepAspect(true)
self.Logo:SetSize(580, 70)
self.Logo:SetPos(10, 0)
self.Frame = vgui.Create("DPanel", self.Container)
self.Frame:SetPaintBackground(false)
self.Frame:Dock(FILL)
self.Frame:DockMargin(5, 40, 5, 5)
self.Teams = {}
self.Teams.Seekers = vgui.Create("DPlayerList", self.Frame)
self.Teams.Seekers:SetTeam(GAMEMODE.Teams.Seekers)
self.Teams.Seekers:Dock(LEFT)
self.Teams.Seekers:DockMargin(5, 5, 5, 5)
self.Teams.Hiders = vgui.Create("DPlayerList", self.Frame)
self.Teams.Hiders:SetTeam(GAMEMODE.Teams.Hiders)
self.Teams.Hiders:Dock(RIGHT)
self.Teams.Hiders:DockMargin(5, 5, 5, 5)
self.Teams.Spectators = vgui.Create("DPlayerList", self.Container)
self.Teams.Spectators:SetSize(100, 100)
self.Teams.Spectators:SetTeam(GAMEMODE.Teams.Spectators)
self.Teams.Spectators:ShowFlags(false, false)
self.Teams.Spectators:Dock(BOTTOM)
self.Teams.Spectators:DockMargin(10, 0, 10, 10)
self:SetVisible(false)
self:SetAlpha(0)
end
function DScoreBoard:PerformLayout(w, h)
local frameW, frameH = self.Frame:GetSize()
local contW, contH = self.Container:GetSize()
-- Update Team Lists
self.Teams.Seekers:SetSize(frameW / 2 - 10, 0)
self.Teams.Hiders:SetSize(frameW / 2 - 10, 0)
self.Teams.Spectators:SetSize(100, contH / 5)
self.Frame:InvalidateLayout()
self.Container:InvalidateLayout()
end
function DScoreBoard:Show()
-- Size and Position
local w, h = ScrW() / 2, ScrH() / 4 * 3
if (w < 600) then w = 600 end
if (h < 400) then h = 400 end
self:SetSize(w, h)
self:Center()
-- Visibility
self:Stop()
self:AlphaTo(255, 0.1)
self:SetVisible(true)
-- Focus
self:SetPopupStayAtBack(true)
self:SetFocusTopLevel(true)
self:RequestFocus()
end
function DScoreBoard:Hide()
-- Visibility
self:Stop()
self:AlphaTo(0, 0.1, 0, function(animData, pnl)
pnl:SetVisible(false)
end)
end
vgui.Register("DScoreBoard", DScoreBoard, "EditablePanel")
@@ -0,0 +1,43 @@
--[[
The MIT License (MIT)
Copyright (c) 2015-2019 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
local UI = {}
function UI:Init()
self.text = vgui.Create("DLabelDPI", self)
self.text:SetText("Hello World")
UIManager:Listen("UpdateDPI", self, function(dpi) self:UpdateDPI(dpi) end)
self:UpdateDPI(UIManager:GetDPIScale())
end
function UI:OnRemove()
UIManager:Silence("UpdateDPI", self)
end
function UI:UpdateDPI(dpi)
end
derma.DefineControl("PHE_HelpUI_Settings", "Settings Page for Prop Hunt Extended", UI, "DPanel");
@@ -0,0 +1,182 @@
--[[
The MIT License (MIT)
Copyright (c) 2015-2018 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
--[[
# Class UIManager
UIManager is used to simplify the logic required to keep the GameMode's UI looking
good by simply moving all the logic into a single class and then handing off
the UI control to the windows themselves.
# Events
Events must be explicitly listened to by the client object. A client must first call
UIManager:Listen(string event, any uniqueId, function callback)
to listen to an event and call
UIManager:Silence(string event, any uniqueId)
to stop listening to an event.
## UpdateDPI(float DPIPercent)
Called whenever a change is made to the DPI, such as a change in the screen resolution,
or an update from the user of this class. Only parameter is DPI, which is a float.
1.0 designates 100%, 2.0 designates 200% and so on.
--]]
local UIManagerMeta = {}
UIManagerMeta.__index = UIManagerMeta
-- Global Constructor
function UIManager()
local obj = {}
obj.__index = obj
setmetatable(obj, UIManagerMeta)
obj:__construct()
return obj
end
-- Constructor
function UIManagerMeta:__construct()
self:InitializeEvents()
self:UpdateScreen()
self:InitializeDPI()
end
-- Events
function UIManagerMeta:InitializeEvents()
self.events = {}
end
function UIManagerMeta:Listen(event, uniqueName, callback)
assert(type(event) == "string", "UIManager:Listen(event<string>, uniqueName<any>, callback<function>): event must be a string")
assert(type(callback) == "function", "UIManager:Listen(event<string>, uniqueName<any>, callback<function>): callback must be a function")
if (self.events[event] == nil) then
self.events[event] = {}
end
self.events[event][uniqueName] = callback
return true
end
function UIManagerMeta:Silence(event, uniqueName)
assert(type(event) == "string", "UIManager:Silence(event<string>, uniqueName<any>): event must be a string")
if (self.events[event] == nil) then
return false
end
if (self.events[event][uniqueName] == nil) then
return false
end
self.events[event][uniqueName] = nil
return true
end
function UIManagerMeta:Call(event, ...)
if (self.events[event] == nil) then
return
end
for k,v in pairs(self.events[event]) do
v(...)
end
end
-- Screen
function UIManagerMeta:UpdateScreen()
if (self.screen == nil) then
self.screen = {}
end
if ((self.screen.width != ScrW()) || (self.screen.height != ScrH())) then
self.screen.width = ScrW()
self.screen.height = ScrH()
return true
end
return false
end
-- Tick
function UIManagerMeta:Tick()
if (self:UpdateScreen() == true) then
self.dpi.calculated = self:CalculateDPI()
self:SetDPIScale(self.dpi.override)
end
end
-- DPI Scaling
function UIManagerMeta:InitializeDPI()
self.dpi = {}
-- Calculate DPI using these base sizes.
self.dpi.base = {}
self.dpi.base.width = 1280
self.dpi.base.height = 720
-- Limits
self.dpi.limits = {}
self.dpi.limits.min = 0.25
self.dpi.limits.max = 10.00
-- Final Value
self.dpi.override = nil
self.dpi.calculated = self:CalculateDPI()
end
function UIManagerMeta:CalculateDPI()
--[[
DPI Scaling is linear in respect to the base resolution.
That means that at 50% of the Base resolution, the output is 0.5,
and at 200% of the Base resolution, the output is 2.0.
--]]
-- Shortest Edge scaling
local wScale, hScale = self.screen.width / self.dpi.base.width, self.screen.height / self.dpi.base.height
if (wScale < hScale) then
return wScale
end
return hScale
end
function UIManagerMeta:GetDPIScale()
if (self.dpi.override != nil) then
return self.dpi.override
end
return self.dpi.calculated
end
function UIManagerMeta:SetDPIScale(newDPIScale)
self.dpi.override = newDPIScale
if (self.dpi.override == nil) then
self:Call("UpdateDPI", self.dpi.calculated)
else
if (self.dpi.override < self.dpi.limits.min) then
self.dpi.override = self.dpi.limits.min
end
if (self.dpi.override > self.dpi.limits.max) then
self.dpi.override = self.dpi.limits.max
end
self:Call("UpdateDPI", self.dpi.override)
end
end
_G["UIManager"] = UIManager()
@@ -0,0 +1,64 @@
--[[
The MIT License (MIT)
Copyright (c) 2015-2019 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
-- DPI Aware Frame
local UI = {}
function UI:Init()
self.scale = 1.0
self.fontdata = FontManager:CreateFontData({})
UIManager:Listen("UpdateDPI", self, function(dpi) self:UpdateDPI(dpi) end)
self:UpdateDPI(UIManager:GetDPIScale())
end
function UI:OnRemove()
UIManager:Silence("UpdateDPI", self)
end
function UI:SetFontEx(fontData)
self.fontdata = FontManager:CreateFontData(fontData)
local scaled = table.Merge({}, self.fontdata)
scaled.size = math.Round(self.fontdata.size * self.scale)
scaled.blursize = math.Round(self.fontdata.blursize * self.scale)
self.font = FontManager:Request(FontManager:ToName(scaled), scaled)
self.lblTitle:SetFont(self.font)
self.lblTitle:InvalidateLayout()
self.lblTitle:InvalidateParent()
--self.btnClose:SetFont(self.font)
--self.btnMinim:SetFont(self.font)
--self.btnMaxim:SetFont(self.font)
end
function UI:UpdateDPI(dpi)
self.scale = dpi
self:SetFontEx(self.fontdata)
--self:InvalidateLayout()
--self:InvalidateParent()
end
derma.DefineControl("DFrameDPI", "DPI Aware DFrame (requires UIManager)", UI, "DFrame");
@@ -0,0 +1,58 @@
--[[
The MIT License (MIT)
Copyright (c) 2015-2019 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
-- DPI Aware Label
local UI = {}
function UI:Init()
self.scale = 1.0
self.fontdata = FontManager:CreateFontData({})
UIManager:Listen("UpdateDPI", self, function(dpi) self:UpdateDPI(dpi) end)
self:UpdateDPI(UIManager:GetDPIScale())
end
function UI:OnRemove()
UIManager:Silence("UpdateDPI", self)
end
function UI:SetFontEx(fontData)
self.fontdata = FontManager:CreateFontData(fontData)
local scaled = table.Merge({}, self.fontdata)
scaled.size = math.Round(self.fontdata.size * self.scale)
scaled.blursize = math.Round(self.fontdata.blursize * self.scale)
self:SetFont(FontManager:Request(FontManager:ToName(scaled), scaled))
end
function UI:UpdateDPI(dpi)
self.scale = dpi
self:SetFontEx(self.fontdata)
self:InvalidateLayout()
self:InvalidateParent()
end
derma.DefineControl("DLabelDPI", "DPI Aware DLabel (requires UIManager)", UI, "DLabel");
@@ -40,10 +40,7 @@ function CompatTauntPackLoader()
if (ty == "string") then if (ty == "string") then
Taunts[#Taunts+1] = t Taunts[#Taunts+1] = t
elseif (ty == "table") then elseif (ty == "table") then
Taunts[#Taunts+1] = t[2] Taunts[#Taunts+1] = t[1]
-- for j,snd in ipairs(t) do
-- HiderTaunts[#HiderTaunts+1] = snd
-- end
end end
end end
GAMEMODE.Config.Taunt.HidersCacheStatic = Taunts GAMEMODE.Config.Taunt.HidersCacheStatic = Taunts
@@ -53,10 +50,7 @@ function CompatTauntPackLoader()
if (ty == "string") then if (ty == "string") then
Taunts[#Taunts+1] = t Taunts[#Taunts+1] = t
elseif (ty == "table") then elseif (ty == "table") then
Taunts[#Taunts+1] = t[2] Taunts[#Taunts+1] = t[1]
-- for j,snd in ipairs(t) do
-- SeekerTaunts[#SeekerTaunts+1] = snd
-- end
end end
end end
GAMEMODE.Config.Taunt.SeekersCacheStatic = Taunts GAMEMODE.Config.Taunt.SeekersCacheStatic = Taunts
@@ -27,17 +27,30 @@
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
-- Shared -- Shared
AddCSLuaFile("sh_init.lua") AddCSLuaFile("sh_init.lua")
AddCSLuaFile("sh_defines.lua")
AddCSLuaFile("sh_config.lua") AddCSLuaFile("sh_config.lua")
AddCSLuaFile("meta/player.lua")
AddCSLuaFile("player_class/class_default.lua") AddCSLuaFile("player_class/class_default.lua")
AddCSLuaFile("player_class/class_spectator.lua") AddCSLuaFile("player_class/class_spectator.lua")
AddCSLuaFile("player_class/class_seeker.lua") AddCSLuaFile("player_class/class_seeker.lua")
AddCSLuaFile("player_class/class_hider.lua") AddCSLuaFile("player_class/class_hider.lua")
-- Client-Only -- Client-Only
AddCSLuaFile("cl_init.lua") AddCSLuaFile("vgui/fontmanager.lua")
AddCSLuaFile("vgui/uimanager.lua")
AddCSLuaFile("vgui/dlabeldpi.lua")
AddCSLuaFile("vgui/dframedpi.lua")
AddCSLuaFile("client/ui/help.lua")
AddCSLuaFile("client/ui/settings.lua")
AddCSLuaFile("client/ui/scoreboard.lua")
AddCSLuaFile("client/hud/gamestatedisplay.lua")
AddCSLuaFile("client/roundmanager.lua")
AddCSLuaFile("client/cl_ui_help.lua") AddCSLuaFile("client/cl_ui_help.lua")
AddCSLuaFile("client/cl_ui_teamselection.lua") AddCSLuaFile("client/cl_ui_teamselection.lua")
-- Client Init
AddCSLuaFile("cl_init.lua") -- Immediately executed when downloaded, weird behavior.
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
--! Code --! Code
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
@@ -70,10 +83,12 @@ function GM:Initialize()
print("Prop Hunt: Initializing Gamemode Data...") print("Prop Hunt: Initializing Gamemode Data...")
self.Data = {} self.Data = {}
self.Data.StartTime = CurTime() self.Data.RoundTime = 0
self.Data.RoundStartTime = 0
self.Data.StateTime = 0
print("Prop Hunt: Setting initial RoundManager State...") print("Prop Hunt: Initializing Round Manager")
self.RoundManager:SetState(StatePreMatch) RoundManager:SetState(StatePreRound)
print("Prop Hunt: Precaching...") print("Prop Hunt: Precaching...")
GAMEMODE.Config.Taunt:Seekers() GAMEMODE.Config.Taunt:Seekers()
@@ -83,10 +98,6 @@ function GM:Initialize()
print("-------------------------------------------------------------------------") print("-------------------------------------------------------------------------")
end end
function GM:Think()
self.RoundManager:Tick()
end
-- Player Connected -- Player Connected
function GM:PlayerConnect(name, ip) function GM:PlayerConnect(name, ip)
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Player '"..name.."' connecting from IP '"..ip.."'.") end if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Player '"..name.."' connecting from IP '"..ip.."'.") end
@@ -269,12 +280,16 @@ function GM:SetRound(Round)
SetGlobalInt("Round", Round) SetGlobalInt("Round", Round)
end end
function GM:SetRoundTime(Time)
SetGlobalInt("RoundTime", Time)
end
function GM:SetRoundState(State) function GM:SetRoundState(State)
SetGlobalInt("RoundState", State) SetGlobalInt("RoundState", State)
end end
function GM:SetRoundTime(Time) function GM:SetRoundStateTime(Time)
SetGlobalInt("RoundTime", Time) SetGlobalInt("RoundStateTime", Time)
end end
function GM:SetRoundWinner(Winner) function GM:SetRoundWinner(Winner)
@@ -390,15 +405,23 @@ net.Receive("PlayerEnablePropRotation", function(len, ply)
if (ply:Team() != GAMEMODE.Teams.Hiders) then if (ply:Team() != GAMEMODE.Teams.Hiders) then
return return
end end
print("Prop Hunt: Enabling Prop Rotation")
angle = net.ReadAngle()
ply:SetNWBool("PropRotation", true) ply:SetNWBool("PropRotation", true)
ply.Data.Prop:ApplyRotation(net.ReadAngle()) ply.Data.Prop:ApplyRotation(angle)
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") enabled prop rotation with angle ["..tostring(angle).."].") end
end) end)
net.Receive("PlayerDisablePropRotation", function(len, ply) net.Receive("PlayerDisablePropRotation", function(len, ply)
if (ply:Team() != GAMEMODE.Teams.Hiders) then if (ply:Team() != GAMEMODE.Teams.Hiders) then
return return
end end
print("Prop Hunt: Disabling Prop Rotation")
angle = net.ReadAngle()
ply:SetNWBool("PropRotation", false) ply:SetNWBool("PropRotation", false)
ply.Data.Prop:ApplyRotation(net.ReadAngle()) ply.Data.Prop:ApplyRotation(angle)
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Player '"..ply:GetName().."' (SteamID: "..ply:SteamID()..") enabled prop rotation with angle ["..tostring(angle).."].") end
end) end)
@@ -0,0 +1,259 @@
--[[
The MIT License (MIT)
Copyright (c) 2017 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
-- Finds the player meta table or terminates
local meta = FindMetaTable("Player")
if !meta then print("FAILED TO FIND PLAYER META") return end
-- Blinds the player by setting view out into the void
function meta:Blind(bool)
if !self:IsValid() then return end
if SERVER then
umsg.Start("SetBlind", self)
if bool then
umsg.Bool(true)
else
umsg.Bool(false)
end
umsg.End()
elseif CLIENT then
blind = bool
end
end
-- Blinds the player by setting view out into the void
function meta:RemoveProp()
if CLIENT || !self:IsValid() then return end
if self.ph_prop && self.ph_prop:IsValid() then
self.ph_prop:Remove()
self.ph_prop = nil
end
end
-- Sets a new Hull for a player.
function meta:NewHull(hullOBBMin, hullOBBMax)
if !self:IsValid() then return end
if hullOBBMax == nil then return end
if hullOBBMin == nil then return end
local hullOBB = hullOBBMax - hullOBBMin
local hullOBBXY = math.max(hullOBB.x, hullOBB.y)
local xyMul = 0.5
local hullMin = Vector(-hullOBBXY * xyMul, -hullOBBXY * xyMul, 0)
local hullMax = Vector( hullOBBXY * xyMul, hullOBBXY * xyMul, hullOBB.z)
self:SetHull(hullMin, hullMax)
self:SetHullDuck(hullMin, hullMax)
self:SetViewOffset(Vector(0, 0, hullOBB.z))
self:SetViewOffsetDucked(Vector(0, 0, hullOBB.z / 2.0))
end
-- Can the passed entity be used by the player?
function testflag(set, flag)
if (flag == 0) then return true end -- Mod(%) by 0 is nan.
return (set % (2 * flag)) >= flag
end
function meta:IsUseableEntity(ent, requiredCaps)
if ((ent != nil) && (ent:IsValid())) then
local caps = ent:ObjectCaps()
local capsmask = 16 + 32 + 64 + 128
if (testflag(caps, 16)
|| testflag(caps, 32)
|| testflag(caps, 64)
|| testflag(caps, 128)
) && testflag(caps, requiredCaps) then
return true
end
end
return false
end
function IntervalDistance(x, x0, x1)
-- swap so x0 < x1
if ( x0 > x1 ) then
local tmp = x0
x0 = x1
x1 = tmp
end
if ( x < x0 ) then
return x0-x
elseif ( x > x1 ) then
return x - x1
end
return 0
end
-- Find useable entity (Lua version of CBasePlayer:FindUseEntity)
function meta:FindUseEntity()
-- https://raw.githubusercontent.com/ValveSoftware/source-sdk-2013/0d8dceea4310fde5706b3ce1c70609d72a38efdf/mp/src/game/shared/baseplayer_shared.cpp
local PLAYER_USE_RADIUS = 80
-- Vectors
local forward = self:EyeAngles():Forward()
local up = self:EyeAngles():Up()
local center = self:EyePos()
local trace = {
start = center,
endpos = center,
mins = Vector(-16, -16, -16),
maxs = Vector( 16, 16, 16),
mask = MASK_SOLID + CONTENTS_DEBRIS + CONTENTS_PLAYERCLIP,
filter = function(ent)
if (ent == self) then return false end
if (!ent:IsValid()) then return false end
if (ent:IsPlayer()) then return false end
if (ent == self:GetHands()) then return false end
return true
end,
output = {}
}
local foundEnt = nil
local nearestDist = 16777216
local nearestEnt = nil
local tangents_num = 8
local tangents = {}
tangents[1] = 0
tangents[2] = 1
tangents[3] = 0.57735026919
tangents[4] = 0.3639702342
tangents[5] = 0.267949192431
tangents[6] = 0.1763269807
tangents[7] = -0.1763269807
tangents[8] = -0.267949192431
for idx=1,tangents_num,1 do
if (idx == 1) then
trace.endpos = center + forward * 1024
util.TraceLine(trace)
else
local down = forward - (Vector(tangents[idx], tangents[idx], tangents[idx]) * up)
down:Normalize()
trace.endpos = center + down * 72
util.TraceHull(trace)
end
foundEnt = trace.output.Entity
local useable = self:IsUseableEntity(foundEnt, 0)
while ((foundEnt:IsValid()) && !useable && (foundEnt:GetMoveParent():IsValid())) do
foundEnt = foundEnt:GetMoveParent()
useable = self:IsUseableEntity(foundEnt, 0)
end
if (useable) then
local delta = trace.output.HitPos - trace.output.StartPos
local centerZ = foundEnt:WorldSpaceCenter().z
delta.z = IntervalDistance(trace.output.HitPos.z, centerZ + foundEnt:OBBMins().z, centerZ + foundEnt:OBBMaxs().z)
local dist = delta:Length()
if (dist < PLAYER_USE_RADIUS) then
if (foundEnt:IsNPC() && (foundEnt:Team() == self:Team())) then
foundEnt = self:DoubleCheckUseNPC(foundEnt, center, forward)
end
--if (dist < nearestDist) then -- Not identical to CBasePlayer
--nearestDist = dist
nearestEnt = foundEnt
--end
if (idx == 1) then return foundEnt end
end
end
end
-- check ground entity first
-- if you've got a useable ground entity, then shrink the cone of this search to 45 degrees
-- otherwise, search out in a 90 degree cone (hemisphere)
if (self:GetGroundEntity():IsValid() && self:IsUseableEntity(self:GetGroundEntity(), 256)) then
nearestEnt = self:GetGroundEntity()
end
if (nearestEnt) then
local point = self:NearestPoint(center)
nearestDist = util.DistanceToLine(point, center, forward)
end
local search = ents.FindInSphere(center, PLAYER_USE_RADIUS)
for k,v in ipairs(search) do
if (v) && (v:IsValid()) && (self:IsUseableEntity(v, 512)) then
local point = v:NearestPoint(center)
local dir = (point - center):GetNormalized()
local dot = dir:Dot(forward)
if (dot >= 0.8) then
local dist = util.DistanceToLine(point, center, forward)
if (dist < nearestDist) then
trace.endpos = point
util.TraceLine(trace)
if ((trace.output.Fraction == 1.0) || (trace.output.Entity == v)) then
nearestEnt = v
nearestDist = dist
end
end
end
end
end
if (!nearestEnt) then
trace.endpos = center + forward * PLAYER_USE_RADIUS
trace.mask = MASK_OPAQUE_AND_NPCS
util.TraceLine(trace)
if (trace.output.Entity
&& trace.output.Entity:IsValid()
&& self:IsUseableEntity(trace.output.Entity, 0)
&& trace.output.Entity:IsNPC()
&& (trace.output.Entity:Team() == self:Team())) then
nearestEnt = trace.output.Entity
end
end
if (foundEnt:IsNPC() && (foundEnt:Team() == self:Team())) then
foundEnt = self:DoubleCheckUseNPC(foundEnt, center, forward)
end
return nearestEnt
end
-- Double Check NPC
-- Perhaps a poorly-named function. This function traces against the supplied
-- NPC's hitboxes (instead of hull). If the trace hits a different NPC, the
-- new NPC is selected. Otherwise, the supplied NPC is determined to be the
-- one the citizen wants. This function allows the selection of a citizen over
-- another citizen's shoulder, which is impossible without tracing against
-- hitboxes instead of the hull (sjb)
function meta:DoubleCheckUseNPC(npc, src, dir)
local trace = {
start = src,
endpos = src + dir * 1024,
mask = MASK_SHOT,
result = {}
}
util.TraceLine(trace)
if ((trace.result.Entity != nil) && (trace.result.Entity:IsValid()) && (trace.result.Entity:IsNPC()) && (trace.result.Entity != npc)) then
-- Player is selecting a different NPC through some negative space
-- in the first NPC's hitboxes (between legs, over shoulder, etc).
return trace.result.Entity
end
return npc
end
@@ -44,7 +44,10 @@ CLASS.UseVMHands = true -- Uses viewmodel hands
--! Server-Side --! Server-Side
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
-- Spawn -- Spawn
function CLASS:InitialSpawn() end function CLASS:InitialSpawn()
self.Player.Data = {}
self.Player.Data.SelectionHaloTime = CurTime()
end
function CLASS:Spawn() end function CLASS:Spawn() end
function CLASS:Loadout() end function CLASS:Loadout() end
@@ -58,6 +61,14 @@ function CLASS:DamageEntity(ent, attacker, dmginfo) end -- Damage Dealt To Entit
function CLASS:Death(inflictor, attacker) function CLASS:Death(inflictor, attacker)
self.Player.Data.Alive = false self.Player.Data.Alive = false
self.Player.Data.AliveTime = CurTime() self.Player.Data.AliveTime = CurTime()
-- Score support
self.Player:AddDeaths(1)
if IsValid(attacker) && attacker:IsPlayer() then
if ((attacker == self.Player)
|| (attacker:Team() == self.Player:Team())) then
self.Player:AddFrags(-1)
end
end
end end
function CLASS:SilentDeath() function CLASS:SilentDeath()
self.Player.Data.Alive = false self.Player.Data.Alive = false
@@ -80,14 +91,14 @@ function CLASS:SetModel() BaseClass.SetModel( self ) end
-- Interaction -- Interaction
function CLASS:Use(ent) function CLASS:Use(ent)
-- Entity must be valid and not a player. -- Entity must be valid and not a player.
if (!ent) || (!ent:IsValid()) || (ent:IsPlayer()) then if (!ent || !ent:IsValid()) then
return false return false
end end
-- Cool Down -- Cool Down
if (self.Player.Data.UseTime) then if (self.Player.Data.UseTime) then
local timeSinceUse = (CurTime() - self.Player.Data.UseTime) local timeSinceUse = (CurTime() - self.Player.Data.UseTime)
if (0.2 > timeSinceUse) then if (0.5 > timeSinceUse) then
return false return false
end end
@@ -122,6 +133,8 @@ function CLASS:ShowSpare2() end
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
function CLASS:PostThink() end function CLASS:PostThink() end
function CLASS:Tick(mv) end function CLASS:Tick(mv) end
function CLASS:FindUseEntity(defEnt) return defEnt end
function CLASS:Alive() return false end
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
--! Client-Side --! Client-Side
@@ -137,69 +150,6 @@ function CLASS:ClientSpawn() end
function CLASS:GetHandsModel() return BaseClass.GetHandsModel(self) end function CLASS:GetHandsModel() return BaseClass.GetHandsModel(self) end
function CLASS:ShouldDrawLocal() return false end function CLASS:ShouldDrawLocal() return false end
function CLASS:HUDPaint() function CLASS:HUDPaint()
local State = GetGlobalInt("RoundState", GAMEMODE.States.PreMatch)
if State == -1 then
return
end
-- Status Box at the top.
local statusW, statusH = 256,48
local statusX, statusY = ScrW() / 2 - statusW / 2, 0
draw.RoundedBox(0, statusX, statusY, statusW, statusH, Color(0,0,0,204)) -- Background
draw.RoundedBox(0, statusX, statusY+statusH, statusW, 4, team.GetColor(LocalPlayer():Team())) -- Team Bar
-- Title
surface.SetFont("Trebuchet18")
surface.SetTextColor(Color(255,255,255,255))
local titleText = ""
if (State == GAMEMODE.States.PreMatch) then
titleText = "Waiting for Players"
elseif (State == GAMEMODE.States.PreRound) then
titleText = "Preparing Round..."
elseif (State == GAMEMODE.States.Hide) then -- Hide
titleText = "Seekers unblinded in:"
elseif (State == GAMEMODE.States.Seek) then -- Seek
titleText = "Seek Time!"
elseif (State == GAMEMODE.States.PostRound) then -- Post Round
titleText = "Match Result:"
elseif (State == GAMEMODE.States.PostMatch) then -- Post Match
end
local w,h = surface.GetTextSize(titleText)
surface.SetTextPos(statusX + statusW/2 - w/2, statusY)
surface.DrawText(titleText)
-- Subtitle
local stateText = ""
surface.SetFont("Trebuchet24")
surface.SetTextColor(Color(255,255,255,255))
if (State == GAMEMODE.States.PreMatch) then
stateText = tostring(team.NumPlayers(GAMEMODE.Teams.Seekers)) .. " Seeker(s), " .. tostring(team.NumPlayers(GAMEMODE.Teams.Hiders)) .. " Hider(s)"
elseif (State == GAMEMODE.States.PreRound) then
stateText = "Initiating..."
elseif (State == GAMEMODE.States.Hide) -- Hide
|| (State == GAMEMODE.States.Seek) then -- Seek
local intTime = math.ceil(GetGlobalInt("RoundTime"))
local strTime = string.format("%d:%02d", math.floor(intTime / 60), math.ceil(intTime % 60))
stateText = strTime
elseif (State == GAMEMODE.States.PostRound) then -- Post Round
local victor = GAMEMODE:GetRoundWinner()
local victorName = "Draw"
if (victor == GAMEMODE.Teams.Spectator) then
victorName = "Draw"
elseif (victor == GAMEMODE.Teams.Hiders) then
victorName = "Hiders Win"
elseif (victor == GAMEMODE.Teams.Seekers) then
victorName = "Seekers Win"
end
stateText = victorName
surface.SetTextColor(team.GetColor(victor))
elseif (State == GAMEMODE.States.PostMatch) then -- Post Match
end
local w,h = surface.GetTextSize(stateText)
surface.SetTextPos(statusX + statusW/2 - w/2, statusY + 32 - h / 2)
surface.DrawText(stateText)
-- Death Notices -- Death Notices
GAMEMODE:DrawDeathNotice((ScrW() - 192) / ScrW() , 24 / ScrH()) GAMEMODE:DrawDeathNotice((ScrW() - 192) / ScrW() , 24 / ScrH())
end end
@@ -66,6 +66,7 @@ function CLASS:Spawn()
self.Player.Data.Prop:SetOwner(self.Player) self.Player.Data.Prop:SetOwner(self.Player)
self.Player.Data.Prop:Spawn() self.Player.Data.Prop:Spawn()
self.Player:DeleteOnRemove(self.Player.Data.Prop) self.Player:DeleteOnRemove(self.Player.Data.Prop)
self.Player.Data.PropContraint = constraint.NoCollide(self.Player, self.Player.Data.Prop, 0, 0)
-- Assign Hands (Auto Networked Sync!) -- Assign Hands (Auto Networked Sync!)
local oldhands = self.Player:GetHands() local oldhands = self.Player:GetHands()
@@ -74,11 +75,35 @@ function CLASS:Spawn()
end end
-- Death -- Death
function CLASS:PostDeath(attacker, dmginfo) function CLASS:DoDeath(attacker, dmginfo)
BaseClass.DoDeath(self, attacker, dmginfo)
if GAMEMODE.Config:DebugLog() then
if (IsValid(attacker) && attacker:IsPlayer() && attacker != self.Player) then
print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") killed by '"..attacker:GetName().."' (SteamID: "..attacker:SteamID()..").")
end
end
if (!IsValid(attacker)) then return end
if (!attacker:IsPlayer()) then return end
if (attacker:Team() == self.Player:Team()) then return end
if (attacker:Team() == GAMEMODE.Teams.Seekers) then
if GAMEMODE.Config:DebugLog() then
print("Prop Hunt: Seeker '"..attacker:GetName().."' (SteamID: "..attacker:SteamID()..") gained "..GAMEMODE.Config.Seeker:HealthBonus().." health for killing Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..").")
end
local newhealth = attacker:Health() + GAMEMODE.Config.Seeker:HealthBonus()
if (newhealth > attacker:GetMaxHealth()) then newhealth = attacker:GetMaxHealth() end
attacker:SetHealth(newhealth)
end
end
function CLASS:PostDeath()
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") died.") end if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") died.") end
BaseClass.PostDeath(self, inflictor, attacker) BaseClass.PostDeath(self, inflictor, attacker)
-- Delete Hands Model -- Delete Hands Model
if IsValid(self.Player.Data.PropConstraint) then
self.Player.Data.PropConstraint:Remove()
end
if IsValid(self.Player:GetHands()) then if IsValid(self.Player:GetHands()) then
self.Player:GetHands():Remove() self.Player:GetHands():Remove()
end end
@@ -111,7 +136,9 @@ function CLASS:DeathThink()
end end
-- Visible Stuff -- Visible Stuff
function CLASS:SetModel() self.Player:SetModel("models/Gibs/Antlion_gib_small_3.mdl") end -- does "" even work? function CLASS:SetModel()
self.Player:SetModel("models/Gibs/Antlion_gib_small_3.mdl")
end
-- Interaction -- Interaction
function CLASS:Use(ent) function CLASS:Use(ent)
@@ -121,6 +148,7 @@ function CLASS:Use(ent)
-- Allow interacting while crouched instead of turning into the prop. -- Allow interacting while crouched instead of turning into the prop.
if (self.Player:Crouching()) then if (self.Player:Crouching()) then
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Hider '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") interacted with "..ent:GetClass().." ("..ent:GetModel()..").") end
return true return true
end end
@@ -179,6 +207,33 @@ end
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
--! Shared --! Shared
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
if SERVER then
function CLASS:FindUseEntity(defEnt)
return self.Player:FindUseEntity()
end
function CLASS:Tick(mv)
if (self.Player.Data == nil) then return end
-- Selection Halo
if (GAMEMODE.Config.SelectionHalo:Allow()) && (!GAMEMODE.Config.SelectionHalo:Approximate()) then
if (self.Player.Data.SelectionHaloTime == nil) then
self.Player.Data.SelectionHaloTime = CurTime()
elseif ((CurTime() - self.Player.Data.SelectionHaloTime) > GAMEMODE.Config.SelectionHalo:Interval()) then
self.Player.Data.SelectionHaloTime = CurTime()
local ent = self.Player:FindUseEntity()
if (IsValid(ent)
&& table.HasValue(GAMEMODE.Config.Lists:ClassWhitelist(), ent:GetClass())
&& !table.HasValue(GAMEMODE.Config.Lists:ModelBlacklist(), ent:GetModel())) then
self.Player:SetNWEntity("SelectionHalo", ent)
else
self.Player:SetNWBool("SelectionHalo", false)
end
end
end
end
end
function CLASS:Alive() return true end
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
--! Client-Side --! Client-Side
@@ -146,8 +146,13 @@ function CLASS:DamageEntity(ent, att, dmg)
end end
-- Death -- Death
function CLASS:Death(inflictor, attacker) function CLASS:DoDeath(attacker, dmginfo)
BaseClass.Death(self, inflictor, attacker) BaseClass.DoDeath(self, attacker, dmginfo)
if GAMEMODE.Config:DebugLog() then
if (IsValid(attacker) && attacker:IsPlayer() && attacker != self.Player) then
print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") killed by '"..attacker:GetName().."' (SteamID: "..attacker:SteamID()..").")
end
end
if SERVER then if SERVER then
self.Player:SetShouldServerRagdoll(true) self.Player:SetShouldServerRagdoll(true)
@@ -205,6 +210,11 @@ function CLASS:ShowSpare1()
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") taunted with sound '"..tauntList[index].."'.") end if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Seeker '"..self.Player:GetName().."' (SteamID: "..self.Player:SteamID()..") taunted with sound '"..tauntList[index].."'.") end
end end
-- ------------------------------------------------------------------------- --
--! Shared
-- ------------------------------------------------------------------------- --
function CLASS:Alive() return true end
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
--! Client-Side --! Client-Side
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
@@ -1,549 +0,0 @@
--[[
The MIT License (MIT)
Copyright (c) 2015 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
--! Initialize configuration table.
GM.Config = { }
GM.Config.ConVars = {}
-- ------------------------------------------------------------------------- --
--! Basic Settings
-- ------------------------------------------------------------------------- --
-- Debug Mode
GM.Config.ConVars.Debug = CreateConVar("ph_debug", 0, FCVAR_CHEAT + FCVAR_REPLICATED)
function GM.Config:Debug()
return self.ConVars.Debug:GetBool()
end
-- Game Mode (See sh_init.lua)
GM.Config.ConVars.GameMode = CreateConVar("ph_gamemode", GM.Modes.Original, FCVAR_REPLICATED)
function GM.Config:GameMode()
return self.ConVars.GameMode:GetInt()
end
-- Timelimit in minutes
GM.Config.ConVars.TimeLimit = GetConVar("mp_timelimit")
function GM.Config:TimeLimit()
return self.ConVars.TimeLimit:GetFloat()
end
-- Enable Sprinting?
GM.Config.ConVars.Sprinting = CreateConVar("ph_sprinting", 0, FCVAR_REPLICATED)
function GM.Config:Sprinting()
return self.ConVars.Sprinting:GetBool()
end
-- Taunt Cooldown (Seconds)
GM.Config.ConVars.TauntCoolDown = CreateConVar("ph_tauntcooldown", 5, FCVAR_REPLICATED)
function GM.Config:TauntCoolDown()
return self.ConVars.TauntCoolDown:GetFloat()
end
-- ------------------------------------------------------------------------- --
--! Round Settings
-- ------------------------------------------------------------------------- --
GM.Config.Round = {}
GM.Config.Round.ConVars = {}
-- How many rounds should the gamemode attempt to fit into the map timelimit, if there is any?
GM.Config.Round.ConVars.Amount = CreateConVar("ph_round_limit", 10, FCVAR_REPLICATED)
function GM.Config.Round:Amount()
return self.ConVars.Amount:GetInt()
end
-- Round Time Limit (Seconds, Default 3 minutes)
GM.Config.Round.ConVars.Time = CreateConVar("ph_round_timelimit", 180, FCVAR_REPLICATED)
function GM.Config.Round:Time()
return self.ConVars.Time:GetInt() - GAMEMODE.Config.Round:BlindTime()
end
-- For how many seconds are the Seekers blinded? (Seconds)
GM.Config.Round.ConVars.BlindTime = CreateConVar("ph_round_blindtime", 30, FCVAR_REPLICATED, "How long are hunters blinded? (positive values will be inside the round time limit, negative will add to the round time limit)")
function GM.Config.Round:BlindTime()
return self.ConVars.BlindTime:GetInt()
end
-- ------------------------------------------------------------------------- --
--! Seeker Settings
-- ------------------------------------------------------------------------- --
GM.Config.Seeker = {}
GM.Config.Seeker.ConVars = {}
GM.Config.Seeker.ConVars.Health = CreateConVar("ph_seeker_health", 100, FCVAR_REPLICATED)
function GM.Config.Seeker:Health()
return self.ConVars.Health:GetInt()
end
GM.Config.Seeker.ConVars.HealthMax = CreateConVar("ph_seeker_health_max", 100, FCVAR_REPLICATED)
function GM.Config.Seeker:HealthMax()
return self.ConVars.HealthMax:GetInt()
end
GM.Config.Seeker.ConVars.HealthBonus = CreateConVar("ph_seeker_health_bonus", 20, FCVAR_REPLICATED)
function GM.Config.Seeker:HealthBonus()
return self.ConVars.HealthBonus:GetInt()
end
GM.Config.Seeker.ConVars.HealthPenalty = CreateConVar("ph_seeker_health_penalty", 5, FCVAR_REPLICATED)
function GM.Config.Seeker:HealthPenalty()
return self.ConVars.HealthPenalty:GetInt()
end
GM.Config.Seeker.ConVars.Weapons = CreateConVar("ph_seeker_weapons", "weapon_crowbar,weapon_pistol,weapon_ph_smg,weapon_shotgun", FCVAR_REPLICATED)
function GM.Config.Seeker:Weapons()
return string.Split(self.ConVars.Weapons:GetString(), ",")
end
GM.Config.Seeker.ConVars.Ammo = CreateConVar("ph_seeker_ammo", "Pistol:100,SMG1:300,SMG1_Grenade:1,Buckshot:64", FCVAR_REPLICATED)
function GM.Config.Seeker:Ammo()
return string.Split(self.ConVars.Ammo:GetString(), ",")
end
-- ------------------------------------------------------------------------- --
--! Hider Settings
-- ------------------------------------------------------------------------- --
GM.Config.Hider = {}
GM.Config.Hider.ConVars = {}
GM.Config.Hider.ConVars.Health = CreateConVar("ph_hider_health", 100, FCVAR_REPLICATED)
function GM.Config.Hider:Health()
return self.ConVars.Health:GetInt()
end
GM.Config.Hider.ConVars.HealthMax = CreateConVar("ph_hider_health_max", 100, FCVAR_REPLICATED)
function GM.Config.Hider:HealthMax()
return self.ConVars.HealthMax:GetInt()
end
GM.Config.Hider.ConVars.HealthScaling = CreateConVar("ph_hider_health_scaling", 100, FCVAR_REPLICATED)
function GM.Config.Hider:HealthScaling()
return self.ConVars.HealthScaling:GetBool()
end
GM.Config.Hider.ConVars.HealthScalingMax = CreateConVar("ph_hider_health_scaling_max", 200, FCVAR_REPLICATED)
function GM.Config.Hider:HealthScalingMax()
return self.ConVars.HealthScalingMax:GetInt()
end
-- ------------------------------------------------------------------------- --
--! Whitelist & Blacklist
-- ------------------------------------------------------------------------- --
GM.Config.Lists = {}
GM.Config.Lists.ConVars = {}
GM.Config.Lists.ConCmds = {}
GM.Config.Lists.ConVars.ClassWhitelist = CreateConVar("ph_list_class_whitelist", "prop_physics,prop_physics_multiplayer,prop_physics_respawnable", FCVAR_REPLICATED)
function GM.Config.Lists:ClassWhitelist()
return string.Split(self.ConVars.ClassWhitelist:GetString(), ",")
end
-- Use Abuse Blacklist
GM.Config.Lists.ConVars.AbuseBlacklist = CreateConVar("ph_list_abuse_blacklist", "func_button,func_door,func_door_rotation,prop_door_rotation,func_tracktrain,func_tanktrain,func_breakable", FCVAR_REPLICATED)
function GM.Config.Lists:AbuseBlacklist()
return string.Split(self.ConVars.AbuseBlacklist:GetString(), ",")
end
-- Model Blacklist
GM.Config.Lists.ModelBlacklist = {}
GM.Config.Lists.ModelBlacklist["models/props/cs_assault/dollar.mdl"] = true
GM.Config.Lists.ModelBlacklist["models/props/cs_assault/money.mdl"] = true
GM.Config.Lists.ModelBlacklist["models/props/cs_office/snowman_arm.mdl"] = true
GM.Config.Lists.ModelBlacklist["models/props/cs_office/projector_remote.mdl"] = true
--GM.Config.Lists.ModelBlacklist["models/props_junk/garbage_plasticbottle001a.mdl"] = true
GM.Config.Lists.ConCmds.ModelBlacklistList = concommand.Add("ph_list_model_blacklist_list", function(ply, cmd, args, argStr)
print("Model Blacklist:")
for k,v in pairs(GAMEMODE.Config.Lists.ModelBlacklist) do
print(" "..k)
end
end, "List all blacklisted models.")
GM.Config.Lists.ConCmds.ModelBlacklistClear = concommand.Add("ph_list_model_blacklist_list", function(ply, cmd, args, argStr)
GM.Config.Lists.ModelBlacklist = {}
end, "Clear blacklisted models.")
GM.Config.Lists.ConCmds.ModelBlacklistAdd = concommand.Add("ph_list_model_blacklist_add", function(ply, cmd, args, argStr)
if (table.count(args) > 0) then
GAMEMODE.Config.Lists.ModelBlacklist[args[1]] = true
else
print("Missing model name")
end
end, "Add a new blacklisted model.")
GM.Config.Lists.ConCmds.ModelBlacklistRemove = concommand.Add("ph_list_model_blacklist_remove", function(ply, cmd, args, argStr)
if (table.count(args) > 0) then
GAMEMODE.Config.Lists.ModelBlacklist[args[1]] = nil
else
print("Missing model name")
end
end, "Removes a blacklisted model.")
-- ------------------------------------------------------------------------- --
--! Taunts
-- ------------------------------------------------------------------------- --
-- GM.Config.Taunts = {
-- Seeker = { },
-- Hider = { },
-- }
-- -- Taunts.Clear()
-- --@desc: Clears the current taunt list.
-- GM.Config.Taunts.Clear = function()
-- this.Seeker = {}
-- this.Hider = {}
-- end
-- -- Taunts.Load(sTauntListFile)
-- --@desc: Loads the taunt list from disk.
-- --@param:
-- -- sTauntListFile - A string containing the path to the taunt list to load.
-- --@return: true or false depending on success.
-- GM.Config.Taunts.Load = function(sTauntListFile)
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: Loading taunt list from file '"..sTauntListFile.."'...") end
-- -- Safeguard against idiots.
-- if type(sTauntListFile) != "string" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: <sTauntListFile> is not a string.") end
-- return false
-- end
-- -- Given file must exist for us to continue.
-- if ! file.Exists(sTauntListFile, "GAME") then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: File not found.") end
-- return false
-- end
-- -- Read the file and check if it's empty.
-- sTauntListData = file.Read(sTauntListFile, "GAME")
-- if sTauntListData == "" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: File is empty.") end
-- return false
-- end
-- -- Convert JSON to a table for us to use.
-- sTauntList = util.JSONToTable(sTauntListData)
-- -- Is it nil? Then it's not valid JSON
-- if sTauntList == nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: File contains invalid JSON.") end
-- return false
-- end
-- -- Finally, append the taunt lists.
-- if sTauntList.Seeker != nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: Adding Seeker taunts...") end
-- for k,v in pairs(sTauntList.Seeker) do
-- GAMEMODE.Taunts.Seeker[k] = v
-- end
-- end
-- if sTauntList.Hider != nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: Adding Hider taunts...") end
-- for k,v in pairs(sTauntList.Hider) do
-- GAMEMODE.Taunts.Hider[k] = v
-- end
-- end
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Load: Complete.") end
-- return true
-- end
-- -- Taunts.Save(sTauntListFile)
-- --@desc: Saves the current taunt list to disk.
-- --@param:
-- -- sTauntListFile - A string containing the path to the file to save to.
-- --@return: true or false depending on success.
-- GM.Config.Taunts.Save = function(sTauntListFile)
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: Saving taunt list to file '"..sTauntListFile.."'...") end
-- -- Safeguard against idiots.
-- if type(sTauntListFile) != "string" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: <sTauntListFile> is not a string.") end
-- return false
-- end
-- -- File must not be nil, otherwise we can't write to it.
-- if sTauntListFile == nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: No file given.") end
-- return false
-- end
-- -- Convert our taunt table to JSON.
-- sTauntListData = util.TableToJSON(GAMEMODE.Taunts);
-- if sTauntListData == nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: Corrupted GAMEMODE table.") end
-- return false
-- end
-- -- Write out JSON out to file
-- if ! file.Write(sTauntListFile, sTauntListData) then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: Failed to write to file.") end
-- return false
-- end
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Save: Complete.") end
-- return true
-- end
-- -- Taunts.Add(sTauntName, sSoundFile, iTeamID, mPropFilter)
-- --@desc: Registers a new taunt with the given name, file, team and filter.
-- --@param:
-- -- sTauntName - The unique name of the taunt.
-- -- sSoundFile - A sound file to play when this taunt is selected.
-- -- iTeamID - The team that should receive the taunt or nil for all teams.
-- -- mPropFilter - A string or a table containing strings for props that should be able to use this taunt.
-- --@return: true or false depending on success.
-- GM.Config.Taunts.Add = function(sTauntName, sSoundFile, iTeamID, mPropFilter)
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: Adding new taunt '"..sTauntName.."'...") end
-- -- Safeguard against idiots.
-- if type(sTauntName) != "string" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: <sTauntName> is not a string.") end
-- return false
-- end
-- if type(sSoundFile) != "string" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: <sSoundFile> is not a string.") end
-- return false
-- end
-- if (type(iTeamID) != "number" && iTeamID != nil) then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: <iTeamID> is not a number or nil.") end
-- return false
-- end
-- if (type(mPropFilter) != "string" && type(mPropFilter) != "table" && mPropFilter != nil) then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: <mPropFilter> is not a string, table or nil.") end
-- return false
-- end
-- -- Check if the sound file actually exists
-- if !file.Exists("sound/"..sSoundFile, "GAME") then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: File '"..sSoundFile.."' does not exist.") end
-- return false
-- end
-- -- Make sure that our prop filter is a table listing the props it's supposed to work for.
-- if (mPropFilter == nil) then
-- mPropFilter = { }
-- elseif type(mPropFilter) == "string" then
-- mPropFilter = { mPropFilter }
-- end
-- -- Prepare Taunt table
-- Taunt = {
-- File = sSoundFile,
-- Filter = mPropFilter
-- }
-- -- If iTeamID is nil, both teams will receive the taunt.
-- if iTeamID == nil then
-- GAMEMODE.Taunts.Seeker[sTauntName] = Taunt
-- GAMEMODE.Taunts.Hider[sTauntName] = Taunt
-- else
-- -- Make sure that the team is valid.
-- if ! team.Valid(iTeamID) then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: Team "..iTeamID.."' does not exist.") end
-- return false
-- end
-- if (iTeamID == TEAM_SEEKERS) then
-- GAMEMODE.Taunts.Seeker[sTauntName] = Taunt
-- elseif (iTeamID == TEAM_HIDERS) then
-- GAMEMODE.Taunts.Hider[sTauntName] = Taunt
-- else
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: Team "..iTeamID.."' can't have taunts.") end
-- return false
-- end
-- end
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Add: Complete.") end
-- return true
-- end
-- -- Taunts.Remove(sTauntName, iTeamID)
-- --@desc: Removes a registered taunt with the given name and team.
-- --@param:
-- -- sTauntName - The unique name of the taunt.
-- -- iTeamID - The team that the taunt should be removed from or nil for all teams.
-- --@return: true or false depending on success.
-- GM.Config.Taunts.Remove = function(sTauntName, iTeamID)
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: Removing taunt '"..sTauntName.."'...") end
-- -- Safeguard against idiots.
-- if type(sTauntName) != "string" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: <sTauntName> is not a string.") end
-- return false
-- end
-- if (type(iTeamID) != "number" && iTeamID != nil) then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: <iTeamID> is not a number or nil.") end
-- return false
-- end
-- -- if iTeamID is nil, both teams will have the taunt removed.
-- if (iTeamID == nil) then
-- GAMEMODE.Taunts.Seeker[sTauntName] = nil
-- GAMEMODE.Taunts.Hider[sTauntName] = nil
-- else
-- -- Make sure we have a valid Team.
-- if ! team.Valid(iTeamID) then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: Team "..iTeamID.."' does not exist.") end
-- return false
-- end
-- if iTeamID == TEAM_SEEKERS then
-- GAMEMODE.Taunts.Seeker[sTauntName] = nil
-- elseif iTeamID == TEAM_HIDERS then
-- GAMEMODE.Taunts.Hider[sTauntName] = nil
-- else
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: Team "..iTeamID.."' can't have taunts.") end
-- return false
-- end
-- end
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Taunts.Remove: Complete.") end
-- return true
-- end
-- -- ToDo: Taunts.Get(iTeamID, sPropName)
-- --! Announcers (Round Start, Unblind, Win, Loss)
-- GM.Config.Announcers = {
-- Start = { },
-- Unblind = { },
-- Win = { },
-- Loss = { }
-- }
-- -- Announcers.Clear()
-- --@desc: Clears the current announcer list.
-- GM.Config.Announcers.Clear = function()
-- Announcers.Start = { }
-- Announcers.Unblind = { }
-- Announcers.Win = { }
-- Announcers.Loss = { }
-- end
-- -- Announcers.Load(sAnnouncerListFile)
-- --@desc: Tries to load the given announcer list.
-- --@param:
-- -- sAnnouncerListFile - A string containing the path to the announcer list to load.
-- --@return: true or false depending on success.
-- GM.Config.Announcers.Load = function(sAnnouncerListFile)
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Loading announcer list from file '"..sAnnouncerListFile.."'...") end
-- -- Safeguard against idiots.
-- if type(sAnnouncerListFile) != "string" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: <sAnnouncerListFile> is not a string.") end
-- return false
-- end
-- -- Given file must exist for us to continue.
-- if ! file.Exists(sAnnouncerListFile, "GAME") then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: File not found.") end
-- return false
-- end
-- -- Read the file and check if it's empty.
-- sAnnouncerListData = file.Read(sAnnouncerListFile, "GAME")
-- if sAnnouncerListData == "" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: File is empty.") end
-- return false
-- end
-- -- Convert JSON to a table for us to use.
-- sAnnouncerList = util.JSONToTable(sAnnouncerListData)
-- -- Is it nil? Then it's not valid JSON
-- if sAnnouncerList == nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: File contains invalid JSON.") end
-- return false
-- end
-- -- Finally, insert the announcer lists.
-- if sAnnouncerList.Start != nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Adding Start announcers...") end
-- for k,v in pairs(sAnnouncerList.Start) do
-- GAMEMODE.Announcers.Start[k] = v
-- end
-- end
-- if sAnnouncerList.Unblind != nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Adding Unblind announcers...") end
-- for k,v in pairs(sAnnouncerList.Unblind) do
-- GAMEMODE.Announcers.Unblind[k] = v
-- end
-- end
-- if sAnnouncerList.Win != nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Adding Win announcers...") end
-- for k,v in pairs(sAnnouncerList.Win) do
-- GAMEMODE.Announcers.Win[k] = v
-- end
-- end
-- if sAnnouncerList.Loss != nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Adding Loss announcers...") end
-- for k,v in pairs(sAnnouncerList.Loss) do
-- GAMEMODE.Announcers.Loss[k] = v
-- end
-- end
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Load: Complete.") end
-- return true
-- end
-- -- Announcers.Save(sAnnouncerListFile)
-- --@desc: Saves the current taunt list to disk.
-- --@param:
-- -- sAnnouncerListFile - A string containing the path to the file to save to.
-- --@return: true or false depending on success.
-- GM.Config.Announcers.Save = function(sAnnouncerListFile)
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: Saving announcer list to file '"..sAnnouncerListFile.."'...") end
-- -- Safeguard against idiots.
-- if type(sAnnouncerListFile) != "string" then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: <sAnnouncerListFile> is not a string.") end
-- return false
-- end
-- -- File must not be nil, otherwise we can't write to it.
-- if sAnnouncerListFile == nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: No file given.") end
-- return false
-- end
-- -- Convert our taunt table to JSON.
-- sAnnouncerListData = util.TableToJSON(GAMEMODE.Announcers);
-- if sAnnouncerListData == nil then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: Corrupted GAMEMODE table.") end
-- return false
-- end
-- -- Write out JSON out to file
-- if ! file.Write(sAnnouncerListFile, sAnnouncerListData) then
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: Failed to write to file.") end
-- return false
-- end
-- if GAMEMODE.Config:Debug() then print("Prop Hunt.Announcers.Save: Complete.") end
-- return true
-- end
-- -- ToDo: Announcers.Add
-- -- ToDo: Announcers.Remove
-- -- ToDo: Announcers.Get(iType)
@@ -1,7 +1,7 @@
--[[ --[[
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015 Xaymar Copyright (c) 2015-2018 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -22,42 +22,131 @@
SOFTWARE. SOFTWARE.
--]] --]]
GM.RoundManager = {} local CLASS = {}
GM.RoundManager.State = nil; CLASS.__index = CLASS
GM.RoundManager.NextState = nil;
function GM.RoundManager:Tick(...) local netmsg = {
if (self.State != nil) then refresh = "RoundManagerUpdate",
if (self.State.Tick != nil) then winner = "RoundManagerWinner"
self.State:Tick(...) }
function CLASS:__construct()
self.state = nil
self.next_state = nil
-- Custom Timer Stuff
self.timers = {}
self.timers.funcs = {}
self.timers.times = {}
self.timers.delay = {}
-- Register all network string
for k, v in pairs(netmsg) do
util.AddNetworkString(v)
end
-- And some more Timers based functionality.
self:_RegisterTimer("refresh", 2.0, function() self:RefreshAll() end)
-- We need a Think hook.
hook.Add("Think", "RoundManagerThink", function(...) self:Tick(...) end)
end
function CLASS:_RegisterTimer(name, delay, func)
self.timers.funcs[name] = func
self.timers.delay[name] = delay
self.timers.times[name] = CurTime()
end
function CLASS:GetState()
return self.state
end
function CLASS:GetNextState()
return self.next_state
end
function CLASS:SetState(state)
self.next_state = state
end
function CLASS:Tick(...)
-- Tick State
if (self.state != nil) then
if (self.state.Tick != nil) then
self.state:Tick(...)
end end
end end
-- Advance States -- Advance States
if (self.NextState != self.State) then if (self.next_state != self.state) then
-- Call OnLeave(NewState) local to_id = -1
if (self.State != nil) then local to_name = ""
if (self.State.OnLeave != nil) then
self.State:OnLeave(self.NextState) -- Call OnLeave
end if (self.state != nil) then
if (self.state.OnLeave != nil) then
self.state:OnLeave(self.next_state)
end end
-- Call OnEnter(OldState) -- Run Hook
if (self.NextState != nil) then hook.Run("RoundManagerLeaveState", self.state:GetId(), self.state:GetName())
if (self.NextState.OnEnter != nil) then
self.NextState:OnEnter(self.State)
end end
-- Call OnEnter
if (self.next_state != nil) then
if (self.next_state.OnEnter != nil) then
self.next_state:OnEnter(self.state)
end end
to_id = self.next_state:GetId()
to_name = self.next_state:GetName()
-- Run Hook
hook.Run("RoundManagerEnterState", self.next_state:GetId(), self.next_state:GetName())
end
-- Send Network Message
self:RefreshAll()
-- Set State -- Set State
self.State = self.NextState self.state = self.next_state
end
-- Run all timers.
for k, v in pairs(self.timers.times) do
if ((CurTime() - self.timers.times[k]) >= self.timers.delay[k]) then
self.timers.funcs[k]()
self.timers.times[k] = CurTime()
end
end end
end end
function GM.RoundManager:GetState() function CLASS:RefreshAll()
return self.State local data = {}
if (self.state != nil) then
data.state = self.state:GetId()
data.state_name = self.state:GetName()
else
data.state = -1
data.state_name = "Unknown"
end
net.Start(netmsg.refresh)
net.WriteTable(data)
net.Broadcast()
end end
function GM.RoundManager:SetState(State) function CLASS:AnnounceWinner(team)
self.NextState = State
end end
function CreateRoundManager()
local obj = {}
obj.__index = obj
setmetatable(obj, CLASS)
obj:__construct()
return obj
end
_G["RoundManager"] = CreateRoundManager()
@@ -0,0 +1,59 @@
--[[
The MIT License (MIT)
Copyright (c) 2018 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]]
local CLASS = {}
CLASS.__index = CLASS
function CLASS:__construct()
self.name = "Unnamed"
self.id = 0
end
function CLASS:GetName()
return self.name
end
function CLASS:GetId()
return self.id
end
function CLASS:OnEnter() end
function CLASS:Tick() end
function CLASS:OnLeave() end
function state(name, id)
local obj = {}
obj.__index = obj
setmetatable(obj, CLASS)
obj:__construct()
if (name != nil) then
obj.name = name
end
if (id != nil) then
obj.id = id
end
return obj;
end
@@ -1,7 +1,7 @@
--[[ --[[
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015 Xaymar Copyright (c) 2015-2018 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -22,29 +22,28 @@
SOFTWARE. SOFTWARE.
--]] --]]
StateHide = {} include "base.lua"
function StateHide:OnEnter(OldState) local CLASS = state("Hide", GM.States.Hide)
function CLASS:OnEnter(OldState)
if GAMEMODE.Config:DebugLog() then print("StateHide: OnEnter") end if GAMEMODE.Config:DebugLog() then print("StateHide: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.Hide) GAMEMODE:SetRoundState(GAMEMODE.States.Hide)
-- Round Data
GAMEMODE.Data.RoundTime = math.abs(GAMEMODE.Config.Round:BlindTime())
GAMEMODE.Data.RoundStartTime = CurTime()
GAMEMODE:SetRoundTime(GAMEMODE.Data.RoundTime)
end end
function StateHide:Tick() function CLASS:Tick()
-- Update Game Time -- Update Game Time
GAMEMODE.Data.RoundTime = math.abs(GAMEMODE.Config.Round:BlindTime()) - (CurTime() - GAMEMODE.Data.RoundStartTime) local deltaTime = (CurTime() - GAMEMODE.Data.RoundStartTime)
GAMEMODE.Data.RoundTime = GAMEMODE.Config.Round:Time() - deltaTime
GAMEMODE.Data.StateTime = math.abs(GAMEMODE.Config.Round:BlindTime()) - deltaTime
GAMEMODE:SetRoundTime(GAMEMODE.Data.RoundTime) GAMEMODE:SetRoundTime(GAMEMODE.Data.RoundTime)
GAMEMODE:SetRoundStateTime(GAMEMODE.Data.StateTime)
-- Advance to Seeking State -- Advance to Seeking State
if (GAMEMODE.Data.RoundTime <= 0) then if (GAMEMODE.Data.StateTime <= 0) then
if GAMEMODE.Config:Debug() then print("StateHide: Advancing to Seek stage.") end if GAMEMODE.Config:Debug() then print("StateHide: Advancing to Seek stage.") end
GAMEMODE.RoundManager:SetState(StateSeek) RoundManager:SetState(StateSeek)
end end
-- Freeze Seekers -- Freeze Seekers
@@ -57,9 +56,11 @@ function StateHide:Tick()
-- ToDo: Logic for more game modes here? -- ToDo: Logic for more game modes here?
end end
function StateHide:OnLeave(NewState) function CLASS:OnLeave(NewState)
if GAMEMODE.Config:Debug() then print("StateHide: OnLeave") end if GAMEMODE.Config:Debug() then print("StateHide: OnLeave") end
-- Fretta Hooks -- Fretta Hooks
hook.Run("PropHuntUnblind") hook.Run("PropHuntUnblind")
end end
_G["StateHide"] = CLASS
@@ -1,7 +1,7 @@
--[[ --[[
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015 Xaymar Copyright (c) 2015-2018 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -22,9 +22,11 @@
SOFTWARE. SOFTWARE.
--]] --]]
StatePostMatch = {} include "base.lua"
function StatePostMatch:OnEnter(OldState) local CLASS = state("PostMatch", GM.States.PostMatch)
function CLASS:OnEnter(OldState)
if GAMEMODE.Config:DebugLog() then print("StatePostMatch: OnEnter") end if GAMEMODE.Config:DebugLog() then print("StatePostMatch: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.PostMatch) GAMEMODE:SetRoundState(GAMEMODE.States.PostMatch)
@@ -32,7 +34,7 @@ function StatePostMatch:OnEnter(OldState)
-- Check Change map conditions. -- Check Change map conditions.
if ((GAMEMODE.Config:TimeLimit() > 0) && ((CurTime() - GAMEMODE.Data.StartTime) >= (GAMEMODE.Config:TimeLimit() * 60))) -- Over Time if ((GAMEMODE.Config:TimeLimit() > 0) && ((CurTime() - GAMEMODE.Data.StartTime) >= (GAMEMODE.Config:TimeLimit() * 60))) -- Over Time
|| (GAMEMODE:GetRound() >= GAMEMODE.Config.Round:Limit()) -- Over Round Limit || ((GAMEMODE.Config.Round:Limit() > 0) && (GAMEMODE:GetRound() >= GAMEMODE.Config.Round:Limit())) -- Over Round Limit
then then
-- Advance to nothing -- Advance to nothing
@@ -44,11 +46,13 @@ function StatePostMatch:OnEnter(OldState)
end end
end end
function StatePostMatch:Tick() function CLASS:Tick()
-- Advance State -- Advance State
GAMEMODE.RoundManager:SetState(self.NextState) RoundManager:SetState(self.NextState)
end end
function StatePostMatch:OnLeave(NewState) function CLASS:OnLeave(NewState)
if GAMEMODE.Config:DebugLog() then print("StatePostMatch: OnLeave") end if GAMEMODE.Config:DebugLog() then print("StatePostMatch: OnLeave") end
end end
_G["StatePostMatch"] = CLASS
@@ -1,7 +1,7 @@
--[[ --[[
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015 Xaymar Copyright (c) 2015-2018 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -22,9 +22,11 @@
SOFTWARE. SOFTWARE.
--]] --]]
StatePostRound = {} include "base.lua"
function StatePostRound:OnEnter(OldState) local CLASS = state("PostRound", GM.States.PostRound)
function CLASS:OnEnter(OldState)
if GAMEMODE.Config:DebugLog() then print("StatePostRound: OnEnter") end if GAMEMODE.Config:DebugLog() then print("StatePostRound: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.PostRound) GAMEMODE:SetRoundState(GAMEMODE.States.PostRound)
@@ -34,10 +36,10 @@ function StatePostRound:OnEnter(OldState)
hook.Run("RoundEnd") hook.Run("RoundEnd")
end end
function StatePostRound:Tick() function CLASS:Tick()
-- Advance State -- Advance State
if (CurTime() - GAMEMODE.Data.RoundStartTime) >= 5 then -- ToDo: configureable time? if (CurTime() - GAMEMODE.Data.RoundStartTime) >= 5 then -- ToDo: configureable time?
GAMEMODE.RoundManager:SetState(StatePostMatch) RoundManager:SetState(StatePostMatch)
local players = team.GetPlayers(GAMEMODE.Teams.Seekers) local players = team.GetPlayers(GAMEMODE.Teams.Seekers)
table.Add(players, team.GetPlayers(GAMEMODE.Teams.Hiders)) table.Add(players, team.GetPlayers(GAMEMODE.Teams.Hiders))
@@ -95,7 +97,7 @@ function StatePostRound:Tick()
if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Swapping Teams.") end if GAMEMODE.Config:DebugLog() then print("Prop Hunt: Swapping Teams.") end
table.sort(players, function(a,b) table.sort(players, function(a,b)
return math.random(100) > 50 return (math.random(100) > 50)
end) end)
table.sort(players, function(a,b) table.sort(players, function(a,b)
if (b:Team() == GAMEMODE.Teams.Seekers) then if (b:Team() == GAMEMODE.Teams.Seekers) then
@@ -107,21 +109,11 @@ function StatePostRound:Tick()
-- Team Distribution Logic -- Team Distribution Logic
local hiders, seekers = {}, {} local hiders, seekers = {}, {}
if (GAMEMODE.Config:GameType() == GAMEMODE.Types.Original) then
-- Game Mode: Basic
local plyCount, finalPlyCount = #players, math.max(math.ceil(#players / 2), 1) local plyCount, finalPlyCount = #players, math.max(math.ceil(#players / 2), 1)
for c = 1,finalPlyCount do for c = 1,finalPlyCount do
seekers[c] = table.remove(players, 1) seekers[c] = table.remove(players, 1)
end end
hiders = players hiders = players
elseif (GAMEMODE.Config:GameType() == GAMEMODE.Types.TheDeadHunt) then
-- Game Mode: The Dead Hunt
local plyCount, finalPlyCount = #players, math.max(math.ceil(#players * GAMEMODE.Config.Teams:SeekerPercentage()), 1)
for c = 1,finalPlyCount do
seekers[c] = table.remove(players, 1)
end
hiders = players
end
-- Kill & Assign Teams -- Kill & Assign Teams
for i, ply in ipairs(hiders) do for i, ply in ipairs(hiders) do
@@ -137,6 +129,8 @@ function StatePostRound:Tick()
end end
end end
function StatePostRound:OnLeave(NewState) function CLASS:OnLeave(NewState)
if GAMEMODE.Config:DebugLog() then print("StatePostRound: OnLeave") end if GAMEMODE.Config:DebugLog() then print("StatePostRound: OnLeave") end
end end
_G["StatePostRound"] = CLASS
@@ -1,7 +1,7 @@
--[[ --[[
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015 Xaymar Copyright (c) 2015-2018 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -22,34 +22,33 @@
SOFTWARE. SOFTWARE.
--]] --]]
-- Precache Network Message include "base.lua"
StatePreMatch = {}
function StatePreMatch:OnEnter(OldState) local CLASS = state("PreMatch", GM.States.PreMatch)
function CLASS:OnEnter(OldState)
if GAMEMODE.Config:DebugLog() then print("StatePreMatch: OnEnter") end if GAMEMODE.Config:DebugLog() then print("StatePreMatch: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.PreMatch) GAMEMODE:SetRoundState(GAMEMODE.States.PreMatch)
math.randomseed(CurTime()) math.randomseed(CurTime())
end end
function StatePreMatch:Tick() function CLASS:Tick()
-- Debug: Auto Advance to PreRound State -- Debug: Auto Advance to PreRound State
if (GAMEMODE.Config:Debug()) then if (GAMEMODE.Config:Debug()) then
if GAMEMODE.Config:DebugLog() then print("StatePreMatch: Advancing to StatePreRound") end if GAMEMODE.Config:DebugLog() then print("StatePreMatch: Advancing to StatePreRound") end
GAMEMODE.RoundManager:SetState(StatePreRound) RoundManager:SetState(StatePreRound)
end end
-- Game Mode: Basic
if (GAMEMODE.Config:GameType() == GAMEMODE.Types.Original) then
-- Both Teams must have at least 1 player. -- Both Teams must have at least 1 player.
if ((team.NumPlayers(GAMEMODE.Teams.Seekers) >= 1) && (team.NumPlayers(GAMEMODE.Teams.Hiders) >= 1)) then if ((team.NumPlayers(GAMEMODE.Teams.Seekers) >= 1) && (team.NumPlayers(GAMEMODE.Teams.Hiders) >= 1)) then
GAMEMODE.RoundManager:SetState(StatePreRound) RoundManager:SetState(StatePreRound)
if GAMEMODE.Config:DebugLog() then print("StatePreMatch: <Original> Have enough players to start match.") end if GAMEMODE.Config:DebugLog() then print("StatePreMatch: <Original> Have enough players to start match.") end
end end
-- TODO: Other Gamemodes
end
end end
function StatePreMatch:OnLeave(NewState) function CLASS:OnLeave(NewState)
if GAMEMODE.Config:DebugLog() then print("StatePreMatch: OnLeave") end if GAMEMODE.Config:DebugLog() then print("StatePreMatch: OnLeave") end
end end
_G["StatePreMatch"] = CLASS
@@ -1,7 +1,7 @@
--[[ --[[
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015 Xaymar Copyright (c) 2015-2018 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -22,9 +22,11 @@
SOFTWARE. SOFTWARE.
--]] --]]
StatePreRound = {} include "base.lua"
function StatePreRound:OnEnter(OldState) local CLASS = state("PreRound", GM.States.PreRound)
function CLASS:OnEnter(OldState)
if GAMEMODE.Config:DebugLog() then print("StatePreRound: OnEnter") end if GAMEMODE.Config:DebugLog() then print("StatePreRound: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.PreRound) GAMEMODE:SetRoundState(GAMEMODE.States.PreRound)
GAMEMODE:SetRound(GAMEMODE:GetRound() + 1) GAMEMODE:SetRound(GAMEMODE:GetRound() + 1)
@@ -32,12 +34,17 @@ function StatePreRound:OnEnter(OldState)
-- Clean Up the Map -- Clean Up the Map
game.CleanUpMap() game.CleanUpMap()
-- Set Round Start Time
GAMEMODE.Data.RoundStartTime = CurTime()
end end
function StatePreRound:Tick()
function CLASS:Tick()
-- Advance State -- Advance State
GAMEMODE.RoundManager:SetState(StateHide) RoundManager:SetState(StateHide)
end end
function StatePreRound:OnLeave(NewState)
function CLASS:OnLeave(NewState)
if GAMEMODE.Config:DebugLog() then print("StatePreRound: OnLeave") end if GAMEMODE.Config:DebugLog() then print("StatePreRound: OnLeave") end
-- Respawn Everyone -- Respawn Everyone
@@ -59,3 +66,5 @@ function StatePreRound:OnLeave(NewState)
-- Fretta Hooks -- Fretta Hooks
hook.Run("RoundStart") hook.Run("RoundStart")
end end
_G["StatePreRound"] = CLASS
@@ -1,7 +1,7 @@
--[[ --[[
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015 Xaymar Copyright (c) 2015-2018 Xaymar
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -22,15 +22,14 @@
SOFTWARE. SOFTWARE.
--]] --]]
StateSeek = {} include "base.lua"
function StateSeek:OnEnter(OldState) local CLASS = state("Seek", GM.States.Seek)
function CLASS:OnEnter(OldState)
if GAMEMODE.Config:DebugLog() then print("StateSeek: OnEnter") end if GAMEMODE.Config:DebugLog() then print("StateSeek: OnEnter") end
GAMEMODE:SetRoundState(GAMEMODE.States.Seek) GAMEMODE:SetRoundState(GAMEMODE.States.Seek)
-- Round Data
GAMEMODE.Data.RoundTime = GAMEMODE.Config.Round:Time()
-- Unfreeze Seekers -- Unfreeze Seekers
for i, ply in ipairs(team.GetPlayers(GAMEMODE.Teams.Seekers)) do for i, ply in ipairs(team.GetPlayers(GAMEMODE.Teams.Seekers)) do
ply:Freeze(false) ply:Freeze(false)
@@ -40,10 +39,13 @@ function StateSeek:OnEnter(OldState)
end end
end end
function StateSeek:Tick() function CLASS:Tick()
-- Update Game Time -- Update Game Time
GAMEMODE.Data.RoundTime = GAMEMODE.Config.Round:Time() - (CurTime() - GAMEMODE.Data.RoundStartTime) local deltaTime = (CurTime() - GAMEMODE.Data.RoundStartTime)
GAMEMODE.Data.RoundTime = GAMEMODE.Config.Round:Time() - deltaTime
GAMEMODE.Data.StateTime = GAMEMODE.Config.Round:Time() - deltaTime
GAMEMODE:SetRoundTime(GAMEMODE.Data.RoundTime) GAMEMODE:SetRoundTime(GAMEMODE.Data.RoundTime)
GAMEMODE:SetRoundStateTime(GAMEMODE.Data.StateTime)
-- Victory Conditions -- Victory Conditions
local hiders, seekers = team.GetPlayers(GAMEMODE.Teams.Hiders), team.GetPlayers(GAMEMODE.Teams.Seekers) local hiders, seekers = team.GetPlayers(GAMEMODE.Teams.Hiders), team.GetPlayers(GAMEMODE.Teams.Seekers)
@@ -58,38 +60,49 @@ function StateSeek:Tick()
end end
for i,ply in ipairs(seekers) do for i,ply in ipairs(seekers) do
if (ply.Data.Alive) then if (ply.Data.Alive) then
seekerAlive = true seekerAlive = truew
end end
end end
if (hiderAlive == false) then if (hiderAlive == false) then
if (seekerAlive == false) then -- Draw, both teams dead. if (seekerAlive == false) then -- Draw, both teams dead.
GAMEMODE:SetRoundWinner(GAMEMODE.Teams.Spectators) GAMEMODE:SetRoundWinner(GAMEMODE.Teams.Spectators)
GAMEMODE.RoundManager:SetState(StatePostRound) RoundManager:SetState(StatePostRound)
else -- Seeker victory, Hiders dead else -- Seeker victory, Hiders dead
GAMEMODE:SetRoundWinner(GAMEMODE.Teams.Seekers) GAMEMODE:SetRoundWinner(GAMEMODE.Teams.Seekers)
GAMEMODE.RoundManager:SetState(StatePostRound) RoundManager:SetState(StatePostRound)
end end
else else
if (seekerAlive == false) then -- Hider Victory, Seeker dead. if (seekerAlive == false) then -- Hider Victory, Seeker dead.
GAMEMODE:SetRoundWinner(GAMEMODE.Teams.Hiders) GAMEMODE:SetRoundWinner(GAMEMODE.Teams.Hiders)
GAMEMODE.RoundManager:SetState(StatePostRound) RoundManager:SetState(StatePostRound)
else else
if (GAMEMODE.Data.RoundTime <= 0) then -- No Time remaining if (GAMEMODE.Data.StateTime <= 0) then -- No Time remaining
GAMEMODE:SetRoundWinner(GAMEMODE.Teams.Hiders) GAMEMODE:SetRoundWinner(GAMEMODE.Teams.Hiders)
GAMEMODE.RoundManager:SetState(StatePostRound) RoundManager:SetState(StatePostRound)
end end
end end
end end
end end
function StateSeek:OnLeave(NewState) function CLASS:OnLeave(NewState)
if GAMEMODE.Config:DebugLog() then print("StateSeek: OnLeave") end if GAMEMODE.Config:DebugLog() then print("StateSeek: OnLeave") end
if GAMEMODE:GetRoundWinner() == GAMEMODE.Teams.Seekers then if GAMEMODE:GetRoundWinner() == GAMEMODE.Teams.Seekers then
-- Run external Hooks
hook.Run("RoundVictorySeeker") hook.Run("RoundVictorySeeker")
-- Assign Team Points
team.SetScore(GAMEMODE.Teams.Seekers, team.GetScore(GAMEMODE.Teams.Seekers) + 1)
elseif GAMEMODE:GetRoundWinner() == GAMEMODE.Teams.Hiders then elseif GAMEMODE:GetRoundWinner() == GAMEMODE.Teams.Hiders then
-- Run external Hooks
hook.Run("RoundVictoryHider") hook.Run("RoundVictoryHider")
-- Assign Team Points
team.SetScore(GAMEMODE.Teams.Hiders, team.GetScore(GAMEMODE.Teams.Hiders) + 1)
else else
-- Run external Hooks
hook.Run("RoundVictoryDraw") hook.Run("RoundVictoryDraw")
end end
end end
_G["StateSeek"] = CLASS
@@ -36,6 +36,17 @@ function CreateConVarIfNotExists(name, value, flags, helptext)
return cv return cv
end end
-- ------------------------------------------------------------------------- --
--! Options
-- ------------------------------------------------------------------------- --
GM.Options = { }
-- Friendly Fire
GM.Options.FriendlyFire = { }
GM.Options.FriendlyFire.Off = 0
GM.Options.FriendlyFire.On = 1
GM.Options.FriendlyFire.Reflect = 2
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
--! Debug Settings --! Debug Settings
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
@@ -54,18 +65,23 @@ end
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
--! Basic Settings --! Basic Settings
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
-- Game Mode (See sh_init.lua)
GM.Config.ConVars.GameType = CreateConVarIfNotExists("ph_gametype", GM.Types.Original, FCVAR_REPLICATED, "Prop Hunt: Which Game Type should be played? ("..GM.Types.Original.." = Original Prop Hunt, "..GM.Types.TheDeadHunt.." = The Dead Hunt Mode)")
function GM.Config:GameType()
return self.ConVars.GameType:GetInt()
end
-- Timelimit in minutes -- Timelimit in minutes
GM.Config.ConVars.TimeLimit = CreateConVarIfNotExists("mp_timelimit", "20", FCVAR_REPLICATED, "Map Time Limit (in Minutes)") GM.Config.ConVars.TimeLimit = CreateConVarIfNotExists("mp_timelimit", "20", FCVAR_REPLICATED, "Map Time Limit (in Minutes)")
function GM.Config:TimeLimit() function GM.Config:TimeLimit()
return self.ConVars.TimeLimit:GetFloat() return self.ConVars.TimeLimit:GetFloat()
end end
-- Friendly Fire
GM.Config.ConVars.FriendlyFire = CreateConVarIfNotExists(
"mp_friendlyfire",
GM.Options.FriendlyFire.Off,
FCVAR_REPLICATED,
"Enable Friendly Fire? (0 = Off, 1 = On, 2 = Reflect)"
)
function GM.Config:FriendlyFire()
return self.ConVars.FriendlyFire:GetInt()
end
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
--! Round Settings --! Round Settings
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
@@ -85,7 +101,7 @@ function GM.Config.Round:Time()
end end
-- For how many seconds are the Seekers blinded? (Seconds) -- For how many seconds are the Seekers blinded? (Seconds)
GM.Config.Round.ConVars.BlindTime = CreateConVarIfNotExists("ph_round_blindtime", "-30", FCVAR_REPLICATED, "Round Manager: Blind Time for Seekers (in Seconds, positive takes away from ph_round_timelimit, negative adds extra time to ph_round_timelimit") GM.Config.Round.ConVars.BlindTime = CreateConVarIfNotExists("ph_round_blindtime", "-30", FCVAR_REPLICATED, "Round Manager: Blind Time for Seekers (in Seconds, positive takes away from ph_round_timelimit, negative adds extra time to ph_round_timelimit)")
function GM.Config.Round:BlindTime() function GM.Config.Round:BlindTime()
return self.ConVars.BlindTime:GetFloat() return self.ConVars.BlindTime:GetFloat()
end end
@@ -97,7 +113,7 @@ GM.Config.Teams = {}
GM.Config.Teams.ConVars = {} GM.Config.Teams.ConVars = {}
-- Should teams be ranomized each round? -- Should teams be ranomized each round?
GM.Config.Teams.ConVars.Randomize = CreateConVarIfNotExists("ph_teams_randomize", "0", FCVAR_REPLICATED, "Teams: Randomize Each Round") GM.Config.Teams.ConVars.Randomize = CreateConVarIfNotExists("ph_teams_randomize", "0", FCVAR_REPLICATED, "Teams: Randomize Teams instead of swapping each round")
function GM.Config.Teams:Randomize() function GM.Config.Teams:Randomize()
return self.ConVars.Randomize:GetBool() return self.ConVars.Randomize:GetBool()
end end
@@ -115,7 +131,7 @@ end
-- The Dead Hunt: Percent of players to assign to seeker. -- The Dead Hunt: Percent of players to assign to seeker.
GM.Config.Teams.ConVars.SeekerPercentage = CreateConVarIfNotExists("ph_teams_seekerpct", "25", FCVAR_REPLICATED, "Teams: Initial percentage of Seekers in Dead Hunt Game Type") GM.Config.Teams.ConVars.SeekerPercentage = CreateConVarIfNotExists("ph_teams_seekerpct", "25", FCVAR_REPLICATED, "Teams: Initial percentage of Seekers in Dead Hunt Game Type")
function GM.Config.Teams:SeekerPercentage() function GM.Config.Teams:SeekerPercentage()
return self.ConVars.Teams:GetFloat() / 100 return self.ConVars.SeekerPercentage:GetFloat() / 100
end end
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
@@ -462,3 +478,79 @@ if CLIENT then
return self.ConVars.TintTeam:GetBool() return self.ConVars.TintTeam:GetBool()
end end
end end
-- ------------------------------------------------------------------------- --
--! Selection Halo
-- ------------------------------------------------------------------------- --
GM.Config.SelectionHalo = {}
GM.Config.SelectionHalo.ConVars = {}
-- Allow
GM.Config.SelectionHalo.ConVars.Allow = CreateConVarIfNotExists("ph_selectionhalo_allow", "1", FCVAR_REPLICATED, "Selection Halo: Allow clients to enable halo around the currently looked at prop?")
function GM.Config.SelectionHalo:Allow()
return self.ConVars.Allow:GetBool()
end
-- Approximate
GM.Config.SelectionHalo.ConVars.Approximate = CreateConVarIfNotExists("ph_selectionhalo_approximate", "1", FCVAR_REPLICATED, "Selection Halo: Enable approximate selection halo, which only checks the forward vector on the client.")
function GM.Config.SelectionHalo:Approximate()
return self.ConVars.Approximate:GetBool()
end
if SERVER then
-- Update Interval
GM.Config.SelectionHalo.ConVars.Interval = CreateConVarIfNotExists("ph_selectionhalo_interval", "0.05", FCVAR_ARCHIVE, "Selection Halo: Interval for updates of the accuracte selection halo in seconds.")
function GM.Config.SelectionHalo:Interval()
return self.ConVars.Interval:GetFloat()
end
end
if CLIENT then
-- Enabled
GM.Config.SelectionHalo.ConVars.Enabled = CreateConVarIfNotExists("ph_selectionhalo_enabled", "1", FCVAR_ARCHIVE, "Selection Halo: Enable halo around prop you might become.")
function GM.Config.SelectionHalo:Enabled()
if (self:Allow()) then
return self.ConVars.Enabled:GetBool()
else
return false
end
end
-- Settings
GM.Config.SelectionHalo.ConVars.Passes = CreateConVarIfNotExists("ph_selectionhalo_passes", "1", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Passes")
function GM.Config.SelectionHalo:Passes()
return self.ConVars.Passes:GetInt()
end
GM.Config.SelectionHalo.ConVars.Additive = CreateConVarIfNotExists("ph_selectionhalo_additive", "1", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Additive")
function GM.Config.SelectionHalo:Additive()
return self.ConVars.Additive:GetBool()
end
GM.Config.SelectionHalo.ConVars.IgnoreZ = CreateConVarIfNotExists("ph_selectionhalo_ignorez", "0", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Ignore Z")
function GM.Config.SelectionHalo:IgnoreZ()
return self.ConVars.IgnoreZ:GetBool()
end
-- Blur
GM.Config.SelectionHalo.ConVars.BlurX = CreateConVarIfNotExists("ph_selectionhalo_blur_x", "2", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Blur X")
function GM.Config.SelectionHalo:BlurX()
return self.ConVars.BlurX:GetFloat()
end
GM.Config.SelectionHalo.ConVars.BlurY = CreateConVarIfNotExists("ph_selectionhalo_blur_y", "2", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Blur Y")
function GM.Config.SelectionHalo:BlurY()
return self.ConVars.BlurY:GetFloat()
end
-- Tint Color
GM.Config.SelectionHalo.ConVars.TintHue = CreateConVarIfNotExists("ph_selectionhalo_tint_hue", "0", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Tint Hue")
function GM.Config.SelectionHalo:TintHue()
return self.ConVars.TintHue:GetFloat()
end
GM.Config.SelectionHalo.ConVars.TintSaturation = CreateConVarIfNotExists("ph_selectionhalo_tint_saturation", "0", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Tint Saturation")
function GM.Config.SelectionHalo:TintSaturation()
return self.ConVars.TintSaturation:GetFloat()
end
GM.Config.SelectionHalo.ConVars.TintValue = CreateConVarIfNotExists("ph_selectionhalo_tint_value", "1", FCVAR_ARCHIVE + FCVAR_CLIENTDLL, "Selection Halo: Tint Value")
function GM.Config.SelectionHalo:TintValue()
return self.ConVars.TintValue:GetFloat()
end
end
@@ -46,11 +46,6 @@ GM.States.Seek = 3
GM.States.PostRound = 4 GM.States.PostRound = 4
GM.States.PostMatch = 5 GM.States.PostMatch = 5
-- Game Modes
GM.Types = {}
GM.Types.Original = 0
GM.Types.TheDeadHunt = 1 -- One Hunter, Dead Prop become Hunter, Props can't see each other.
-- Teams -- Teams
GM.Teams = {} GM.Teams = {}
GM.Teams.Spectators = 0 GM.Teams.Spectators = 0
@@ -61,12 +56,13 @@ function GM:CreateTeams()
-- Specators -- Specators
team.SetUp(self.Teams.Spectators, "Spectators", Color(127, 127, 127, 255)) team.SetUp(self.Teams.Spectators, "Spectators", Color(127, 127, 127, 255))
team.SetSpawnPoint(self.Teams.Spectators, { team.SetSpawnPoint(self.Teams.Spectators, {
"info_player_start",
"info_player_spawn",
"info_player_deathmatch", "info_player_deathmatch",
"info_player_combine", "info_player_combine",
"info_player_counterterrorist", "info_player_counterterrorist",
"info_player_allies", "info_player_allies",
"info_player_terrorist", "info_player_terrorist"
"info_player_start"
}) })
team.SetClass(self.Teams.Spectators, { "Spectator", "Spectator" }) team.SetClass(self.Teams.Spectators, { "Spectator", "Spectator" })
@@ -104,6 +100,10 @@ function GM:PlayerTick(ply, mv)
return player_manager.RunClass(ply, "Tick", mv) return player_manager.RunClass(ply, "Tick", mv)
end end
function GM:FindUseEntity(ply, defaultEnt)
return player_manager.RunClass(ply, "FindUseEntity", defaultEnt)
end
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
--! Gamemode Functionality --! Gamemode Functionality
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
@@ -111,12 +111,16 @@ function GM:GetRound()
return GetGlobalInt("Round", 0) return GetGlobalInt("Round", 0)
end end
function GM:GetRoundTime()
return GetGlobalInt("RoundTime", 0)
end
function GM:GetRoundState() function GM:GetRoundState()
return GetGlobalInt("RoundState", self.States.PreMatch) return GetGlobalInt("RoundState", self.States.PreMatch)
end end
function GM:GetRoundTime() function GM:GetRoundStateTime()
return GetGlobalInt("RoundTime", 0) return GetGlobalInt("RoundStateTime", 0)
end end
function GM:GetRoundWinner() function GM:GetRoundWinner()
@@ -126,6 +130,13 @@ end
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
--! Includes --! Includes
-- ------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------- --
-- Defines
include "sh_defines.lua"
-- Meta
include "meta/player.lua"
-- Configuration
include "sh_config.lua" include "sh_config.lua"
-- Player Classes -- Player Classes
@@ -1,49 +0,0 @@
-- Finds the player meta table or terminates
local meta = FindMetaTable("Player")
if !meta then return end
-- Blinds the player by setting view out into the void
function meta:Blind(bool)
if !self:IsValid() then return end
if SERVER then
umsg.Start("SetBlind", self)
if bool then
umsg.Bool(true)
else
umsg.Bool(false)
end
umsg.End()
elseif CLIENT then
blind = bool
end
end
-- Blinds the player by setting view out into the void
function meta:RemoveProp()
if CLIENT || !self:IsValid() then return end
if self.ph_prop && self.ph_prop:IsValid() then
self.ph_prop:Remove()
self.ph_prop = nil
end
end
-- Sets a new Hull for a player.
function meta:NewHull(hullOBBMin, hullOBBMax)
if !self:IsValid() then return end
if hullOBBMax == nil then return end
if hullOBBMin == nil then return end
local hullOBB = hullOBBMax - hullOBBMin
local hullOBBXY = math.max(hullOBB.x, hullOBB.y)
local xyMul = 0.5
local hullMin = Vector(-hullOBBXY * xyMul, -hullOBBXY * xyMul, 0)
local hullMax = Vector( hullOBBXY * xyMul, hullOBBXY * xyMul, hullOBB.z)
self:SetHull(hullMin, hullMax)
self:SetHullDuck(hullMin, hullMax)
self:SetViewOffset(Vector(0, 0, hullOBB.z))
self:SetViewOffsetDucked(Vector(0, 0, hullOBB.z / 2.0))
end
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 920 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 134 KiB

@@ -8,236 +8,77 @@
"settings" "settings"
{ {
// Debug Settings
1
{
"name" "ph_debug"
"text" "Enable Debug Mode"
"type" "CheckBox"
"default" "0"
}
2
{
"name" "ph_debug_log"
"text" "Enable Debug Logging"
"type" "CheckBox"
"default" "1"
}
// Basic Settings // Basic Settings
11 100
{
"name" "ph_gametype"
"text" "Game Type to use"
"type" "Numeric"
"default" "0"
}
12
{ {
"name" "mp_timelimit" "name" "mp_timelimit"
"text" "Map Time Limit" "text" "Core: Time Limit for the entire Map"
"type" "Numeric" "type" "Numeric"
"default" "0" "default" "0"
"help" "Map Time Limit (in Minutes)"
} }
13 101
{ {
"name" "ph_sprinting" "name" "mp_friendlyfire"
"text" "Enable Sprinting" "text" "Core: Friendly fire"
"type" "CheckBox" "type" "Numeric"
"default" "0" "default" "0"
"help" "Allow friendly fire? (0 = No, 1 = Yes, 2 = Reflect)"
} }
// Round Settings // Round Settings
21 200
{ {
"name" "ph_round_limit" "name" "ph_round_limit"
"text" "Maximum Rounds Played" "text" "Rounds: Limit"
"type" "Numeric" "type" "Numeric"
"default" "10" "default" "10"
"help" "Round Manager: Maximum Rounds to Play on a single Map"
} }
201
22
{ {
"name" "ph_round_timelimit" "name" "ph_round_timelimit"
"text" "Time Limit per Round" "text" "Rounds: Time Limit per Round"
"type" "Numeric" "type" "Numeric"
"default" "180" "default" "180"
"help" "Round Manager: Time Limit per Round (in Seconds)"
} }
202
23
{ {
"name" "ph_round_blindtime" "name" "ph_round_blindtime"
"text" "Seeker Blind time per Round" "text" "Rounds: Blind Time per Round"
"type" "Numeric" "type" "Numeric"
"default" "-30" "default" "-30"
"help" "Round Manager: Blind Time for Seekers (in Seconds, positive takes away from ph_round_timelimit, negative adds extra time to ph_round_timelimit)"
} }
// Team Settings // Team Settings
31 300
{ {
"name" "ph_teams_randomize" "name" "ph_teams_randomize"
"text" "Randomize Teams" "text" "Teams: Randomize instead of Swap"
"type" "CheckBox"
"default" "1"
}
32
{
"name" "ph_teams_weighted"
"text" "Randomize with weighted Score"
"type" "CheckBox"
"default" "1"
}
33
{
"name" "ph_teams_seekerpct"
"text" "Pct of Pl. becoming Seeker"
"type" "Numeric"
"default" "25"
}
// Seeker Settings
41
{
"name" "ph_seeker_health"
"text" "Seeker Health"
"type" "Numeric"
"default" "100"
}
42
{
"name" "ph_seeker_health_max"
"text" "Seeker Max Health"
"type" "Numeric"
"default" "100"
}
43
{
"name" "ph_seeker_health_bonus"
"text" "Seeker Health Kill-Bonus"
"type" "Numeric"
"default" "20"
}
44
{
"name" "ph_seeker_health_penalty"
"text" "Seeker Health Penalty"
"type" "Numeric"
"default" "5"
}
45
{
"name" "ph_seeker_weapons"
"text" "Seeker Weapons"
"type" "Text"
"default" "weapon_crowbar,weapon_pistol,weapon_ph_smg,weapon_shotgun"
}
46
{
"name" "ph_seeker_ammo"
"text" "Seeker Ammo"
"type" "Text"
"default" "Pistol:100,SMG1:300,SMG1_Grenade:1,Buckshot:64"
}
// Hider Settings
51
{
"name" "ph_hider_health"
"text" "Hider Health"
"type" "Numeric"
"default" "100"
}
52
{
"name" "ph_hider_health_max"
"text" "Hider Max Health"
"type" "Numeric"
"default" "100"
}
53
{
"name" "ph_hider_health_scaling"
"text" "Hider Enable Health Scaling"
"type" "CheckBox"
"default" "1"
}
54
{
"name" "ph_hider_health_scaling_max"
"text" "Hider Scaled Max Health"
"type" "Numeric"
"default" "200"
}
55
{
"name" "ph_hider_allow_full_rotation"
"text" "Hider 3-Dimensional Rotation"
"type" "CheckBox" "type" "CheckBox"
"default" "0" "default" "0"
"help" "Teams: Randomize Teams instead of swapping each round"
} }
301
// Whitelist & Blacklist
61
{ {
"name" "ph_list_class_whitelist" "name" "ph_teams_weighted"
"text" "Allowed Entity Classes" "text" "Teams: Weighted Randomization"
"type" "Text" "type" "CheckBox"
"default" "ph_prop,prop_physics,prop_physics_multiplayer,prop_physics_respawnable" "default" "0"
} "help" "Teams: Use Weighted Randomization, which may seem more fair towards players."
62
{
"name" "ph_list_abuse_blacklist"
"text" "Abuse Blacklist"
"type" "Text"
"default" "func_button,func_door,func_door_rotation,prop_door_rotation,func_tracktrain,func_tanktrain,func_breakable"
}
63
{
"name" "ph_list_model_blacklist"
"text" "Model Blacklist"
"type" "Text"
"default" "models/props/cs_assault/dollar.mdl,models/props/cs_assault/money.mdl,models/props/cs_office/snowman_arm.mdl,models/props/cs_office/projector_remote.mdl"
} }
// Taunts // Taunts
71 700
{ {
"name" "ph_taunt_cooldown" "name" "ph_taunt_cooldown"
"text" "Cooldown for Taunts" "text" "Cooldown for Taunts"
"type" "Numeric" "type" "Numeric"
"default" "5" "default" "5"
} "help" "Prop Hunt: Cooldown between Taunts"
72
{
"name" "ph_taunt_seekers"
"text" "Seeker Taunts"
"type" "Text"
"default" "bot/a_bunch_of_them.wav,bot/come_out_and_fight_like_a_man.wav,bot/come_out_wherever_you_are.wav,bot/come_to_papa.wav,bot/dont_worry_hell_get_it.wav,bot/hang_on_i_heard_something.wav,bot/hang_on_im_coming.wav,bot/i_dont_think_so.wav,bot/i_have_the_hostages.wav,bot/i_see_our_target.wav,bot/im_waiting_here.wav,bot/keeping_an_eye_on_the_hostages.wav,bot/nnno_sir.wav,bot/spotted_the_delivery_boy.wav,bot/target_acquired.wav,bot/target_spotted.wav,bot/you_heard_the_man_lets_go.wav"
}
73
{
"name" "ph_taunt_hiders"
"text" "Hider Taunts"
"type" "Text"
"default" "ambient/alarms/apc_alarm_pass1.wav,ambient/alarms/manhack_alert_pass1.wav,ambient/alarms/razortrain_horn1.wav,ambient/alarms/scanner_alert_pass1.wav,ambient/alarms/train_horn2.wav,ambient/alarms/train_horn_distant1.wav,ambient/alarms/warningbell1.wav,ambient/energy/whiteflash.wav,ambient/intro/alyxremove.wav,ambient/intro/logosfx.wav,ambient/levels/launch/1stfiringwarning.wav,ambient/levels/launch/rockettakeoffblast.wav,ambient/misc/ambulance1.wav,ambient/misc/carhonk1.wav,ambient/misc/carhonk2.wav,ambient/misc/carhonk3.wav,ambient/outro/gunshipcrash.wav,ambient/3dmeagle.wav,beams/beamstart5.wav,buttons/bell1.wav,buttons/weapon_cant_buy.wav,common/bass.wav,common/bugreporter_failed.wav,common/warning.wav,doors/door_squeek1.wav,friends/friend_join.wav,friends/friend_online.wav,friends/message.wav,hostage/hunuse/comeback.wav,hostage/hunuse/dontleaveme.wav,hostage/hunuse/yeahillstay.wav,items/gift_drop.wav,music/radio1.mp3,phx/eggcrack.wav,plats/elevbell1.wav,player/headshot1.wav,player/headshot2.wav,player/sprayer.wav,radio/enemydown.wav,radio/go.wav,radio/locknload.wav,radio/negative.wav,radio/rounddraw.wav,radio/takepoint.wav,resource/warning.wav,ui/achievement_earned.wav,ui/freeze_cam.wav,vehicles/junker/radar_ping_friendly1.wav,weapons/c4/c4_beep1.wav,weapons/c4/c4_click.wav,weapons/awp/awp1.wav,vo/canals/female01/gunboat_giveemhell.wav,vo/canals/female01/gunboat_justintime.wav,vo/canals/female01/stn6_incoming.wav,vo/canals/male01/gunboat_giveemhell.wav,vo/canals/male01/gunboat_justintime.wav,vo/canals/male01/stn6_incoming.wav,vo/canals/al_radio_stn6.wav,vo/canals/arrest_getgoing.wav,vo/canals/arrest_helpme.wav,vo/canals/arrest_lookingforyou.wav,vo/canals/boxcar_lethimhelp.wav,vo/canals/matt_closecall.wav,vo/canals/premassacre.wav,vo/ravenholm/aimforhead.wav,vo/ravenholm/bucket_patience.wav,vo/ravenholm/madlaugh01.wav,vo/ravenholm/madlaugh02.wav,vo/ravenholm/madlaugh03.wav,vo/ravenholm/madlaugh04.wav,weapons/strider_buster/ol12_stickybombcreator.wav,weapons/c4/c4_explode1.wav,weapons/357/357_fire2.wav,weapons/357/357_fire3.wav,weapons/scout/scout_fire-1.wav,weapons/smokegrenade/sg_explode.wav,weapons/grenade_launcher1.wav,weapons/explode3.wav,weapons/underwater_explode3.wav,items/nvg_on.wav,hostage/huse/letsdoit.wav,hostage/huse/illfollow.wav,hostage/huse/getouttahere.wav,doors/door_screen_move1.wav,doors/heavy_metal_stop1.wav,doors/default_move.wav,common/stuck2.wav,ambient/water_splash1.wav,ambient/water_splash2.wav,ambient/water_splash3.wav,ambient/weather/thunder1.wav,ambient/weather/thunder2.wav,ambient/weather/thunder3.wav,ambient/weather/thunder4.wav,ambient/weather/thunder5.wav,ambient/weather/thunder6.wav,ambient/outro/thunder7.wav,ambient/voices/crying_loop1.wav,ambient/voices/playground_memory.wav,ambient/voices/f_scream1.wav,ambient/voices/m_scream1.wav,ambient/voices/cough1.wav,ambient/voices/cough2.wav,ambient/voices/cough3.wav,ambient/voices/cough4.wav,ambient/overhead/plane1.wav,ambient/overhead/plane2.wav,ambient/overhead/plane3.wav,ambient/overhead/hel1.wav,ambient/overhead/hel2.wav,ambient/misc/truck_backup1.wav,ambient/misc/truck_drive1.wav,ambient/misc/truck_drive2.wav,ambient/machines/pneumatic_drill_1.wav,ambient/machines/pneumatic_drill_2.wav,ambient/machines/pneumatic_drill_3.wav,ambient/machines/pneumatic_drill_4.wav,ambient/machines/station_train_squeel.wav,ambient/machines/ticktock.wav,ambient/creatures/teddy.wav,ambient/creatures/town_child_scream1.wav,ambient/creatures/town_moan1.wav,ambient/creatures/town_muffled_cry1.wav,ambient/creatures/town_scared_breathing1.wav,ambient/creatures/town_scared_breathing2.wav,ambient/creatures/town_scared_sob1.wav,ambient/creatures/town_scared_sob2.wav,ambient/creatures/town_zombie_call1.wav"
} }
} }
} }
+17
View File
@@ -0,0 +1,17 @@
@ECHO OFF
ECHO This script must be run as administrator, or will fail with unknown results.
ECHO I've been run from "%CD%", and am in "%~dp0", switching directory to set up environment.
PUSHD "%~dp0"
CALL "%~dp0\env.win.bat"
SET "PATH_GMOD=%GARRYSMODPATH%"
SET "PATH_REPO=%ROOT%\.."
PUSHD "%PATH_GMOD%\garrysmod\addons"
MKLINK /J prophuntextended "%PATH_REPO%\source"
MKLINK /J prophunt "%PATH_REPO%\proxy"
POPD
POPD
PAUSE
+4 -1
View File
@@ -1,7 +1,10 @@
@ECHO OFF @ECHO OFF
:: Root and repo
SET "ROOT=%~dp0"
:: Garry's Mod :: Garry's Mod
SET "GARRYSMODPATH=C:\Program Files (x86)\Steam\steamapps\common\GarrysMod" SET "GARRYSMODPATH="
FOR /F "tokens=2* delims= " %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 4000" /v InstallLocation') DO SET "GARRYSMODPATH=%%B" FOR /F "tokens=2* delims= " %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 4000" /v InstallLocation') DO SET "GARRYSMODPATH=%%B"
IF "%GARRYSMODPATH%" == "" ( IF "%GARRYSMODPATH%" == "" (
FOR /F "tokens=2* delims= " %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 4000" /v InstallLocation') DO SET "GARRYSMODPATH=%%B" FOR /F "tokens=2* delims= " %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 4000" /v InstallLocation') DO SET "GARRYSMODPATH=%%B"
+10
View File
@@ -0,0 +1,10 @@
@ECHO OFF
CALL "env.win.bat"
SET "GMANAME=%TMP%\prophuntextended-%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%.gma"
PUSHD "%REPO%"
"%GARRYSMODPATH%\bin\gmad.exe" create -folder "%REPO%source" -out "%GMANAME%"
"%GARRYSMODPATH%\bin\gmpublish.exe" update -id 468149739 -icon "media\workshop-gamemode.jpg" -addon "%GMANAME%" -changes "To be added (see Github in the mean time)"
POPD
PAUSE
+10
View File
@@ -0,0 +1,10 @@
@ECHO OFF
CALL "env.win.bat"
SET "GMANAME=%TMP%\prophuntproxy-%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%.gma"
PUSHD "%REPO%"
"%GARRYSMODPATH%\bin\gmad.exe" create -folder "%REPO%source" -out "%GMANAME%"
"%GARRYSMODPATH%\bin\gmpublish.exe" update -id 1327985306 -icon "media\workshop-gamemode.jpg" -addon "%GMANAME%" -changes "To be added (see Github in the mean time)"
POPD
PAUSE
View File
+8
View File
@@ -0,0 +1,8 @@
{
"folders": [
{
"path": "."
}
],
"settings": {}
}