Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f035b865e5 | ||
|
|
9f77e10934 | ||
|
|
75596ad87e | ||
|
|
f57c7760f7 | ||
|
|
8ed6c4eb2b | ||
|
|
c1660a0e48 | ||
|
|
efb7a1117b | ||
|
|
91f34169b5 | ||
|
|
272482c5e7 | ||
|
|
12f8eea011 | ||
|
|
1d2a284197 | ||
|
|
fbe70a5691 | ||
|
|
b87538ff59 | ||
|
|
fa39abd61c | ||
|
|
95461427b2 | ||
|
|
c782c2aaf5 | ||
|
|
efd801bdea | ||
|
|
92d14a6fd3 | ||
|
|
ba9414ea6e | ||
|
|
f751720e59 | ||
|
|
0ac8fc00d5 | ||
|
|
5da691b5fe | ||
|
|
ec45c6f23b | ||
|
|
d00fec91b8 | ||
|
|
e1e2a48f89 | ||
|
|
1d8a6768aa | ||
|
|
2cf22ab66b | ||
|
|
bfa59a2419 | ||
|
|
66be4861a3 | ||
|
|
fb92c2369f | ||
|
|
62c17b14e4 | ||
|
|
28c18952f8 | ||
|
|
18268776ae | ||
|
|
acc22bc9ef | ||
|
|
79d4b3b21d | ||
|
|
074635bf8d | ||
|
|
a3086aaaa4 | ||
|
|
c813f6e76a | ||
|
|
b757c65345 | ||
|
|
ecf3bd9a3d | ||
|
|
bc7633bf9c | ||
|
|
3b1c99d2cc | ||
|
|
5478860f27 | ||
|
|
76d4c3b4bd | ||
|
|
9849c5296b | ||
|
|
b364915799 | ||
|
|
bd9fe1f487 | ||
|
|
73f240ddb1 | ||
|
|
750b916666 | ||
|
|
bd02a95260 | ||
|
|
62063e34da | ||
|
|
55dfee7d74 | ||
|
|
2140e3413d | ||
|
|
e1bd51b220 | ||
|
|
4b087efde8 | ||
|
|
08846e8dee | ||
|
|
7075efe7d9 | ||
|
|
b265a65fe1 | ||
|
|
4c7579c3e2 | ||
|
|
035e70e776 | ||
|
|
d4ecb16bf7 | ||
|
|
513cde6231 | ||
|
|
e33eaf4d1e | ||
|
|
e29e79052d | ||
|
|
8d28e23e16 | ||
|
|
0622ccc638 | ||
|
|
6e1081d793 | ||
|
|
5830ac7908 | ||
|
|
2f80da1e15 | ||
|
|
c32827b4cb | ||
|
|
5f7abc2df0 | ||
|
|
875d6610ae | ||
|
|
94fc64226c | ||
|
|
19b7c69b14 | ||
|
|
0fd2d27b6f | ||
|
|
87210e5f6c | ||
|
|
9df28b9d3f | ||
|
|
9602f862c9 | ||
|
|
5b0ced8e7d | ||
|
|
63779c0471 | ||
|
|
433bb24dcd | ||
|
|
ba25f7710c | ||
|
|
bf607621b3 | ||
|
|
769ec8852f | ||
|
|
7fcf39b6d3 | ||
|
|
2762dbc0b2 |
76
README.md
76
README.md
@@ -21,27 +21,59 @@ A small light is seen at the distance...
|
|||||||
|
|
||||||
## What is this?
|
## What is this?
|
||||||
|
|
||||||
MonsterMod is a MetaMod plugin. It's purpose was to allow support for monsters to spawn in multiplayer games where they are not. The project updates became incredibly obscure, getting up-to-date versions and the new additions was very difficult. And the only one who had even futher progress kept the plugin private.
|
MonsterMod is a MetaMod plugin. Its purpose was to allow multiplayer games to add monsters, where it wasn't possible to do so by normal means. The updates of the project became incredibly obscure: Getting the "up-to-date" versions containing the new additions (opposing force monsters, for example) were very difficult. And the only one who managed to bring the plugin even futher kept the progress of the plugin private.
|
||||||
|
|
||||||
Nearly 18 years after botman's original plugin was released, the future of the project became nothing but a forgotten, ancient relic of the past.
|
After 21 years since botman's original plugin was released, the future of the project became nothing but a forgotten, ancient relic of the past.
|
||||||
|
|
||||||
Not anymore...
|
Not anymore...
|
||||||
|
|
||||||
This project aims towards the recreation of the new features of the "obscured and updated" Monster Mod plugin. Taking botman's original 2002 plugin and working up from the ground, and to rebuild it with the new features and monsters that only few were able to see.
|
The first goal of this project aims towards the recreation of the new features of the "obscured and updated" Monster Mod plugin. Taking botman's original 2002 plugin and working from the ground up, the mission is to rebuild it with the new features and monsters that only few were able to see.
|
||||||
|
|
||||||
The source code is completely free to use for everyone: In the event that the development of this new project falls and becomes stagnant again, the plugin will live on, as the project's second goal is it's preservation. The original botman's page where you can download the 2002 plugin will not stay up forever.
|
The source code is completely free for everyone to use: In the event that the development of this project falls and becomes stagnant again, the plugin will live on, as the project's second goal is its preservation. ~~The original botman's page where you can download the 2002 plugin will not stay up forever.~~ **April 2023 update**: The page is gone, the original 2002 plugin can no longer be found.
|
||||||
|
|
||||||
Under no circumstances we shall allow this project to fade away and become lost amidst the gears of time.
|
Under no circumstances shall we allow this project to fade away and become lost amidst the gears of time.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
The plugin -should- be able to be used out-of-the-box by simply downloading the binary and adding the appropiate entry in metamod's plugin list.
|
||||||
|
|
||||||
|
**Windows:**
|
||||||
|
`win32 addons\monstermod\monster_mm.dll`
|
||||||
|
|
||||||
|
**Linux:**
|
||||||
|
`linux addons/monstermod/monster_mm_i386.so`
|
||||||
|
|
||||||
|
To start adding monsters onto your maps, additional configuration files are included in the release files, each explaining its usage and installation instructions. Nevertheless, if you are felling lost, the [wiki](https://github.com/JulianR0/monstermod-redo/wiki) contains usage instructions, and how to configure MonsterMod to your liking.
|
||||||
|
|
||||||
|
Extra MonsterMod features can be unlocked with additional AMX Mod X plugins which are located in the `extra` folder. All these plugins are optional, and only required based on your use-case.
|
||||||
|
|
||||||
|
## Build Instructions
|
||||||
|
|
||||||
|
The [Building](https://github.com/JulianR0/monstermod-redo/wiki) section of the wiki contains instructions on how to compile MonsterMod by yourself.
|
||||||
|
|
||||||
|
## MonsterMod and ReHLDS
|
||||||
|
|
||||||
|
Usage of ReHLDS is highly recommended, as you can use the command `rescount` which will reveal the current number of precached models and sounds. You can also use `reslist model` and `reslist sound` to see the entire list of precached content.
|
||||||
|
|
||||||
|
Keeping track of the number of precached content will allow you to maximize the number of monsters you can use without risking going over the limits.
|
||||||
|
|
||||||
|
## Known Bugs and Issues
|
||||||
|
|
||||||
|
I'm aware that the plugin is far from perfect, and there are a few things that need polishing *-especially the AI-*. I'll try to fix/will be fixing as the project evolves:
|
||||||
|
|
||||||
|
- Rarely, Stukabats will become unable to fly towards their target, standing in air doing seemingly nothing.
|
||||||
|
|
||||||
|
- Monsters are very prone to gibbing.
|
||||||
|
|
||||||
|
- Houndeyes and Hornets (Alien Grunts) do not get along. The server will crash if a houndeye damages a hornet.
|
||||||
|
|
||||||
|
There are probably more issues that aren't listed here, I'll attempt to fix them as I find them. Of course, any bug report is welcome. If reporting a bug, try to explain step by step how the bug ocurred. The easier it is to replicate a bug, the easier it is to locate it and fix it.
|
||||||
|
|
||||||
## Milestones
|
## Milestones
|
||||||
|
|
||||||
Attempting to recreate everything in one go is a daunting task.
|
Attempting to recreate everything in one go is a daunting task.
|
||||||
Let it be known that the original 2002 source code will NOT compile on today's compilers, and does NOT contain all the necessary files for compilation. The preliminary was to rewrite and provide as many files or lines of code to ensure it can compile again, and be usable on an actual HLDS installation.
|
Let it be known that the original 2002 source code will NOT compile on today's compilers, and does NOT contain all the necessary files for compilation. The preliminary was to rewrite and provide as many files or lines of code to ensure it can compile again, and be usable on an actual HLDS installation.
|
||||||
|
|
||||||
Currently, I aim working this for linux only. While the original 2002 Visual C++ DSP file exists in the repository, it has not been updated to newer formats. Who knows if it can even open on newer Visual Studio versions, let alone, to compile?
|
|
||||||
|
|
||||||
Even so, in linux, I had to resort to compile under GCC 4.8 for the plugin to work. While I could use a newer compiler (GCC 9 at the time of this writing), whenever or not the plugin will run is dependant on the HLDS installation and the system libraries is it hosted with. If you compile with newer GCC compilers, be warned that it may refuse to load, as it will complain about libstdc++ not having CXXABI_1.X.X or similar.
|
|
||||||
|
|
||||||
Current milestones are separated by "Tiers", which are as follows:
|
Current milestones are separated by "Tiers", which are as follows:
|
||||||
|
|
||||||
### Tier 0
|
### Tier 0
|
||||||
@@ -63,19 +95,31 @@ Current milestones are separated by "Tiers", which are as follows:
|
|||||||
|
|
||||||
### Tier 3
|
### Tier 3
|
||||||
|
|
||||||
- Implement *-almost-* all Opposing Force monsters.
|
- Update source code so it can compile AND run **ON WINDOWS**. **[DONE]**
|
||||||
- Implement *-almost-* all default Sven Co-op monsters.
|
- Implement *-almost-* all Opposing Force monsters. **[DONE]**
|
||||||
- Add configurations to change AI behaviour.
|
- Implement *-almost-* all default Sven Co-op monsters. **[DONE]**
|
||||||
|
- Make MonsterMod aware of normal game entities. *-For those wanting to use this in vanilla HL.-* **[DONE]**
|
||||||
|
- Custom model support. **[DONE]**
|
||||||
|
|
||||||
### Tier 4
|
### Tier 4
|
||||||
|
|
||||||
- Custom model support, along with scaling.
|
- Implement reading entities within the BSP itself. **[DONE]**
|
||||||
- Custom sound support.
|
- Add build instructions. **[DONE]**
|
||||||
- Implement extra entities to enhance map gameplay.
|
- Global Model Replacement. **[DONE]**
|
||||||
|
- Global Sound Replacement. **[DONE]**
|
||||||
|
- Miscellaneous customization options, such as blood color. **[DONE]**
|
||||||
|
- Individual sound replacement: "soundlist" keyvalue for monsters. **[DONE]**
|
||||||
|
- Sentences support for speakable monsters. **[DONE]**
|
||||||
|
- Attempt to fix bugs as they appear. **[DONE]**
|
||||||
|
|
||||||
### Tier 5
|
### Tier 5
|
||||||
|
|
||||||
- Update source code so it can compile AND run **ON WINDOWS**.
|
- Enhance the AI.
|
||||||
|
- Add configurations to change AI behaviour.
|
||||||
|
- Create "tool" entities for easier map customization.
|
||||||
|
- Optimize and clean the code.
|
||||||
|
- Add a wiki with full documentation.
|
||||||
|
- Fix **ALL** bugs, specially those not covered in Tier 4.
|
||||||
|
|
||||||
|
|
||||||
What will the future hold after all Tiers has been completed?
|
What will the future hold after all Tiers has been completed?
|
||||||
|
|||||||
@@ -2,33 +2,13 @@
|
|||||||
// Make a copy of this file and rename it to "<mapname>_monster.cfg".
|
// Make a copy of this file and rename it to "<mapname>_monster.cfg".
|
||||||
// Send this new file to your maps folder.
|
// Send this new file to your maps folder.
|
||||||
//
|
//
|
||||||
// To add entries to this file, just pretend it's ripent.
|
// Adding entities to this file is done in the same way as ripenting a map.
|
||||||
//
|
//
|
||||||
// "delay" means monster respawndelay.
|
// For more detailed instructions, check the wiki at
|
||||||
//
|
// https://github.com/JulianR0/monstermod-redo/wiki
|
||||||
// You may also be interesed in these other 2 keyvalues:
|
|
||||||
//
|
|
||||||
// "displayname" to change the monster's name, shown in HUD when you point at it.
|
|
||||||
// "classify" to change the monster's default classification, use one of these values:
|
|
||||||
//
|
|
||||||
// CLASS_NONE 0
|
|
||||||
// CLASS_MACHINE 1
|
|
||||||
// CLASS_PLAYER 2
|
|
||||||
// CLASS_HUMAN_PASSIVE 3
|
|
||||||
// CLASS_HUMAN_MILITARY 4
|
|
||||||
// CLASS_ALIEN_MILITARY 5
|
|
||||||
// CLASS_ALIEN_PASSIVE 6
|
|
||||||
// CLASS_ALIEN_MONSTER 7
|
|
||||||
// CLASS_ALIEN_PREY 8
|
|
||||||
// CLASS_ALIEN_PREDATOR 9
|
|
||||||
// CLASS_INSECT 10
|
|
||||||
// CLASS_PLAYER_ALLY 11
|
|
||||||
// CLASS_PLAYER_BIOWEAPON 12
|
|
||||||
// CLASS_ALIEN_BIOWEAPON 13
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"origin" "90 -180 150"
|
"origin" "90 -180 150"
|
||||||
"delay" "30"
|
|
||||||
"displayname" "Example Custom Name"
|
"displayname" "Example Custom Name"
|
||||||
"orientation" "1"
|
"orientation" "1"
|
||||||
"spawnflags" "32"
|
"spawnflags" "32"
|
||||||
@@ -36,7 +16,6 @@
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
"origin" "123 456 789"
|
"origin" "123 456 789"
|
||||||
"delay" "5"
|
|
||||||
"classify" "7"
|
"classify" "7"
|
||||||
"angles" "0 45 0"
|
"angles" "0 45 0"
|
||||||
"classname" "monster_houndeye"
|
"classname" "monster_houndeye"
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
|
// This file constains the monsters that you always want to precache for dynamic spawning.
|
||||||
//
|
//
|
||||||
// MONSTERS - monsters that you always want to precache (for dynamic spawning)
|
// Dynamic spawning means - Monsters that you want to invoke at any time, on any map.
|
||||||
//
|
//
|
||||||
// Install this file to your mod's base directory.
|
// Install this file to your mod's base directory.
|
||||||
|
// Then, remove the comment characters at the beginning of the line for the
|
||||||
|
// monsters that you always want to precache.
|
||||||
//
|
//
|
||||||
// (just remove the comment characters at the beginning of the line for the
|
// Be wary if you precache too many monsters, it may easily crash your
|
||||||
// monsters that you always want to precache.)
|
// server due to the age-old 512 limit.
|
||||||
|
|
||||||
//monster_alien_grunt
|
//monster_alien_grunt
|
||||||
//monster_apache
|
//monster_apache
|
||||||
//monster_barney
|
//monster_barney
|
||||||
//monster_bigmomma
|
//monster_bigmomma
|
||||||
//monster_bullsquid
|
//monster_bullchicken
|
||||||
//monster_gargantua
|
//monster_gargantua
|
||||||
//monster_human_assassin
|
//monster_human_assassin
|
||||||
//monster_headcrab
|
//monster_headcrab
|
||||||
@@ -24,3 +27,14 @@
|
|||||||
//monster_turret
|
//monster_turret
|
||||||
//monster_miniturret
|
//monster_miniturret
|
||||||
//monster_sentry
|
//monster_sentry
|
||||||
|
//monster_gonome
|
||||||
|
//monster_male_assassin
|
||||||
|
//monster_otis
|
||||||
|
//monster_pitdrone
|
||||||
|
//monster_shocktrooper
|
||||||
|
//monster_alien_voltigore
|
||||||
|
//monster_alien_babyvoltigore
|
||||||
|
//monster_babygarg
|
||||||
|
//monster_hwgrunt
|
||||||
|
//monster_robogrunt
|
||||||
|
//monster_stukabat
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
//
|
//
|
||||||
// Install this file to your mod's base directory.
|
// Install this file to your mod's base directory.
|
||||||
|
|
||||||
|
|
||||||
|
// ORIGINAL HALF-LIFE MONSTERS
|
||||||
|
|
||||||
// Alien Grunt
|
// Alien Grunt
|
||||||
sk_agrunt_health 90
|
sk_agrunt_health 90
|
||||||
sk_agrunt_dmg_punch 20
|
sk_agrunt_dmg_punch 20
|
||||||
@@ -13,7 +16,7 @@ sk_apache_health 250
|
|||||||
// Barney
|
// Barney
|
||||||
sk_barney_health 35
|
sk_barney_health 35
|
||||||
|
|
||||||
// Big Momma
|
// Big Momma (HP = 150 * health_factor)
|
||||||
sk_bigmomma_health_factor 1.5
|
sk_bigmomma_health_factor 1.5
|
||||||
sk_bigmomma_dmg_slash 60
|
sk_bigmomma_dmg_slash 60
|
||||||
sk_bigmomma_dmg_blast 120
|
sk_bigmomma_dmg_blast 120
|
||||||
@@ -55,10 +58,6 @@ sk_islave_dmg_claw 10
|
|||||||
sk_islave_dmg_clawrake 25
|
sk_islave_dmg_clawrake 25
|
||||||
sk_islave_dmg_zap 10
|
sk_islave_dmg_zap 10
|
||||||
|
|
||||||
// Icthyosaur
|
|
||||||
sk_ichthyosaur_health 200
|
|
||||||
sk_ichthyosaur_shake 35
|
|
||||||
|
|
||||||
// Controller
|
// Controller
|
||||||
sk_controller_health 60
|
sk_controller_health 60
|
||||||
sk_controller_dmgzap 25
|
sk_controller_dmgzap 25
|
||||||
@@ -88,8 +87,75 @@ sk_miniturret_health 40
|
|||||||
// Sentry Turret
|
// Sentry Turret
|
||||||
sk_sentry_health 40
|
sk_sentry_health 40
|
||||||
|
|
||||||
|
|
||||||
|
// OPPOSING FORCE MONSTERS
|
||||||
|
|
||||||
|
// Gonome
|
||||||
|
sk_gonome_health 85
|
||||||
|
sk_gonome_dmg_one_slash 20
|
||||||
|
sk_gonome_dmg_guts 10
|
||||||
|
sk_gonome_dmg_one_bite 14
|
||||||
|
|
||||||
|
// Male Assassin
|
||||||
|
sk_massassin_health 50
|
||||||
|
sk_massassin_kick 25
|
||||||
|
|
||||||
|
// Otis
|
||||||
|
sk_otis_health 35
|
||||||
|
|
||||||
|
// Pit Drone
|
||||||
|
sk_pitdrone_health 40
|
||||||
|
sk_pitdrone_dmg_bite 25
|
||||||
|
sk_pitdrone_dmg_whip 35
|
||||||
|
sk_pitdrone_dmg_spit 10
|
||||||
|
|
||||||
|
// Shock Roach
|
||||||
|
sk_shockroach_health 10
|
||||||
|
sk_shockroach_lifespan 10
|
||||||
|
|
||||||
|
// ShockTrooper
|
||||||
|
sk_shocktrooper_health 50
|
||||||
|
sk_shocktrooper_kick 10
|
||||||
|
sk_shocktrooper_maxcharge 8
|
||||||
|
sk_shocktrooper_rchgspeed 1
|
||||||
|
sk_shock_dmg 15
|
||||||
|
sk_spore_dmg 50
|
||||||
|
|
||||||
|
// Voltigore
|
||||||
|
sk_voltigore_health 320
|
||||||
|
sk_voltigore_dmg_beam 50
|
||||||
|
sk_voltigore_dmg_punch 40
|
||||||
|
|
||||||
|
// Baby Voltigore
|
||||||
|
sk_babyvoltigore_health 60
|
||||||
|
sk_babyvoltigore_dmg_punch 15
|
||||||
|
|
||||||
|
|
||||||
|
// SVEN CO-OP MONSTERS
|
||||||
|
|
||||||
|
// Baby Gargantua
|
||||||
|
sk_babygarg_health 640
|
||||||
|
sk_babygarg_dmg_slash 24
|
||||||
|
sk_babygarg_dmg_fire 4
|
||||||
|
sk_babygarg_dmg_stomp 80
|
||||||
|
|
||||||
|
// Heavy Weapons Grunt
|
||||||
|
sk_hwgrunt_health 100
|
||||||
|
|
||||||
|
// Robo Grunt
|
||||||
|
sk_rgrunt_health 50
|
||||||
|
sk_rgrunt_armor 0.75
|
||||||
|
|
||||||
|
// Stukabat
|
||||||
|
sk_stukabat_health 80
|
||||||
|
sk_stukabat_dmg_bite 11
|
||||||
|
sk_stukabat_speed 400
|
||||||
|
|
||||||
|
|
||||||
// MONSTER WEAPON DAMAGE
|
// MONSTER WEAPON DAMAGE
|
||||||
sk_9mm_bullet 5
|
sk_9mm_bullet 5
|
||||||
sk_9mmAR_bullet 4
|
sk_9mmAR_bullet 4
|
||||||
sk_9mmAR_grenade 100
|
sk_9mmAR_grenade 100
|
||||||
sk_12mm_bullet 10
|
sk_12mm_bullet 10
|
||||||
|
sk_762_bullet 100
|
||||||
|
sk_357_bullet 40
|
||||||
|
|||||||
9
extra/README.md
Normal file
9
extra/README.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
## Auxiliary Tools
|
||||||
|
|
||||||
|
This folder contains auxiliary tools used to enhance the compatibility and/or interaction of MonsterMod with other mods.
|
||||||
|
|
||||||
|
As these are auxiliary, they aren't needed to enjoy MonsterMod. If you want an extra boost, feel free to install these.
|
||||||
|
|
||||||
|
Plugins from the `base` folder should come first, then the ones from the appropiate mod folder.
|
||||||
|
|
||||||
|
Once all milestones are completed, the possibility of removing the need for external plugins will be considered. Until then, this has to stay.
|
||||||
29
extra/base/README.md
Normal file
29
extra/base/README.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
## Base Plugins (All Mods)
|
||||||
|
|
||||||
|
Auxiliary Tools to use MonsterMod in any GoldSrc game.
|
||||||
|
|
||||||
|
These are base plugins that should be installed first before adding any mod-specific plugin.
|
||||||
|
|
||||||
|
### AMX Mod X Plugins
|
||||||
|
|
||||||
|
#### -A note about AMXX plugins-
|
||||||
|
|
||||||
|
All plugins in this section require AMXX 1.9.0 or greater, they will not work on 1.8.2 or older.
|
||||||
|
|
||||||
|
Compiled plugins are provided in the `bin` folder for your convenience. However, if you prefer to build the plugins yourself, the source code of all AMXX plugins are located in the `src` folder for compilation.
|
||||||
|
|
||||||
|
#### Use Dispatcher
|
||||||
|
|
||||||
|
Because MonsterMod entities are, -quite literally-, just a func_wall with its own logic, trying to trigger any MonsterMod entity from the outside will fail, as it will attempt to use the logic of game's "func_wall" instead of our own.
|
||||||
|
|
||||||
|
In normal circunstances, you do not need this plugin. But let's say you have a turret monster, disabled by default, and you gave it a targetname. Even with a name, triggering this turret regardless of the method used will not activate it.
|
||||||
|
|
||||||
|
The same problem occurs from the other side, a MonsterMod entity trying to trigger something will expect said entity to be part of MonsterMod as well.
|
||||||
|
|
||||||
|
This plugin redirects the game's func_wall Use() function to MonsterMod, as well as bridging Use() calls from MonsterMod back to the game, connecting the missing pieces and allowing you to trigger MonsterMod entities from the game, and game entities from MonsterMod.
|
||||||
|
|
||||||
|
#### External TakeDamage
|
||||||
|
|
||||||
|
When a MonsterMod entity tries to inflict damage to something, it expects said entity to be either a player or a MonsterMod monster. If something else is to be found, it will deal no damage to it, as it doesn't know how to manage it.
|
||||||
|
|
||||||
|
This plugin allows MonsterMod entities to inflict damage to normal game entities, such as breakables.
|
||||||
BIN
extra/base/bin/glb_dispatchuse.amxx
Normal file
BIN
extra/base/bin/glb_dispatchuse.amxx
Normal file
Binary file not shown.
BIN
extra/base/bin/glb_takedamage.amxx
Normal file
BIN
extra/base/bin/glb_takedamage.amxx
Normal file
Binary file not shown.
57
extra/base/src/glb_dispatchuse.sma
Normal file
57
extra/base/src/glb_dispatchuse.sma
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#pragma semicolon 1
|
||||||
|
|
||||||
|
#include <amxmodx>
|
||||||
|
#include <engine>
|
||||||
|
#include <hamsandwich>
|
||||||
|
|
||||||
|
public plugin_init()
|
||||||
|
{
|
||||||
|
register_plugin( "GAME-MONSTER: Use Dispatcher", "1.1", "Giegue" );
|
||||||
|
|
||||||
|
register_cvar( "_glb_use", "1" );
|
||||||
|
|
||||||
|
// Game --> MonsterMod
|
||||||
|
RegisterHam( Ham_Use, "func_wall", "DispatchUse" );
|
||||||
|
|
||||||
|
// MonsterMod --> Game
|
||||||
|
register_srvcmd( "_trigger", "FireTargets" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public DispatchUse( entity, caller, activator, useType, Float:value )
|
||||||
|
{
|
||||||
|
// all monstermod entities have this set
|
||||||
|
if ( entity_get_edict( entity, EV_ENT_euser4 ) )
|
||||||
|
{
|
||||||
|
server_cmd( "_use %i %i %i %i %f", entity, caller, activator, useType, value );
|
||||||
|
return HAM_SUPERCEDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HAM_IGNORED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FireTargets()
|
||||||
|
{
|
||||||
|
if ( read_argc() == 6 )
|
||||||
|
{
|
||||||
|
new entity, caller, activator;
|
||||||
|
new Float:value;
|
||||||
|
new useType;
|
||||||
|
|
||||||
|
entity = read_argv_int( 1 );
|
||||||
|
caller = read_argv_int( 2 );
|
||||||
|
activator = read_argv_int( 3 );
|
||||||
|
value = read_argv_float( 4 );
|
||||||
|
useType = read_argv_int( 5 );
|
||||||
|
|
||||||
|
// caller and activator can be null, but never allow entity to be null
|
||||||
|
if ( !is_valid_ent( entity ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( !is_valid_ent( caller ) )
|
||||||
|
caller = 0;
|
||||||
|
if ( !is_valid_ent( activator ) )
|
||||||
|
activator = 0;
|
||||||
|
|
||||||
|
ExecuteHamB( Ham_Use, entity, caller, activator, useType, value );
|
||||||
|
}
|
||||||
|
}
|
||||||
42
extra/base/src/glb_takedamage.sma
Normal file
42
extra/base/src/glb_takedamage.sma
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma semicolon 1
|
||||||
|
|
||||||
|
#include <amxmodx>
|
||||||
|
#include <engine>
|
||||||
|
#include <hamsandwich>
|
||||||
|
|
||||||
|
public plugin_init()
|
||||||
|
{
|
||||||
|
register_plugin( "GAME-MONSTER: External TakeDamage", "1.0", "Giegue" );
|
||||||
|
|
||||||
|
register_cvar( "_glb_takedamage", "1" );
|
||||||
|
|
||||||
|
// MonsterMod --> Game
|
||||||
|
register_srvcmd( "_takedamage", "TakeDamage" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public TakeDamage()
|
||||||
|
{
|
||||||
|
if ( read_argc() == 6 )
|
||||||
|
{
|
||||||
|
new victim, inflictor, attacker;
|
||||||
|
new Float:damage;
|
||||||
|
new damageBits;
|
||||||
|
|
||||||
|
victim = read_argv_int( 1 );
|
||||||
|
inflictor = read_argv_int( 2 );
|
||||||
|
attacker = read_argv_int( 3 );
|
||||||
|
damage = read_argv_float( 4 );
|
||||||
|
damageBits = read_argv_int( 5 );
|
||||||
|
|
||||||
|
// attacker and inflictor can be null, but never allow victim to be null
|
||||||
|
if ( !is_valid_ent( victim ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( !is_valid_ent( inflictor ) )
|
||||||
|
inflictor = 0;
|
||||||
|
if ( !is_valid_ent( attacker ) )
|
||||||
|
attacker = 0;
|
||||||
|
|
||||||
|
ExecuteHamB( Ham_TakeDamage, victim, inflictor, attacker, damage, damageBits );
|
||||||
|
}
|
||||||
|
}
|
||||||
17
extra/cstrike/README.md
Normal file
17
extra/cstrike/README.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
## Counter-Strike (cstrike)
|
||||||
|
|
||||||
|
Auxiliary Tools to use MonsterMod in Counter-Strike.
|
||||||
|
|
||||||
|
### AMX Mod X Plugins
|
||||||
|
|
||||||
|
#### -A note about AMXX plugins-
|
||||||
|
|
||||||
|
All plugins in this section require AMXX 1.9.0 or greater, they will not work on 1.8.2 or older.
|
||||||
|
|
||||||
|
Compiled plugins are provided in the `bin` folder for your convenience. However, if you prefer to build the plugins yourself, the source code of all AMXX plugins are located in the `src` folder for compilation.
|
||||||
|
|
||||||
|
#### Unprecacher
|
||||||
|
|
||||||
|
Counter-Strike precaches the sounds of all weapons. This means that sounds such as "clip-ins", "clip-outs" are added to the list, taking quite a bit of space in the precache count. Let it be a reminder that our good old GoldSrc can only store a maximum of 512 precached resources. Most of these sounds are handled client-side by the models themselves, so there is no need for them to be kept precached on the server. Only the weapons fire sounds are needed.
|
||||||
|
|
||||||
|
This plugin removes 85 sounds from the precache list, adding extra space for additional monsters to fit in the map.
|
||||||
BIN
extra/cstrike/bin/cs_unprecacher.amxx
Normal file
BIN
extra/cstrike/bin/cs_unprecacher.amxx
Normal file
Binary file not shown.
126
extra/cstrike/src/cs_unprecacher.sma
Normal file
126
extra/cstrike/src/cs_unprecacher.sma
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#pragma semicolon 1
|
||||||
|
|
||||||
|
#include <amxmodx>
|
||||||
|
#include <fakemeta>
|
||||||
|
|
||||||
|
// List of sounds that must NOT be precached
|
||||||
|
new g_SoundList[][64] =
|
||||||
|
{
|
||||||
|
"weapons/ak47_boltpull.wav",
|
||||||
|
"weapons/ak47_clipin.wav",
|
||||||
|
"weapons/ak47_clipout.wav",
|
||||||
|
"weapons/aug_boltpull.wav",
|
||||||
|
"weapons/aug_boltslap.wav",
|
||||||
|
"weapons/aug_clipin.wav",
|
||||||
|
"weapons/aug_clipout.wav",
|
||||||
|
"weapons/aug_forearm.wav",
|
||||||
|
"weapons/awp_clipin.wav",
|
||||||
|
"weapons/awp_clipout.wav",
|
||||||
|
"weapons/awp_deploy.wav",
|
||||||
|
"weapons/boltdown.wav",
|
||||||
|
"weapons/boltpull1.wav",
|
||||||
|
"weapons/boltup.wav",
|
||||||
|
"weapons/clipin1.wav",
|
||||||
|
"weapons/clipout1.wav",
|
||||||
|
"weapons/de_clipin.wav",
|
||||||
|
"weapons/de_clipout.wav",
|
||||||
|
"weapons/de_deploy.wav",
|
||||||
|
"weapons/elite_clipout.wav",
|
||||||
|
"weapons/elite_deploy.wav",
|
||||||
|
"weapons/elite_leftclipin.wav",
|
||||||
|
"weapons/elite_reloadstart.wav",
|
||||||
|
"weapons/elite_rightclipin.wav",
|
||||||
|
"weapons/elite_sliderelease.wav",
|
||||||
|
"weapons/elite_twirl.wav",
|
||||||
|
"weapons/famas_boltpull.wav",
|
||||||
|
"weapons/famas_boltslap.wav",
|
||||||
|
"weapons/famas_clipin.wav",
|
||||||
|
"weapons/famas_clipout.wav",
|
||||||
|
"weapons/famas_forearm.wav",
|
||||||
|
"weapons/fiveseven_clipin.wav",
|
||||||
|
"weapons/fiveseven_clipout.wav",
|
||||||
|
"weapons/fiveseven_slidepull.wav",
|
||||||
|
"weapons/fiveseven_sliderelease.wav",
|
||||||
|
"weapons/g3sg1_clipin.wav",
|
||||||
|
"weapons/g3sg1_clipout.wav",
|
||||||
|
"weapons/g3sg1_slide.wav",
|
||||||
|
"weapons/galil_boltpull.wav",
|
||||||
|
"weapons/galil_clipin.wav",
|
||||||
|
"weapons/galil_clipout.wav",
|
||||||
|
"weapons/m4a1_boltpull.wav",
|
||||||
|
"weapons/m4a1_clipin.wav",
|
||||||
|
"weapons/m4a1_clipout.wav",
|
||||||
|
"weapons/m4a1_deploy.wav",
|
||||||
|
"weapons/m4a1_silencer_off.wav",
|
||||||
|
"weapons/m4a1_silencer_on.wav",
|
||||||
|
"weapons/m249_boxin.wav",
|
||||||
|
"weapons/m249_boxout.wav",
|
||||||
|
"weapons/m249_chain.wav",
|
||||||
|
"weapons/m249_coverdown.wav",
|
||||||
|
"weapons/m249_coverup.wav",
|
||||||
|
"weapons/mac10_boltpull.wav",
|
||||||
|
"weapons/mac10_clipin.wav",
|
||||||
|
"weapons/mac10_clipout.wav",
|
||||||
|
"weapons/mp5_clipin.wav",
|
||||||
|
"weapons/mp5_clipout.wav",
|
||||||
|
"weapons/mp5_slideback.wav",
|
||||||
|
"weapons/p90_boltpull.wav",
|
||||||
|
"weapons/p90_clipin.wav",
|
||||||
|
"weapons/p90_clipout.wav",
|
||||||
|
"weapons/p90_cliprelease.wav",
|
||||||
|
"weapons/p228_clipin.wav",
|
||||||
|
"weapons/p228_clipout.wav",
|
||||||
|
"weapons/p228_slidepull.wav",
|
||||||
|
"weapons/p228_sliderelease.wav",
|
||||||
|
"weapons/scout_bolt.wav",
|
||||||
|
"weapons/scout_clipin.wav",
|
||||||
|
"weapons/scout_clipout.wav",
|
||||||
|
"weapons/sg550_boltpull.wav",
|
||||||
|
"weapons/sg550_clipin.wav",
|
||||||
|
"weapons/sg550_clipout.wav",
|
||||||
|
"weapons/sg552_boltpull.wav",
|
||||||
|
"weapons/sg552_clipin.wav",
|
||||||
|
"weapons/sg552_clipout.wav",
|
||||||
|
"weapons/slideback1.wav",
|
||||||
|
"weapons/sliderelease1.wav",
|
||||||
|
"weapons/ump45_boltslap.wav",
|
||||||
|
"weapons/ump45_clipin.wav",
|
||||||
|
"weapons/ump45_clipout.wav",
|
||||||
|
"weapons/usp_clipin.wav",
|
||||||
|
"weapons/usp_clipout.wav",
|
||||||
|
"weapons/usp_silencer_off.wav",
|
||||||
|
"weapons/usp_silencer_on.wav",
|
||||||
|
"weapons/usp_slideback.wav",
|
||||||
|
"weapons/usp_sliderelease.wav"
|
||||||
|
};
|
||||||
|
|
||||||
|
public plugin_init()
|
||||||
|
{
|
||||||
|
register_plugin( "CS-MONSTER: Unprecacher", "1.0", "Giegue" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public plugin_precache()
|
||||||
|
{
|
||||||
|
register_forward( FM_PrecacheSound, "fw_PrecacheSound" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public fw_PrecacheSound( const sound[] )
|
||||||
|
{
|
||||||
|
static bool:bBlock, i;
|
||||||
|
bBlock = false;
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
for ( i = 0; i < sizeof( g_SoundList ); i++ )
|
||||||
|
{
|
||||||
|
if (contain( sound, g_SoundList[ i ] ) != -1 )
|
||||||
|
{
|
||||||
|
bBlock = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( bBlock )
|
||||||
|
return FMRES_SUPERCEDE;
|
||||||
|
|
||||||
|
return FMRES_IGNORED;
|
||||||
|
}
|
||||||
40
extra/valve/README.md
Normal file
40
extra/valve/README.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
## Half-Life (valve)
|
||||||
|
|
||||||
|
Auxiliary Tools to use MonsterMod in the original Half-Life.
|
||||||
|
|
||||||
|
### AMX Mod X Plugins
|
||||||
|
|
||||||
|
#### -A note about AMXX plugins-
|
||||||
|
|
||||||
|
All plugins in this section require AMXX 1.9.0 or greater, they will not work on 1.8.2 or older.
|
||||||
|
|
||||||
|
Compiled plugins are provided in the `bin` folder for your convenience. However, if you prefer to build the plugins yourself, the source code of all AMXX plugins are located in the `src` folder for compilation.
|
||||||
|
|
||||||
|
#### Bridge Plugin
|
||||||
|
|
||||||
|
MonsterMod monsters are hacked "func_wall"'s with simulated AI. Because of this, MonsterMod cannot interact with the Half-Life monsters. This issue also happens on the other side: The Half-Life monsters cannot interact with the MonsterMod monsters.
|
||||||
|
|
||||||
|
In simple terms, this plugin acts as a "bridge" to help Half-Life and MonsterMod communicate with each other. With this plugin, HL and MM monsters can "see" and interact with each other, and will react accordingly.
|
||||||
|
|
||||||
|
Without this plugin, HL and MM monsters will be "invisible" to each other.
|
||||||
|
|
||||||
|
#### Soundlist
|
||||||
|
|
||||||
|
This plugin allows you to use the "soundlist" keyvalue in HL monsters to individually replace monster sounds. Path starts from `sound/MAPNAME`. Use `../` to go to the previous directory if needed.
|
||||||
|
|
||||||
|
The plugin can work standalone, meaning it can be used without MonsterMod.
|
||||||
|
|
||||||
|
#### Extra Keyvalues
|
||||||
|
|
||||||
|
**"Bridge Plugin" is REQUIRED for this add-on to work**
|
||||||
|
|
||||||
|
This plugin allows you use the following keyvalues on HL monsters:
|
||||||
|
|
||||||
|
- classify
|
||||||
|
- is_player_ally *(non-monstermaker entities)*
|
||||||
|
- bloodcolor
|
||||||
|
- respawn_as_playerally *(monstermaker entity)*
|
||||||
|
|
||||||
|
The plugin also adds a 5th keyvalue, **"use_monstermod"**. When reading entities from the BSP file, if MonsterMod finds an entity that already exists in the game, it will stick to the game entity and ignore it. By setting this keyvalue to "1", it will explicity use MonsterMod for this entity.
|
||||||
|
|
||||||
|
This is useful when, for example, you are trying to spawn a Pit Drone from a monstermaker. HL does not recognize monster_pitdrone, but MonsterMod does. By redirecting the entity to MonsterMod, Pit Drones will spawn from this monstermaker.
|
||||||
BIN
extra/valve/bin/hl_extra_keyvalues.amxx
Normal file
BIN
extra/valve/bin/hl_extra_keyvalues.amxx
Normal file
Binary file not shown.
BIN
extra/valve/bin/hl_monsterbridge.amxx
Normal file
BIN
extra/valve/bin/hl_monsterbridge.amxx
Normal file
Binary file not shown.
BIN
extra/valve/bin/hl_soundlist.amxx
Normal file
BIN
extra/valve/bin/hl_soundlist.amxx
Normal file
Binary file not shown.
232
extra/valve/src/hl_extra_keyvalues.sma
Normal file
232
extra/valve/src/hl_extra_keyvalues.sma
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
#pragma semicolon 1
|
||||||
|
|
||||||
|
#include <amxmodx>
|
||||||
|
#include <engine>
|
||||||
|
#include <fakemeta>
|
||||||
|
#include <hamsandwich>
|
||||||
|
|
||||||
|
const bits_MEMORY_SPAWN = ( 1 << 1 );
|
||||||
|
|
||||||
|
const BLOOD_COLOR_BLUE = 211;
|
||||||
|
const BLOOD_COLOR_PINK = 147;
|
||||||
|
const BLOOD_COLOR_WHITE = 11;
|
||||||
|
const BLOOD_COLOR_ORANGE = 231;
|
||||||
|
const BLOOD_COLOR_BLACK = 49; // not 100% black but close enough
|
||||||
|
const BLOOD_COLOR_DARKGREEN = 181; // GREEN is aliased to YELLOW, use custom name
|
||||||
|
|
||||||
|
public plugin_init()
|
||||||
|
{
|
||||||
|
register_plugin( "HL-MONSTER Extra Keyvalues", "1.0", "Giegue" );
|
||||||
|
|
||||||
|
/* CLASSIFY */
|
||||||
|
// HACK: since Ham_Spawn won't work, this should do as an alternative
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_headcrab", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_babycrab", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_bullchicken", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_barnacle", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_bigmomma", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_houndeye", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_slave", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_controller", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_grunt", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_zombie", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_ichthyosaur", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_human_grunt", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_human_assassin", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_barney", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_gman", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_scientist", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_sentry", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_snark", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_miniturret", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_turret", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_apache", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_osprey", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_gargantua", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_nihilanth", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_tentacle", "MonsterSpawn_Post", 1 );
|
||||||
|
|
||||||
|
/* BLOODCOLOR */
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_headcrab", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_babycrab", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_bullchicken", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_barnacle", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_bigmomma", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_houndeye", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_alien_slave", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_alien_controller", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_alien_grunt", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_zombie", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_ichthyosaur", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_human_grunt", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_human_assassin", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_barney", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_gman", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_scientist", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_sentry", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_snark", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_miniturret", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_turret", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_apache", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_osprey", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_gargantua", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_nihilanth", "MonsterBlood" );
|
||||||
|
RegisterHam( Ham_BloodColor, "monster_tentacle", "MonsterBlood" );
|
||||||
|
|
||||||
|
// "use_monstermod" keyvalue
|
||||||
|
register_cvar( "_hl_explicit", "1" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public plugin_precache()
|
||||||
|
{
|
||||||
|
register_forward( FM_KeyValue, "ScanKeys" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanKeys( entid, kvd_handle )
|
||||||
|
{
|
||||||
|
if (is_valid_ent(entid))
|
||||||
|
{
|
||||||
|
static classname[ 33 ], keyname[ 33 ], value[ 128 ];
|
||||||
|
get_kvd( kvd_handle, KV_ClassName, classname, charsmax( classname ) );
|
||||||
|
|
||||||
|
// Monsters
|
||||||
|
if ( equal( classname, "monster_", 8 ) )
|
||||||
|
{
|
||||||
|
get_kvd( kvd_handle, KV_KeyName, keyname, charsmax( keyname ) );
|
||||||
|
get_kvd( kvd_handle, KV_Value, value, charsmax( value ) );
|
||||||
|
|
||||||
|
// Classification override
|
||||||
|
if ( equal( keyname, "classify" ) )
|
||||||
|
entity_set_int( entid, EV_INT_iuser4, str_to_num( value ) );
|
||||||
|
|
||||||
|
// Allied monster
|
||||||
|
if ( equal( keyname, "is_player_ally" ) )
|
||||||
|
{
|
||||||
|
if ( str_to_num( value ) )
|
||||||
|
entity_set_int( entid, EV_INT_iuser4, 11 ); // CLASS_PLAYER_ALLY
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom blood color
|
||||||
|
if ( equal( keyname, "bloodcolor" ) )
|
||||||
|
{
|
||||||
|
switch ( str_to_num( value ) )
|
||||||
|
{
|
||||||
|
case -1: entity_set_int( entid, EV_INT_iuser3, DONT_BLEED );
|
||||||
|
// 0 = Monster Default
|
||||||
|
case 1: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_RED );
|
||||||
|
case 2: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_YELLOW );
|
||||||
|
case 3: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_BLUE );
|
||||||
|
case 4: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_PINK );
|
||||||
|
case 5: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_WHITE );
|
||||||
|
case 6: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_ORANGE );
|
||||||
|
case 7: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_BLACK );
|
||||||
|
case 8: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_DARKGREEN );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirect entity to MonsterMod
|
||||||
|
if ( equal( keyname, "use_monstermod" ) )
|
||||||
|
{
|
||||||
|
if ( str_to_num( value ) )
|
||||||
|
{
|
||||||
|
// MonsterMod will inherit this entity, remove it from here
|
||||||
|
remove_entity( entid );
|
||||||
|
return FMRES_SUPERCEDE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FMRES_IGNORED;
|
||||||
|
}
|
||||||
|
// Monster Makers
|
||||||
|
else if ( equal( classname, "monstermaker" ) )
|
||||||
|
{
|
||||||
|
get_kvd( kvd_handle, KV_KeyName, keyname, charsmax( keyname ) );
|
||||||
|
get_kvd( kvd_handle, KV_Value, value, charsmax( value ) );
|
||||||
|
|
||||||
|
// Classification override
|
||||||
|
if ( equal( keyname, "classify" ) )
|
||||||
|
entity_set_int( entid, EV_INT_iuser4, str_to_num( value ) );
|
||||||
|
|
||||||
|
// Allied monster
|
||||||
|
if ( equal( keyname, "respawn_as_playerally" ) )
|
||||||
|
{
|
||||||
|
if ( str_to_num( value ) )
|
||||||
|
entity_set_int( entid, EV_INT_iuser4, 11 ); // CLASS_PLAYER_ALLY
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom blood color
|
||||||
|
if ( equal( keyname, "bloodcolor" ) )
|
||||||
|
{
|
||||||
|
switch ( str_to_num( value ) )
|
||||||
|
{
|
||||||
|
case -1: entity_set_int( entid, EV_INT_iuser3, DONT_BLEED );
|
||||||
|
// 0 = Monster Default
|
||||||
|
case 1: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_RED );
|
||||||
|
case 2: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_YELLOW );
|
||||||
|
case 3: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_BLUE );
|
||||||
|
case 4: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_PINK );
|
||||||
|
case 5: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_WHITE );
|
||||||
|
case 6: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_ORANGE );
|
||||||
|
case 7: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_BLACK );
|
||||||
|
case 8: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_DARKGREEN );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirect entity to MonsterMod
|
||||||
|
if ( equal( keyname, "use_monstermod" ) )
|
||||||
|
{
|
||||||
|
if ( str_to_num( value ) )
|
||||||
|
{
|
||||||
|
// MonsterMod will inherit this entity, remove it from here
|
||||||
|
remove_entity( entid );
|
||||||
|
return FMRES_IGNORED; // not a typo, must not supercede or it will crash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FMRES_IGNORED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FMRES_IGNORED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonsterSpawn_Post( entity )
|
||||||
|
{
|
||||||
|
// Why is it called 3 times? Restrict this to only once
|
||||||
|
if ( !( entity_get_int( entity, EV_INT_impulse ) & bits_MEMORY_SPAWN ) )
|
||||||
|
{
|
||||||
|
// monstermaker sets owner after monster spawn, wait next frame
|
||||||
|
set_task( 0.000001, "MakerSpawn_Post", entity );
|
||||||
|
|
||||||
|
entity_set_int( entity, EV_INT_impulse, entity_get_int( entity, EV_INT_impulse ) | bits_MEMORY_SPAWN );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MakerSpawn_Post( entity )
|
||||||
|
{
|
||||||
|
if ( is_valid_ent( entity ) )
|
||||||
|
{
|
||||||
|
static owner;
|
||||||
|
owner = entity_get_edict( entity, EV_ENT_owner );
|
||||||
|
if ( owner )
|
||||||
|
{
|
||||||
|
// pass parent configurations to child entity
|
||||||
|
entity_set_int( entity, EV_INT_iuser4, entity_get_int( owner, EV_INT_iuser4 ) ); // classify
|
||||||
|
entity_set_int( entity, EV_INT_iuser3, entity_get_int( owner, EV_INT_iuser3 ) ); // bloodcolor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonsterBlood( entity )
|
||||||
|
{
|
||||||
|
static newBlood;
|
||||||
|
newBlood = entity_get_int( entity, EV_INT_iuser3 );
|
||||||
|
|
||||||
|
if ( newBlood )
|
||||||
|
{
|
||||||
|
SetHamReturnInteger( newBlood );
|
||||||
|
return HAM_OVERRIDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HAM_IGNORED;
|
||||||
|
}
|
||||||
200
extra/valve/src/hl_monsterbridge.sma
Normal file
200
extra/valve/src/hl_monsterbridge.sma
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
#pragma semicolon 1
|
||||||
|
|
||||||
|
#include <amxmodx>
|
||||||
|
#include <engine>
|
||||||
|
#include <hamsandwich>
|
||||||
|
|
||||||
|
// (monster.h from HLSDK) monster to monster relationship types
|
||||||
|
const R_AL = -2; // (ALLY) pals. Good alternative to R_NO when applicable.
|
||||||
|
const R_FR = -1; // (FEAR) will run.
|
||||||
|
const R_NO = 0; // (NO RELATIONSHIP) disregard.
|
||||||
|
const R_DL = 1; // (DISLIKE) will attack.
|
||||||
|
const R_HT = 2; // (HATE) will attack this character instead of any visible DISLIKEd characters.
|
||||||
|
//const R_NM = 3; // (NEMESIS) a monster will ALWAYS attack its nemesis, no matter what.
|
||||||
|
|
||||||
|
new Trie:g_HLDefaultNames;
|
||||||
|
|
||||||
|
const bits_MEMORY_NAMED = ( 1 << 2 );
|
||||||
|
|
||||||
|
public plugin_init()
|
||||||
|
{
|
||||||
|
register_plugin( "HL-MONSTER Bridge", "1.2", "Giegue" );
|
||||||
|
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_alien_controller", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_alien_grunt", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_alien_slave", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_apache", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_babycrab", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_barnacle", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_barney", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_bigmomma", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_bullchicken", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_gargantua", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_headcrab", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_houndeye", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_human_assassin", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_human_grunt", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_ichthyosaur", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_miniturret", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_scientist", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_sentry", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_snark", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_turret", "mmIRelationship" );
|
||||||
|
RegisterHam( Ham_IRelationship, "monster_zombie", "mmIRelationship" );
|
||||||
|
|
||||||
|
g_HLDefaultNames = TrieCreate();
|
||||||
|
|
||||||
|
// Better than a nest of if-else if i guess...
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_headcrab", "Head Crab" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_babycrab", "Baby Head Crab" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_bullchicken", "Bullsquid" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_barnacle", "Barnacle" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_bigmomma", "Big Momma" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_houndeye", "Houndeye" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_alien_slave", "Alien Slave" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_alien_controller", "Alien Controller" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_alien_grunt", "Alien Grunt" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_zombie", "Zombie" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_ichthyosaur", "Ichthyosaur" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_human_grunt", "Human Grunt" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_human_assassin", "Female Assassin" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_barney", "Barney" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_gman", "Goverment Man" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_scientist", "Scientist" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_sentry", "Sentry Turret" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_snark", "Snark" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_miniturret", "Mini-Turret" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_turret", "Turret" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_apache", "Apache" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_osprey", "Osprey Helicopter" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_gargantua", "Gargantua" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_nihilanth", "Nihilanth" );
|
||||||
|
TrieSetString( g_HLDefaultNames, "monster_tentacle", "Tentacle" );
|
||||||
|
|
||||||
|
// HACK: since Ham_Spawn won't work, this should do as an alternative
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_headcrab", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_babycrab", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_bullchicken", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_barnacle", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_bigmomma", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_houndeye", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_slave", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_controller", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_grunt", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_zombie", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_ichthyosaur", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_human_grunt", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_human_assassin", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_barney", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_gman", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_scientist", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_sentry", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_snark", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_miniturret", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_turret", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_apache", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_osprey", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_gargantua", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_nihilanth", "hlSpawn", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_tentacle", "hlSpawn", 1 );
|
||||||
|
|
||||||
|
RegisterHam( Ham_Killed, "player", "PlayerKilled", 1 );
|
||||||
|
}
|
||||||
|
public plugin_end()
|
||||||
|
{
|
||||||
|
TrieDestroy( g_HLDefaultNames ); // free the handle
|
||||||
|
}
|
||||||
|
|
||||||
|
public mmIRelationship( entity, other )
|
||||||
|
{
|
||||||
|
new selfClassify, otherClassify;
|
||||||
|
|
||||||
|
selfClassify = entity_get_int( entity, EV_INT_iuser4 );
|
||||||
|
otherClassify = entity_get_int( other, EV_INT_iuser4 );
|
||||||
|
|
||||||
|
if ( entity_get_int( other, EV_INT_flags ) & FL_CLIENT )
|
||||||
|
otherClassify = 2;
|
||||||
|
|
||||||
|
// Get proper relationship
|
||||||
|
SetHamReturnInteger( IRelationshipByClass( selfClassify, otherClassify ) );
|
||||||
|
return HAM_OVERRIDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public hlSpawn( entity )
|
||||||
|
{
|
||||||
|
// Why is it called 3 times? Restrict this to only once
|
||||||
|
if ( !( entity_get_int( entity, EV_INT_impulse ) & bits_MEMORY_NAMED ) )
|
||||||
|
{
|
||||||
|
// Classify not overriden?
|
||||||
|
if ( !entity_get_int( entity, EV_INT_iuser4 ) )
|
||||||
|
{
|
||||||
|
// Set default
|
||||||
|
entity_set_int( entity, EV_INT_iuser4, ExecuteHam( Ham_Classify, entity ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blood color not overriden?
|
||||||
|
if ( !entity_get_int( entity, EV_INT_iuser3 ) )
|
||||||
|
{
|
||||||
|
// Set default
|
||||||
|
entity_set_int( entity, EV_INT_iuser3, ExecuteHam( Ham_BloodColor, entity ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// No name set?
|
||||||
|
new szDisplayname[ 129 ];
|
||||||
|
entity_get_string( entity, EV_SZ_netname, szDisplayname, charsmax( szDisplayname ) );
|
||||||
|
if ( !strlen( szDisplayname ) )
|
||||||
|
{
|
||||||
|
// Find a default name
|
||||||
|
new szClassname[ 33 ], bool:found;
|
||||||
|
entity_get_string( entity, EV_SZ_classname, szClassname, charsmax( szClassname ) );
|
||||||
|
found = TrieGetString( g_HLDefaultNames, szClassname, szDisplayname, charsmax( szDisplayname ) );
|
||||||
|
|
||||||
|
// Use this name
|
||||||
|
entity_set_string( entity, EV_SZ_netname, ( found ? szDisplayname : "Monster" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_set_int( entity, EV_INT_impulse, entity_get_int( entity, EV_INT_impulse ) | bits_MEMORY_NAMED );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stock IRelationshipByClass( classEntity, classOther )
|
||||||
|
{
|
||||||
|
if ( classEntity == -1 )
|
||||||
|
classEntity = 0; // CLASS_FORCE_NONE
|
||||||
|
|
||||||
|
new iEnemy[16][16] =
|
||||||
|
{ // NONE MACH PLYR HPASS HMIL AMIL APASS AMONST APREY APRED INSECT PLRALY PBWPN ABWPN RXPIT RXSHK
|
||||||
|
/*NONE*/ { R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO, R_NO, R_NO },
|
||||||
|
/*MACHINE*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_DL, R_DL, R_DL, R_DL },
|
||||||
|
/*PLAYER*/ { R_NO ,R_DL ,R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_DL, R_DL, R_DL, R_DL },
|
||||||
|
/*HUMANPASSIVE*/{ R_NO ,R_FR ,R_AL ,R_AL ,R_HT ,R_DL ,R_DL ,R_HT ,R_DL ,R_DL ,R_NO ,R_AL, R_NO, R_NO, R_FR, R_FR },
|
||||||
|
/*HUMANMILITAR*/{ R_NO ,R_NO ,R_DL ,R_DL ,R_AL ,R_HT ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_NO, R_NO, R_HT, R_HT },
|
||||||
|
/*ALIENMILITAR*/{ R_NO ,R_DL ,R_DL ,R_DL ,R_HT ,R_AL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO, R_DL, R_HT },
|
||||||
|
/*ALIENPASSIVE*/{ R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO, R_NO, R_NO },
|
||||||
|
/*ALIENMONSTER*/{ R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO, R_NO, R_NO },
|
||||||
|
/*ALIENPREY */{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_FR ,R_NO ,R_DL, R_NO, R_NO, R_FR, R_NO },
|
||||||
|
/*ALIENPREDATO*/{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_HT ,R_NO ,R_NO ,R_DL, R_NO, R_NO, R_DL, R_DL },
|
||||||
|
/*INSECT*/ { R_NO ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR, R_NO, R_NO, R_NO, R_NO },
|
||||||
|
/*PLAYERALLY*/ { R_NO ,R_DL ,R_AL ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_NO, R_NO, R_DL, R_DL },
|
||||||
|
/*PBIOWEAPON*/ { R_NO ,R_NO ,R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_NO, R_DL, R_DL, R_DL },
|
||||||
|
/*ABIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_AL ,R_NO ,R_DL ,R_DL ,R_NO ,R_NO ,R_DL, R_DL, R_NO, R_DL, R_DL },
|
||||||
|
/*RXPITDRONE*/ { R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL ,R_DL ,R_NO ,R_DL, R_NO, R_NO, R_AL, R_AL },
|
||||||
|
/*RXSHOCKTRP*/ { R_NO ,R_DL ,R_HT ,R_DL ,R_HT ,R_HT ,R_DL ,R_NO ,R_NO ,R_DL ,R_NO ,R_DL, R_NO, R_NO, R_AL, R_AL }
|
||||||
|
};
|
||||||
|
|
||||||
|
return iEnemy[ classEntity ][ classOther ];
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerKilled( victim, attacker, shouldgib )
|
||||||
|
{
|
||||||
|
// don't obstruct monstermod
|
||||||
|
if ( victim == attacker )
|
||||||
|
return HAM_IGNORED;
|
||||||
|
|
||||||
|
// fix monster score
|
||||||
|
if ( entity_get_int( attacker, EV_INT_flags ) & FL_MONSTER )
|
||||||
|
entity_set_float( attacker, EV_FL_frags, entity_get_float( attacker, EV_FL_frags ) + 2 );
|
||||||
|
|
||||||
|
entity_set_edict( victim, EV_ENT_dmg_inflictor, attacker );
|
||||||
|
return HAM_IGNORED;
|
||||||
|
}
|
||||||
204
extra/valve/src/hl_soundlist.sma
Normal file
204
extra/valve/src/hl_soundlist.sma
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
#pragma semicolon 1
|
||||||
|
|
||||||
|
#include <amxmodx>
|
||||||
|
#include <engine>
|
||||||
|
#include <fakemeta>
|
||||||
|
#include <hamsandwich>
|
||||||
|
|
||||||
|
const bits_MEMORY_SOUNDLIST = ( 1 << 3 );
|
||||||
|
new Trie:m_Sounds;
|
||||||
|
|
||||||
|
public plugin_init()
|
||||||
|
{
|
||||||
|
register_plugin( "HL-MONSTER Soundlist", "1.0", "Giegue" );
|
||||||
|
|
||||||
|
/* STOP DUPLICATING CODE FFS */
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_headcrab", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_babycrab", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_bullchicken", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_barnacle", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_bigmomma", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_houndeye", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_slave", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_controller", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_grunt", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_zombie", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_ichthyosaur", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_human_grunt", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_human_assassin", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_barney", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_gman", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_scientist", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_sentry", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_snark", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_miniturret", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_turret", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_apache", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_osprey", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_gargantua", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_nihilanth", "MonsterSpawn_Post", 1 );
|
||||||
|
RegisterHam( Ham_SetObjectCollisionBox, "monster_tentacle", "MonsterSpawn_Post", 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public plugin_end()
|
||||||
|
{
|
||||||
|
if ( m_Sounds )
|
||||||
|
TrieDestroy( m_Sounds );
|
||||||
|
}
|
||||||
|
|
||||||
|
// has to be in precache or it won't work
|
||||||
|
public plugin_precache()
|
||||||
|
{
|
||||||
|
// check individual monster soundlists
|
||||||
|
register_forward( FM_KeyValue, "ScanSL" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScanSL( entid, kvd_handle )
|
||||||
|
{
|
||||||
|
if (is_valid_ent(entid))
|
||||||
|
{
|
||||||
|
static classname[ 33 ], keyname[ 33 ], value[ 128 ];
|
||||||
|
get_kvd( kvd_handle, KV_ClassName, classname, charsmax( classname ) );
|
||||||
|
|
||||||
|
// Monsters
|
||||||
|
if ( equal( classname, "monster_", 8 ) )
|
||||||
|
{
|
||||||
|
get_kvd( kvd_handle, KV_KeyName, keyname, charsmax( keyname ) );
|
||||||
|
get_kvd( kvd_handle, KV_Value, value, charsmax( value ) );
|
||||||
|
|
||||||
|
// Individual sound replacement
|
||||||
|
if ( equal( keyname, "soundlist" ) )
|
||||||
|
{
|
||||||
|
ProcessSoundList( entid, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
return FMRES_IGNORED;
|
||||||
|
}
|
||||||
|
// Monster Makers
|
||||||
|
else if ( equal( classname, "monstermaker" ) )
|
||||||
|
{
|
||||||
|
get_kvd( kvd_handle, KV_KeyName, keyname, charsmax( keyname ) );
|
||||||
|
get_kvd( kvd_handle, KV_Value, value, charsmax( value ) );
|
||||||
|
|
||||||
|
// Children sound list
|
||||||
|
if ( equal( keyname, "soundlist" ) )
|
||||||
|
{
|
||||||
|
ProcessSoundList( entid, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
return FMRES_IGNORED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FMRES_IGNORED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProcessSoundList( entity, const filename[] )
|
||||||
|
{
|
||||||
|
// First time?
|
||||||
|
if ( !m_Sounds )
|
||||||
|
m_Sounds = TrieCreate();
|
||||||
|
|
||||||
|
new fullPath[ 129 ];
|
||||||
|
|
||||||
|
new mapName[ 33 ], pFile;
|
||||||
|
get_mapname( mapName, charsmax( mapName ) );
|
||||||
|
|
||||||
|
// path always starts from sound/[MAPNAME] (SC behaviour)
|
||||||
|
formatex( fullPath, charsmax( fullPath ), "sound/%s/%s", mapName, filename );
|
||||||
|
pFile = fopen( fullPath, "r" );
|
||||||
|
if ( pFile )
|
||||||
|
{
|
||||||
|
new line[ 258 ], soundSrc[ 129 ], soundDest[ 129 ];
|
||||||
|
|
||||||
|
while ( fgets( pFile, line, charsmax( line ) ) )
|
||||||
|
{
|
||||||
|
// Replace newlines
|
||||||
|
replace_all( line, charsmax( line ), "^n", "" );
|
||||||
|
|
||||||
|
// Ignore blank lines
|
||||||
|
if ( !line[ 0 ] ) continue;
|
||||||
|
|
||||||
|
// source --> destination
|
||||||
|
parse( line, soundSrc, charsmax( soundSrc ), soundDest, charsmax( soundDest ) );
|
||||||
|
|
||||||
|
// Precache destination sound
|
||||||
|
// HACK: precache_sound outside of plugin_precache
|
||||||
|
engfunc( EngFunc_PrecacheSound, soundDest );
|
||||||
|
|
||||||
|
// HACK: prepend the entityID at the beginning of the soundSrc for later identification
|
||||||
|
format( soundSrc, charsmax( soundSrc ), "%i#%s", entity, soundSrc );
|
||||||
|
|
||||||
|
TrieSetString( m_Sounds, soundSrc, soundDest );
|
||||||
|
entity_set_int( entity, EV_INT_impulse, entity_get_int( entity, EV_INT_impulse ) | bits_MEMORY_SOUNDLIST );
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose( pFile );
|
||||||
|
|
||||||
|
// file could be empty
|
||||||
|
if ( TrieGetSize( m_Sounds ) )
|
||||||
|
{
|
||||||
|
register_forward( FM_EmitSound, "ReplaceSound" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReplaceSound( entity, channel, const sample[], Float:volume, Float:attn, flags, pitch )
|
||||||
|
{
|
||||||
|
static newSound[ 129 ];
|
||||||
|
|
||||||
|
// replace monster sound?
|
||||||
|
if ( entity_get_int( entity, EV_INT_impulse ) & bits_MEMORY_SOUNDLIST )
|
||||||
|
{
|
||||||
|
// get entityID
|
||||||
|
static owner, entid;
|
||||||
|
owner = entity_get_edict( entity, EV_ENT_owner );
|
||||||
|
if ( owner )
|
||||||
|
entid = owner;
|
||||||
|
else
|
||||||
|
entid = entity;
|
||||||
|
|
||||||
|
// get sound
|
||||||
|
static searchSound[ 129 ];
|
||||||
|
formatex( searchSound, charsmax( searchSound ), "%i#%s", entid, sample );
|
||||||
|
|
||||||
|
// if found, stick to that one
|
||||||
|
if ( TrieGetString( m_Sounds, searchSound, newSound, charsmax( newSound ) ) )
|
||||||
|
{
|
||||||
|
// emit new sound and supercede this one
|
||||||
|
emit_sound( entity, channel, newSound, volume, attn, flags, pitch );
|
||||||
|
return FMRES_SUPERCEDE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FMRES_IGNORED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* extra_keyvalues.sma duplication */
|
||||||
|
public MonsterSpawn_Post( entity )
|
||||||
|
{
|
||||||
|
// monstermaker sets owner after monster spawn, wait next frame
|
||||||
|
set_task( 0.000001, "MakerSpawn_Post", entity );
|
||||||
|
}
|
||||||
|
|
||||||
|
public MakerSpawn_Post( entity )
|
||||||
|
{
|
||||||
|
if ( is_valid_ent( entity ) )
|
||||||
|
{
|
||||||
|
static owner;
|
||||||
|
owner = entity_get_edict( entity, EV_ENT_owner );
|
||||||
|
if ( owner )
|
||||||
|
{
|
||||||
|
// monstermaker has soundlist defined?
|
||||||
|
if ( entity_get_int( owner, EV_INT_impulse ) & bits_MEMORY_SOUNDLIST )
|
||||||
|
{
|
||||||
|
// 3 time call
|
||||||
|
if ( !( entity_get_int( entity, EV_INT_impulse ) & bits_MEMORY_SOUNDLIST ) )
|
||||||
|
{
|
||||||
|
// this monster is to use sound replacements
|
||||||
|
entity_set_int( entity, EV_INT_impulse, entity_get_int( entity, EV_INT_impulse ) | bits_MEMORY_SOUNDLIST );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/dlls/.gitignore
vendored
4
src/dlls/.gitignore
vendored
@@ -1,5 +1,9 @@
|
|||||||
|
Release/
|
||||||
|
Debug/
|
||||||
msgs/
|
msgs/
|
||||||
opt.*/
|
opt.*/
|
||||||
debug.*/
|
debug.*/
|
||||||
*.o
|
*.o
|
||||||
*.so
|
*.so
|
||||||
|
*.suo
|
||||||
|
*.sdf
|
||||||
@@ -1085,7 +1085,7 @@ jlb*/
|
|||||||
{
|
{
|
||||||
m_movementActivity = ACT_FLY;
|
m_movementActivity = ACT_FLY;
|
||||||
}
|
}
|
||||||
if ( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE )
|
else if ( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE )
|
||||||
{
|
{
|
||||||
m_movementActivity = ACT_WALK;
|
m_movementActivity = ACT_WALK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
CPP = g++-7
|
CPP = g++
|
||||||
BASEFLAGS = -Dstricmp=strcasecmp -Dstrcmpi=strcasecmp -m32
|
BASEFLAGS = -Dstricmp=strcasecmp -Dstrcmpi=strcasecmp -m32 -fPIC
|
||||||
OPTFLAGS = -O2
|
OPTFLAGS = -O2
|
||||||
CPPFLAGS = ${BASEFLAGS} ${OPTFLAGS} -w -I. -I../engine -I../common -I../pm_shared -I../metamod
|
CPPFLAGS = ${BASEFLAGS} ${OPTFLAGS} -w -I. -I../engine -I../common -I../pm_shared -I../metamod
|
||||||
|
|
||||||
@@ -17,10 +17,13 @@ OBJ = \
|
|||||||
controller.o \
|
controller.o \
|
||||||
defaultai.o \
|
defaultai.o \
|
||||||
dllapi.o \
|
dllapi.o \
|
||||||
explode.o \
|
|
||||||
effects.o \
|
effects.o \
|
||||||
|
explode.o \
|
||||||
|
flyingmonster.o \
|
||||||
gargantua.o \
|
gargantua.o \
|
||||||
ggrenade.o \
|
ggrenade.o \
|
||||||
|
globalreplace.o \
|
||||||
|
gonome.o \
|
||||||
h_ai.o \
|
h_ai.o \
|
||||||
h_export.o \
|
h_export.o \
|
||||||
hassassin.o \
|
hassassin.o \
|
||||||
@@ -28,21 +31,37 @@ OBJ = \
|
|||||||
hgrunt.o \
|
hgrunt.o \
|
||||||
hornet.o \
|
hornet.o \
|
||||||
houndeye.o \
|
houndeye.o \
|
||||||
|
hwgrunt.o \
|
||||||
islave.o \
|
islave.o \
|
||||||
|
massn.o \
|
||||||
monster_api.o \
|
monster_api.o \
|
||||||
monster_config.o \
|
monster_config.o \
|
||||||
|
monstermaker.o \
|
||||||
monsters.o \
|
monsters.o \
|
||||||
monsterstate.o \
|
monsterstate.o \
|
||||||
|
music.o \
|
||||||
nodes.o \
|
nodes.o \
|
||||||
|
otis.o \
|
||||||
|
pitdrone.o \
|
||||||
|
rgrunt.o \
|
||||||
|
ripent.o \
|
||||||
scientist.o \
|
scientist.o \
|
||||||
|
setcvar.o \
|
||||||
|
shock.o \
|
||||||
|
shockroach.o \
|
||||||
skill.o \
|
skill.o \
|
||||||
sound.o \
|
sound.o \
|
||||||
|
sporegrenade.o \
|
||||||
squeakgrenade.o \
|
squeakgrenade.o \
|
||||||
|
strooper.o \
|
||||||
|
stukabat.o \
|
||||||
subs.o \
|
subs.o \
|
||||||
talkmonster.o \
|
talkmonster.o \
|
||||||
turret.o \
|
turret.o \
|
||||||
util.o \
|
util.o \
|
||||||
|
voltigore.o \
|
||||||
weapons.o \
|
weapons.o \
|
||||||
|
xenmaker.o \
|
||||||
zombie.o
|
zombie.o
|
||||||
|
|
||||||
monster_mm_i386.so: ${OBJ}
|
monster_mm_i386.so: ${OBJ}
|
||||||
|
|||||||
@@ -87,6 +87,13 @@ const char *CMAGrunt::pAttackSounds[] =
|
|||||||
"agrunt/ag_attack3.wav",
|
"agrunt/ag_attack3.wav",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *CMAGrunt::pFireSounds[] =
|
||||||
|
{
|
||||||
|
"agrunt/ag_fire1.wav",
|
||||||
|
"agrunt/ag_fire2.wav",
|
||||||
|
"agrunt/ag_fire3.wav",
|
||||||
|
};
|
||||||
|
|
||||||
const char *CMAGrunt::pDieSounds[] =
|
const char *CMAGrunt::pDieSounds[] =
|
||||||
{
|
{
|
||||||
"agrunt/ag_die1.wav",
|
"agrunt/ag_die1.wav",
|
||||||
@@ -184,13 +191,8 @@ void CMAGrunt :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vec
|
|||||||
if (flDamage <= 0)
|
if (flDamage <= 0)
|
||||||
flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated
|
flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood.
|
|
||||||
TraceBleed( flDamage, vecDir, ptr, bitsDamageType );
|
|
||||||
}
|
|
||||||
|
|
||||||
AddMultiDamage( pevAttacker, this->edict(), flDamage, bitsDamageType );
|
CMBaseMonster::TraceAttack(pevAttacker, flDamage, vecDir, ptr, bitsDamageType);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -418,6 +420,8 @@ void CMAGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent )
|
|||||||
UTIL_MakeVectors ( pHornet->pev->angles );
|
UTIL_MakeVectors ( pHornet->pev->angles );
|
||||||
pHornet->pev->velocity = gpGlobals->v_forward * 300;
|
pHornet->pev->velocity = gpGlobals->v_forward * 300;
|
||||||
|
|
||||||
|
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, pFireSounds[RANDOM_LONG(0, ARRAYSIZE(pFireSounds) - 1)], 1.0, ATTN_NORM, 0, 100);
|
||||||
|
|
||||||
CMBaseMonster *pHornetMonster = pHornet->MyMonsterPointer();
|
CMBaseMonster *pHornetMonster = pHornet->MyMonsterPointer();
|
||||||
|
|
||||||
if ( pHornetMonster )
|
if ( pHornetMonster )
|
||||||
@@ -532,14 +536,14 @@ void CMAGrunt :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/agrunt.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/agrunt.mdl"));
|
||||||
UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64));
|
UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64));
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
pev->movetype = MOVETYPE_STEP;
|
pev->movetype = MOVETYPE_STEP;
|
||||||
m_bloodColor = BLOOD_COLOR_GREEN;
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
|
||||||
pev->effects = 0;
|
pev->effects = 0;
|
||||||
pev->health = gSkillData.agruntHealth;
|
if (!pev->health) { pev->health = gSkillData.agruntHealth; }
|
||||||
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
m_MonsterState = MONSTERSTATE_NONE;
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
m_afCapability = 0;
|
m_afCapability = 0;
|
||||||
@@ -563,35 +567,18 @@ void CMAGrunt :: Spawn()
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
void CMAGrunt :: Precache()
|
void CMAGrunt :: Precache()
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
PRECACHE_MODEL("models/agrunt.mdl");
|
PRECACHE_MODEL("models/agrunt.mdl");
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
|
PRECACHE_SOUND_ARRAY( pAttackHitSounds );
|
||||||
PRECACHE_SOUND((char *)pAttackHitSounds[i]);
|
PRECACHE_SOUND_ARRAY( pAttackHitSounds );
|
||||||
|
PRECACHE_SOUND_ARRAY( pAttackMissSounds );
|
||||||
|
PRECACHE_SOUND_ARRAY( pIdleSounds );
|
||||||
|
PRECACHE_SOUND_ARRAY( pDieSounds );
|
||||||
|
PRECACHE_SOUND_ARRAY( pPainSounds );
|
||||||
|
PRECACHE_SOUND_ARRAY( pAttackSounds );
|
||||||
|
PRECACHE_SOUND_ARRAY( pAlertSounds );
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
|
iAgruntMuzzleFlash = PRECACHE_MODELINDEX("sprites/muz4.spr");
|
||||||
PRECACHE_SOUND((char *)pAttackMissSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pIdleSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pDieSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pDieSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pPainSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pAttackSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pAlertSounds[i]);
|
|
||||||
|
|
||||||
|
|
||||||
PRECACHE_SOUND( "hassault/hw_shoot1.wav" );
|
|
||||||
|
|
||||||
iAgruntMuzzleFlash = PRECACHE_MODEL( "sprites/muz4.spr" );
|
|
||||||
|
|
||||||
CMHornet hornet;
|
CMHornet hornet;
|
||||||
hornet.Precache();
|
hornet.Precache();
|
||||||
@@ -1030,7 +1017,7 @@ Schedule_t *CMAGrunt :: GetSchedule ( void )
|
|||||||
// zap player!
|
// zap player!
|
||||||
if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) )
|
if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) )
|
||||||
{
|
{
|
||||||
AttackSound();// this is a total hack. Should be parto f the schedule
|
AttackSound();// this is a total hack. Should be part of the schedule
|
||||||
return GetScheduleOfType ( SCHED_MELEE_ATTACK1 );
|
return GetScheduleOfType ( SCHED_MELEE_ATTACK1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -163,7 +163,11 @@ int LookupSequence( void *pmodel, const char *label )
|
|||||||
|
|
||||||
for (int i = 0; i < pstudiohdr->numseq; i++)
|
for (int i = 0; i < pstudiohdr->numseq; i++)
|
||||||
{
|
{
|
||||||
|
#if defined (_WIN32)
|
||||||
|
if (_stricmp( pseqdesc[i].label, label ) == 0)
|
||||||
|
#else
|
||||||
if (stricmp( pseqdesc[i].label, label ) == 0)
|
if (stricmp( pseqdesc[i].label, label ) == 0)
|
||||||
|
#endif
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +213,7 @@ void SequencePrecache( void *pmodel, const char *pSequenceName )
|
|||||||
ALERT( at_error, "Bad sound event %d in sequence %s :: %s (sound is \"%s\")\n", pevent[i].event, pstudiohdr->name, pSequenceName, pevent[i].options );
|
ALERT( at_error, "Bad sound event %d in sequence %s :: %s (sound is \"%s\")\n", pevent[i].event, pstudiohdr->name, pSequenceName, pevent[i].options );
|
||||||
}
|
}
|
||||||
|
|
||||||
PRECACHE_SOUND( (char *)(gpGlobals->pStringBase + ALLOC_STRING(pevent[i].options) ) );
|
PRECACHE_SOUND2( (char *)(gpGlobals->pStringBase + ALLOC_STRING(pevent[i].options) ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,9 +301,14 @@ int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEve
|
|||||||
|
|
||||||
for (; index < pseqdesc->numevents; index++)
|
for (; index < pseqdesc->numevents; index++)
|
||||||
{
|
{
|
||||||
|
// Some Sven Co-op monsters rely on client-side events.
|
||||||
|
// Let those be sent to the server AI, even if it's wrong. -Giegue
|
||||||
|
|
||||||
|
/*
|
||||||
// Don't send client-side events to the server AI
|
// Don't send client-side events to the server AI
|
||||||
if ( pevent[index].event >= EVENT_CLIENT )
|
if ( pevent[index].event >= EVENT_CLIENT )
|
||||||
continue;
|
continue;
|
||||||
|
*/
|
||||||
|
|
||||||
if ( (pevent[index].frame >= flStart && pevent[index].frame < flEnd) ||
|
if ( (pevent[index].frame >= flStart && pevent[index].frame < flEnd) ||
|
||||||
((pseqdesc->flags & STUDIO_LOOPING) && flEnd >= pseqdesc->numframes - 1 && pevent[index].frame < flEnd - pseqdesc->numframes + 1) )
|
((pseqdesc->flags & STUDIO_LOOPING) && flEnd >= pseqdesc->numframes - 1 && pevent[index].frame < flEnd - pseqdesc->numframes + 1) )
|
||||||
|
|||||||
@@ -35,13 +35,13 @@ void CMApache :: Spawn( void )
|
|||||||
pev->movetype = MOVETYPE_FLY;
|
pev->movetype = MOVETYPE_FLY;
|
||||||
pev->solid = SOLID_BBOX;
|
pev->solid = SOLID_BBOX;
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/apache.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/apache.mdl"));
|
||||||
UTIL_SetSize( pev, Vector( -32, -32, -64 ), Vector( 32, 32, 0 ) );
|
UTIL_SetSize( pev, Vector( -32, -32, -64 ), Vector( 32, 32, 0 ) );
|
||||||
UTIL_SetOrigin( pev, pev->origin );
|
UTIL_SetOrigin( pev, pev->origin );
|
||||||
|
|
||||||
pev->flags |= FL_MONSTER;
|
pev->flags |= FL_MONSTER;
|
||||||
pev->takedamage = DAMAGE_AIM;
|
pev->takedamage = DAMAGE_AIM;
|
||||||
pev->health = gSkillData.apacheHealth;
|
if (!pev->health) { pev->health = gSkillData.apacheHealth; }
|
||||||
|
|
||||||
m_flFieldOfView = -0.707; // 270 degrees
|
m_flFieldOfView = -0.707; // 270 degrees
|
||||||
|
|
||||||
@@ -105,14 +105,14 @@ void CMApache::Precache( void )
|
|||||||
|
|
||||||
PRECACHE_SOUND("weapons/mortarhit.wav");
|
PRECACHE_SOUND("weapons/mortarhit.wav");
|
||||||
|
|
||||||
m_iSpriteTexture = PRECACHE_MODEL( "sprites/white.spr" );
|
m_iSpriteTexture = PRECACHE_MODELINDEX( "sprites/white.spr" );
|
||||||
|
|
||||||
PRECACHE_SOUND("turret/tu_fire1.wav");
|
PRECACHE_SOUND("turret/tu_fire1.wav");
|
||||||
|
|
||||||
PRECACHE_MODEL("sprites/lgtning.spr");
|
PRECACHE_MODEL("sprites/lgtning.spr");
|
||||||
|
|
||||||
m_iExplode = PRECACHE_MODEL( "sprites/fexplo.spr" );
|
m_iExplode = PRECACHE_MODELINDEX( "sprites/fexplo.spr" );
|
||||||
m_iBodyGibs = PRECACHE_MODEL( "models/metalplategibs_green.mdl" );
|
m_iBodyGibs = PRECACHE_MODELINDEX( "models/metalplategibs_green.mdl" );
|
||||||
|
|
||||||
CMApacheHVR apache_rocket;
|
CMApacheHVR apache_rocket;
|
||||||
apache_rocket.Precache();
|
apache_rocket.Precache();
|
||||||
@@ -157,6 +157,11 @@ void CMApache :: Killed( entvars_t *pevAttacker, int iGib )
|
|||||||
pev->health = 0;
|
pev->health = 0;
|
||||||
pev->takedamage = DAMAGE_NO;
|
pev->takedamage = DAMAGE_NO;
|
||||||
|
|
||||||
|
pev->deadflag = DEAD_DYING;
|
||||||
|
FCheckAITrigger(); // trigger death condition
|
||||||
|
if ( UTIL_IsPlayer( ENT( pevAttacker ) ) ) // If a player killed this monster, add score
|
||||||
|
pevAttacker->frags += 1.0;
|
||||||
|
|
||||||
if (pev->spawnflags & SF_NOWRECKAGE)
|
if (pev->spawnflags & SF_NOWRECKAGE)
|
||||||
{
|
{
|
||||||
m_flNextRocket = gpGlobals->time + 4.0;
|
m_flNextRocket = gpGlobals->time + 4.0;
|
||||||
@@ -178,7 +183,7 @@ void CMApache :: DyingThink( void )
|
|||||||
if (m_flNextRocket > gpGlobals->time )
|
if (m_flNextRocket > gpGlobals->time )
|
||||||
{
|
{
|
||||||
if (g_sModelIndexFireball == 0)
|
if (g_sModelIndexFireball == 0)
|
||||||
g_sModelIndexFireball = PRECACHE_MODEL ("sprites/zerogxplode.spr"); // fireball
|
g_sModelIndexFireball = PRECACHE_MODELINDEX("sprites/zerogxplode.spr"); // fireball
|
||||||
|
|
||||||
// random explosions
|
// random explosions
|
||||||
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
||||||
@@ -193,7 +198,7 @@ void CMApache :: DyingThink( void )
|
|||||||
MESSAGE_END();
|
MESSAGE_END();
|
||||||
|
|
||||||
if (g_sModelIndexSmoke == 0)
|
if (g_sModelIndexSmoke == 0)
|
||||||
g_sModelIndexSmoke = PRECACHE_MODEL ("sprites/steam1.spr"); // smoke
|
g_sModelIndexSmoke = PRECACHE_MODELINDEX("sprites/steam1.spr"); // smoke
|
||||||
|
|
||||||
// lots of smoke
|
// lots of smoke
|
||||||
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
||||||
@@ -419,7 +424,7 @@ void CMApache :: HuntThink( void )
|
|||||||
|
|
||||||
// if (m_hEnemy == NULL)
|
// if (m_hEnemy == NULL)
|
||||||
{
|
{
|
||||||
Look( 4092 );
|
Look( 4096 );
|
||||||
m_hEnemy = BestVisibleEnemy( );
|
m_hEnemy = BestVisibleEnemy( );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -930,7 +935,7 @@ void CMApacheHVR :: Spawn( void )
|
|||||||
void CMApacheHVR :: Precache( void )
|
void CMApacheHVR :: Precache( void )
|
||||||
{
|
{
|
||||||
PRECACHE_MODEL("models/HVR.mdl");
|
PRECACHE_MODEL("models/HVR.mdl");
|
||||||
m_iTrail = PRECACHE_MODEL("sprites/smoke.spr");
|
m_iTrail = PRECACHE_MODELINDEX("sprites/smoke.spr");
|
||||||
PRECACHE_SOUND ("weapons/rocket1.wav");
|
PRECACHE_SOUND ("weapons/rocket1.wav");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -345,13 +345,13 @@ void CMBarney :: Spawn()
|
|||||||
// when a level is loaded, nobody will talk (time is reset to 0)
|
// when a level is loaded, nobody will talk (time is reset to 0)
|
||||||
TalkInit();
|
TalkInit();
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/barney.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/barney.mdl"));
|
||||||
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
pev->movetype = MOVETYPE_STEP;
|
pev->movetype = MOVETYPE_STEP;
|
||||||
m_bloodColor = BLOOD_COLOR_RED;
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
|
||||||
pev->health = gSkillData.barneyHealth;
|
if (!pev->health) { pev->health = gSkillData.barneyHealth; }
|
||||||
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
|
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
|
||||||
m_flFieldOfView = VIEW_FIELD_FULL;
|
m_flFieldOfView = VIEW_FIELD_FULL;
|
||||||
m_MonsterState = MONSTERSTATE_NONE;
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
|
|||||||
@@ -603,14 +603,14 @@ void CMBigMomma :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/big_mom.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/big_mom.mdl"));
|
||||||
// UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
|
// UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
|
||||||
UTIL_SetSize( pev, Vector( -64, -64, 0 ), Vector( 64, 64, 128 ) );
|
UTIL_SetSize( pev, Vector( -64, -64, 0 ), Vector( 64, 64, 128 ) );
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
pev->movetype = MOVETYPE_STEP;
|
pev->movetype = MOVETYPE_STEP;
|
||||||
m_bloodColor = BLOOD_COLOR_GREEN;
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
|
||||||
pev->health = 150 * gSkillData.bigmommaHealthFactor;
|
if (!pev->health) { pev->health = 150 * gSkillData.bigmommaHealthFactor; }
|
||||||
pev->view_ofs = Vector ( 0, 0, 128 );// position of the eyes relative to monster's origin.
|
pev->view_ofs = Vector ( 0, 0, 128 );// position of the eyes relative to monster's origin.
|
||||||
m_flFieldOfView = 0.3;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
m_flFieldOfView = 0.3;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
m_MonsterState = MONSTERSTATE_NONE;
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
@@ -648,8 +648,8 @@ void CMBigMomma :: Precache()
|
|||||||
|
|
||||||
// TEMP: Squid
|
// TEMP: Squid
|
||||||
PRECACHE_MODEL("sprites/mommaspit.spr");// spit projectile.
|
PRECACHE_MODEL("sprites/mommaspit.spr");// spit projectile.
|
||||||
gSpitSprite = PRECACHE_MODEL("sprites/mommaspout.spr");// client side spittle.
|
gSpitSprite = PRECACHE_MODELINDEX("sprites/mommaspout.spr");// client side spittle.
|
||||||
gSpitDebrisSprite = PRECACHE_MODEL("sprites/mommablob.spr" );
|
gSpitDebrisSprite = PRECACHE_MODELINDEX("sprites/mommablob.spr" );
|
||||||
|
|
||||||
PRECACHE_SOUND( "bullchicken/bc_acid1.wav" );
|
PRECACHE_SOUND( "bullchicken/bc_acid1.wav" );
|
||||||
PRECACHE_SOUND( "bullchicken/bc_spithit1.wav" );
|
PRECACHE_SOUND( "bullchicken/bc_spithit1.wav" );
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ public:
|
|||||||
void EXPORT Animate( void );
|
void EXPORT Animate( void );
|
||||||
|
|
||||||
int m_maxFrame;
|
int m_maxFrame;
|
||||||
|
EHANDLE m_hOwner;
|
||||||
};
|
};
|
||||||
|
|
||||||
void CSquidSpit:: Spawn( void )
|
void CSquidSpit:: Spawn( void )
|
||||||
@@ -110,6 +111,7 @@ void CSquidSpit::Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity
|
|||||||
UTIL_SetOrigin( pSpit->pev, vecStart );
|
UTIL_SetOrigin( pSpit->pev, vecStart );
|
||||||
pSpit->pev->velocity = vecVelocity;
|
pSpit->pev->velocity = vecVelocity;
|
||||||
pSpit->pev->owner = ENT(pevOwner);
|
pSpit->pev->owner = ENT(pevOwner);
|
||||||
|
pSpit->m_hOwner = ENT(pevOwner);
|
||||||
|
|
||||||
pSpit->SetThink ( &CSquidSpit::Animate );
|
pSpit->SetThink ( &CSquidSpit::Animate );
|
||||||
pSpit->pev->nextthink = gpGlobals->time + 0.1;
|
pSpit->pev->nextthink = gpGlobals->time + 0.1;
|
||||||
@@ -118,6 +120,9 @@ void CSquidSpit::Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity
|
|||||||
|
|
||||||
void CSquidSpit :: SpitTouch ( edict_t *pOther )
|
void CSquidSpit :: SpitTouch ( edict_t *pOther )
|
||||||
{
|
{
|
||||||
|
if (m_hOwner == NULL)
|
||||||
|
pev->owner = NULL;
|
||||||
|
|
||||||
TraceResult tr;
|
TraceResult tr;
|
||||||
int iPitch;
|
int iPitch;
|
||||||
|
|
||||||
@@ -166,6 +171,8 @@ void CSquidSpit :: SpitTouch ( edict_t *pOther )
|
|||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||||
pMonster->TakeDamage ( pev, pev, gSkillData.bullsquidDmgSpit, DMG_GENERIC );
|
pMonster->TakeDamage ( pev, pev, gSkillData.bullsquidDmgSpit, DMG_GENERIC );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
UTIL_TakeDamageExternal( pOther, pev, pev, gSkillData.bullsquidDmgSpit, DMG_GENERIC );
|
||||||
}
|
}
|
||||||
|
|
||||||
SetThink ( &CSquidSpit::SUB_Remove );
|
SetThink ( &CSquidSpit::SUB_Remove );
|
||||||
@@ -608,14 +615,14 @@ void CMBullsquid :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/bullsquid.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/bullsquid.mdl"));
|
||||||
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
|
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
pev->movetype = MOVETYPE_STEP;
|
pev->movetype = MOVETYPE_STEP;
|
||||||
m_bloodColor = BLOOD_COLOR_GREEN;
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
|
||||||
pev->effects = 0;
|
pev->effects = 0;
|
||||||
pev->health = gSkillData.bullsquidHealth;
|
if (!pev->health) { pev->health = gSkillData.bullsquidHealth; }
|
||||||
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
m_MonsterState = MONSTERSTATE_NONE;
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
|
|
||||||
@@ -640,7 +647,7 @@ void CMBullsquid :: Precache()
|
|||||||
|
|
||||||
PRECACHE_MODEL("sprites/bigspit.spr");// spit projectile.
|
PRECACHE_MODEL("sprites/bigspit.spr");// spit projectile.
|
||||||
|
|
||||||
iSquidSpitSprite = PRECACHE_MODEL("sprites/tinyspit.spr");// client side spittle.
|
iSquidSpitSprite = PRECACHE_MODELINDEX("sprites/tinyspit.spr");// client side spittle.
|
||||||
|
|
||||||
PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event
|
PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
#include "cmbase.h"
|
#include "cmbase.h"
|
||||||
#include "decals.h"
|
#include "decals.h"
|
||||||
|
|
||||||
|
void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd );
|
||||||
|
|
||||||
extern Vector VecBModelOrigin( entvars_t* pevBModel );
|
extern Vector VecBModelOrigin( entvars_t* pevBModel );
|
||||||
extern DLL_GLOBAL Vector g_vecAttackDir;
|
extern DLL_GLOBAL Vector g_vecAttackDir;
|
||||||
|
|
||||||
@@ -103,6 +105,15 @@ edict_t *CMBaseEntity::CreateEntity(char *classname)
|
|||||||
return pent;
|
return pent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// process entvar keyvalue
|
||||||
|
void CMBaseEntity :: KeyValue( KeyValueData* pkvd )
|
||||||
|
{
|
||||||
|
if ( !pev || !pkvd )
|
||||||
|
return;
|
||||||
|
|
||||||
|
EntvarsKeyvalue( pev, pkvd );
|
||||||
|
}
|
||||||
|
|
||||||
// give health
|
// give health
|
||||||
int CMBaseEntity :: TakeHealth( float flHealth, int bitsDamageType )
|
int CMBaseEntity :: TakeHealth( float flHealth, int bitsDamageType )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ CMBaseEntity
|
|||||||
// C functions for external declarations that call the appropriate C++ methods
|
// C functions for external declarations that call the appropriate C++ methods
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define EXPORT _declspec( dllexport )
|
#define EXPORT __declspec( dllexport )
|
||||||
#else
|
#else
|
||||||
#define EXPORT /* */
|
#define EXPORT /* */
|
||||||
#endif
|
#endif
|
||||||
@@ -80,6 +80,8 @@ typedef void (CMBaseEntity::*USEPTR)( edict_t *pActivator, edict_t *pCaller, USE
|
|||||||
#define CLASS_PLAYER_ALLY 11
|
#define CLASS_PLAYER_ALLY 11
|
||||||
#define CLASS_PLAYER_BIOWEAPON 12 // hornets and snarks.launched by players
|
#define CLASS_PLAYER_BIOWEAPON 12 // hornets and snarks.launched by players
|
||||||
#define CLASS_ALIEN_BIOWEAPON 13 // hornets and snarks.launched by the alien menace
|
#define CLASS_ALIEN_BIOWEAPON 13 // hornets and snarks.launched by the alien menace
|
||||||
|
#define CLASS_RACEX_PITDRONE 14
|
||||||
|
#define CLASS_RACEX_SHOCK 15
|
||||||
#define CLASS_BARNACLE 99 // special because no one pays attention to it, and it eats a wide cross-section of creatures.
|
#define CLASS_BARNACLE 99 // special because no one pays attention to it, and it eats a wide cross-section of creatures.
|
||||||
|
|
||||||
class CMBaseEntity;
|
class CMBaseEntity;
|
||||||
@@ -132,7 +134,7 @@ public:
|
|||||||
// initialization functions
|
// initialization functions
|
||||||
virtual void Spawn( void ) { return; }
|
virtual void Spawn( void ) { return; }
|
||||||
virtual void Precache( void ) { return; }
|
virtual void Precache( void ) { return; }
|
||||||
virtual void KeyValue( KeyValueData* pkvd) { pkvd->fHandled = FALSE; }
|
virtual void KeyValue( KeyValueData* pkvd );
|
||||||
virtual int ObjectCaps( void ) { return FCAP_ACROSS_TRANSITION; }
|
virtual int ObjectCaps( void ) { return FCAP_ACROSS_TRANSITION; }
|
||||||
virtual void Activate( void ) {}
|
virtual void Activate( void ) {}
|
||||||
|
|
||||||
@@ -599,7 +601,6 @@ template <class T> T * CreateClassPtr( T *a )
|
|||||||
// store the class pointer in the array here!!!
|
// store the class pointer in the array here!!!
|
||||||
monsters[monster_index].monster_index = edict_index;
|
monsters[monster_index].monster_index = edict_index;
|
||||||
monsters[monster_index].monster_pent = temp_edict;
|
monsters[monster_index].monster_pent = temp_edict;
|
||||||
monsters[monster_index].respawn_index = -1;
|
|
||||||
monsters[monster_index].pMonster = (CMBaseMonster *)a;
|
monsters[monster_index].pMonster = (CMBaseMonster *)a;
|
||||||
|
|
||||||
// get the private data
|
// get the private data
|
||||||
@@ -607,3 +608,7 @@ template <class T> T * CreateClassPtr( T *a )
|
|||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef GLOBALREPLACE_H
|
||||||
|
#include "globalreplace.h"
|
||||||
|
#endif
|
||||||
|
|||||||
104
src/dlls/cmbaseextra.h
Normal file
104
src/dlls/cmbaseextra.h
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#ifndef BASEEXTRA_H
|
||||||
|
#define BASEEXTRA_H
|
||||||
|
|
||||||
|
// any extra entities created in this project that aren't
|
||||||
|
// monsters will go here
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// MonsterMaker - this ent creates monsters during the game.
|
||||||
|
//=========================================================
|
||||||
|
class CMMonsterMaker : public CMBaseMonster
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn( void );
|
||||||
|
void Precache( void );
|
||||||
|
void KeyValue( KeyValueData* pkvd);
|
||||||
|
void EXPORT ToggleUse ( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value );
|
||||||
|
void EXPORT CyclicUse ( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value );
|
||||||
|
void EXPORT MakerThink ( void );
|
||||||
|
void DeathNotice ( entvars_t *pevChild );// monster maker children use this to tell the monster maker that they have died.
|
||||||
|
void MakeMonster( void );
|
||||||
|
|
||||||
|
int m_iMonsterIndex;// index of the monster(s) that will be created.
|
||||||
|
string_t m_iszCustomModel;// custom model that the monster will use.
|
||||||
|
int m_iMonsterBlood;//blood color of spawned monsters.
|
||||||
|
|
||||||
|
int m_cNumMonsters;// max number of monsters this ent can create
|
||||||
|
int m_iMaxLiveChildren;// max number of monsters that this maker may have out at one time.
|
||||||
|
|
||||||
|
int m_cLiveChildren;// how many monsters made by this monster maker that are currently alive
|
||||||
|
|
||||||
|
float m_flGround; // z coord of the ground under me, used to make sure no monsters are under the maker when it drops a new child
|
||||||
|
|
||||||
|
BOOL m_fActive;
|
||||||
|
BOOL m_fFadeChildren;// should we make the children fadeout?
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Ambient Music - Plays an mp3 music file to players.
|
||||||
|
//=========================================================
|
||||||
|
class CMAmbientMusic : public CMBaseMonster
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn(void);
|
||||||
|
//void Precache(void); // accessed before entvars are valid, manual precache in monster_config.cpp
|
||||||
|
void KeyValue(KeyValueData* pkvd);
|
||||||
|
void EXPORT MusicUse(edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value);
|
||||||
|
|
||||||
|
BOOL m_fPlaying; // music is active
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// XenMaker - spawns a monster with a teleportation effect.
|
||||||
|
//=========================================================
|
||||||
|
class CMXenMaker : public CMBaseMonster
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn(void);
|
||||||
|
void Precache(void);
|
||||||
|
void KeyValue(KeyValueData* pkvd);
|
||||||
|
void EXPORT CyclicUse(edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value);
|
||||||
|
void EXPORT RetryThink(void);
|
||||||
|
void StartEffect(void);
|
||||||
|
void EXPORT MiddleEffect(void);
|
||||||
|
void EXPORT EndEffect(void);
|
||||||
|
|
||||||
|
int m_iMonsterIndex;// index of the monster that will be created.
|
||||||
|
|
||||||
|
float m_flBeamRadius; // Maximum beam strike radius.
|
||||||
|
int m_iBeamAlpha;
|
||||||
|
int m_iBeamCount; // Number of single beam instances.
|
||||||
|
Vector m_vBeamColor;
|
||||||
|
|
||||||
|
float m_flLightRadius;
|
||||||
|
Vector m_vLightColor;
|
||||||
|
|
||||||
|
float m_flStartSpriteFramerate;
|
||||||
|
float m_flStartSpriteScale;
|
||||||
|
int m_iStartSpriteAlpha;
|
||||||
|
Vector m_vStartSpriteColor;
|
||||||
|
|
||||||
|
float m_flEndSpriteFramerate;
|
||||||
|
float m_flEndSpriteScale;
|
||||||
|
int m_iEndSpriteAlpha;
|
||||||
|
Vector m_vEndSpriteColor;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SpawnBeam(void);
|
||||||
|
int m_iBeamIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Set CVar - Adjust a map CVar when triggered.
|
||||||
|
//=========================================================
|
||||||
|
class CMSetCVar : public CMBaseMonster
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn(void);
|
||||||
|
void KeyValue(KeyValueData* pkvd);
|
||||||
|
void EXPORT ActUse(edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value);
|
||||||
|
|
||||||
|
string_t m_iszCVarToChange;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BASEEXTRA_H
|
||||||
@@ -105,6 +105,11 @@ public:
|
|||||||
string_t m_szMonsterName; // Monster name to display on HUD
|
string_t m_szMonsterName; // Monster name to display on HUD
|
||||||
int m_iClassifyOverride; // Overriden classification for this monster
|
int m_iClassifyOverride; // Overriden classification for this monster
|
||||||
|
|
||||||
|
REPLACER::REPLACER *m_srSoundList; // individual sound replacements for this monster
|
||||||
|
int m_isrSounds; // number of replaced sounds
|
||||||
|
|
||||||
|
float m_flLastYawTime;
|
||||||
|
|
||||||
void KeyValue( KeyValueData *pkvd );
|
void KeyValue( KeyValueData *pkvd );
|
||||||
|
|
||||||
// monster use function
|
// monster use function
|
||||||
@@ -134,6 +139,8 @@ public:
|
|||||||
virtual void MonsterThink( void );
|
virtual void MonsterThink( void );
|
||||||
void EXPORT CallMonsterThink( void ) { this->MonsterThink(); }
|
void EXPORT CallMonsterThink( void ) { this->MonsterThink(); }
|
||||||
virtual int IRelationship ( CMBaseEntity *pTarget );
|
virtual int IRelationship ( CMBaseEntity *pTarget );
|
||||||
|
virtual int IRelationship ( int iTargetClass );
|
||||||
|
int IRelationshipByClass ( int iClass );
|
||||||
virtual void MonsterInit ( void );
|
virtual void MonsterInit ( void );
|
||||||
virtual void MonsterInitDead( void ); // Call after animation/pose is set up
|
virtual void MonsterInitDead( void ); // Call after animation/pose is set up
|
||||||
virtual void BecomeDead( void );
|
virtual void BecomeDead( void );
|
||||||
@@ -213,7 +220,7 @@ public:
|
|||||||
void AdvanceRoute ( float distance );
|
void AdvanceRoute ( float distance );
|
||||||
virtual BOOL FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, edict_t *pTargetEnt, Vector *pApex );
|
virtual BOOL FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, edict_t *pTargetEnt, Vector *pApex );
|
||||||
void MakeIdealYaw( Vector vecTarget );
|
void MakeIdealYaw( Vector vecTarget );
|
||||||
virtual void SetYawSpeed ( void ) { return; };// allows different yaw_speeds for each activity
|
virtual void SetYawSpeed ( void ) { return; }; // allows different yaw_speeds for each activity
|
||||||
BOOL BuildRoute ( const Vector &vecGoal, int iMoveFlag, edict_t *pTarget );
|
BOOL BuildRoute ( const Vector &vecGoal, int iMoveFlag, edict_t *pTarget );
|
||||||
virtual BOOL BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist );
|
virtual BOOL BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist );
|
||||||
int RouteClassify( int iMoveFlag );
|
int RouteClassify( int iMoveFlag );
|
||||||
@@ -347,7 +354,7 @@ public:
|
|||||||
|
|
||||||
virtual float GetDamageAmount( void ) { return gSkillData.headcrabDmgBite; }
|
virtual float GetDamageAmount( void ) { return gSkillData.headcrabDmgBite; }
|
||||||
virtual int GetVoicePitch( void ) { return 100; }
|
virtual int GetVoicePitch( void ) { return 100; }
|
||||||
virtual float GetSoundVolue( void ) { return 1.0; }
|
virtual float GetSoundVolume( void ) { return 1.0; }
|
||||||
Schedule_t* GetScheduleOfType ( int Type );
|
Schedule_t* GetScheduleOfType ( int Type );
|
||||||
|
|
||||||
CUSTOM_SCHEDULES;
|
CUSTOM_SCHEDULES;
|
||||||
@@ -370,7 +377,7 @@ public:
|
|||||||
BOOL CheckRangeAttack1 ( float flDot, float flDist );
|
BOOL CheckRangeAttack1 ( float flDot, float flDist );
|
||||||
Schedule_t* GetScheduleOfType ( int Type );
|
Schedule_t* GetScheduleOfType ( int Type );
|
||||||
virtual int GetVoicePitch( void ) { return PITCH_NORM + RANDOM_LONG(40,50); }
|
virtual int GetVoicePitch( void ) { return PITCH_NORM + RANDOM_LONG(40,50); }
|
||||||
virtual float GetSoundVolue( void ) { return 0.8; }
|
virtual float GetSoundVolume( void ) { return 0.8; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -625,6 +632,7 @@ public:
|
|||||||
void IdleSound( void );
|
void IdleSound( void );
|
||||||
|
|
||||||
void Killed( entvars_t *pevAttacker, int iGib );
|
void Killed( entvars_t *pevAttacker, int iGib );
|
||||||
|
void UpdateOnRemove();
|
||||||
|
|
||||||
void StartTask ( Task_t *pTask );
|
void StartTask ( Task_t *pTask );
|
||||||
Schedule_t *GetSchedule( void );
|
Schedule_t *GetSchedule( void );
|
||||||
@@ -727,6 +735,7 @@ public:
|
|||||||
static const char *pAttackHitSounds[];
|
static const char *pAttackHitSounds[];
|
||||||
static const char *pAttackMissSounds[];
|
static const char *pAttackMissSounds[];
|
||||||
static const char *pAttackSounds[];
|
static const char *pAttackSounds[];
|
||||||
|
static const char *pFireSounds[];
|
||||||
static const char *pDieSounds[];
|
static const char *pDieSounds[];
|
||||||
static const char *pPainSounds[];
|
static const char *pPainSounds[];
|
||||||
static const char *pIdleSounds[];
|
static const char *pIdleSounds[];
|
||||||
@@ -1087,6 +1096,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
edict_t *GargantuaCheckTraceHullAttack(float flDist, int iDamage, int iDmgType);
|
edict_t *GargantuaCheckTraceHullAttack(float flDist, int iDamage, int iDmgType);
|
||||||
|
|
||||||
|
protected:
|
||||||
CMSprite *m_pEyeGlow; // Glow around the eyes
|
CMSprite *m_pEyeGlow; // Glow around the eyes
|
||||||
CMBeam *m_pFlame[4]; // Flame beams
|
CMBeam *m_pFlame[4]; // Flame beams
|
||||||
|
|
||||||
@@ -1237,4 +1247,480 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// opposing force monsters
|
||||||
|
//
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Gonome's guts projectile
|
||||||
|
//=========================================================
|
||||||
|
class CGonomeGuts : public CMBaseEntity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn( void );
|
||||||
|
|
||||||
|
static edict_t *Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity );
|
||||||
|
void GutsTouch( edict_t *pOther );
|
||||||
|
void EXPORT Animate( void );
|
||||||
|
|
||||||
|
int m_maxFrame;
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Gonome
|
||||||
|
//=========================================================
|
||||||
|
class CMGonome : public CMBaseMonster
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
void Spawn(void);
|
||||||
|
void Precache(void);
|
||||||
|
|
||||||
|
int Classify(void);
|
||||||
|
void SetYawSpeed();
|
||||||
|
void HandleAnimEvent(MonsterEvent_t *pEvent);
|
||||||
|
int IgnoreConditions();
|
||||||
|
void IdleSound( void );
|
||||||
|
void PainSound( void );
|
||||||
|
void DeathSound( void );
|
||||||
|
void AlertSound( void );
|
||||||
|
void StartTask(Task_t *pTask);
|
||||||
|
|
||||||
|
BOOL CheckMeleeAttack2(float flDot, float flDist);
|
||||||
|
BOOL CheckRangeAttack1(float flDot, float flDist);
|
||||||
|
void SetActivity( Activity NewActivity );
|
||||||
|
|
||||||
|
Schedule_t *GetSchedule();
|
||||||
|
Schedule_t *GetScheduleOfType( int Type );
|
||||||
|
void RunTask(Task_t* pTask);
|
||||||
|
|
||||||
|
int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType);
|
||||||
|
void Killed(entvars_t *pevAttacker, int iGib);
|
||||||
|
|
||||||
|
void UnlockPlayer();
|
||||||
|
CGonomeGuts* GetGonomeGuts(entvars_t *pevOwner, const Vector& pos);
|
||||||
|
void ClearGuts();
|
||||||
|
|
||||||
|
CUSTOM_SCHEDULES;
|
||||||
|
|
||||||
|
static const char* pPainSounds[];
|
||||||
|
static const char* pIdleSounds[];
|
||||||
|
static const char* pDeathSounds[];
|
||||||
|
static const char *pAttackHitSounds[];
|
||||||
|
static const char *pAttackMissSounds[];
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float m_flNextFlinch;
|
||||||
|
float m_flNextThrowTime;// last time the gonome used the guts attack.
|
||||||
|
CGonomeGuts* m_pGonomeGuts;
|
||||||
|
|
||||||
|
BOOL m_fPlayerLocked;
|
||||||
|
EHANDLE m_lockedPlayer;
|
||||||
|
|
||||||
|
bool m_meleeAttack2;
|
||||||
|
bool m_playedAttackSound;
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Male Assassin
|
||||||
|
//=========================================================
|
||||||
|
class CMMassn : public CMHGrunt
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int Classify(void);
|
||||||
|
void HandleAnimEvent(MonsterEvent_t *pEvent);
|
||||||
|
void Sniperrifle(void);
|
||||||
|
|
||||||
|
BOOL FOkToSpeak(void);
|
||||||
|
|
||||||
|
void Spawn( void );
|
||||||
|
void Precache( void );
|
||||||
|
|
||||||
|
void DeathSound(void);
|
||||||
|
void PainSound(void);
|
||||||
|
void IdleSound(void);
|
||||||
|
|
||||||
|
void SetActivity(Activity NewActivity);
|
||||||
|
Schedule_t *GetScheduleOfType( int Type );
|
||||||
|
|
||||||
|
CUSTOM_SCHEDULES;
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Otis
|
||||||
|
//=========================================================
|
||||||
|
class CMOtis : public CMBarney
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void KeyValue(KeyValueData *pkvd);
|
||||||
|
|
||||||
|
void Spawn(void);
|
||||||
|
void Precache(void);
|
||||||
|
void BarneyFirePistol(void);
|
||||||
|
void AlertSound(void);
|
||||||
|
void HandleAnimEvent(MonsterEvent_t *pEvent);
|
||||||
|
|
||||||
|
int TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType);
|
||||||
|
|
||||||
|
// Override these to set behavior
|
||||||
|
Schedule_t *GetSchedule(void);
|
||||||
|
|
||||||
|
void TalkInit(void);
|
||||||
|
void TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
|
||||||
|
void Killed(entvars_t *pevAttacker, int iGib);
|
||||||
|
|
||||||
|
int head;
|
||||||
|
int bodystate;
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Pit Drone's spit projectile
|
||||||
|
//=========================================================
|
||||||
|
class CPitdroneSpike : public CMBaseEntity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn(void);
|
||||||
|
void EXPORT SpikeTouch(edict_t *pOther);
|
||||||
|
void EXPORT StartTrail();
|
||||||
|
static edict_t *Shoot(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, Vector vecAngles);
|
||||||
|
|
||||||
|
EHANDLE m_hOwner;
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Pit Drone
|
||||||
|
//=========================================================
|
||||||
|
class CMPitdrone : public CMBaseMonster
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn(void);
|
||||||
|
void Precache(void);
|
||||||
|
void HandleAnimEvent(MonsterEvent_t *pEvent);
|
||||||
|
void SetYawSpeed(void);
|
||||||
|
int ISoundMask();
|
||||||
|
void KeyValue(KeyValueData *pkvd);
|
||||||
|
|
||||||
|
int Classify(void);
|
||||||
|
|
||||||
|
BOOL CheckMeleeAttack1(float flDot, float flDist);
|
||||||
|
BOOL CheckRangeAttack1(float flDot, float flDist);
|
||||||
|
void IdleSound(void);
|
||||||
|
void PainSound(void);
|
||||||
|
void AlertSound(void);
|
||||||
|
void DeathSound(void);
|
||||||
|
void BodyChange(float spikes);
|
||||||
|
int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType);
|
||||||
|
int IgnoreConditions(void);
|
||||||
|
Schedule_t* GetSchedule(void);
|
||||||
|
Schedule_t* GetScheduleOfType(int Type);
|
||||||
|
void StartTask(Task_t *pTask);
|
||||||
|
void RunTask(Task_t *pTask);
|
||||||
|
void RunAI(void);
|
||||||
|
void CheckAmmo();
|
||||||
|
void GibMonster();
|
||||||
|
CUSTOM_SCHEDULES;
|
||||||
|
|
||||||
|
float m_flLastHurtTime;
|
||||||
|
float m_flNextSpitTime;// last time the PitDrone used the spit attack.
|
||||||
|
float m_flNextFlinch;
|
||||||
|
int m_iInitialAmmo;
|
||||||
|
bool shouldAttackWithLeftClaw;
|
||||||
|
|
||||||
|
static const char *pIdleSounds[];
|
||||||
|
static const char *pAlertSounds[];
|
||||||
|
static const char *pPainSounds[];
|
||||||
|
static const char *pDieSounds[];
|
||||||
|
static const char *pAttackMissSounds[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Shock Roach
|
||||||
|
//=========================================================
|
||||||
|
class CMShockRoach : public CMHeadCrab
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn(void);
|
||||||
|
void Precache(void);
|
||||||
|
void EXPORT LeapTouch(edict_t *pOther);
|
||||||
|
void PainSound(void);
|
||||||
|
void DeathSound(void);
|
||||||
|
void IdleSound(void);
|
||||||
|
void AlertSound(void);
|
||||||
|
void MonsterThink(void);
|
||||||
|
void StartTask(Task_t* pTask);
|
||||||
|
void HandleAnimEvent(MonsterEvent_t *pEvent);
|
||||||
|
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
|
||||||
|
|
||||||
|
static const char *pIdleSounds[];
|
||||||
|
static const char *pAlertSounds[];
|
||||||
|
static const char *pPainSounds[];
|
||||||
|
static const char *pAttackSounds[];
|
||||||
|
static const char *pDeathSounds[];
|
||||||
|
static const char *pBiteSounds[];
|
||||||
|
|
||||||
|
float m_flBirthTime;
|
||||||
|
BOOL m_fRoachSolid;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void AttackSound();
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Shock Trooper
|
||||||
|
//=========================================================
|
||||||
|
class CMStrooper : public CMHGrunt
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn(void);
|
||||||
|
void MonsterThink();
|
||||||
|
void Precache(void);
|
||||||
|
int Classify(void);
|
||||||
|
BOOL CheckRangeAttack1(float flDot, float flDist);
|
||||||
|
BOOL CheckRangeAttack2(float flDot, float flDist);
|
||||||
|
void HandleAnimEvent(MonsterEvent_t *pEvent);
|
||||||
|
void SetObjectCollisionBox( void )
|
||||||
|
{
|
||||||
|
pev->absmin = pev->origin + Vector( -24, -24, 0 );
|
||||||
|
pev->absmax = pev->origin + Vector( 24, 24, 72 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetActivity(Activity NewActivity);
|
||||||
|
|
||||||
|
void DeathSound(void);
|
||||||
|
void PainSound(void);
|
||||||
|
void IdleSound(void);
|
||||||
|
void GibMonster(void);
|
||||||
|
|
||||||
|
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
|
||||||
|
|
||||||
|
void DropShockRoach(bool gibbed);
|
||||||
|
|
||||||
|
Schedule_t *GetSchedule(void);
|
||||||
|
Schedule_t *GetScheduleOfType(int Type);
|
||||||
|
|
||||||
|
void SpeakSentence();
|
||||||
|
|
||||||
|
BOOL m_fRightClaw;
|
||||||
|
float m_rechargeTime;
|
||||||
|
float m_blinkTime;
|
||||||
|
float m_eyeChangeTime;
|
||||||
|
|
||||||
|
static const char *pGruntSentences[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Voltigore's energy ball projectile
|
||||||
|
//=========================================================
|
||||||
|
#define VOLTIGORE_MAX_BEAMS 8
|
||||||
|
class CMVoltigoreEnergyBall : public CMBaseEntity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn(void);
|
||||||
|
|
||||||
|
static edict_t *Shoot(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity);
|
||||||
|
void EXPORT BallTouch(edict_t *pOther);
|
||||||
|
void EXPORT FlyThink(void);
|
||||||
|
|
||||||
|
void CreateBeams();
|
||||||
|
void ClearBeams();
|
||||||
|
void UpdateBeams();
|
||||||
|
|
||||||
|
CMBeam* m_pBeam[VOLTIGORE_MAX_BEAMS];
|
||||||
|
int m_iBeams;
|
||||||
|
float m_timeToDie;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void CreateBeam(int nIndex, const Vector& vecPos, int width, int brightness);
|
||||||
|
void UpdateBeam(int nIndex, const Vector& vecPos, bool show);
|
||||||
|
void ClearBeam(int nIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Voltigore
|
||||||
|
//=========================================================
|
||||||
|
class CMVoltigore : public CMBaseMonster
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void Spawn(void);
|
||||||
|
virtual void Precache(void);
|
||||||
|
void SetYawSpeed(void);
|
||||||
|
virtual int Classify(void);
|
||||||
|
virtual void HandleAnimEvent(MonsterEvent_t *pEvent);
|
||||||
|
virtual void IdleSound(void);
|
||||||
|
virtual void PainSound(void);
|
||||||
|
virtual void DeathSound(void);
|
||||||
|
virtual void AlertSound(void);
|
||||||
|
void AttackSound(void);
|
||||||
|
virtual void StartTask(Task_t *pTask);
|
||||||
|
virtual BOOL CheckMeleeAttack1(float flDot, float flDist);
|
||||||
|
virtual BOOL CheckRangeAttack1(float flDot, float flDist);
|
||||||
|
virtual void RunAI(void);
|
||||||
|
virtual void GibMonster();
|
||||||
|
Schedule_t *GetSchedule(void);
|
||||||
|
Schedule_t *GetScheduleOfType(int Type);
|
||||||
|
virtual int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType);
|
||||||
|
virtual void Killed(entvars_t *pevAttacker, int iGib);
|
||||||
|
void UpdateOnRemove();
|
||||||
|
|
||||||
|
CUSTOM_SCHEDULES
|
||||||
|
|
||||||
|
float m_flNextZapTime; // last time the voltigore used the spit attack.
|
||||||
|
BOOL m_fShouldUpdateBeam;
|
||||||
|
CMBeam* m_pBeam[3];
|
||||||
|
CMSprite* m_pBeamGlow;
|
||||||
|
int m_glowBrightness;
|
||||||
|
|
||||||
|
static const char* pAlertSounds[];
|
||||||
|
static const char* pAttackMeleeSounds[];
|
||||||
|
static const char* pMeleeHitSounds[];
|
||||||
|
static const char* pMeleeMissSounds[];
|
||||||
|
static const char* pComSounds[];
|
||||||
|
static const char* pDeathSounds[];
|
||||||
|
static const char* pFootstepSounds[];
|
||||||
|
static const char* pIdleSounds[];
|
||||||
|
static const char* pPainSounds[];
|
||||||
|
static const char* pGruntSounds[];
|
||||||
|
|
||||||
|
void CreateBeams();
|
||||||
|
void DestroyBeams();
|
||||||
|
void UpdateBeams();
|
||||||
|
|
||||||
|
void CreateGlow();
|
||||||
|
void DestroyGlow();
|
||||||
|
void GlowUpdate();
|
||||||
|
void GlowOff(void);
|
||||||
|
void GlowOn(int level);
|
||||||
|
protected:
|
||||||
|
void GibBeamDamage();
|
||||||
|
void PrecacheImpl(char* modelName);
|
||||||
|
int m_beamTexture;
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Baby Voltigore
|
||||||
|
//=========================================================
|
||||||
|
class CMBabyVoltigore : public CMVoltigore
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn(void);
|
||||||
|
void Precache(void);
|
||||||
|
void HandleAnimEvent(MonsterEvent_t* pEvent);
|
||||||
|
BOOL CheckMeleeAttack1(float flDot, float flDist);
|
||||||
|
BOOL CheckRangeAttack1(float flDot, float flDist);
|
||||||
|
void StartTask(Task_t *pTask);
|
||||||
|
void Killed(entvars_t *pevAttacker, int iGib);
|
||||||
|
void GibMonster();
|
||||||
|
Schedule_t* GetSchedule();
|
||||||
|
Schedule_t* GetScheduleOfType(int Type);
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// sven co-op monsters
|
||||||
|
//
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Baby Gargantua
|
||||||
|
//=========================================================
|
||||||
|
class CMBabyGargantua : public CMGargantua
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn( void );
|
||||||
|
void Precache( void );
|
||||||
|
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
|
||||||
|
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
|
||||||
|
void HandleAnimEvent( MonsterEvent_t *pEvent );
|
||||||
|
|
||||||
|
BOOL CheckMeleeAttack1( float flDot, float flDist ); // Swipe
|
||||||
|
BOOL CheckMeleeAttack2( float flDot, float flDist ); // Flames
|
||||||
|
BOOL CheckRangeAttack1( float flDot, float flDist ); // Stomp attack
|
||||||
|
|
||||||
|
void StartTask( Task_t *pTask );
|
||||||
|
void RunTask( Task_t *pTask );
|
||||||
|
|
||||||
|
void StompAttack( void );
|
||||||
|
void FlameCreate( void );
|
||||||
|
void FlameUpdate( void );
|
||||||
|
void FlameDestroy( void );
|
||||||
|
|
||||||
|
static const char *pBeamAttackSounds[];
|
||||||
|
static const char *pFootSounds[];
|
||||||
|
static const char *pIdleSounds[];
|
||||||
|
static const char *pAlertSounds[];
|
||||||
|
static const char *pPainSounds[];
|
||||||
|
static const char *pAttackSounds[];
|
||||||
|
static const char *pStompSounds[];
|
||||||
|
static const char *pBreatheSounds[];
|
||||||
|
static const char *pDieSounds[];
|
||||||
|
|
||||||
|
private:
|
||||||
|
edict_t *BabyGargCheckTraceHullAttack(float flDist, int iDamage, int iDmgType);
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Heavy Weapons Grunt
|
||||||
|
//=========================================================
|
||||||
|
class CMHWGrunt : public CMHGrunt
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn( void );
|
||||||
|
void Precache( void );
|
||||||
|
int Classify(void);
|
||||||
|
|
||||||
|
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
|
||||||
|
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
|
||||||
|
|
||||||
|
void HandleAnimEvent(MonsterEvent_t *pEvent);
|
||||||
|
void SetActivity(Activity NewActivity);
|
||||||
|
|
||||||
|
Schedule_t *GetSchedule( void );
|
||||||
|
Schedule_t *GetScheduleOfType ( int Type );
|
||||||
|
|
||||||
|
BOOL CheckRangeAttack1( float flDot, float flDist );
|
||||||
|
BOOL CheckMeleeAttack1( float flDot, float flDist );
|
||||||
|
BOOL CheckRangeAttack2( float flDot, float flDist );
|
||||||
|
|
||||||
|
void Minigun(void);
|
||||||
|
|
||||||
|
CUSTOM_SCHEDULES
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Robo Grunt
|
||||||
|
//=========================================================
|
||||||
|
class CMRGrunt : public CMHGrunt
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int Classify(void);
|
||||||
|
|
||||||
|
void Spawn( void );
|
||||||
|
void Precache( void );
|
||||||
|
|
||||||
|
void DeathSound(void);
|
||||||
|
void PainSound(void);
|
||||||
|
|
||||||
|
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
|
||||||
|
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
|
||||||
|
|
||||||
|
void RunAI(void);
|
||||||
|
|
||||||
|
void Killed(entvars_t *pevAttacker, int iGib);
|
||||||
|
void GibMonster();
|
||||||
|
|
||||||
|
void EXPORT SparkTouch(edict_t *pOther);
|
||||||
|
void EXPORT StartGib(void);
|
||||||
|
|
||||||
|
float m_flNextSpark;
|
||||||
|
float m_flNextDischarge;
|
||||||
|
float m_flActiveDischarge;
|
||||||
|
|
||||||
|
int m_iBodyGibs;
|
||||||
|
|
||||||
|
static const char *pRobotSentences[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Looking for Stukabat? It's located in cmflyingmonster.h
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
#endif // BASEMONSTER_H
|
#endif // BASEMONSTER_H
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
#ifndef FLYINGMONSTER_H
|
#ifndef FLYINGMONSTER_H
|
||||||
#define FLYINGMONSTER_H
|
#define FLYINGMONSTER_H
|
||||||
|
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
|
||||||
class CMFlyingMonster : public CMBaseMonster
|
class CMFlyingMonster : public CMBaseMonster
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -49,5 +51,31 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Stukabat
|
||||||
|
//=========================================================
|
||||||
|
class CMStukabat : public CMFlyingMonster
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn( void );
|
||||||
|
void Precache( void );
|
||||||
|
void SetYawSpeed( void );
|
||||||
|
int Classify ( void );
|
||||||
|
|
||||||
|
void SetActivity ( Activity NewActivity );
|
||||||
|
void HandleAnimEvent( MonsterEvent_t *pEvent );
|
||||||
|
Schedule_t *GetScheduleOfType ( int Type );
|
||||||
|
|
||||||
|
int GetBitePitch( void ) { return PITCH_NORM + RANDOM_LONG( 40, 50 ); }
|
||||||
|
BOOL CheckRangeAttack1 ( float flDot, float flDist );
|
||||||
|
|
||||||
|
// Not used
|
||||||
|
BOOL CheckRangeAttack2 ( float flDot, float flDist ) { return FALSE; }
|
||||||
|
BOOL CheckMeleeAttack1 ( float flDot, float flDist ) { return FALSE; }
|
||||||
|
BOOL CheckMeleeAttack2 ( float flDot, float flDist ) { return FALSE; }
|
||||||
|
|
||||||
|
CUSTOM_SCHEDULES
|
||||||
|
};
|
||||||
|
|
||||||
#endif //FLYINGMONSTER_H
|
#endif //FLYINGMONSTER_H
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ public:
|
|||||||
int FIdleStare( void );
|
int FIdleStare( void );
|
||||||
int FIdleHello( void );
|
int FIdleHello( void );
|
||||||
void IdleHeadTurn( Vector &vecFriend );
|
void IdleHeadTurn( Vector &vecFriend );
|
||||||
int FOkToSpeak( void );
|
virtual int FOkToSpeak( void );
|
||||||
void TrySmellTalk( void );
|
void TrySmellTalk( void );
|
||||||
edict_t *EnumFriends( edict_t *pentPrevious, int listNumber, BOOL bTrace );
|
edict_t *EnumFriends( edict_t *pentPrevious, int listNumber, BOOL bTrace );
|
||||||
void AlertFriends( void );
|
void AlertFriends( void );
|
||||||
|
|||||||
@@ -30,8 +30,7 @@
|
|||||||
#include "weapons.h"
|
#include "weapons.h"
|
||||||
#include "func_break.h"
|
#include "func_break.h"
|
||||||
|
|
||||||
const Vector g_vecZero = Vector(0,0,0);
|
extern DLL_GLOBAL Vector g_vecAttackDir;
|
||||||
Vector g_vecAttackDir;
|
|
||||||
entvars_t *g_pevLastInflictor;
|
entvars_t *g_pevLastInflictor;
|
||||||
|
|
||||||
#define HUMAN_GIB_COUNT 6
|
#define HUMAN_GIB_COUNT 6
|
||||||
@@ -177,7 +176,15 @@ void CMGib :: SpawnHeadGib( entvars_t *pevVictim )
|
|||||||
pGib->LimitVelocity();
|
pGib->LimitVelocity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Overload
|
||||||
void CMGib :: SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human )
|
void CMGib :: SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human )
|
||||||
|
{
|
||||||
|
if ( human )
|
||||||
|
CMGib::SpawnRandomGibs( pevVictim, cGibs, "models/hgibs.mdl", human );
|
||||||
|
else
|
||||||
|
CMGib::SpawnRandomGibs( pevVictim, cGibs, "models/agibs.mdl", human );
|
||||||
|
}
|
||||||
|
void CMGib :: SpawnRandomGibs( entvars_t *pevVictim, int cGibs, const char *pGibModel, int human )
|
||||||
{
|
{
|
||||||
int cSplat;
|
int cSplat;
|
||||||
|
|
||||||
@@ -191,13 +198,13 @@ void CMGib :: SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human )
|
|||||||
if ( human )
|
if ( human )
|
||||||
{
|
{
|
||||||
// human pieces
|
// human pieces
|
||||||
pGib->Spawn( "models/hgibs.mdl" );
|
pGib->Spawn( pGibModel );
|
||||||
pGib->pev->body = RANDOM_LONG(1,HUMAN_GIB_COUNT-1);// start at one to avoid throwing random amounts of skulls (0th gib)
|
pGib->pev->body = RANDOM_LONG(1,HUMAN_GIB_COUNT-1);// start at one to avoid throwing random amounts of skulls (0th gib)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// aliens
|
// aliens
|
||||||
pGib->Spawn( "models/agibs.mdl" );
|
pGib->Spawn( pGibModel );
|
||||||
pGib->pev->body = RANDOM_LONG(0,ALIEN_GIB_COUNT-1);
|
pGib->pev->body = RANDOM_LONG(0,ALIEN_GIB_COUNT-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -610,14 +617,11 @@ void CMBaseMonster :: Killed( entvars_t *pevAttacker, int iGib )
|
|||||||
SetConditions( bits_COND_LIGHT_DAMAGE );
|
SetConditions( bits_COND_LIGHT_DAMAGE );
|
||||||
|
|
||||||
// tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality.
|
// tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality.
|
||||||
/*jlb monstermaker
|
|
||||||
CMBaseEntity *pOwner = CMBaseEntity::Instance(pev->owner);
|
CMBaseEntity *pOwner = CMBaseEntity::Instance(pev->owner);
|
||||||
if ( pOwner )
|
if ( pOwner )
|
||||||
{
|
{
|
||||||
//jlb it crashes here sometimes!!!
|
|
||||||
pOwner->DeathNotice( pev );
|
pOwner->DeathNotice( pev );
|
||||||
}
|
}
|
||||||
jlb*/
|
|
||||||
|
|
||||||
if ( ShouldGibMonster( iGib ) )
|
if ( ShouldGibMonster( iGib ) )
|
||||||
{
|
{
|
||||||
@@ -970,10 +974,15 @@ int CMBaseMonster :: DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAtta
|
|||||||
vecDir = Vector( 0, 0, 0 );
|
vecDir = Vector( 0, 0, 0 );
|
||||||
if (!FNullEnt( pevInflictor ))
|
if (!FNullEnt( pevInflictor ))
|
||||||
{
|
{
|
||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pevInflictor));
|
if (pevInflictor->euser4 != NULL)
|
||||||
if (pMonster)
|
|
||||||
{
|
{
|
||||||
vecDir = ( pMonster->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize();
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pevInflictor));
|
||||||
|
vecDir = (pMonster->Center() - Vector(0, 0, 10) - Center()).Normalize();
|
||||||
|
vecDir = g_vecAttackDir = vecDir.Normalize();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vecDir = (UTIL_Center(ENT(pevInflictor)) - Vector(0, 0, 10) - Center()).Normalize();
|
||||||
vecDir = g_vecAttackDir = vecDir.Normalize();
|
vecDir = g_vecAttackDir = vecDir.Normalize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1146,6 +1155,56 @@ void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacke
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
edict_t *pMonster = pEntity;
|
||||||
|
|
||||||
|
if ( iClassIgnore != CLASS_NONE && pMonster->v.iuser4 == iClassIgnore )
|
||||||
|
{// houndeyes don't hurt other houndeyes with their attack
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// blast's don't tavel into or out of water
|
||||||
|
if (bInWater && pEntity->v.waterlevel == 0)
|
||||||
|
continue;
|
||||||
|
if (!bInWater && pEntity->v.waterlevel == 3)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
vecSpot = UTIL_BodyTarget( pMonster, vecSrc );
|
||||||
|
|
||||||
|
UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pevInflictor), &tr );
|
||||||
|
|
||||||
|
if ( tr.flFraction == 1.0 || tr.pHit == pEntity )
|
||||||
|
{// the explosion can 'see' this entity, so hurt them!
|
||||||
|
if (tr.fStartSolid)
|
||||||
|
{
|
||||||
|
// if we're stuck inside them, fixup the position and distance
|
||||||
|
tr.vecEndPos = vecSrc;
|
||||||
|
tr.flFraction = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrease damage for an ent that's farther from the bomb.
|
||||||
|
flAdjustedDamage = ( vecSrc - tr.vecEndPos ).Length() * falloff;
|
||||||
|
flAdjustedDamage = flDamage - flAdjustedDamage;
|
||||||
|
|
||||||
|
if ( flAdjustedDamage < 0 )
|
||||||
|
{
|
||||||
|
flAdjustedDamage = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) );
|
||||||
|
if (tr.flFraction != 1.0)
|
||||||
|
{
|
||||||
|
ClearMultiDamage( );
|
||||||
|
UTIL_TraceAttack( pMonster, pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, bitsDamageType );
|
||||||
|
ApplyMultiDamage( pevInflictor, pevAttacker );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UTIL_TakeDamageExternal( pMonster, pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1199,6 +1258,8 @@ edict_t* CMBaseMonster :: CheckTraceHullAttack( float flDist, int iDamage, int i
|
|||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
|
||||||
pMonster->TakeDamage( pev, pev, iDamage, iDmgType );
|
pMonster->TakeDamage( pev, pev, iDamage, iDmgType );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
UTIL_TakeDamageExternal( pEntity, pev, pev, iDamage, iDmgType );
|
||||||
}
|
}
|
||||||
|
|
||||||
return pEntity;
|
return pEntity;
|
||||||
@@ -1266,32 +1327,32 @@ void CMBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vecto
|
|||||||
{
|
{
|
||||||
m_LastHitGroup = ptr->iHitgroup;
|
m_LastHitGroup = ptr->iHitgroup;
|
||||||
|
|
||||||
/*jlb
|
// do we need the hitboxes to be customizable? use vanilla HL skill.cfg for now
|
||||||
switch ( ptr->iHitgroup )
|
switch ( ptr->iHitgroup )
|
||||||
{
|
{
|
||||||
case HITGROUP_GENERIC:
|
case HITGROUP_GENERIC:
|
||||||
break;
|
break;
|
||||||
case HITGROUP_HEAD:
|
case HITGROUP_HEAD:
|
||||||
flDamage *= gSkillData.monHead;
|
flDamage *= 3; //gSkillData.monHead;
|
||||||
break;
|
break;
|
||||||
case HITGROUP_CHEST:
|
case HITGROUP_CHEST:
|
||||||
flDamage *= gSkillData.monChest;
|
flDamage *= 1; //gSkillData.monChest;
|
||||||
break;
|
break;
|
||||||
case HITGROUP_STOMACH:
|
case HITGROUP_STOMACH:
|
||||||
flDamage *= gSkillData.monStomach;
|
flDamage *= 1; //gSkillData.monStomach;
|
||||||
break;
|
break;
|
||||||
case HITGROUP_LEFTARM:
|
case HITGROUP_LEFTARM:
|
||||||
case HITGROUP_RIGHTARM:
|
case HITGROUP_RIGHTARM:
|
||||||
flDamage *= gSkillData.monArm;
|
flDamage *= 1; //gSkillData.monArm;
|
||||||
break;
|
break;
|
||||||
case HITGROUP_LEFTLEG:
|
case HITGROUP_LEFTLEG:
|
||||||
case HITGROUP_RIGHTLEG:
|
case HITGROUP_RIGHTLEG:
|
||||||
flDamage *= gSkillData.monLeg;
|
flDamage *= 1; //gSkillData.monLeg;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
jlb*/
|
|
||||||
SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood.
|
SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood.
|
||||||
TraceBleed( flDamage, vecDir, ptr, bitsDamageType );
|
TraceBleed( flDamage, vecDir, ptr, bitsDamageType );
|
||||||
AddMultiDamage( pevAttacker, this->edict(), flDamage, bitsDamageType );
|
AddMultiDamage( pevAttacker, this->edict(), flDamage, bitsDamageType );
|
||||||
@@ -1360,6 +1421,8 @@ void CMBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShootin
|
|||||||
case BULLET_MONSTER_MP5:
|
case BULLET_MONSTER_MP5:
|
||||||
case BULLET_MONSTER_9MM:
|
case BULLET_MONSTER_9MM:
|
||||||
case BULLET_MONSTER_12MM:
|
case BULLET_MONSTER_12MM:
|
||||||
|
case BULLET_MONSTER_762:
|
||||||
|
case BULLET_MONSTER_357:
|
||||||
default:
|
default:
|
||||||
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecTracerSrc );
|
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecTracerSrc );
|
||||||
WRITE_BYTE( TE_TRACER );
|
WRITE_BYTE( TE_TRACER );
|
||||||
@@ -1386,7 +1449,9 @@ void CMBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShootin
|
|||||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||||
DecalGunshot( &tr, iBulletType );
|
DecalGunshot( &tr, iBulletType );
|
||||||
}
|
}
|
||||||
else switch(iBulletType)
|
else
|
||||||
|
{
|
||||||
|
switch(iBulletType)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case BULLET_MONSTER_9MM:
|
case BULLET_MONSTER_9MM:
|
||||||
@@ -1412,6 +1477,20 @@ void CMBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShootin
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BULLET_MONSTER_762:
|
||||||
|
UTIL_TraceAttack(pPlayer, pevAttacker, gSkillData.monDmg762, vecDir, &tr, DMG_BULLET);
|
||||||
|
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||||
|
DecalGunshot( &tr, iBulletType );
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BULLET_MONSTER_357:
|
||||||
|
UTIL_TraceAttack(pPlayer, pevAttacker, gSkillData.monDmg357, vecDir, &tr, DMG_BULLET);
|
||||||
|
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||||
|
DecalGunshot( &tr, iBulletType );
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case BULLET_NONE: // FIX
|
case BULLET_NONE: // FIX
|
||||||
UTIL_TraceAttack(pPlayer, pevAttacker, 50, vecDir, &tr, DMG_CLUB);
|
UTIL_TraceAttack(pPlayer, pevAttacker, 50, vecDir, &tr, DMG_CLUB);
|
||||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||||
@@ -1424,7 +1503,8 @@ void CMBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShootin
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (tr.pHit->v.euser4 != NULL)
|
}
|
||||||
|
else if (tr.pHit->v.euser4 != NULL) // monstermod monster
|
||||||
{
|
{
|
||||||
CMBaseEntity *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit));
|
CMBaseEntity *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit));
|
||||||
|
|
||||||
@@ -1434,7 +1514,9 @@ void CMBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShootin
|
|||||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||||
DecalGunshot( &tr, iBulletType );
|
DecalGunshot( &tr, iBulletType );
|
||||||
}
|
}
|
||||||
else switch(iBulletType)
|
else
|
||||||
|
{
|
||||||
|
switch(iBulletType)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case BULLET_MONSTER_9MM:
|
case BULLET_MONSTER_9MM:
|
||||||
@@ -1460,6 +1542,20 @@ void CMBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShootin
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BULLET_MONSTER_762:
|
||||||
|
pMonster->TraceAttack(pevAttacker, gSkillData.monDmg762, vecDir, &tr, DMG_BULLET);
|
||||||
|
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||||
|
DecalGunshot( &tr, iBulletType );
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BULLET_MONSTER_357:
|
||||||
|
pMonster->TraceAttack(pevAttacker, gSkillData.monDmg357, vecDir, &tr, DMG_BULLET);
|
||||||
|
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||||
|
DecalGunshot( &tr, iBulletType );
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case BULLET_NONE: // FIX
|
case BULLET_NONE: // FIX
|
||||||
pMonster->TraceAttack(pevAttacker, 50, vecDir, &tr, DMG_CLUB);
|
pMonster->TraceAttack(pevAttacker, 50, vecDir, &tr, DMG_CLUB);
|
||||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||||
@@ -1473,6 +1569,72 @@ void CMBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShootin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else // normal game entity
|
||||||
|
{
|
||||||
|
edict_t *pMonster = tr.pHit;
|
||||||
|
|
||||||
|
if ( iDamage )
|
||||||
|
{
|
||||||
|
UTIL_TraceAttack(pMonster, pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ((iDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB) );
|
||||||
|
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||||
|
DecalGunshot( &tr, iBulletType );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch(iBulletType)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case BULLET_MONSTER_9MM:
|
||||||
|
UTIL_TraceAttack(pMonster, pevAttacker, gSkillData.monDmg9MM, vecDir, &tr, DMG_BULLET);
|
||||||
|
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||||
|
DecalGunshot( &tr, iBulletType );
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BULLET_MONSTER_MP5:
|
||||||
|
UTIL_TraceAttack(pMonster, pevAttacker, gSkillData.monDmgMP5, vecDir, &tr, DMG_BULLET);
|
||||||
|
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||||
|
DecalGunshot( &tr, iBulletType );
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BULLET_MONSTER_12MM:
|
||||||
|
UTIL_TraceAttack(pMonster, pevAttacker, gSkillData.monDmg12MM, vecDir, &tr, DMG_BULLET);
|
||||||
|
if ( !tracer )
|
||||||
|
{
|
||||||
|
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||||
|
DecalGunshot( &tr, iBulletType );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BULLET_MONSTER_762:
|
||||||
|
UTIL_TraceAttack(pMonster, pevAttacker, gSkillData.monDmg762, vecDir, &tr, DMG_BULLET);
|
||||||
|
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||||
|
DecalGunshot( &tr, iBulletType );
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BULLET_MONSTER_357:
|
||||||
|
UTIL_TraceAttack(pMonster, pevAttacker, gSkillData.monDmg357, vecDir, &tr, DMG_BULLET);
|
||||||
|
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||||
|
DecalGunshot( &tr, iBulletType );
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BULLET_NONE: // FIX
|
||||||
|
UTIL_TraceAttack(pMonster, pevAttacker, 50, vecDir, &tr, DMG_CLUB);
|
||||||
|
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||||
|
// only decal glass
|
||||||
|
if ( !FNullEnt(tr.pHit) && VARS(tr.pHit)->rendermode != 0)
|
||||||
|
{
|
||||||
|
UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG(0,2) );
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// make bullet trails
|
// make bullet trails
|
||||||
UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (flDistance * tr.flFraction) / 64.0 );
|
UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (flDistance * tr.flFraction) / 64.0 );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -302,14 +302,14 @@ void CMController :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/controller.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/controller.mdl"));
|
||||||
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ));
|
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ));
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
pev->movetype = MOVETYPE_FLY;
|
pev->movetype = MOVETYPE_FLY;
|
||||||
pev->flags |= FL_FLY;
|
pev->flags |= FL_FLY;
|
||||||
m_bloodColor = BLOOD_COLOR_GREEN;
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
|
||||||
pev->health = gSkillData.controllerHealth;
|
if (!pev->health) { pev->health = gSkillData.controllerHealth; }
|
||||||
pev->view_ofs = Vector( 0, 0, -2 );// position of the eyes relative to monster's origin.
|
pev->view_ofs = Vector( 0, 0, -2 );// position of the eyes relative to monster's origin.
|
||||||
m_flFieldOfView = VIEW_FIELD_FULL;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
m_flFieldOfView = VIEW_FIELD_FULL;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
m_MonsterState = MONSTERSTATE_NONE;
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
@@ -1185,6 +1185,8 @@ void CMControllerHeadBall :: HuntThink( void )
|
|||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit));
|
||||||
pMonster->TraceAttack( VARS(m_hOwner), gSkillData.controllerDmgZap, pev->velocity, &tr, DMG_SHOCK );
|
pMonster->TraceAttack( VARS(m_hOwner), gSkillData.controllerDmgZap, pev->velocity, &tr, DMG_SHOCK );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
UTIL_TraceAttack( tr.pHit, VARS(m_hOwner), gSkillData.controllerDmgZap, pev->velocity, &tr, DMG_SHOCK );
|
||||||
|
|
||||||
ApplyMultiDamage( pev, VARS(m_hOwner) );
|
ApplyMultiDamage( pev, VARS(m_hOwner) );
|
||||||
}
|
}
|
||||||
@@ -1361,6 +1363,8 @@ void CMControllerZapBall::ExplodeTouch( edict_t *pOther )
|
|||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||||
pMonster->TraceAttack(pevOwner, gSkillData.controllerDmgBall, pev->velocity.Normalize(), &tr, DMG_ENERGYBEAM );
|
pMonster->TraceAttack(pevOwner, gSkillData.controllerDmgBall, pev->velocity.Normalize(), &tr, DMG_ENERGYBEAM );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
UTIL_TraceAttack(pOther, pevOwner, gSkillData.controllerDmgBall, pev->velocity.Normalize(), &tr, DMG_ENERGYBEAM );
|
||||||
ApplyMultiDamage( pevOwner, pevOwner );
|
ApplyMultiDamage( pevOwner, pevOwner );
|
||||||
|
|
||||||
UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.3, ATTN_NORM, 0, RANDOM_LONG( 90, 99 ) );
|
UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.3, ATTN_NORM, 0, RANDOM_LONG( 90, 99 ) );
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
#include "cmbase.h"
|
#include "cmbase.h"
|
||||||
#include "cmbasemonster.h"
|
#include "cmbasemonster.h"
|
||||||
|
#include "cmbaseextra.h"
|
||||||
#include "monsters.h"
|
#include "monsters.h"
|
||||||
#include "weapons.h"
|
#include "weapons.h"
|
||||||
#include "hornet.h"
|
#include "hornet.h"
|
||||||
@@ -61,18 +62,15 @@ extern cvar_t *monster_spawn;
|
|||||||
extern cvar_t *monster_show_deaths;
|
extern cvar_t *monster_show_deaths;
|
||||||
extern cvar_t *monster_show_info;
|
extern cvar_t *monster_show_info;
|
||||||
|
|
||||||
|
// compiler does not like util.h being included here so i'll just extern the function
|
||||||
|
extern void SENTENCEG_Init();
|
||||||
|
|
||||||
// Player TakeDamage and Killed
|
// Player TakeDamage and Killed
|
||||||
int g_DamageMsg;
|
int g_DamageMsg;
|
||||||
bool g_DamageActive;
|
bool g_DamageActive;
|
||||||
int g_DamageVictim;
|
int g_DamageVictim;
|
||||||
edict_t *g_DamageAttacker[33];
|
|
||||||
int g_DamageBits[33];
|
int g_DamageBits[33];
|
||||||
bool g_PlayerKilled[33];
|
bool g_PlayerKilled[33];
|
||||||
float g_flWaitTillMessage[33];
|
|
||||||
|
|
||||||
// DeathMsg
|
|
||||||
int g_DeathMsg;
|
|
||||||
bool g_DeathActive;
|
|
||||||
|
|
||||||
// TE_TEXTMESSAGE
|
// TE_TEXTMESSAGE
|
||||||
float g_NextMessage[33];
|
float g_NextMessage[33];
|
||||||
@@ -134,11 +132,11 @@ monster_type_t monster_types[]=
|
|||||||
// can be spawned. Monsters should go first.
|
// can be spawned. Monsters should go first.
|
||||||
// DO NOT ALTER THE ORDER OF ELEMENTS!
|
// DO NOT ALTER THE ORDER OF ELEMENTS!
|
||||||
|
|
||||||
"monster_alien_grunt", FALSE, // Monsters
|
"monster_alien_grunt", FALSE, // Original Half-Life Monsters
|
||||||
"monster_apache", FALSE,
|
"monster_apache", FALSE,
|
||||||
"monster_barney", FALSE,
|
"monster_barney", FALSE,
|
||||||
"monster_bigmomma", FALSE,
|
"monster_bigmomma", FALSE,
|
||||||
"monster_bullsquid", FALSE,
|
"monster_bullchicken", FALSE,
|
||||||
"monster_alien_controller", FALSE,
|
"monster_alien_controller", FALSE,
|
||||||
"monster_human_assassin", FALSE,
|
"monster_human_assassin", FALSE,
|
||||||
"monster_headcrab", FALSE,
|
"monster_headcrab", FALSE,
|
||||||
@@ -152,8 +150,25 @@ monster_type_t monster_types[]=
|
|||||||
"monster_turret", FALSE,
|
"monster_turret", FALSE,
|
||||||
"monster_miniturret", FALSE,
|
"monster_miniturret", FALSE,
|
||||||
"monster_sentry", FALSE,
|
"monster_sentry", FALSE,
|
||||||
|
"monster_gonome", FALSE, // Opposing Force Monsters
|
||||||
|
"monster_male_assassin", FALSE,
|
||||||
|
"monster_otis", FALSE,
|
||||||
|
"monster_pitdrone", FALSE,
|
||||||
|
"monster_shockroach", FALSE,
|
||||||
|
"monster_shocktrooper", FALSE,
|
||||||
|
"monster_alien_voltigore", FALSE,
|
||||||
|
"monster_alien_babyvoltigore", FALSE,
|
||||||
|
"monster_babygarg", FALSE, // Sven Co-op Monsters
|
||||||
|
"monster_hwgrunt", FALSE,
|
||||||
|
"monster_robogrunt", FALSE,
|
||||||
|
"monster_stukabat", FALSE,
|
||||||
"info_node", FALSE, // Nodes
|
"info_node", FALSE, // Nodes
|
||||||
"info_node_air", FALSE,
|
"info_node_air", FALSE,
|
||||||
|
"monstermaker", FALSE, // Extra entities
|
||||||
|
"ambient_music", FALSE,
|
||||||
|
"env_xenmaker", FALSE,
|
||||||
|
"trigger_setcvar", FALSE,
|
||||||
|
"squadmaker", FALSE, // Aliases
|
||||||
"", FALSE
|
"", FALSE
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -167,6 +182,7 @@ node_spawnpoint_t node_spawnpoint[MAX_NODES];
|
|||||||
int node_spawn_count = 0;
|
int node_spawn_count = 0;
|
||||||
|
|
||||||
float check_respawn_time;
|
float check_respawn_time;
|
||||||
|
float check_graph_time;
|
||||||
|
|
||||||
bool process_monster_cfg(void);
|
bool process_monster_cfg(void);
|
||||||
bool process_monster_precache_cfg(void);
|
bool process_monster_precache_cfg(void);
|
||||||
@@ -197,15 +213,6 @@ int GetMonsterIndex(void)
|
|||||||
|
|
||||||
void FreeMonsterIndex(int index)
|
void FreeMonsterIndex(int index)
|
||||||
{
|
{
|
||||||
int idx = monsters[index].respawn_index;
|
|
||||||
|
|
||||||
if (idx != -1)
|
|
||||||
{
|
|
||||||
monster_spawnpoint[idx].need_to_respawn = TRUE;
|
|
||||||
monster_spawnpoint[idx].respawn_time = gpGlobals->time +
|
|
||||||
monster_spawnpoint[idx].delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete monsters[index].pMonster;
|
delete monsters[index].pMonster;
|
||||||
|
|
||||||
monsters[index].monster_index = 0;
|
monsters[index].monster_index = 0;
|
||||||
@@ -297,7 +304,7 @@ void check_monster_hurt(edict_t *pAttacker)
|
|||||||
vecSpot = vecSrc + gpGlobals->v_forward * distance;
|
vecSpot = vecSrc + gpGlobals->v_forward * distance;
|
||||||
|
|
||||||
// trace a line ignoring enemies body...
|
// trace a line ignoring enemies body...
|
||||||
UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, pent, &tr );
|
UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, pAttacker, &tr );
|
||||||
|
|
||||||
damage = pent->v.fuser4 - pent->v.health;
|
damage = pent->v.fuser4 - pent->v.health;
|
||||||
|
|
||||||
@@ -305,7 +312,7 @@ void check_monster_hurt(edict_t *pAttacker)
|
|||||||
pent->v.health = pent->v.fuser4;
|
pent->v.health = pent->v.fuser4;
|
||||||
|
|
||||||
ClearMultiDamage( );
|
ClearMultiDamage( );
|
||||||
monsters[index].pMonster->TraceAttack( VARS(pAttacker), damage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, DMG_BULLET );
|
monsters[index].pMonster->TraceAttack( VARS(pAttacker), damage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, DMG_BULLET|DMG_NEVERGIB );
|
||||||
ApplyMultiDamage( VARS(pAttacker), VARS(pAttacker) );
|
ApplyMultiDamage( VARS(pAttacker), VARS(pAttacker) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,47 +395,81 @@ void check_player_dead( edict_t *pPlayer )
|
|||||||
// Killed by a monster?
|
// Killed by a monster?
|
||||||
if ( pAttacker->v.flags & FL_MONSTER )
|
if ( pAttacker->v.flags & FL_MONSTER )
|
||||||
{
|
{
|
||||||
// Check the first character for 'aeiou'.
|
// Try to get the name of the monster
|
||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pAttacker));
|
char szName[129], szCheck[2];
|
||||||
char szCheck[2];
|
|
||||||
strncpy( szCheck, STRING( pMonster->m_szMonsterName ), 1 );
|
|
||||||
|
|
||||||
// Make the first character lowercase
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pAttacker));
|
||||||
szCheck[0] = tolower( szCheck[ 0 ] );
|
if ( pMonster != NULL )
|
||||||
if ( strncmp( szCheck, "a", 1 ) == 0 || strncmp( szCheck, "e", 1 ) == 0 || strncmp( szCheck, "i", 1 ) == 0 || strncmp( szCheck, "o", 1 ) == 0 || strncmp( szCheck, "u", 1 ) == 0 )
|
{
|
||||||
sprintf( szMessage, "* %s was killed by an %s.\n", szPlayerName, STRING( pMonster->m_szMonsterName ) );
|
// One of our monsters
|
||||||
else
|
strcpy(szName, STRING( pMonster->m_szMonsterName ));
|
||||||
sprintf( szMessage, "* %s was killed by a %s.\n", szPlayerName, STRING( pMonster->m_szMonsterName ) );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Any messages from here should only be shown if allowed.
|
// Does this monster have a name?
|
||||||
// Level 0 = Disabled
|
if ( !FStringNull( pAttacker->v.netname ) )
|
||||||
// Level 1 = All messages
|
strcpy(szName, STRING( pAttacker->v.netname ));
|
||||||
// Level 2 = Only monster deaths
|
else
|
||||||
if (monster_show_deaths->value == 1)
|
{
|
||||||
|
// No name, use class
|
||||||
|
strcpy(szName, STRING( pAttacker->v.classname ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, copy the first character to check for 'aeiou'.
|
||||||
|
strncpy( szCheck, szName, 1 );
|
||||||
|
|
||||||
|
// Make this character lowercase and inspect it. Select which message.
|
||||||
|
szCheck[0] = tolower( szCheck[ 0 ] );
|
||||||
|
if ( strncmp( szCheck, "a", 1 ) == 0 || strncmp( szCheck, "e", 1 ) == 0 || strncmp( szCheck, "i", 1 ) == 0 || strncmp( szCheck, "o", 1 ) == 0 || strncmp( szCheck, "u", 1 ) == 0 )
|
||||||
|
sprintf( szMessage, "* %s was killed by an %s.\n", szPlayerName, szName );
|
||||||
|
else
|
||||||
|
sprintf( szMessage, "* %s was killed by a %s.\n", szPlayerName, szName );
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// Suicide?
|
// Suicide?
|
||||||
if ( pAttacker == pPlayer )
|
if ( pAttacker == pPlayer )
|
||||||
sprintf( szMessage, "* %s commited suicide.\n", szPlayerName );
|
sprintf( szMessage, "* %s commited suicide.\n", szPlayerName );
|
||||||
|
// Player killed by another player
|
||||||
|
else if ( UTIL_IsPlayer( pAttacker ) )
|
||||||
|
{
|
||||||
|
// Get attacker name
|
||||||
|
char szAttackerName[33];
|
||||||
|
strcpy(szAttackerName, STRING(pAttacker->v.netname));
|
||||||
|
|
||||||
|
// Print a very basic death message until we can detect teamkills
|
||||||
|
sprintf( szMessage, "* %s was killed by %s.\n", szPlayerName, szAttackerName );
|
||||||
|
}
|
||||||
// An entity killed this player.
|
// An entity killed this player.
|
||||||
else if ( ENTINDEX( pAttacker ) > 0 )
|
else if ( ENTINDEX( pAttacker ) > 0 )
|
||||||
{
|
{
|
||||||
|
// HLSDK: "int visibleDamageBits = m_bitsDamageType & DMG_SHOWNHUD;"
|
||||||
|
// When the game sends a "Damage" NetworkMessage, the damageBits
|
||||||
|
// gets filtered so only damages that can be shown on HUD will pass
|
||||||
|
// through, otherwise it gets neutered to DMG_GENERIC.
|
||||||
|
|
||||||
|
// This means that players will only see a few death messages
|
||||||
|
// instead of all possibilities that are written here.
|
||||||
|
|
||||||
|
// If you want to make use of all possible death messages, you
|
||||||
|
// will have to override the NetworkMessage. -Giegue
|
||||||
|
|
||||||
// Gather damage type and format death message
|
// Gather damage type and format death message
|
||||||
if ( g_DamageBits[ iPlayerIndex ] == DMG_GENERIC )
|
if ( g_DamageBits[ iPlayerIndex ] == DMG_GENERIC )
|
||||||
sprintf( szMessage, "* %s died mysteriously.\n", szPlayerName );
|
sprintf( szMessage, "* %s died mysteriously.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_CRUSH )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_CRUSH )
|
||||||
sprintf( szMessage, "* %s was smashed.\n", szPlayerName );
|
sprintf( szMessage, "* %s was crushed.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_BULLET )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_BULLET )
|
||||||
sprintf( szMessage, "* %s was shot.\n", szPlayerName );
|
sprintf( szMessage, "* %s was shot.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_SLASH )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_SLASH )
|
||||||
sprintf( szMessage, "* %s lost it's jelly.\n", szPlayerName );
|
sprintf( szMessage, "* %s has been chopped.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_BURN )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_BURN )
|
||||||
sprintf( szMessage, "* %s burned to death.\n", szPlayerName );
|
sprintf( szMessage, "* %s burned down.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_FREEZE )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_FREEZE )
|
||||||
sprintf( szMessage, "* %s froze to death.\n", szPlayerName );
|
sprintf( szMessage, "* %s froze to death.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_FALL )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_FALL )
|
||||||
sprintf( szMessage, "* %s broke it's bones.\n", szPlayerName );
|
sprintf( szMessage, "* %s fell.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_BLAST )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_BLAST )
|
||||||
sprintf( szMessage, "* %s blew up.\n", szPlayerName );
|
sprintf( szMessage, "* %s blew up.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_CLUB )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_CLUB )
|
||||||
@@ -438,33 +479,29 @@ void check_player_dead( edict_t *pPlayer )
|
|||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_SONIC )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_SONIC )
|
||||||
sprintf( szMessage, "* %s ears popped.\n", szPlayerName );
|
sprintf( szMessage, "* %s ears popped.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_ENERGYBEAM )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_ENERGYBEAM )
|
||||||
sprintf( szMessage, "* %s saw the pretty lights.\n", szPlayerName );
|
sprintf( szMessage, "* %s was cut by a laser.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] == DMG_NEVERGIB )
|
else if ( g_DamageBits[ iPlayerIndex ] == DMG_NEVERGIB )
|
||||||
sprintf( szMessage, "* %s had a painful death.\n", szPlayerName );
|
sprintf( szMessage, "* %s had a painful death.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] == DMG_ALWAYSGIB )
|
else if ( g_DamageBits[ iPlayerIndex ] == DMG_ALWAYSGIB )
|
||||||
sprintf( szMessage, "* %s was gibbed.\n", szPlayerName );
|
sprintf( szMessage, "* %s was gibbed.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_DROWN )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_DROWN )
|
||||||
sprintf( szMessage, "* %s became too drunk.\n", szPlayerName );
|
sprintf( szMessage, "* %s drowned.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_PARALYZE )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_PARALYZE )
|
||||||
sprintf( szMessage, "* %s was paralyzed.\n", szPlayerName );
|
sprintf( szMessage, "* %s was paralyzed.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_NERVEGAS )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_NERVEGAS )
|
||||||
sprintf( szMessage, "* %s lost it's brain.\n", szPlayerName );
|
sprintf( szMessage, "* %s lost its brain.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_POISON )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_POISON )
|
||||||
sprintf( szMessage, "* %s had a slow death.\n", szPlayerName );
|
sprintf( szMessage, "* %s has been poisoned.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_RADIATION )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_RADIATION )
|
||||||
sprintf( szMessage, "* %s went nuclear.\n", szPlayerName );
|
sprintf( szMessage, "* %s went nuclear.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_DROWNRECOVER )
|
|
||||||
sprintf( szMessage, "* %s used too much flex tape.\n", szPlayerName ); // is this type of death even possible?
|
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_ACID )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_ACID )
|
||||||
sprintf( szMessage, "* %s was melted.\n", szPlayerName );
|
sprintf( szMessage, "* %s was melted.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_SLOWBURN )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_SLOWBURN )
|
||||||
sprintf( szMessage, "* %s became a cake.\n", szPlayerName );
|
sprintf( szMessage, "* %s was baked like a cake.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_SLOWFREEZE )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_SLOWFREEZE )
|
||||||
sprintf( szMessage, "* %s died of hypothermia.\n", szPlayerName );
|
sprintf( szMessage, "* %s died of hypothermia.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_MORTAR )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_MORTAR )
|
||||||
sprintf( szMessage, "* %s blew his missile pet.\n", szPlayerName );
|
sprintf( szMessage, "* %s was killed by a Mortar Shell.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] == (1 << 30) ) // (1 << 30) = 1073741824. For custom death messages
|
|
||||||
sprintf( szMessage, "* %s %s.\n", szPlayerName, STRING( pAttacker->v.noise ) );
|
|
||||||
else // other mods could have more DMG_ variants that aren't registered here.
|
else // other mods could have more DMG_ variants that aren't registered here.
|
||||||
sprintf( szMessage, "* %s deadly died.\n", szPlayerName );
|
sprintf( szMessage, "* %s deadly died.\n", szPlayerName );
|
||||||
}
|
}
|
||||||
@@ -472,7 +509,6 @@ void check_player_dead( edict_t *pPlayer )
|
|||||||
else
|
else
|
||||||
sprintf( szMessage, "* %s fell or drowned or something.\n", szPlayerName );
|
sprintf( szMessage, "* %s fell or drowned or something.\n", szPlayerName );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Print the message
|
// Print the message
|
||||||
if ( strlen( szMessage ) > 0 )
|
if ( strlen( szMessage ) > 0 )
|
||||||
@@ -515,14 +551,46 @@ void check_monster_info( edict_t *pPlayer )
|
|||||||
// Hit an entity?
|
// Hit an entity?
|
||||||
if (tr.pHit != NULL)
|
if (tr.pHit != NULL)
|
||||||
{
|
{
|
||||||
// Must be a monster
|
// It should be alive
|
||||||
if (tr.pHit->v.flags & FL_MONSTER)
|
if ( UTIL_IsAlive( tr.pHit ) )
|
||||||
{
|
{
|
||||||
|
// Must be a monster (and strictly a monster!)
|
||||||
|
if (strncmp( STRING( tr.pHit->v.classname ), "monster_", 8 ) == 0 && tr.pHit->v.flags & FL_MONSTER)
|
||||||
|
{
|
||||||
|
char szName[129];
|
||||||
|
float monsterHealth, monsterFrags;
|
||||||
|
int classify;
|
||||||
|
BOOL isAlly = FALSE;
|
||||||
|
|
||||||
// Get monster info
|
// Get monster info
|
||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit));
|
||||||
|
if ( pMonster != NULL )
|
||||||
|
{
|
||||||
|
strcpy(szName, STRING( pMonster->m_szMonsterName ));
|
||||||
|
classify = pMonster->Classify();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// A monster that we do not recognize, use its netname
|
||||||
|
if ( !FStringNull( tr.pHit->v.netname ) )
|
||||||
|
strcpy(szName, STRING( tr.pHit->v.netname ));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If all else fails, use classname as monster name
|
||||||
|
strcpy(szName, STRING( tr.pHit->v.classname ));
|
||||||
|
}
|
||||||
|
classify = tr.pHit->v.iuser4;
|
||||||
|
}
|
||||||
|
monsterHealth = tr.pHit->v.health;
|
||||||
|
monsterFrags = tr.pHit->v.frags;
|
||||||
|
|
||||||
char szInfo[512];
|
// Unless it is strictly ally to us, treat as enemy monster
|
||||||
sprintf(szInfo, "Enemy: %s\nHealth: %.0f\nFrags: %.0f\n", STRING( pMonster->m_szMonsterName ), pMonster->pev->health, pMonster->pev->frags );
|
if ( classify == CLASS_HUMAN_PASSIVE || classify == CLASS_PLAYER_ALLY )
|
||||||
|
isAlly = TRUE;
|
||||||
|
|
||||||
|
// Prepare the message
|
||||||
|
char szInfo[257];
|
||||||
|
sprintf(szInfo, "%s: %s\nHealth: %.0f\nFrags: %.0f\n", ( isAlly ? "Friend" : "Enemy" ), szName, monsterHealth, monsterFrags );
|
||||||
|
|
||||||
// Create a TE_TEXTMESSAGE and show the monster information
|
// Create a TE_TEXTMESSAGE and show the monster information
|
||||||
MESSAGE_BEGIN( MSG_ONE, SVC_TEMPENTITY, NULL, pPlayer );
|
MESSAGE_BEGIN( MSG_ONE, SVC_TEMPENTITY, NULL, pPlayer );
|
||||||
@@ -531,9 +599,18 @@ void check_monster_info( edict_t *pPlayer )
|
|||||||
WRITE_SHORT( 327 ); // X
|
WRITE_SHORT( 327 ); // X
|
||||||
WRITE_SHORT( 4771 ); // Y
|
WRITE_SHORT( 4771 ); // Y
|
||||||
WRITE_BYTE( 0 ); // Effect
|
WRITE_BYTE( 0 ); // Effect
|
||||||
|
if ( isAlly )
|
||||||
|
{
|
||||||
|
WRITE_BYTE( 9 ); // R1
|
||||||
|
WRITE_BYTE( 172 ); // G1
|
||||||
|
WRITE_BYTE( 96 ); // B1
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
WRITE_BYTE( 171 ); // R1
|
WRITE_BYTE( 171 ); // R1
|
||||||
WRITE_BYTE( 23 ); // G1
|
WRITE_BYTE( 23 ); // G1
|
||||||
WRITE_BYTE( 7 ); // B1
|
WRITE_BYTE( 7 ); // B1
|
||||||
|
}
|
||||||
WRITE_BYTE( 0 ); // A1
|
WRITE_BYTE( 0 ); // A1
|
||||||
WRITE_BYTE( 207 ); // R2
|
WRITE_BYTE( 207 ); // R2
|
||||||
WRITE_BYTE( 23 ); // G2
|
WRITE_BYTE( 23 ); // G2
|
||||||
@@ -546,13 +623,14 @@ void check_monster_info( edict_t *pPlayer )
|
|||||||
MESSAGE_END();
|
MESSAGE_END();
|
||||||
|
|
||||||
// Delay till next scan
|
// Delay till next scan
|
||||||
g_NextMessage[ ENTINDEX( pPlayer ) ] = gpGlobals->time + 0.875;
|
g_NextMessage[ ENTINDEX( pPlayer ) ] = gpGlobals->time + 0.30;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_index, int spawnflags, pKVD *keyvalue)
|
edict_t* spawn_monster(int monster_type, Vector origin, Vector angles, int spawnflags, pKVD *keyvalue)
|
||||||
{
|
{
|
||||||
int monster_index;
|
int monster_index;
|
||||||
edict_t *monster_pent;
|
edict_t *monster_pent;
|
||||||
@@ -562,7 +640,7 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i
|
|||||||
{
|
{
|
||||||
//META_CONS("[MONSTER] ERROR: No FREE Monster edicts!");
|
//META_CONS("[MONSTER] ERROR: No FREE Monster edicts!");
|
||||||
LOG_MESSAGE(PLID, "ERROR: No FREE Monster edicts!");
|
LOG_MESSAGE(PLID, "ERROR: No FREE Monster edicts!");
|
||||||
return TRUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// was this monster NOT precached?
|
// was this monster NOT precached?
|
||||||
@@ -596,11 +674,12 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i
|
|||||||
LOG_MESSAGE(PLID, "%s", msg);
|
LOG_MESSAGE(PLID, "%s", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (monster_type)
|
switch (monster_type)
|
||||||
{
|
{
|
||||||
|
// Monsters
|
||||||
case 0: monsters[monster_index].pMonster = CreateClassPtr((CMAGrunt *)NULL); break;
|
case 0: monsters[monster_index].pMonster = CreateClassPtr((CMAGrunt *)NULL); break;
|
||||||
case 1: monsters[monster_index].pMonster = CreateClassPtr((CMApache *)NULL); break;
|
case 1: monsters[monster_index].pMonster = CreateClassPtr((CMApache *)NULL); break;
|
||||||
case 2: monsters[monster_index].pMonster = CreateClassPtr((CMBarney *)NULL); break;
|
case 2: monsters[monster_index].pMonster = CreateClassPtr((CMBarney *)NULL); break;
|
||||||
@@ -619,17 +698,33 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i
|
|||||||
case 15: monsters[monster_index].pMonster = CreateClassPtr((CMTurret *)NULL); break;
|
case 15: monsters[monster_index].pMonster = CreateClassPtr((CMTurret *)NULL); break;
|
||||||
case 16: monsters[monster_index].pMonster = CreateClassPtr((CMMiniTurret *)NULL); break;
|
case 16: monsters[monster_index].pMonster = CreateClassPtr((CMMiniTurret *)NULL); break;
|
||||||
case 17: monsters[monster_index].pMonster = CreateClassPtr((CMSentry *)NULL); break;
|
case 17: monsters[monster_index].pMonster = CreateClassPtr((CMSentry *)NULL); break;
|
||||||
|
case 18: monsters[monster_index].pMonster = CreateClassPtr((CMGonome *)NULL); break;
|
||||||
|
case 19: monsters[monster_index].pMonster = CreateClassPtr((CMMassn *)NULL); break;
|
||||||
|
case 20: monsters[monster_index].pMonster = CreateClassPtr((CMOtis *)NULL); break;
|
||||||
|
case 21: monsters[monster_index].pMonster = CreateClassPtr((CMPitdrone *)NULL); break;
|
||||||
|
case 22: monsters[monster_index].pMonster = CreateClassPtr((CMShockRoach *)NULL); break;
|
||||||
|
case 23: monsters[monster_index].pMonster = CreateClassPtr((CMStrooper *)NULL); break;
|
||||||
|
case 24: monsters[monster_index].pMonster = CreateClassPtr((CMVoltigore *)NULL); break;
|
||||||
|
case 25: monsters[monster_index].pMonster = CreateClassPtr((CMBabyVoltigore *)NULL); break;
|
||||||
|
case 26: monsters[monster_index].pMonster = CreateClassPtr((CMBabyGargantua *)NULL); break;
|
||||||
|
case 27: monsters[monster_index].pMonster = CreateClassPtr((CMHWGrunt *)NULL); break;
|
||||||
|
case 28: monsters[monster_index].pMonster = CreateClassPtr((CMRGrunt *)NULL); break;
|
||||||
|
case 29: monsters[monster_index].pMonster = CreateClassPtr((CMStukabat *)NULL); break;
|
||||||
|
// Extra entities
|
||||||
|
case 32: monsters[monster_index].pMonster = CreateClassPtr((CMMonsterMaker *)NULL); break;
|
||||||
|
case 33: monsters[monster_index].pMonster = CreateClassPtr((CMAmbientMusic *)NULL); break;
|
||||||
|
case 34: monsters[monster_index].pMonster = CreateClassPtr((CMXenMaker *)NULL); break;
|
||||||
|
case 35: monsters[monster_index].pMonster = CreateClassPtr((CMSetCVar *)NULL); break;
|
||||||
|
default: LOG_MESSAGE(PLID, "ERROR: Invalid monster type! (%i)", monster_type); return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (monsters[monster_index].pMonster == NULL)
|
if (monsters[monster_index].pMonster == NULL)
|
||||||
{
|
{
|
||||||
//META_CONS("[MONSTER] ERROR: Error Creating Monster!" );
|
//META_CONS("[MONSTER] ERROR: Error Creating Monster!" );
|
||||||
LOG_MESSAGE(PLID, "ERROR: Error Creating Monster!");
|
LOG_MESSAGE(PLID, "ERROR: Error Creating Monster!");
|
||||||
return TRUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
monsters[monster_index].respawn_index = respawn_index;
|
|
||||||
|
|
||||||
monster_pent = ENT(monsters[monster_index].pMonster->pev);
|
monster_pent = ENT(monsters[monster_index].pMonster->pev);
|
||||||
monsters[monster_index].monster_pent = monster_pent;
|
monsters[monster_index].monster_pent = monster_pent;
|
||||||
|
|
||||||
@@ -638,6 +733,9 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i
|
|||||||
monster_pent->v.origin = origin;
|
monster_pent->v.origin = origin;
|
||||||
monster_pent->v.angles = angles;
|
monster_pent->v.angles = angles;
|
||||||
|
|
||||||
|
// Pass spawnflags first if no keyvalue data exists for it
|
||||||
|
monster_pent->v.spawnflags = spawnflags;
|
||||||
|
|
||||||
// Keyvalue data
|
// Keyvalue data
|
||||||
if (keyvalue != NULL)
|
if (keyvalue != NULL)
|
||||||
{
|
{
|
||||||
@@ -652,19 +750,21 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
monster_pent->v.spawnflags = spawnflags;
|
|
||||||
|
|
||||||
monsters[monster_index].pMonster->Spawn();
|
monsters[monster_index].pMonster->Spawn();
|
||||||
|
|
||||||
|
// Only modify starting spawnflags for monsters, not for entities!
|
||||||
|
if ( monster_index <= 29 )
|
||||||
|
{
|
||||||
// Reverse fadecorpse behaviour
|
// Reverse fadecorpse behaviour
|
||||||
if ( ( spawnflags & SF_MONSTER_FADECORPSE ) )
|
if ( ( spawnflags & SF_MONSTER_FADECORPSE ) )
|
||||||
monster_pent->v.spawnflags &= ~SF_MONSTER_FADECORPSE;
|
monster_pent->v.spawnflags &= ~SF_MONSTER_FADECORPSE;
|
||||||
else
|
else
|
||||||
monster_pent->v.spawnflags |= SF_MONSTER_FADECORPSE;
|
monster_pent->v.spawnflags |= SF_MONSTER_FADECORPSE;
|
||||||
|
}
|
||||||
|
|
||||||
monster_pent->v.fuser4 = monster_pent->v.health; // save the original health
|
monster_pent->v.fuser4 = monster_pent->v.health; // save the original health
|
||||||
|
|
||||||
return FALSE;
|
return monster_pent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -681,8 +781,7 @@ void check_respawn(void)
|
|||||||
|
|
||||||
for (int index=0; index < monster_spawn_count; index++)
|
for (int index=0; index < monster_spawn_count; index++)
|
||||||
{
|
{
|
||||||
if (monster_spawnpoint[index].need_to_respawn &&
|
if (monster_spawnpoint[index].need_to_respawn)
|
||||||
(monster_spawnpoint[index].respawn_time <= gpGlobals->time))
|
|
||||||
{
|
{
|
||||||
monster_spawnpoint[index].need_to_respawn = FALSE;
|
monster_spawnpoint[index].need_to_respawn = FALSE;
|
||||||
|
|
||||||
@@ -696,20 +795,18 @@ void check_respawn(void)
|
|||||||
|
|
||||||
keyvalue = monster_spawnpoint[index].keyvalue;
|
keyvalue = monster_spawnpoint[index].keyvalue;
|
||||||
|
|
||||||
if (spawn_monster(monster_type, origin, angles, index, spawnflags, keyvalue))
|
if (spawn_monster(monster_type, origin, angles, spawnflags, keyvalue) == NULL)
|
||||||
{
|
{
|
||||||
// spawn_monster failed, retry again after delay...
|
// spawn_monster failed
|
||||||
monster_spawnpoint[index].need_to_respawn = TRUE;
|
ALERT( at_error, "[MONSTER] Failed to spawn %s at origin %f %f %f\n", monster_types[monster_type].name, origin.x, origin.y, origin.z );
|
||||||
monster_spawnpoint[index].respawn_time = gpGlobals->time +
|
|
||||||
monster_spawnpoint[index].delay;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DLL_GLOBAL short g_sModelIndexFireball;// holds the index for the fireball
|
DLL_GLOBAL short g_sModelIndexFireball;// holds the index for the fireball
|
||||||
DLL_GLOBAL short g_sModelIndexSmoke;// holds the index for the smoke cloud
|
DLL_GLOBAL short g_sModelIndexSmoke;// holds the index for the smoke cloud
|
||||||
|
DLL_GLOBAL short g_sModelIndexTinySpit;// holds the index for the spore grenade explosion
|
||||||
DLL_GLOBAL short g_sModelIndexWExplosion;// holds the index for the underwater explosion
|
DLL_GLOBAL short g_sModelIndexWExplosion;// holds the index for the underwater explosion
|
||||||
DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model
|
DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model
|
||||||
DLL_GLOBAL short g_sModelIndexBloodDrop;// holds the sprite index for the initial blood
|
DLL_GLOBAL short g_sModelIndexBloodDrop;// holds the sprite index for the initial blood
|
||||||
@@ -718,22 +815,27 @@ DLL_GLOBAL short g_sModelIndexLaser;// holds the index for the laser beam
|
|||||||
DLL_GLOBAL const char *g_pModelNameLaser = "sprites/laserbeam.spr";
|
DLL_GLOBAL const char *g_pModelNameLaser = "sprites/laserbeam.spr";
|
||||||
DLL_GLOBAL short g_sModelIndexLaserDot;// holds the index for the laser beam dot
|
DLL_GLOBAL short g_sModelIndexLaserDot;// holds the index for the laser beam dot
|
||||||
|
|
||||||
|
// globals.cpp
|
||||||
|
DLL_GLOBAL const Vector g_vecZero = Vector(0, 0, 0); // null vector
|
||||||
|
DLL_GLOBAL Vector g_vecAttackDir; // attack direction
|
||||||
|
|
||||||
|
|
||||||
void world_precache(void)
|
void world_precache(void)
|
||||||
{
|
{
|
||||||
g_sModelIndexFireball = PRECACHE_MODEL ("sprites/zerogxplode.spr");// fireball
|
g_sModelIndexFireball = PRECACHE_MODELINDEX("sprites/zerogxplode.spr");// fireball
|
||||||
g_sModelIndexSmoke = PRECACHE_MODEL ("sprites/steam1.spr");// smoke
|
g_sModelIndexSmoke = PRECACHE_MODELINDEX("sprites/steam1.spr");// smoke
|
||||||
g_sModelIndexWExplosion = PRECACHE_MODEL ("sprites/WXplo1.spr");// underwater fireball
|
g_sModelIndexTinySpit = PRECACHE_MODELINDEX("sprites/tinyspit.spr");// spore
|
||||||
g_sModelIndexBubbles = PRECACHE_MODEL ("sprites/bubble.spr");//bubbles
|
g_sModelIndexWExplosion = PRECACHE_MODELINDEX("sprites/WXplo1.spr");// underwater fireball
|
||||||
g_sModelIndexBloodSpray = PRECACHE_MODEL ("sprites/bloodspray.spr"); // initial blood
|
g_sModelIndexBubbles = PRECACHE_MODELINDEX("sprites/bubble.spr");//bubbles
|
||||||
g_sModelIndexBloodDrop = PRECACHE_MODEL ("sprites/blood.spr"); // splattered blood
|
g_sModelIndexBloodSpray = PRECACHE_MODELINDEX("sprites/bloodspray.spr"); // initial blood
|
||||||
|
g_sModelIndexBloodDrop = PRECACHE_MODELINDEX("sprites/blood.spr"); // splattered blood
|
||||||
|
|
||||||
g_sModelIndexLaser = PRECACHE_MODEL( (char *)g_pModelNameLaser );
|
g_sModelIndexLaser = PRECACHE_MODELINDEX( (char *)g_pModelNameLaser );
|
||||||
g_sModelIndexLaserDot = PRECACHE_MODEL("sprites/laserdot.spr");
|
g_sModelIndexLaserDot = PRECACHE_MODELINDEX("sprites/laserdot.spr");
|
||||||
|
|
||||||
PRECACHE_MODEL ("models/w_grenade.mdl");
|
PRECACHE_MODEL("models/w_grenade.mdl");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MonsterCommand(void)
|
void MonsterCommand(void)
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
@@ -867,7 +969,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -895,7 +997,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -923,7 +1025,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -950,7 +1052,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -977,7 +1079,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1004,7 +1106,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1142,6 +1244,28 @@ void SpawnViewerCommand(void)
|
|||||||
LOG_MESSAGE(PLID, "spawns a node viewer at the player's location");
|
LOG_MESSAGE(PLID, "spawns a node viewer at the player's location");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebugGetEntities(void)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "count: %i ents of max %i\n", monster_ents_used, MAX_MONSTER_ENTS);
|
||||||
|
for (int index = 0; index < MAX_MONSTER_ENTS; index++)
|
||||||
|
{
|
||||||
|
if (monsters[index].monster_index)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "SLOT #%i:", index);
|
||||||
|
edict_t *pent = (*g_engfuncs.pfnPEntityOfEntIndex)(monsters[index].monster_index);
|
||||||
|
|
||||||
|
if (pent)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "Class is \"%s\"\n", STRING(pent->v.classname));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "NULL entity\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void mmGameDLLInit( void )
|
void mmGameDLLInit( void )
|
||||||
{
|
{
|
||||||
// one time initialization stuff here...
|
// one time initialization stuff here...
|
||||||
@@ -1165,10 +1289,11 @@ int mmDispatchSpawn( edict_t *pent )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// free any allocated keyvalue memory
|
// free any allocated keyvalue memory
|
||||||
for (index = 0; index < monster_spawn_count; index++)
|
for (index = 0; index < MAX_MONSTERS; index++)
|
||||||
{
|
{
|
||||||
if (monster_spawnpoint[index].keyvalue)
|
if (monster_spawnpoint[index].keyvalue != NULL)
|
||||||
free(monster_spawnpoint[index].keyvalue);
|
free(monster_spawnpoint[index].keyvalue);
|
||||||
|
monster_spawnpoint[index].keyvalue = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// do level initialization stuff here...
|
// do level initialization stuff here...
|
||||||
@@ -1176,7 +1301,9 @@ int mmDispatchSpawn( edict_t *pent )
|
|||||||
for (index = 0; monster_types[index].name[0]; index++)
|
for (index = 0; monster_types[index].name[0]; index++)
|
||||||
monster_types[index].need_to_precache = FALSE;
|
monster_types[index].need_to_precache = FALSE;
|
||||||
|
|
||||||
world_precache();
|
CVAR_SET_STRING("monster_gmr", "");
|
||||||
|
CVAR_SET_STRING("monster_gsr", "");
|
||||||
|
REPLACER::Init();
|
||||||
|
|
||||||
monster_spawn_count = 0;
|
monster_spawn_count = 0;
|
||||||
node_spawn_count = 0;
|
node_spawn_count = 0;
|
||||||
@@ -1187,32 +1314,16 @@ int mmDispatchSpawn( edict_t *pent )
|
|||||||
|
|
||||||
process_monster_cfg();
|
process_monster_cfg();
|
||||||
|
|
||||||
|
// precache last in the event of a GMR being present
|
||||||
|
world_precache();
|
||||||
|
SENTENCEG_Init();
|
||||||
|
|
||||||
// node support. -Giegue
|
// node support. -Giegue
|
||||||
// init the WorldGraph.
|
// init the WorldGraph.
|
||||||
WorldGraph.InitGraph();
|
WorldGraph.InitGraph();
|
||||||
|
check_graph_time = gpGlobals->time + 2.00; // give enough gap
|
||||||
|
|
||||||
// make sure the .NOD file is newer than the .BSP file.
|
check_respawn_time = gpGlobals->time + 4.00;
|
||||||
if ( !WorldGraph.CheckNODFile ( ( char * )STRING( gpGlobals->mapname ) ) )
|
|
||||||
{
|
|
||||||
// NOD file is not present, or is older than the BSP file.
|
|
||||||
WorldGraph.AllocNodes();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Load the node graph for this level
|
|
||||||
if ( !WorldGraph.FLoadGraph ( (char *)STRING( gpGlobals->mapname ) ) )
|
|
||||||
{
|
|
||||||
// couldn't load, so alloc and prepare to build a graph.
|
|
||||||
ALERT ( at_console, "*Error opening .NOD file\n" );
|
|
||||||
WorldGraph.AllocNodes();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ALERT ( at_console, "\n*Graph Loaded!\n" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
check_respawn_time = 0.0;
|
|
||||||
|
|
||||||
for (index = 0; index < MAX_MONSTER_ENTS; index++)
|
for (index = 0; index < MAX_MONSTER_ENTS; index++)
|
||||||
{
|
{
|
||||||
@@ -1271,12 +1382,53 @@ void mmDispatchTouch( edict_t *pentTouched, edict_t *pentOther )
|
|||||||
RETURN_META(MRES_IGNORED);
|
RETURN_META(MRES_IGNORED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pfnUse has been deprecated so the only way to trigger a monstermod
|
||||||
|
// entity from the outside is to do it manually. ARRGHH! -Giegue
|
||||||
|
void mmDispatchUse( void )
|
||||||
|
{
|
||||||
|
if ( CMD_ARGC() >= 6 ) // the command itself is an argument, we need 5. so argc == 6
|
||||||
|
{
|
||||||
|
edict_t *entity = INDEXENT( atoi( CMD_ARGV( 1 ) ) );
|
||||||
|
edict_t *caller = INDEXENT( atoi( CMD_ARGV( 2 ) ) );
|
||||||
|
edict_t *activator = INDEXENT( atoi( CMD_ARGV( 3 ) ) );
|
||||||
|
USE_TYPE useType = USE_TYPE( atoi( CMD_ARGV( 4 ) ) );
|
||||||
|
float flValue = atof( CMD_ARGV( 5 ) );
|
||||||
|
|
||||||
|
// nevermind the unoptimization that this brings... >C
|
||||||
|
for (int index=0; index < monster_ents_used; index++)
|
||||||
|
{
|
||||||
|
if ((entity != NULL) && (entity == monsters[index].monster_pent))
|
||||||
|
{
|
||||||
|
if ( FNullEnt( caller ) ) caller = NULL;
|
||||||
|
if ( FNullEnt( activator ) ) activator = NULL;
|
||||||
|
|
||||||
|
monsters[index].pMonster->Use( activator, caller, useType, flValue );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmDispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd )
|
||||||
|
{
|
||||||
|
for (int index=0; index < monster_ents_used; index++)
|
||||||
|
{
|
||||||
|
if ((pentKeyvalue != NULL) && (pentKeyvalue == monsters[index].monster_pent))
|
||||||
|
{
|
||||||
|
monsters[index].pMonster->KeyValue( pkvd );
|
||||||
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_META(MRES_IGNORED);
|
||||||
|
}
|
||||||
|
|
||||||
void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
CMAGrunt agrunt;
|
// Monsters
|
||||||
|
CMAGrunt agrunt; // 0
|
||||||
CMApache apache;
|
CMApache apache;
|
||||||
CMBarney barney;
|
CMBarney barney;
|
||||||
CMBigMomma bigmomma;
|
CMBigMomma bigmomma;
|
||||||
@@ -1294,11 +1446,31 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
|||||||
CMTurret turret;
|
CMTurret turret;
|
||||||
CMMiniTurret miniturret;
|
CMMiniTurret miniturret;
|
||||||
CMSentry sentry;
|
CMSentry sentry;
|
||||||
|
CMGonome gonome;
|
||||||
|
CMMassn massn;
|
||||||
|
CMOtis otis;
|
||||||
|
CMPitdrone pitdrone;
|
||||||
|
CMShockRoach shockroach;
|
||||||
|
CMStrooper strooper;
|
||||||
|
CMVoltigore voltigore;
|
||||||
|
CMBabyVoltigore babyvoltigore;
|
||||||
|
CMBabyGargantua babygargantua;
|
||||||
|
CMHWGrunt hwgrunt;
|
||||||
|
CMRGrunt rgrunt;
|
||||||
|
CMStukabat stukabat; // 29
|
||||||
|
|
||||||
|
// Extra entities
|
||||||
|
CMMonsterMaker monstermaker; // 32
|
||||||
|
CMAmbientMusic ambientmusic;
|
||||||
|
CMXenMaker xenmaker;
|
||||||
|
CMSetCVar setcvar;
|
||||||
|
|
||||||
g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" );
|
g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" );
|
||||||
|
|
||||||
(g_engfuncs.pfnAddServerCommand)("monster", MonsterCommand);
|
(g_engfuncs.pfnAddServerCommand)("monster", MonsterCommand);
|
||||||
(g_engfuncs.pfnAddServerCommand)("node_viewer", SpawnViewerCommand);
|
(g_engfuncs.pfnAddServerCommand)("node_viewer", SpawnViewerCommand);
|
||||||
|
(g_engfuncs.pfnAddServerCommand)("get_edicts", DebugGetEntities);
|
||||||
|
(g_engfuncs.pfnAddServerCommand)("_use", mmDispatchUse);
|
||||||
|
|
||||||
for (index = 0; monster_types[index].name[0]; index++)
|
for (index = 0; monster_types[index].name[0]; index++)
|
||||||
{
|
{
|
||||||
@@ -1329,6 +1501,22 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
|||||||
case 15: turret.Precache(); break;
|
case 15: turret.Precache(); break;
|
||||||
case 16: miniturret.Precache(); break;
|
case 16: miniturret.Precache(); break;
|
||||||
case 17: sentry.Precache(); break;
|
case 17: sentry.Precache(); break;
|
||||||
|
case 18: gonome.Precache(); break;
|
||||||
|
case 19: massn.Precache(); break;
|
||||||
|
case 20: otis.Precache(); break;
|
||||||
|
case 21: pitdrone.Precache(); break;
|
||||||
|
case 22: shockroach.Precache(); break;
|
||||||
|
case 23: strooper.Precache(); break;
|
||||||
|
case 24: voltigore.Precache(); break;
|
||||||
|
case 25: babyvoltigore.Precache(); break;
|
||||||
|
case 26: babygargantua.Precache(); break;
|
||||||
|
case 27: hwgrunt.Precache(); break;
|
||||||
|
case 28: rgrunt.Precache(); break;
|
||||||
|
case 29: stukabat.Precache(); break;
|
||||||
|
case 32: monstermaker.Precache(); break;
|
||||||
|
//case 33: ambientmusic.Precache(); break;
|
||||||
|
case 34: xenmaker.Precache(); break;
|
||||||
|
//case 35: setcvar.Precache(); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1341,9 +1529,61 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
|||||||
monsters[index].pMonster = NULL;
|
monsters[index].pMonster = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (index = 0; index < 33; index++)
|
||||||
|
{
|
||||||
|
g_DamageBits[index] = 0;
|
||||||
|
g_PlayerKilled[index] = false;
|
||||||
|
g_NextMessage[index] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
monster_ents_used = 0;
|
monster_ents_used = 0;
|
||||||
|
|
||||||
|
RETURN_META(MRES_IGNORED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmStartFrame( void )
|
||||||
|
{
|
||||||
|
// Don't generate node graph right away
|
||||||
|
if (check_graph_time != -1 && check_graph_time <= gpGlobals->time)
|
||||||
|
{
|
||||||
|
BOOL generateNodes = FALSE;
|
||||||
|
|
||||||
|
check_graph_time = -1; // only once
|
||||||
|
|
||||||
|
// it could be possible that the mod can generate the node graph
|
||||||
|
// on it's own, so we wait a bit before attempting to create ours.
|
||||||
|
// if we can use the game's generated graph, stick to that one.
|
||||||
|
// if not, then do standard node allocation and spawns. -Giegue
|
||||||
|
|
||||||
|
// make sure the .NOD file is newer than the .BSP file.
|
||||||
|
if ( !WorldGraph.CheckNODFile ( ( char * )STRING( gpGlobals->mapname ) ) )
|
||||||
|
{
|
||||||
|
// NOD file is not present, or is older than the BSP file.
|
||||||
|
generateNodes = TRUE;
|
||||||
|
WorldGraph.AllocNodes();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Load the node graph for this level
|
||||||
|
if ( !WorldGraph.FLoadGraph ( (char *)STRING( gpGlobals->mapname ) ) )
|
||||||
|
{
|
||||||
|
// couldn't load, so alloc and prepare to build a graph.
|
||||||
|
generateNodes = TRUE;
|
||||||
|
ALERT ( at_console, "*Error opening .NOD file\n" );
|
||||||
|
WorldGraph.AllocNodes();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// node graph is OK, we can spawn the monsters instantly
|
||||||
|
check_respawn_time = 0.0;
|
||||||
|
ALERT ( at_console, "\n[MONSTER] Graph Loaded!\n" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( generateNodes )
|
||||||
|
{
|
||||||
// spawn nodes
|
// spawn nodes
|
||||||
|
int index;
|
||||||
for (index = 0; index < node_spawn_count; index++)
|
for (index = 0; index < node_spawn_count; index++)
|
||||||
{
|
{
|
||||||
CMBaseEntity *pNode;
|
CMBaseEntity *pNode;
|
||||||
@@ -1366,12 +1606,10 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
|||||||
pNode->Spawn();
|
pNode->Spawn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
// Wait for node graph before spawning the monsters
|
||||||
}
|
|
||||||
|
|
||||||
void mmStartFrame( void )
|
|
||||||
{
|
|
||||||
if (check_respawn_time <= gpGlobals->time)
|
if (check_respawn_time <= gpGlobals->time)
|
||||||
{
|
{
|
||||||
check_respawn_time = gpGlobals->time + 1.0;
|
check_respawn_time = gpGlobals->time + 1.0;
|
||||||
@@ -1382,22 +1620,34 @@ void mmStartFrame( void )
|
|||||||
RETURN_META(MRES_IGNORED);
|
RETURN_META(MRES_IGNORED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mmClientKill( edict_t *pPlayer )
|
void mmClientKill_Post( edict_t *pPlayer )
|
||||||
{
|
{
|
||||||
// Just to let the system know the player commited suicide
|
// Show "commited suicide" message
|
||||||
pPlayer->v.dmg_inflictor = pPlayer;
|
pPlayer->v.dmg_inflictor = pPlayer;
|
||||||
|
check_player_dead( pPlayer );
|
||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
RETURN_META(MRES_IGNORED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL mmClientConnect( edict_t *pPlayer, const char *pszName, const char *pszAddress, char *szRejectReason )
|
||||||
|
{
|
||||||
|
// stop any ambient_music that is playing
|
||||||
|
MESSAGE_BEGIN(MSG_ONE, SVC_STUFFTEXT, NULL, pPlayer);
|
||||||
|
WRITE_STRING("mp3 stop\n");
|
||||||
|
MESSAGE_END();
|
||||||
|
|
||||||
|
RETURN_META_VALUE( MRES_IGNORED, TRUE );
|
||||||
|
}
|
||||||
|
|
||||||
static DLL_FUNCTIONS gFunctionTable =
|
static DLL_FUNCTIONS gFunctionTable =
|
||||||
{
|
{
|
||||||
mmGameDLLInit, //! pfnGameInit() Initialize the game (one-time call after loading of game .dll)
|
mmGameDLLInit, //! pfnGameInit() Initialize the game (one-time call after loading of game .dll)
|
||||||
mmDispatchSpawn, //! pfnSpawn()
|
mmDispatchSpawn, //! pfnSpawn()
|
||||||
mmDispatchThink, //! pfnThink
|
mmDispatchThink, //! pfnThink
|
||||||
NULL, // pfnUse
|
NULL, // pfnUse [DEPRECATED]
|
||||||
mmDispatchTouch, //! pfnTouch
|
mmDispatchTouch, //! pfnTouch
|
||||||
NULL, // pfnBlocked
|
NULL, // pfnBlocked
|
||||||
NULL, // pfnKeyValue
|
mmDispatchKeyValue, //! pfnKeyValue
|
||||||
NULL, // pfnSave
|
NULL, // pfnSave
|
||||||
NULL, // pfnRestore
|
NULL, // pfnRestore
|
||||||
NULL, // pfnSetAbsBox
|
NULL, // pfnSetAbsBox
|
||||||
@@ -1409,9 +1659,9 @@ static DLL_FUNCTIONS gFunctionTable =
|
|||||||
NULL, // pfnRestoreGlobalState
|
NULL, // pfnRestoreGlobalState
|
||||||
NULL, // pfnResetGlobalState
|
NULL, // pfnResetGlobalState
|
||||||
|
|
||||||
NULL, // pfnClientConnect
|
mmClientConnect, //! pfnClientConnect
|
||||||
NULL, // pfnClientDisconnect
|
NULL, // pfnClientDisconnect
|
||||||
mmClientKill, //! pfnClientKill
|
NULL, // pfnClientKill
|
||||||
NULL, // pfnClientPutInServer
|
NULL, // pfnClientPutInServer
|
||||||
NULL, // pfnClientCommand
|
NULL, // pfnClientCommand
|
||||||
NULL, // pfnClientUserInfoChanged
|
NULL, // pfnClientUserInfoChanged
|
||||||
@@ -1483,7 +1733,7 @@ void mmPlayerPostThink_Post( edict_t *pEntity )
|
|||||||
{
|
{
|
||||||
check_monster_hurt(pEntity);
|
check_monster_hurt(pEntity);
|
||||||
check_monster_dead(pEntity);
|
check_monster_dead(pEntity);
|
||||||
check_player_dead(pEntity);
|
//check_player_dead(pEntity); // too early for damageBits
|
||||||
check_monster_info(pEntity);
|
check_monster_info(pEntity);
|
||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
RETURN_META(MRES_IGNORED);
|
||||||
@@ -1494,7 +1744,7 @@ static DLL_FUNCTIONS gFunctionTable_Post =
|
|||||||
NULL, // pfnGameInit() Initialize the game (one-time call after loading of game .dll)
|
NULL, // pfnGameInit() Initialize the game (one-time call after loading of game .dll)
|
||||||
NULL, // pfnSpawn()
|
NULL, // pfnSpawn()
|
||||||
mmDispatchThink_Post, //! pfnThink
|
mmDispatchThink_Post, //! pfnThink
|
||||||
NULL, // pfnUse
|
NULL, // pfnUse [DEPRECATED]
|
||||||
NULL, // pfnTouch
|
NULL, // pfnTouch
|
||||||
NULL, // pfnBlocked
|
NULL, // pfnBlocked
|
||||||
NULL, // pfnKeyValue
|
NULL, // pfnKeyValue
|
||||||
@@ -1511,7 +1761,7 @@ static DLL_FUNCTIONS gFunctionTable_Post =
|
|||||||
|
|
||||||
NULL, // pfnClientConnect
|
NULL, // pfnClientConnect
|
||||||
NULL, // pfnClientDisconnect
|
NULL, // pfnClientDisconnect
|
||||||
NULL, // pfnClientKill
|
mmClientKill_Post, //! pfnClientKill
|
||||||
NULL, // pfnClientPutInServer
|
NULL, // pfnClientPutInServer
|
||||||
NULL, // pfnClientCommand
|
NULL, // pfnClientCommand
|
||||||
NULL, // pfnClientUserInfoChanged
|
NULL, // pfnClientUserInfoChanged
|
||||||
@@ -1588,8 +1838,6 @@ int mmRegUserMsg_Post( const char *pName, int iSize )
|
|||||||
|
|
||||||
if ( strcmp( pName, "Damage" ) == 0 )
|
if ( strcmp( pName, "Damage" ) == 0 )
|
||||||
g_DamageMsg = META_RESULT_ORIG_RET( int ) - cs_server;
|
g_DamageMsg = META_RESULT_ORIG_RET( int ) - cs_server;
|
||||||
else if ( strcmp( pName, "DeathMsg" ) == 0 )
|
|
||||||
g_DeathMsg = META_RESULT_ORIG_RET( int );// - cs_server;
|
|
||||||
|
|
||||||
RETURN_META_VALUE( MRES_IGNORED, 0 );
|
RETURN_META_VALUE( MRES_IGNORED, 0 );
|
||||||
}
|
}
|
||||||
@@ -1603,14 +1851,8 @@ void mmMessageBegin_Post( int msg_dest, int msg_type, const float *pOrigin, edic
|
|||||||
{
|
{
|
||||||
g_DamageActive = true;
|
g_DamageActive = true;
|
||||||
g_DamageVictim = ENTINDEX( ed );
|
g_DamageVictim = ENTINDEX( ed );
|
||||||
g_DamageAttacker[ g_DamageVictim ] = ed->v.dmg_inflictor;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( msg_type == g_DeathMsg )
|
|
||||||
{
|
|
||||||
// Prepare to update deathmsg
|
|
||||||
g_DeathActive = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_META( MRES_IGNORED );
|
RETURN_META( MRES_IGNORED );
|
||||||
}
|
}
|
||||||
@@ -1623,35 +1865,17 @@ void mmWriteLong_Post( int iValue )
|
|||||||
RETURN_META( MRES_IGNORED );
|
RETURN_META( MRES_IGNORED );
|
||||||
}
|
}
|
||||||
|
|
||||||
// This cannot be done on post!
|
|
||||||
void mmWriteString( const char *szValue )
|
|
||||||
{
|
|
||||||
if ( g_DeathActive )
|
|
||||||
{
|
|
||||||
// Prevent recursion
|
|
||||||
g_DeathActive = false;
|
|
||||||
|
|
||||||
// Ensure whatever killed the player is a valid entity
|
|
||||||
if (g_DamageAttacker[ g_DamageVictim ] != NULL)
|
|
||||||
{
|
|
||||||
// Send a new WriteString with the killer's classname
|
|
||||||
WRITE_STRING( STRING( g_DamageAttacker[ g_DamageVictim ]->v.classname ) );
|
|
||||||
|
|
||||||
// Supercede the old message
|
|
||||||
RETURN_META( MRES_SUPERCEDE );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_META( MRES_IGNORED );
|
|
||||||
}
|
|
||||||
|
|
||||||
void mmMessageEnd_Post( void )
|
void mmMessageEnd_Post( void )
|
||||||
{
|
{
|
||||||
|
if ( g_DamageActive )
|
||||||
|
{
|
||||||
|
check_player_dead( INDEXENT( g_DamageVictim ) );
|
||||||
|
}
|
||||||
g_DamageActive = false;
|
g_DamageActive = false;
|
||||||
|
|
||||||
RETURN_META( MRES_IGNORED );
|
RETURN_META( MRES_IGNORED );
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
enginefuncs_t meta_engfuncs =
|
enginefuncs_t meta_engfuncs =
|
||||||
{
|
{
|
||||||
NULL, // pfnPrecacheModel()
|
NULL, // pfnPrecacheModel()
|
||||||
@@ -1721,7 +1945,7 @@ enginefuncs_t meta_engfuncs =
|
|||||||
NULL, // pfnWriteLong()
|
NULL, // pfnWriteLong()
|
||||||
NULL, // pfnWriteAngle()
|
NULL, // pfnWriteAngle()
|
||||||
NULL, // pfnWriteCoord()
|
NULL, // pfnWriteCoord()
|
||||||
mmWriteString, //! pfnWriteString()
|
NULL, // pfnWriteString()
|
||||||
NULL, // pfnWriteEntity()
|
NULL, // pfnWriteEntity()
|
||||||
|
|
||||||
NULL, // pfnCVarRegister()
|
NULL, // pfnCVarRegister()
|
||||||
@@ -1875,7 +2099,7 @@ C_DLLEXPORT int GetEngineFunctions(enginefuncs_t *pengfuncsFromEngine, int *inte
|
|||||||
memcpy(pengfuncsFromEngine, &meta_engfuncs, sizeof(enginefuncs_t));
|
memcpy(pengfuncsFromEngine, &meta_engfuncs, sizeof(enginefuncs_t));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
enginefuncs_t meta_engfuncs_post =
|
enginefuncs_t meta_engfuncs_post =
|
||||||
{
|
{
|
||||||
NULL, // pfnPrecacheModel()
|
NULL, // pfnPrecacheModel()
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ void CMBeam::BeamInit( const char *pSpriteName, int width )
|
|||||||
SetFrame( 0 );
|
SetFrame( 0 );
|
||||||
SetScrollRate( 0 );
|
SetScrollRate( 0 );
|
||||||
pev->model = MAKE_STRING( pSpriteName );
|
pev->model = MAKE_STRING( pSpriteName );
|
||||||
SetTexture( PRECACHE_MODEL( (char *)pSpriteName ) );
|
SetTexture( PRECACHE_MODELINDEX( (char *)pSpriteName ) );
|
||||||
SetWidth( width );
|
SetWidth( width );
|
||||||
pev->skin = 0;
|
pev->skin = 0;
|
||||||
pev->sequence = 0;
|
pev->sequence = 0;
|
||||||
@@ -332,14 +332,18 @@ void CMSprite::SpriteInit( const char *pSpriteName, const Vector &origin )
|
|||||||
CMSprite *CMSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate )
|
CMSprite *CMSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate )
|
||||||
{
|
{
|
||||||
CMSprite *pSprite = CreateClassPtr( (CMSprite *)NULL );
|
CMSprite *pSprite = CreateClassPtr( (CMSprite *)NULL );
|
||||||
pSprite->SpriteInit( pSpriteName, origin );
|
if (pSprite)
|
||||||
|
{
|
||||||
|
pSprite->SpriteInit(pSpriteName, origin);
|
||||||
pSprite->pev->classname = MAKE_STRING("env_sprite");
|
pSprite->pev->classname = MAKE_STRING("env_sprite");
|
||||||
pSprite->pev->solid = SOLID_NOT;
|
pSprite->pev->solid = SOLID_NOT;
|
||||||
pSprite->pev->movetype = MOVETYPE_NOCLIP;
|
pSprite->pev->movetype = MOVETYPE_NOCLIP;
|
||||||
if ( animate )
|
if (animate)
|
||||||
pSprite->TurnOn();
|
pSprite->TurnOn();
|
||||||
|
|
||||||
return pSprite;
|
return pSprite;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -79,10 +79,13 @@ public:
|
|||||||
|
|
||||||
inline void AnimateAndDie( float framerate )
|
inline void AnimateAndDie( float framerate )
|
||||||
{
|
{
|
||||||
|
pev->effects = 0;
|
||||||
SetThink(&CMSprite::AnimateUntilDead);
|
SetThink(&CMSprite::AnimateUntilDead);
|
||||||
pev->framerate = framerate;
|
pev->framerate = framerate;
|
||||||
pev->dmgtime = gpGlobals->time + (m_maxFrame / framerate);
|
pev->dmgtime = gpGlobals->time + (m_maxFrame / framerate);
|
||||||
pev->nextthink = gpGlobals->time;
|
pev->nextthink = gpGlobals->time;
|
||||||
|
m_lastTime = gpGlobals->time;
|
||||||
|
pev->frame = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EXPORT AnimateUntilDead( void );
|
void EXPORT AnimateUntilDead( void );
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ extern enginefuncs_t g_engfuncs;
|
|||||||
|
|
||||||
// The actual engine callbacks
|
// The actual engine callbacks
|
||||||
#define GETPLAYERUSERID (*g_engfuncs.pfnGetPlayerUserId)
|
#define GETPLAYERUSERID (*g_engfuncs.pfnGetPlayerUserId)
|
||||||
#define PRECACHE_MODEL (*g_engfuncs.pfnPrecacheModel)
|
#define PRECACHE_MODEL2 (*g_engfuncs.pfnPrecacheModel)
|
||||||
#define PRECACHE_SOUND (*g_engfuncs.pfnPrecacheSound)
|
#define PRECACHE_SOUND2 (*g_engfuncs.pfnPrecacheSound)
|
||||||
#define PRECACHE_GENERIC (*g_engfuncs.pfnPrecacheGeneric)
|
#define PRECACHE_GENERIC (*g_engfuncs.pfnPrecacheGeneric)
|
||||||
#define SET_MODEL (*g_engfuncs.pfnSetModel)
|
#define SET_MODEL2 (*g_engfuncs.pfnSetModel)
|
||||||
#define MODEL_INDEX (*g_engfuncs.pfnModelIndex)
|
#define MODEL_INDEX (*g_engfuncs.pfnModelIndex)
|
||||||
#define MODEL_FRAMES (*g_engfuncs.pfnModelFrames)
|
#define MODEL_FRAMES (*g_engfuncs.pfnModelFrames)
|
||||||
#define SET_SIZE (*g_engfuncs.pfnSetSize)
|
#define SET_SIZE (*g_engfuncs.pfnSetSize)
|
||||||
|
|||||||
69
src/dlls/explode.cpp
Executable file → Normal file
69
src/dlls/explode.cpp
Executable file → Normal file
@@ -54,7 +54,7 @@ void CMShower::Spawn( void )
|
|||||||
pev->speed = RANDOM_FLOAT( 0.5, 1.5 );
|
pev->speed = RANDOM_FLOAT( 0.5, 1.5 );
|
||||||
|
|
||||||
pev->angles = g_vecZero;
|
pev->angles = g_vecZero;
|
||||||
pev->classname = MAKE_STRING( "_spark_shower" );
|
pev->classname = MAKE_STRING( "spark_shower" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -81,13 +81,53 @@ void CMShower::Touch( CMBaseEntity *pOther )
|
|||||||
pev->speed = 0;
|
pev->speed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Puff of Smoke
|
||||||
|
class CSmoker : public CMBaseEntity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn( void );
|
||||||
|
void Think( void );
|
||||||
|
};
|
||||||
|
|
||||||
|
void CSmoker::Spawn( void )
|
||||||
|
{
|
||||||
|
pev->movetype = MOVETYPE_NONE;
|
||||||
|
pev->nextthink = gpGlobals->time;
|
||||||
|
pev->solid = SOLID_NOT;
|
||||||
|
UTIL_SetSize(pev, g_vecZero, g_vecZero );
|
||||||
|
pev->effects |= EF_NODRAW;
|
||||||
|
pev->angles = g_vecZero;
|
||||||
|
pev->classname = MAKE_STRING("env_smoker");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSmoker::Think( void )
|
||||||
|
{
|
||||||
|
// lots of smoke
|
||||||
|
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
||||||
|
WRITE_BYTE( TE_SMOKE );
|
||||||
|
WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -pev->dmg, pev->dmg ));
|
||||||
|
WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -pev->dmg, pev->dmg ));
|
||||||
|
WRITE_COORD( pev->origin.z);
|
||||||
|
WRITE_SHORT( g_sModelIndexSmoke );
|
||||||
|
WRITE_BYTE( RANDOM_LONG(pev->scale, pev->scale * 1.1) );
|
||||||
|
WRITE_BYTE( RANDOM_LONG(8,14) ); // framerate
|
||||||
|
MESSAGE_END();
|
||||||
|
|
||||||
|
pev->health--;
|
||||||
|
if ( pev->health > 0 )
|
||||||
|
pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.1, 0.2);
|
||||||
|
else
|
||||||
|
UTIL_Remove( this->edict() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explosion
|
||||||
class CMEnvExplosion : public CMBaseMonster
|
class CMEnvExplosion : public CMBaseMonster
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void Spawn( );
|
void Spawn( );
|
||||||
void EXPORT Smoke ( void );
|
void EXPORT Smoke ( void );
|
||||||
void KeyValue( KeyValueData *pkvd );
|
void KeyValue( KeyValueData *pkvd );
|
||||||
void DelayUse( void );
|
void EXPORT DelayUse( void );
|
||||||
void Use( CMBaseEntity *pActivator, CMBaseEntity *pCaller, USE_TYPE useType, float value );
|
void Use( CMBaseEntity *pActivator, CMBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||||
|
|
||||||
int m_iMagnitude;// how large is the fireball? how much damage?
|
int m_iMagnitude;// how large is the fireball? how much damage?
|
||||||
@@ -133,7 +173,7 @@ void CMEnvExplosion::Spawn( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_spriteScale = (int)flSpriteScale;
|
m_spriteScale = (int)flSpriteScale;
|
||||||
pev->classname = MAKE_STRING( "_env_explosion" );
|
pev->classname = MAKE_STRING( "env_explosion" );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMEnvExplosion::DelayUse( void )
|
void CMEnvExplosion::DelayUse( void )
|
||||||
@@ -259,7 +299,8 @@ void CMEnvExplosion::Smoke( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Stock to quickly create a one-time explosion
|
// Stocks:
|
||||||
|
// Create a one-time explosion
|
||||||
void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, int flags, float delay )
|
void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, int flags, float delay )
|
||||||
{
|
{
|
||||||
KeyValueData kvd;
|
KeyValueData kvd;
|
||||||
@@ -287,15 +328,19 @@ void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwne
|
|||||||
pExplosion->pev->spawnflags &= ~SF_ENVEXPLOSION_REPEATABLE;
|
pExplosion->pev->spawnflags &= ~SF_ENVEXPLOSION_REPEATABLE;
|
||||||
|
|
||||||
pExplosion->Spawn();
|
pExplosion->Spawn();
|
||||||
if ( delay > 0.0f )
|
|
||||||
{
|
|
||||||
//pExplosion->SetThink( &CMBaseEntity::SUB_CallUseToggle ); // i don't trust you
|
|
||||||
pExplosion->SetThink( &CMEnvExplosion::DelayUse );
|
pExplosion->SetThink( &CMEnvExplosion::DelayUse );
|
||||||
pExplosion->pev->nextthink = gpGlobals->time + delay;
|
pExplosion->pev->nextthink = gpGlobals->time + delay;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
|
||||||
pExplosion->Use( NULL, NULL, USE_TOGGLE, 0 );
|
// Emit smoke
|
||||||
}
|
void SmokeCreate( const Vector &origin, int amount, int size, int radius, float delay )
|
||||||
}
|
{
|
||||||
|
CMBaseEntity *pSmoker = CreateClassPtr((CSmoker *)NULL); // CMBaseEntity::Create( "env_smoker", pev->origin, g_vecZero, NULL );
|
||||||
|
UTIL_SetOrigin( pSmoker->pev, origin );
|
||||||
|
pSmoker->Spawn();
|
||||||
|
pSmoker->pev->health = amount; // number of smoke balls
|
||||||
|
pSmoker->pev->scale = size; // size in 0.1x - size 10 = x1.0
|
||||||
|
pSmoker->pev->dmg = radius; // radial distribution
|
||||||
|
pSmoker->pev->nextthink = gpGlobals->time + delay; // Start in ... seconds
|
||||||
}
|
}
|
||||||
@@ -25,8 +25,9 @@
|
|||||||
|
|
||||||
extern DLL_GLOBAL short g_sModelIndexFireball;
|
extern DLL_GLOBAL short g_sModelIndexFireball;
|
||||||
extern DLL_GLOBAL short g_sModelIndexSmoke;
|
extern DLL_GLOBAL short g_sModelIndexSmoke;
|
||||||
|
extern DLL_GLOBAL short g_sModelIndexTinySpit;
|
||||||
|
|
||||||
extern void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, int flags, float delay );
|
extern void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, int flags, float delay );
|
||||||
|
extern void SmokeCreate( const Vector &origin, int amount, int size, int radius, float delay );
|
||||||
|
|
||||||
#endif //EXPLODE_H
|
#endif //EXPLODE_H
|
||||||
|
|||||||
@@ -26,11 +26,15 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Silence certain warnings
|
// Silence certain warnings
|
||||||
|
// PS: All warnings to be silenced until T5 milestone. -Giegue
|
||||||
#pragma warning(disable : 4244) // int or float down-conversion
|
#pragma warning(disable : 4244) // int or float down-conversion
|
||||||
#pragma warning(disable : 4305) // int or float data truncation
|
#pragma warning(disable : 4305) // int or float data truncation
|
||||||
#pragma warning(disable : 4201) // nameless struct/union
|
#pragma warning(disable : 4201) // nameless struct/union
|
||||||
#pragma warning(disable : 4514) // unreferenced inline function removed
|
#pragma warning(disable : 4514) // unreferenced inline function removed
|
||||||
#pragma warning(disable : 4100) // unreferenced formal parameter
|
#pragma warning(disable : 4100) // unreferenced formal parameter
|
||||||
|
#pragma warning(disable : 4390) // empty controlled statement (seems to work fine? monster_api.cpp[101/115])
|
||||||
|
#pragma warning(disable : 4091) // nameless typedef
|
||||||
|
#pragma warning(disable : 4996) // unsafe string operations
|
||||||
|
|
||||||
// Prevent tons of unused windows definitions
|
// Prevent tons of unused windows definitions
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "cmbase.h"
|
#include "cmbase.h"
|
||||||
#include "cmbasemonster.h"
|
#include "cmbasemonster.h"
|
||||||
|
#include "cmflyingmonster.h"
|
||||||
#include "monsters.h"
|
#include "monsters.h"
|
||||||
#include "schedule.h"
|
#include "schedule.h"
|
||||||
|
|
||||||
@@ -23,8 +24,6 @@
|
|||||||
#define FLYING_AE_FLAPSOUND (9)
|
#define FLYING_AE_FLAPSOUND (9)
|
||||||
|
|
||||||
|
|
||||||
extern DLL_GLOBAL edict_t *g_pBodyQueueHead;
|
|
||||||
|
|
||||||
int CMFlyingMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, edict_t *pTarget, float *pflDist )
|
int CMFlyingMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, edict_t *pTarget, float *pflDist )
|
||||||
{
|
{
|
||||||
// UNDONE: need to check more than the endpoint
|
// UNDONE: need to check more than the endpoint
|
||||||
|
|||||||
684
src/dlls/gargantua.cpp
Executable file → Normal file
684
src/dlls/gargantua.cpp
Executable file → Normal file
@@ -62,13 +62,6 @@ const float GARG_ATTACKDIST = 80.0;
|
|||||||
int gStompSprite = 0, gGargGibModel = 0;
|
int gStompSprite = 0, gGargGibModel = 0;
|
||||||
void SpawnExplosion( Vector center, float randomRange, float time, int magnitude, edict_t *owner );
|
void SpawnExplosion( Vector center, float randomRange, float time, int magnitude, edict_t *owner );
|
||||||
|
|
||||||
class CSmoker : public CMBaseEntity
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void Spawn( void );
|
|
||||||
void Think( void );
|
|
||||||
};
|
|
||||||
|
|
||||||
// Spiral Effect
|
// Spiral Effect
|
||||||
class CSpiral : public CMBaseEntity
|
class CSpiral : public CMBaseEntity
|
||||||
{
|
{
|
||||||
@@ -84,14 +77,14 @@ class CStomp : public CMBaseEntity
|
|||||||
public:
|
public:
|
||||||
void Spawn( void );
|
void Spawn( void );
|
||||||
void Think( void );
|
void Think( void );
|
||||||
static CStomp *StompCreate( const Vector &origin, const Vector &end, float speed );
|
static CStomp *StompCreate( const Vector &origin, const Vector &end, float speed, float damage );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// UNDONE: re-use this sprite list instead of creating new ones all the time
|
// UNDONE: re-use this sprite list instead of creating new ones all the time
|
||||||
// CSprite *m_pSprites[ STOMP_SPRITE_COUNT ];
|
// CSprite *m_pSprites[ STOMP_SPRITE_COUNT ];
|
||||||
};
|
};
|
||||||
|
|
||||||
CStomp *CStomp::StompCreate( const Vector &origin, const Vector &end, float speed )
|
CStomp *CStomp::StompCreate( const Vector &origin, const Vector &end, float speed, float damage )
|
||||||
{
|
{
|
||||||
CStomp *pStomp = CreateClassPtr( (CStomp *)NULL );
|
CStomp *pStomp = CreateClassPtr( (CStomp *)NULL );
|
||||||
|
|
||||||
@@ -100,6 +93,7 @@ CStomp *CStomp::StompCreate( const Vector &origin, const Vector &end, float spee
|
|||||||
pStomp->pev->scale = dir.Length();
|
pStomp->pev->scale = dir.Length();
|
||||||
pStomp->pev->movedir = dir.Normalize();
|
pStomp->pev->movedir = dir.Normalize();
|
||||||
pStomp->pev->speed = speed;
|
pStomp->pev->speed = speed;
|
||||||
|
pStomp->pev->dmg = damage;
|
||||||
pStomp->Spawn();
|
pStomp->Spawn();
|
||||||
|
|
||||||
return pStomp;
|
return pStomp;
|
||||||
@@ -136,13 +130,23 @@ void CStomp::Think( void )
|
|||||||
|
|
||||||
if ( tr.pHit && tr.pHit != pev->owner )
|
if ( tr.pHit && tr.pHit != pev->owner )
|
||||||
{
|
{
|
||||||
CMBaseEntity *pEntity = CMBaseEntity::Instance( tr.pHit );
|
edict_t *pEntity = tr.pHit;
|
||||||
entvars_t *pevOwner = pev;
|
entvars_t *pevOwner = pev;
|
||||||
if ( pev->owner )
|
if ( pev->owner )
|
||||||
pevOwner = VARS(pev->owner);
|
pevOwner = VARS(pev->owner);
|
||||||
|
|
||||||
if ( pEntity )
|
if (pEntity->v.takedamage)
|
||||||
pEntity->TakeDamage( pev, pevOwner, gSkillData.gargantuaDmgStomp, DMG_SONIC );
|
{
|
||||||
|
if (UTIL_IsPlayer(pEntity))
|
||||||
|
UTIL_TakeDamage(pEntity, pev, pevOwner, pev->dmg, DMG_SONIC);
|
||||||
|
else if (pEntity->v.euser4 != NULL)
|
||||||
|
{
|
||||||
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
|
||||||
|
pMonster->TakeDamage(pev, pevOwner, pev->dmg, DMG_SONIC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
UTIL_TakeDamageExternal(pEntity, pev, pevOwner, pev->dmg, DMG_SONIC);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accelerate the effect
|
// Accelerate the effect
|
||||||
@@ -388,7 +392,7 @@ void CMGargantua::StompAttack( void )
|
|||||||
Vector vecEnd = (vecAim * 1024) + vecStart;
|
Vector vecEnd = (vecAim * 1024) + vecStart;
|
||||||
|
|
||||||
UTIL_TraceLine( vecStart, vecEnd, ignore_monsters, edict(), &trace );
|
UTIL_TraceLine( vecStart, vecEnd, ignore_monsters, edict(), &trace );
|
||||||
CStomp::StompCreate( vecStart, trace.vecEndPos, 0 );
|
CStomp::StompCreate( vecStart, trace.vecEndPos, 0, gSkillData.gargantuaDmgStomp );
|
||||||
UTIL_ScreenShake( pev->origin, 12.0, 100.0, 2.0, 1000 );
|
UTIL_ScreenShake( pev->origin, 12.0, 100.0, 2.0, 1000 );
|
||||||
EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pStompSounds[ RANDOM_LONG(0,ARRAYSIZE(pStompSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10,10) );
|
EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pStompSounds[ RANDOM_LONG(0,ARRAYSIZE(pStompSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10,10) );
|
||||||
|
|
||||||
@@ -489,8 +493,8 @@ void CMGargantua :: FlameUpdate( void )
|
|||||||
streaks = TRUE;
|
streaks = TRUE;
|
||||||
UTIL_DecalTrace( &trace, DECAL_SMALLSCORCH1 + RANDOM_LONG(0,2) );
|
UTIL_DecalTrace( &trace, DECAL_SMALLSCORCH1 + RANDOM_LONG(0,2) );
|
||||||
}
|
}
|
||||||
// RadiusDamage( trace.vecEndPos, pev, pev, gSkillData.gargantuaDmgFire, CLASS_ALIEN_MONSTER, DMG_BURN );
|
// RadiusDamage( trace.vecEndPos, pev, pev, gSkillData.gargantuaDmgFire, Classify(), DMG_BURN );
|
||||||
FlameDamage( vecStart, trace.vecEndPos, pev, pev, gSkillData.gargantuaDmgFire, CLASS_ALIEN_MONSTER, DMG_BURN );
|
FlameDamage( vecStart, trace.vecEndPos, pev, pev, gSkillData.gargantuaDmgFire, Classify(), DMG_BURN );
|
||||||
|
|
||||||
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
||||||
WRITE_BYTE( TE_ELIGHT );
|
WRITE_BYTE( TE_ELIGHT );
|
||||||
@@ -570,6 +574,8 @@ void CMGargantua :: FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevI
|
|||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
|
||||||
pMonster->TraceAttack( pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize(), &tr, bitsDamageType );
|
pMonster->TraceAttack( pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize(), &tr, bitsDamageType );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
UTIL_TraceAttack( pEntity, pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize(), &tr, bitsDamageType );
|
||||||
ApplyMultiDamage( pevInflictor, pevAttacker );
|
ApplyMultiDamage( pevInflictor, pevAttacker );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -581,6 +587,8 @@ void CMGargantua :: FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevI
|
|||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
|
||||||
pMonster->TakeDamage( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType );
|
pMonster->TakeDamage( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
UTIL_TakeDamageExternal( pEntity, pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -670,13 +678,13 @@ void CMGargantua :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/garg.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/garg.mdl"));
|
||||||
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
|
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
pev->movetype = MOVETYPE_STEP;
|
pev->movetype = MOVETYPE_STEP;
|
||||||
m_bloodColor = BLOOD_COLOR_GREEN;
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
|
||||||
pev->health = gSkillData.gargantuaHealth;
|
if (!pev->health) { pev->health = gSkillData.gargantuaHealth; }
|
||||||
//pev->view_ofs = Vector ( 0, 0, 96 );// taken from mdl file
|
//pev->view_ofs = Vector ( 0, 0, 96 );// taken from mdl file
|
||||||
m_flFieldOfView = -0.2;// width of forward view cone ( as a dotproduct result )
|
m_flFieldOfView = -0.2;// width of forward view cone ( as a dotproduct result )
|
||||||
m_MonsterState = MONSTERSTATE_NONE;
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
@@ -704,48 +712,25 @@ void CMGargantua :: Spawn()
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
void CMGargantua :: Precache()
|
void CMGargantua :: Precache()
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
PRECACHE_MODEL("models/garg.mdl");
|
PRECACHE_MODEL("models/garg.mdl");
|
||||||
PRECACHE_MODEL( GARG_EYE_SPRITE_NAME );
|
PRECACHE_MODEL( GARG_EYE_SPRITE_NAME );
|
||||||
PRECACHE_MODEL( GARG_BEAM_SPRITE_NAME );
|
PRECACHE_MODEL( GARG_BEAM_SPRITE_NAME );
|
||||||
PRECACHE_MODEL( GARG_BEAM_SPRITE2 );
|
PRECACHE_MODEL( GARG_BEAM_SPRITE2 );
|
||||||
gStompSprite = PRECACHE_MODEL( GARG_STOMP_SPRITE_NAME );
|
gStompSprite = PRECACHE_MODELINDEX( GARG_STOMP_SPRITE_NAME );
|
||||||
gGargGibModel = PRECACHE_MODEL( GARG_GIB_MODEL );
|
gGargGibModel = PRECACHE_MODELINDEX( GARG_GIB_MODEL );
|
||||||
PRECACHE_SOUND( GARG_STOMP_BUZZ_SOUND );
|
PRECACHE_SOUND( GARG_STOMP_BUZZ_SOUND );
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
|
PRECACHE_SOUND_ARRAY(pAttackHitSounds);
|
||||||
PRECACHE_SOUND((char *)pAttackHitSounds[i]);
|
PRECACHE_SOUND_ARRAY(pBeamAttackSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pAttackMissSounds);
|
||||||
for ( i = 0; i < ARRAYSIZE( pBeamAttackSounds ); i++ )
|
PRECACHE_SOUND_ARRAY(pRicSounds);
|
||||||
PRECACHE_SOUND((char *)pBeamAttackSounds[i]);
|
PRECACHE_SOUND_ARRAY(pFootSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pIdleSounds);
|
||||||
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
|
PRECACHE_SOUND_ARRAY(pAlertSounds);
|
||||||
PRECACHE_SOUND((char *)pAttackMissSounds[i]);
|
PRECACHE_SOUND_ARRAY(pPainSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pAttackSounds);
|
||||||
for ( i = 0; i < ARRAYSIZE( pRicSounds ); i++ )
|
PRECACHE_SOUND_ARRAY(pStompSounds);
|
||||||
PRECACHE_SOUND((char *)pRicSounds[i]);
|
PRECACHE_SOUND_ARRAY(pBreatheSounds);
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pFootSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pFootSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pIdleSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pAlertSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pPainSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pAttackSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pStompSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pStompSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pBreatheSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pBreatheSounds[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -780,7 +765,7 @@ void CMGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector ve
|
|||||||
// if ( RANDOM_LONG(0,100) < 25 )
|
// if ( RANDOM_LONG(0,100) < 25 )
|
||||||
// EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, pRicSounds[ RANDOM_LONG(0,ARRAYSIZE(pRicSounds)-1) ], 1.0, ATTN_NORM, 0, PITCH_NORM );
|
// EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, pRicSounds[ RANDOM_LONG(0,ARRAYSIZE(pRicSounds)-1) ], 1.0, ATTN_NORM, 0, PITCH_NORM );
|
||||||
}
|
}
|
||||||
flDamage *= (1.01f - gSkillData.gargantuaArmor); // Again, for mods (see below)
|
// flDamage *= (1.00f - gSkillData.gargantuaArmor); // in here...?
|
||||||
}
|
}
|
||||||
|
|
||||||
CMBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
|
CMBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
|
||||||
@@ -788,13 +773,12 @@ void CMGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector ve
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int CMGargantua::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
int CMGargantua::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
||||||
{
|
{
|
||||||
if ( IsAlive() )
|
if ( IsAlive() )
|
||||||
{
|
{
|
||||||
if ( !(bitsDamageType & GARG_DAMAGE) )
|
if ( !(bitsDamageType & GARG_DAMAGE) )
|
||||||
flDamage *= (1.01f - gSkillData.gargantuaArmor); // This is for mods that don't use explosives of any kind or do not work with the gargantua.
|
flDamage *= (1.00f - gSkillData.gargantuaArmor); // This is for mods that don't use explosives of any kind or do not work with the gargantua.
|
||||||
|
|
||||||
// Always set
|
// Always set
|
||||||
SetConditions( bits_COND_LIGHT_DAMAGE );
|
SetConditions( bits_COND_LIGHT_DAMAGE );
|
||||||
@@ -821,21 +805,22 @@ void CMGargantua::DeathEffect( void )
|
|||||||
position.z += 15;
|
position.z += 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
CMBaseEntity *pSmoker = CreateClassPtr((CSmoker *)NULL); // CMBaseEntity::Create( "env_smoker", pev->origin, g_vecZero, NULL );
|
// 1 smoke balls
|
||||||
UTIL_SetOrigin( pSmoker->pev, pev->origin );
|
// 4.6X normal size
|
||||||
pSmoker->Spawn();
|
// 0 radial distribution
|
||||||
pSmoker->pev->health = 1; // 1 smoke balls
|
// start in 2.5 seconds
|
||||||
pSmoker->pev->scale = 46; // 4.6X normal size
|
SmokeCreate( pev->origin, 1, 46, 0, 2.5 );
|
||||||
pSmoker->pev->dmg = 0; // 0 radial distribution
|
|
||||||
pSmoker->pev->nextthink = gpGlobals->time + 2.5; // Start in 2.5 seconds
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CMGargantua::Killed( entvars_t *pevAttacker, int iGib )
|
void CMGargantua::Killed( entvars_t *pevAttacker, int iGib )
|
||||||
{
|
{
|
||||||
|
if ( m_pEyeGlow )
|
||||||
|
{
|
||||||
EyeOff();
|
EyeOff();
|
||||||
UTIL_Remove( m_pEyeGlow->edict() );
|
UTIL_Remove( m_pEyeGlow->edict() );
|
||||||
m_pEyeGlow = NULL;
|
m_pEyeGlow = NULL;
|
||||||
|
}
|
||||||
CMBaseMonster::Killed( pevAttacker, GIB_NEVER );
|
CMBaseMonster::Killed( pevAttacker, GIB_NEVER );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -985,6 +970,8 @@ edict_t *CMGargantua::GargantuaCheckTraceHullAttack(float flDist, int iDamage, i
|
|||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit));
|
||||||
pMonster->TakeDamage( pev, pev, iDamage, iDmgType );
|
pMonster->TakeDamage( pev, pev, iDamage, iDmgType );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
UTIL_TakeDamageExternal( tr.pHit, pev, pev, iDamage, iDmgType );
|
||||||
}
|
}
|
||||||
|
|
||||||
return tr.pHit;
|
return tr.pHit;
|
||||||
@@ -1166,38 +1153,6 @@ void CMGargantua::RunTask( Task_t *pTask )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSmoker::Spawn( void )
|
|
||||||
{
|
|
||||||
pev->movetype = MOVETYPE_NONE;
|
|
||||||
pev->nextthink = gpGlobals->time;
|
|
||||||
pev->solid = SOLID_NOT;
|
|
||||||
UTIL_SetSize(pev, g_vecZero, g_vecZero );
|
|
||||||
pev->effects |= EF_NODRAW;
|
|
||||||
pev->angles = g_vecZero;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CSmoker::Think( void )
|
|
||||||
{
|
|
||||||
// lots of smoke
|
|
||||||
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
|
||||||
WRITE_BYTE( TE_SMOKE );
|
|
||||||
WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -pev->dmg, pev->dmg ));
|
|
||||||
WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -pev->dmg, pev->dmg ));
|
|
||||||
WRITE_COORD( pev->origin.z);
|
|
||||||
WRITE_SHORT( g_sModelIndexSmoke );
|
|
||||||
WRITE_BYTE( RANDOM_LONG(pev->scale, pev->scale * 1.1) );
|
|
||||||
WRITE_BYTE( RANDOM_LONG(8,14) ); // framerate
|
|
||||||
MESSAGE_END();
|
|
||||||
|
|
||||||
pev->health--;
|
|
||||||
if ( pev->health > 0 )
|
|
||||||
pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.1, 0.2);
|
|
||||||
else
|
|
||||||
UTIL_Remove( this->edict() );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CSpiral::Spawn( void )
|
void CSpiral::Spawn( void )
|
||||||
{
|
{
|
||||||
pev->movetype = MOVETYPE_NONE;
|
pev->movetype = MOVETYPE_NONE;
|
||||||
@@ -1265,13 +1220,10 @@ void CSpiral::Think( void )
|
|||||||
|
|
||||||
void SpawnExplosion( Vector center, float randomRange, float time, int magnitude, edict_t *owner )
|
void SpawnExplosion( Vector center, float randomRange, float time, int magnitude, edict_t *owner )
|
||||||
{
|
{
|
||||||
|
/* no need for this
|
||||||
KeyValueData kvd;
|
KeyValueData kvd;
|
||||||
char buf[128];
|
char buf[128];
|
||||||
|
|
||||||
center.x += RANDOM_FLOAT( -randomRange, randomRange );
|
|
||||||
center.y += RANDOM_FLOAT( -randomRange, randomRange );
|
|
||||||
|
|
||||||
/*
|
|
||||||
CMBaseEntity *pExplosion = CreateClassPtr((CEnvExplosion *)NULL); // CMBaseEntity::Create( "env_explosion", center, g_vecZero, NULL );
|
CMBaseEntity *pExplosion = CreateClassPtr((CEnvExplosion *)NULL); // CMBaseEntity::Create( "env_explosion", center, g_vecZero, NULL );
|
||||||
sprintf( buf, "%3d", magnitude );
|
sprintf( buf, "%3d", magnitude );
|
||||||
kvd.szKeyName = "iMagnitude";
|
kvd.szKeyName = "iMagnitude";
|
||||||
@@ -1284,6 +1236,538 @@ void SpawnExplosion( Vector center, float randomRange, float time, int magnitude
|
|||||||
pExplosion->pev->nextthink = gpGlobals->time + time;
|
pExplosion->pev->nextthink = gpGlobals->time + time;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
center.x += RANDOM_FLOAT( -randomRange, randomRange );
|
||||||
|
center.y += RANDOM_FLOAT( -randomRange, randomRange );
|
||||||
|
|
||||||
// explode.h
|
// explode.h
|
||||||
ExplosionCreate( center, g_vecZero, owner, magnitude, SF_ENVEXPLOSION_NODAMAGE, time );
|
ExplosionCreate( center, g_vecZero, owner, magnitude, SF_ENVEXPLOSION_NODAMAGE, time );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Sven Co-op's monster code was recreated from scratch.
|
||||||
|
* They do not contain their unique new attacks... YET. -Giegue
|
||||||
|
* */
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Baby Gargantua
|
||||||
|
//=========================================================
|
||||||
|
const float BABYGARG_ATTACKDIST = 65.0;
|
||||||
|
#define BABYGARG_FLAME_LENGTH 180
|
||||||
|
|
||||||
|
|
||||||
|
const char *CMBabyGargantua::pBeamAttackSounds[] =
|
||||||
|
{
|
||||||
|
"babygarg/gar_flameoff1.wav",
|
||||||
|
"babygarg/gar_flameon1.wav",
|
||||||
|
"babygarg/gar_flamerun1.wav",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *CMBabyGargantua::pFootSounds[] =
|
||||||
|
{
|
||||||
|
"babygarg/gar_step1.wav",
|
||||||
|
"babygarg/gar_step2.wav",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *CMBabyGargantua::pIdleSounds[] =
|
||||||
|
{
|
||||||
|
"babygarg/gar_idle1.wav",
|
||||||
|
"babygarg/gar_idle2.wav",
|
||||||
|
"babygarg/gar_idle3.wav",
|
||||||
|
"babygarg/gar_idle4.wav",
|
||||||
|
"babygarg/gar_idle5.wav",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *CMBabyGargantua::pAttackSounds[] =
|
||||||
|
{
|
||||||
|
"babygarg/gar_attack1.wav",
|
||||||
|
"babygarg/gar_attack2.wav",
|
||||||
|
"babygarg/gar_attack3.wav",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *CMBabyGargantua::pAlertSounds[] =
|
||||||
|
{
|
||||||
|
"babygarg/gar_alert1.wav",
|
||||||
|
"babygarg/gar_alert2.wav",
|
||||||
|
"babygarg/gar_alert3.wav",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *CMBabyGargantua::pPainSounds[] =
|
||||||
|
{
|
||||||
|
"babygarg/gar_pain1.wav",
|
||||||
|
"babygarg/gar_pain2.wav",
|
||||||
|
"babygarg/gar_pain3.wav",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *CMBabyGargantua::pStompSounds[] =
|
||||||
|
{
|
||||||
|
"babygarg/gar_stomp1.wav",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *CMBabyGargantua::pBreatheSounds[] =
|
||||||
|
{
|
||||||
|
"babygarg/gar_breathe1.wav",
|
||||||
|
"babygarg/gar_breathe2.wav",
|
||||||
|
"babygarg/gar_breathe3.wav",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *CMBabyGargantua::pDieSounds[] =
|
||||||
|
{
|
||||||
|
"babygarg/gar_die1.wav",
|
||||||
|
"babygarg/gar_die2.wav",
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Spawn
|
||||||
|
//=========================================================
|
||||||
|
void CMBabyGargantua::Spawn()
|
||||||
|
{
|
||||||
|
Precache( );
|
||||||
|
|
||||||
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/babygarg.mdl"));
|
||||||
|
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
|
||||||
|
|
||||||
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
pev->movetype = MOVETYPE_STEP;
|
||||||
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
|
||||||
|
if (!pev->health) { pev->health = gSkillData.babygargHealth; }
|
||||||
|
//pev->view_ofs = Vector ( 0, 0, 96 );// taken from mdl file
|
||||||
|
m_flFieldOfView = -0.2;// width of forward view cone ( as a dotproduct result )
|
||||||
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
|
|
||||||
|
MonsterInit();
|
||||||
|
|
||||||
|
// Sven Co-op uses a modified gargeye1.spr for the eye and stomp effects.
|
||||||
|
// To economize precache count, we are going to recycle the normal garg's sprites.
|
||||||
|
|
||||||
|
m_pEyeGlow = CMSprite::SpriteCreate( GARG_EYE_SPRITE_NAME, pev->origin, FALSE );
|
||||||
|
m_pEyeGlow->SetTransparency( kRenderGlow, 255, 255, 255, 0, kRenderFxNoDissipation );
|
||||||
|
m_pEyeGlow->SetAttachment( edict(), 1 );
|
||||||
|
EyeOff();
|
||||||
|
m_seeTime = gpGlobals->time + 5;
|
||||||
|
m_flameTime = gpGlobals->time + 2;
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_babygarg" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Baby Gargantua" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Precache - precaches all resources this monster needs
|
||||||
|
//=========================================================
|
||||||
|
void CMBabyGargantua::Precache()
|
||||||
|
{
|
||||||
|
PRECACHE_MODEL("models/babygarg.mdl");
|
||||||
|
PRECACHE_MODEL( GARG_EYE_SPRITE_NAME );
|
||||||
|
PRECACHE_MODEL( GARG_BEAM_SPRITE_NAME );
|
||||||
|
PRECACHE_MODEL( GARG_BEAM_SPRITE2 );
|
||||||
|
gStompSprite = PRECACHE_MODELINDEX( GARG_STOMP_SPRITE_NAME );
|
||||||
|
gGargGibModel = PRECACHE_MODELINDEX( GARG_GIB_MODEL );
|
||||||
|
PRECACHE_SOUND( GARG_STOMP_BUZZ_SOUND );
|
||||||
|
|
||||||
|
PRECACHE_SOUND_ARRAY(pAttackHitSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pBeamAttackSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pAttackMissSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pRicSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pFootSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pIdleSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pAlertSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pPainSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pAttackSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pStompSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pBreatheSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pDieSounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMBabyGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
|
||||||
|
{
|
||||||
|
ALERT( at_aiconsole, "CMBabyGargantua::TraceAttack\n");
|
||||||
|
|
||||||
|
if ( !IsAlive() )
|
||||||
|
{
|
||||||
|
CMBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( m_painSoundTime < gpGlobals->time )
|
||||||
|
{
|
||||||
|
EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, pPainSounds[ RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM );
|
||||||
|
m_painSoundTime = gpGlobals->time + RANDOM_FLOAT( 2.5, 4 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override Gargantua's specific damage. Baby Garg has no protection from those.
|
||||||
|
CMBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
|
||||||
|
}
|
||||||
|
|
||||||
|
int CMBabyGargantua::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
||||||
|
{
|
||||||
|
if ( IsAlive() )
|
||||||
|
{
|
||||||
|
// Always set
|
||||||
|
SetConditions( bits_COND_LIGHT_DAMAGE );
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// HandleAnimEvent - catches the monster-specific messages
|
||||||
|
// that occur when tagged animation frames are played.
|
||||||
|
//=========================================================
|
||||||
|
void CMBabyGargantua::HandleAnimEvent(MonsterEvent_t *pEvent)
|
||||||
|
{
|
||||||
|
switch( pEvent->event )
|
||||||
|
{
|
||||||
|
case GARG_AE_SLASH_LEFT:
|
||||||
|
{
|
||||||
|
// HACKHACK!!!
|
||||||
|
edict_t *pHurt = BabyGargCheckTraceHullAttack( BABYGARG_ATTACKDIST + 10.0, gSkillData.babygargDmgSlash, DMG_SLASH );
|
||||||
|
if (pHurt)
|
||||||
|
{
|
||||||
|
if ( pHurt->v.flags & (FL_MONSTER|FL_CLIENT) )
|
||||||
|
{
|
||||||
|
// Slightly lower numbers for babygarg (-20%)
|
||||||
|
pHurt->v.punchangle.x = -24; // pitch
|
||||||
|
pHurt->v.punchangle.y = -24; // yaw
|
||||||
|
pHurt->v.punchangle.z = 24; // roll
|
||||||
|
//UTIL_MakeVectors(pev->angles); // called by CheckTraceHullAttack
|
||||||
|
pHurt->v.velocity = pHurt->v.velocity - gpGlobals->v_right * 80;
|
||||||
|
}
|
||||||
|
EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 50 + RANDOM_LONG(0,15) );
|
||||||
|
}
|
||||||
|
else // Play a random attack miss sound
|
||||||
|
EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 50 + RANDOM_LONG(0,15) );
|
||||||
|
|
||||||
|
Vector forward;
|
||||||
|
UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GARG_AE_RIGHT_FOOT:
|
||||||
|
case GARG_AE_LEFT_FOOT:
|
||||||
|
// babygarg does not shake the screen
|
||||||
|
EMIT_SOUND_DYN ( edict(), CHAN_BODY, pFootSounds[ RANDOM_LONG(0,ARRAYSIZE(pFootSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10,10) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GARG_AE_STOMP:
|
||||||
|
StompAttack();
|
||||||
|
m_seeTime = gpGlobals->time + 12;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GARG_AE_BREATHE:
|
||||||
|
EMIT_SOUND_DYN ( edict(), CHAN_VOICE, pBreatheSounds[ RANDOM_LONG(0,ARRAYSIZE(pBreatheSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10,10) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CMBaseMonster::HandleAnimEvent(pEvent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// CheckMeleeAttack1
|
||||||
|
// Garg swipe attack
|
||||||
|
//=========================================================
|
||||||
|
BOOL CMBabyGargantua::CheckMeleeAttack1( float flDot, float flDist )
|
||||||
|
{
|
||||||
|
// ALERT(at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist);
|
||||||
|
|
||||||
|
if (flDot >= 0.7)
|
||||||
|
{
|
||||||
|
if (flDist <= BABYGARG_ATTACKDIST)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// CheckMeleeAttack2
|
||||||
|
// Flame thrower madness!
|
||||||
|
//=========================================================
|
||||||
|
BOOL CMBabyGargantua::CheckMeleeAttack2( float flDot, float flDist )
|
||||||
|
{
|
||||||
|
// ALERT(at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist);
|
||||||
|
|
||||||
|
if ( gpGlobals->time > m_flameTime )
|
||||||
|
{
|
||||||
|
if (flDot >= 0.8 && flDist > BABYGARG_ATTACKDIST)
|
||||||
|
{
|
||||||
|
if ( flDist <= BABYGARG_FLAME_LENGTH )
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// CheckRangeAttack1
|
||||||
|
// Stomp attack
|
||||||
|
//=========================================================
|
||||||
|
BOOL CMBabyGargantua::CheckRangeAttack1( float flDot, float flDist )
|
||||||
|
{
|
||||||
|
if ( gpGlobals->time > m_seeTime )
|
||||||
|
{
|
||||||
|
if (flDot >= 0.7 && flDist > BABYGARG_ATTACKDIST)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMBabyGargantua::StartTask( Task_t *pTask )
|
||||||
|
{
|
||||||
|
switch ( pTask->iTask )
|
||||||
|
{
|
||||||
|
case TASK_FLAME_SWEEP:
|
||||||
|
FlameCreate();
|
||||||
|
m_flWaitFinished = gpGlobals->time + pTask->flData;
|
||||||
|
m_flameTime = gpGlobals->time + 6;
|
||||||
|
m_flameX = 0;
|
||||||
|
m_flameY = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TASK_SOUND_ATTACK:
|
||||||
|
if ( RANDOM_LONG(0,100) < 30 )
|
||||||
|
EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, pAttackSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM );
|
||||||
|
TaskComplete();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TASK_DIE:
|
||||||
|
// no death effect for babygarg, but give it a sound
|
||||||
|
EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pDieSounds[ RANDOM_LONG(0,ARRAYSIZE(pDieSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM );
|
||||||
|
default:
|
||||||
|
CMBaseMonster::StartTask( pTask );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// RunTask
|
||||||
|
//=========================================================
|
||||||
|
void CMBabyGargantua::RunTask( Task_t *pTask )
|
||||||
|
{
|
||||||
|
switch ( pTask->iTask )
|
||||||
|
{
|
||||||
|
// babygarg does not explode upon death
|
||||||
|
case TASK_FLAME_SWEEP:
|
||||||
|
if ( gpGlobals->time > m_flWaitFinished )
|
||||||
|
{
|
||||||
|
FlameDestroy();
|
||||||
|
TaskComplete();
|
||||||
|
FlameControls( 0, 0 );
|
||||||
|
SetBoneController( 0, 0 );
|
||||||
|
SetBoneController( 1, 0 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BOOL cancel = FALSE;
|
||||||
|
|
||||||
|
Vector angles = g_vecZero;
|
||||||
|
|
||||||
|
FlameUpdate();
|
||||||
|
CMBaseEntity *pEnemy = CMBaseEntity::Instance( m_hEnemy.Get() );
|
||||||
|
if ( pEnemy )
|
||||||
|
{
|
||||||
|
Vector org = pev->origin;
|
||||||
|
org.z += 64;
|
||||||
|
Vector dir = pEnemy->BodyTarget(org) - org;
|
||||||
|
angles = UTIL_VecToAngles( dir );
|
||||||
|
angles.x = -angles.x;
|
||||||
|
angles.y -= pev->angles.y;
|
||||||
|
if ( dir.Length() > 400 )
|
||||||
|
cancel = TRUE;
|
||||||
|
}
|
||||||
|
if ( fabs(angles.y) > 60 )
|
||||||
|
cancel = TRUE;
|
||||||
|
|
||||||
|
if ( cancel )
|
||||||
|
{
|
||||||
|
m_flWaitFinished -= 0.5;
|
||||||
|
m_flameTime -= 0.5;
|
||||||
|
}
|
||||||
|
// FlameControls( angles.x + 2 * sin(gpGlobals->time*8), angles.y + 28 * sin(gpGlobals->time*8.5) );
|
||||||
|
FlameControls( angles.x, angles.y );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CMBaseMonster::RunTask( pTask );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMBabyGargantua::StompAttack( void )
|
||||||
|
{
|
||||||
|
TraceResult trace;
|
||||||
|
|
||||||
|
UTIL_MakeVectors( pev->angles );
|
||||||
|
Vector vecStart = pev->origin + Vector(0,0,60) + 35 * gpGlobals->v_forward;
|
||||||
|
Vector vecAim = ShootAtEnemy( vecStart );
|
||||||
|
Vector vecEnd = (vecAim * 1024) + vecStart;
|
||||||
|
|
||||||
|
UTIL_TraceLine( vecStart, vecEnd, ignore_monsters, edict(), &trace );
|
||||||
|
CStomp::StompCreate( vecStart, trace.vecEndPos, 0, gSkillData.babygargDmgStomp );
|
||||||
|
UTIL_ScreenShake( pev->origin, 9.6, 80.0, 1.8, 800 ); // -20% "power" to the babygarg's stomp
|
||||||
|
EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pStompSounds[ RANDOM_LONG(0,ARRAYSIZE(pStompSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10,10) );
|
||||||
|
|
||||||
|
UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,20), ignore_monsters, edict(), &trace );
|
||||||
|
if ( trace.flFraction < 1.0 )
|
||||||
|
UTIL_DecalTrace( &trace, DECAL_GARGSTOMP1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMBabyGargantua::FlameCreate( void )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Vector posGun, angleGun;
|
||||||
|
TraceResult trace;
|
||||||
|
|
||||||
|
UTIL_MakeVectors( pev->angles );
|
||||||
|
|
||||||
|
for ( i = 0; i < 4; i++ )
|
||||||
|
{
|
||||||
|
if ( i < 2 )
|
||||||
|
m_pFlame[i] = CMBeam::BeamCreate( GARG_BEAM_SPRITE_NAME, 120 );
|
||||||
|
else
|
||||||
|
m_pFlame[i] = CMBeam::BeamCreate( GARG_BEAM_SPRITE2, 70 );
|
||||||
|
if ( m_pFlame[i] )
|
||||||
|
{
|
||||||
|
int attach = i%2;
|
||||||
|
// attachment is 0 based in GetAttachment
|
||||||
|
GetAttachment( attach+1, posGun, angleGun );
|
||||||
|
|
||||||
|
Vector vecEnd = (gpGlobals->v_forward * BABYGARG_FLAME_LENGTH) + posGun;
|
||||||
|
UTIL_TraceLine( posGun, vecEnd, dont_ignore_monsters, edict(), &trace );
|
||||||
|
|
||||||
|
m_pFlame[i]->PointEntInit( trace.vecEndPos, entindex() );
|
||||||
|
if ( i < 2 )
|
||||||
|
m_pFlame[i]->SetColor( 255, 130, 90 );
|
||||||
|
else
|
||||||
|
m_pFlame[i]->SetColor( 0, 120, 255 );
|
||||||
|
m_pFlame[i]->SetBrightness( 190 );
|
||||||
|
m_pFlame[i]->SetFlags( BEAM_FSHADEIN );
|
||||||
|
m_pFlame[i]->SetScrollRate( 20 );
|
||||||
|
// attachment is 1 based in SetEndAttachment
|
||||||
|
m_pFlame[i]->SetEndAttachment( attach + 2 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EMIT_SOUND_DYN ( edict(), CHAN_BODY, pBeamAttackSounds[ 1 ], 1.0, ATTN_NORM, 0, PITCH_NORM );
|
||||||
|
EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pBeamAttackSounds[ 2 ], 1.0, ATTN_NORM, 0, PITCH_NORM );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMBabyGargantua::FlameUpdate( void )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
static float offset[2] = { 60, -60 };
|
||||||
|
TraceResult trace;
|
||||||
|
Vector vecStart, angleGun;
|
||||||
|
BOOL streaks = FALSE;
|
||||||
|
|
||||||
|
for ( i = 0; i < 2; i++ )
|
||||||
|
{
|
||||||
|
if ( m_pFlame[i] )
|
||||||
|
{
|
||||||
|
Vector vecAim = pev->angles;
|
||||||
|
vecAim.x += m_flameX;
|
||||||
|
vecAim.y += m_flameY;
|
||||||
|
|
||||||
|
UTIL_MakeVectors( vecAim );
|
||||||
|
|
||||||
|
GetAttachment( i+1, vecStart, angleGun );
|
||||||
|
Vector vecEnd = vecStart + (gpGlobals->v_forward * BABYGARG_FLAME_LENGTH); // - offset[i] * gpGlobals->v_right;
|
||||||
|
|
||||||
|
UTIL_TraceLine( vecStart, vecEnd, dont_ignore_monsters, edict(), &trace );
|
||||||
|
|
||||||
|
m_pFlame[i]->SetStartPos( trace.vecEndPos );
|
||||||
|
m_pFlame[i+2]->SetStartPos( (vecStart * 0.6) + (trace.vecEndPos * 0.4) );
|
||||||
|
|
||||||
|
if ( trace.flFraction != 1.0 && gpGlobals->time > m_streakTime )
|
||||||
|
{
|
||||||
|
StreakSplash( trace.vecEndPos, trace.vecPlaneNormal, 6, 20, 50, 400 );
|
||||||
|
streaks = TRUE;
|
||||||
|
UTIL_DecalTrace( &trace, DECAL_SMALLSCORCH1 + RANDOM_LONG(0,2) );
|
||||||
|
}
|
||||||
|
// RadiusDamage( trace.vecEndPos, pev, pev, gSkillData.babygargDmgFire, Classify(), DMG_BURN );
|
||||||
|
FlameDamage( vecStart, trace.vecEndPos, pev, pev, gSkillData.babygargDmgFire, Classify(), DMG_BURN );
|
||||||
|
|
||||||
|
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
||||||
|
WRITE_BYTE( TE_ELIGHT );
|
||||||
|
WRITE_SHORT( entindex( ) + 0x1000 * (i + 2) ); // entity, attachment
|
||||||
|
WRITE_COORD( vecStart.x ); // origin
|
||||||
|
WRITE_COORD( vecStart.y );
|
||||||
|
WRITE_COORD( vecStart.z );
|
||||||
|
WRITE_COORD( RANDOM_FLOAT( 32, 48 ) ); // radius
|
||||||
|
WRITE_BYTE( 255 ); // R
|
||||||
|
WRITE_BYTE( 255 ); // G
|
||||||
|
WRITE_BYTE( 255 ); // B
|
||||||
|
WRITE_BYTE( 2 ); // life * 10
|
||||||
|
WRITE_COORD( 0 ); // decay
|
||||||
|
MESSAGE_END();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( streaks )
|
||||||
|
m_streakTime = gpGlobals->time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMBabyGargantua::FlameDestroy( void )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pBeamAttackSounds[ 0 ], 1.0, ATTN_NORM, 0, PITCH_NORM ); // sound must stop.
|
||||||
|
for ( i = 0; i < 4; i++ )
|
||||||
|
{
|
||||||
|
if ( m_pFlame[i] )
|
||||||
|
{
|
||||||
|
UTIL_Remove( m_pFlame[i]->edict() );
|
||||||
|
m_pFlame[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// CheckTraceHullAttack - expects a length to trace, amount
|
||||||
|
// of damage to do, and damage type. Returns a pointer to
|
||||||
|
// the damaged entity in case the monster wishes to do
|
||||||
|
// other stuff to the victim (punchangle, etc)
|
||||||
|
// Used for many contact-range melee attacks. Bites, claws, etc.
|
||||||
|
|
||||||
|
// Overridden for Gargantua because his swing starts lower as
|
||||||
|
// a percentage of his height (otherwise he swings over the
|
||||||
|
// players head)
|
||||||
|
|
||||||
|
// Also overriden for Baby Gargantua to prevent players from
|
||||||
|
// dodging the swing attacks by crouching.
|
||||||
|
//=========================================================
|
||||||
|
edict_t *CMBabyGargantua::BabyGargCheckTraceHullAttack(float flDist, int iDamage, int iDmgType)
|
||||||
|
{
|
||||||
|
TraceResult tr;
|
||||||
|
|
||||||
|
UTIL_MakeVectors( pev->angles );
|
||||||
|
Vector vecStart = pev->origin;
|
||||||
|
vecStart.z += 32;
|
||||||
|
Vector vecEnd = vecStart + (gpGlobals->v_forward * flDist) - (gpGlobals->v_up * flDist * 0.3);
|
||||||
|
|
||||||
|
UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr );
|
||||||
|
|
||||||
|
if ( tr.pHit )
|
||||||
|
{
|
||||||
|
if ( iDamage > 0 )
|
||||||
|
{
|
||||||
|
if ( UTIL_IsPlayer( tr.pHit ) )
|
||||||
|
UTIL_TakeDamage( tr.pHit, pev, pev, iDamage, iDmgType );
|
||||||
|
else if ( tr.pHit->v.euser4 != NULL )
|
||||||
|
{
|
||||||
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit));
|
||||||
|
pMonster->TakeDamage( pev, pev, iDamage, iDmgType );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
UTIL_TakeDamageExternal( tr.pHit, pev, pev, iDamage, iDmgType );
|
||||||
|
}
|
||||||
|
|
||||||
|
return tr.pHit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ void CMGrenade::Explode( Vector vecSrc, Vector vecAim )
|
|||||||
// UNDONE: temporary scorching for PreAlpha - find a less sleazy permenant solution.
|
// UNDONE: temporary scorching for PreAlpha - find a less sleazy permenant solution.
|
||||||
void CMGrenade::Explode( TraceResult *pTrace, int bitsDamageType )
|
void CMGrenade::Explode( TraceResult *pTrace, int bitsDamageType )
|
||||||
{
|
{
|
||||||
|
// CRITICAL - always ensure owner of grenade is valid
|
||||||
|
if (m_hOwner == NULL)
|
||||||
|
pev->owner = NULL;
|
||||||
|
|
||||||
float flRndSound;// sound randomizer
|
float flRndSound;// sound randomizer
|
||||||
|
|
||||||
pev->model = iStringNull;//invisible
|
pev->model = iStringNull;//invisible
|
||||||
@@ -234,6 +238,8 @@ void CMGrenade::BounceTouch( edict_t *pOther )
|
|||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||||
pMonster->TraceAttack(pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB );
|
pMonster->TraceAttack(pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
UTIL_TraceAttack(pOther, pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB); // lmao
|
||||||
|
|
||||||
ApplyMultiDamage( pev, pevOwner);
|
ApplyMultiDamage( pev, pevOwner);
|
||||||
}
|
}
|
||||||
@@ -277,7 +283,6 @@ void CMGrenade::BounceTouch( edict_t *pOther )
|
|||||||
pev->framerate = 1;
|
pev->framerate = 1;
|
||||||
else if (pev->framerate < 0.5)
|
else if (pev->framerate < 0.5)
|
||||||
pev->framerate = 0;
|
pev->framerate = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -308,6 +313,10 @@ void CMGrenade::SlideTouch( edict_t *pOther )
|
|||||||
|
|
||||||
void CMGrenade :: BounceSound( void )
|
void CMGrenade :: BounceSound( void )
|
||||||
{
|
{
|
||||||
|
// CRITICAL - always ensure owner of grenade is valid
|
||||||
|
if (m_hOwner == NULL)
|
||||||
|
pev->owner = NULL;
|
||||||
|
|
||||||
switch ( RANDOM_LONG( 0, 2 ) )
|
switch ( RANDOM_LONG( 0, 2 ) )
|
||||||
{
|
{
|
||||||
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/grenade_hit1.wav", 0.25, ATTN_NORM); break;
|
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/grenade_hit1.wav", 0.25, ATTN_NORM); break;
|
||||||
@@ -368,6 +377,7 @@ CMGrenade *CMGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector
|
|||||||
pGrenade->pev->velocity = vecVelocity;
|
pGrenade->pev->velocity = vecVelocity;
|
||||||
pGrenade->pev->angles = UTIL_VecToAngles (pGrenade->pev->velocity);
|
pGrenade->pev->angles = UTIL_VecToAngles (pGrenade->pev->velocity);
|
||||||
pGrenade->pev->owner = ENT(pevOwner);
|
pGrenade->pev->owner = ENT(pevOwner);
|
||||||
|
pGrenade->m_hOwner = ENT(pevOwner);
|
||||||
|
|
||||||
// make monsters afaid of it while in the air
|
// make monsters afaid of it while in the air
|
||||||
pGrenade->SetThink( &CMGrenade::DangerSoundThink );
|
pGrenade->SetThink( &CMGrenade::DangerSoundThink );
|
||||||
@@ -397,6 +407,7 @@ CMGrenade * CMGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector
|
|||||||
pGrenade->pev->velocity = vecVelocity;
|
pGrenade->pev->velocity = vecVelocity;
|
||||||
pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity);
|
pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity);
|
||||||
pGrenade->pev->owner = ENT(pevOwner);
|
pGrenade->pev->owner = ENT(pevOwner);
|
||||||
|
pGrenade->m_hOwner = ENT(pevOwner);
|
||||||
|
|
||||||
pGrenade->SetTouch( &CMGrenade::BounceTouch ); // Bounce if touched
|
pGrenade->SetTouch( &CMGrenade::BounceTouch ); // Bounce if touched
|
||||||
|
|
||||||
@@ -450,6 +461,7 @@ CMGrenade * CMGrenade :: ShootSatchelCharge( entvars_t *pevOwner, Vector vecStar
|
|||||||
pGrenade->pev->velocity = vecVelocity;
|
pGrenade->pev->velocity = vecVelocity;
|
||||||
pGrenade->pev->angles = g_vecZero;
|
pGrenade->pev->angles = g_vecZero;
|
||||||
pGrenade->pev->owner = ENT(pevOwner);
|
pGrenade->pev->owner = ENT(pevOwner);
|
||||||
|
pGrenade->m_hOwner = ENT(pevOwner);
|
||||||
|
|
||||||
// Detonate in "time" seconds
|
// Detonate in "time" seconds
|
||||||
pGrenade->SetThink( &CMGrenade::SUB_DoNothing );
|
pGrenade->SetThink( &CMGrenade::SUB_DoNothing );
|
||||||
|
|||||||
170
src/dlls/globalreplace.cpp
Normal file
170
src/dlls/globalreplace.cpp
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
//=========================================================
|
||||||
|
// Global Replacement:
|
||||||
|
// Tool to replace all default models/sounds with a
|
||||||
|
// customized list.
|
||||||
|
//=========================================================
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "dllapi.h"
|
||||||
|
#include "meta_api.h"
|
||||||
|
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
|
||||||
|
namespace REPLACER
|
||||||
|
{
|
||||||
|
REPLACER *GMR;
|
||||||
|
REPLACER *GSR;
|
||||||
|
int numModels;
|
||||||
|
int numSounds;
|
||||||
|
|
||||||
|
void Init(void)
|
||||||
|
{
|
||||||
|
if ( GMR != NULL )
|
||||||
|
{
|
||||||
|
free( GMR );
|
||||||
|
GMR = NULL;
|
||||||
|
}
|
||||||
|
if ( GSR != NULL )
|
||||||
|
{
|
||||||
|
free( GSR );
|
||||||
|
GSR = NULL;
|
||||||
|
}
|
||||||
|
numModels = 0;
|
||||||
|
numSounds = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddGlobalModel(const char *from, const char *to)
|
||||||
|
{
|
||||||
|
if (numModels < MAX_REPLACEMENTS)
|
||||||
|
{
|
||||||
|
// allocate for the first time
|
||||||
|
if (!numModels)
|
||||||
|
GMR = (REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*GMR));
|
||||||
|
|
||||||
|
strcpy(GMR[numModels].source, from);
|
||||||
|
strcpy(GMR[numModels].destination, to);
|
||||||
|
|
||||||
|
numModels++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_MESSAGE(PLID, "Can't replace model '%s', too many models in GMR.", from);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddGlobalSound(const char *from, const char *to)
|
||||||
|
{
|
||||||
|
if (numSounds < MAX_REPLACEMENTS)
|
||||||
|
{
|
||||||
|
if (from[0] == '!')
|
||||||
|
{
|
||||||
|
// sentence sounds cannot be replaced, skip.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate for the first time
|
||||||
|
if (!numSounds)
|
||||||
|
GSR = (REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*GSR));
|
||||||
|
|
||||||
|
strcpy(GSR[numSounds].source, from);
|
||||||
|
strcpy(GSR[numSounds].destination, to);
|
||||||
|
|
||||||
|
numSounds++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_MESSAGE(PLID, "Can't replace sound '%s', too many sounds in GSR.", from);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddIndividualSound(edict_t *pMonster, const char *from, const char *to)
|
||||||
|
{
|
||||||
|
CMBaseMonster *castMonster = GetClassPtr((CMBaseMonster *)VARS(pMonster));
|
||||||
|
|
||||||
|
if ( castMonster == NULL )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int m_iSounds = castMonster->m_isrSounds;
|
||||||
|
|
||||||
|
if (m_iSounds < MAX_REPLACEMENTS)
|
||||||
|
{
|
||||||
|
// allocate for the first time
|
||||||
|
if (!m_iSounds)
|
||||||
|
castMonster->m_srSoundList = (REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*castMonster->m_srSoundList));
|
||||||
|
|
||||||
|
strcpy(castMonster->m_srSoundList[m_iSounds].source, from);
|
||||||
|
strcpy(castMonster->m_srSoundList[m_iSounds].destination, to);
|
||||||
|
|
||||||
|
castMonster->m_isrSounds++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_MESSAGE(PLID, "Can't replace sound '%s', too many sounds in list.", from);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* FindModelReplacement( edict_t *pMonster, const char *from )
|
||||||
|
{
|
||||||
|
// Individually set models takes priority!
|
||||||
|
if (UTIL_IsValidEntity(pMonster) && !FStringNull(pMonster->v.model))
|
||||||
|
return STRING(pMonster->v.model);
|
||||||
|
|
||||||
|
// Find the model
|
||||||
|
for (int model = 0; model < numModels; model++)
|
||||||
|
{
|
||||||
|
if (strcmp(GMR[model].source, from) == 0)
|
||||||
|
{
|
||||||
|
// If found, use that model instead
|
||||||
|
return GMR[model].destination;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing found, stick with default
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* FindSoundReplacement( edict_t *pMonster, const char *from )
|
||||||
|
{
|
||||||
|
// Individually set sounds takes priority!
|
||||||
|
if (UTIL_IsValidEntity(pMonster))
|
||||||
|
{
|
||||||
|
CMBaseMonster *castMonster = NULL;
|
||||||
|
|
||||||
|
// Check if this is really a monster or not
|
||||||
|
if (pMonster->v.flags & FL_MONSTER)
|
||||||
|
castMonster = GetClassPtr((CMBaseMonster *)VARS(pMonster));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This is probably a monster-owned projectile of sorts
|
||||||
|
if (UTIL_IsValidEntity(pMonster->v.owner))
|
||||||
|
castMonster = GetClassPtr((CMBaseMonster *)VARS(pMonster->v.owner));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If still no valid BaseMonster pointer, full stop, use GSR.
|
||||||
|
if (castMonster != NULL && castMonster->m_srSoundList != NULL && castMonster->m_isrSounds > 0)
|
||||||
|
{
|
||||||
|
for (int sound = 0; sound < castMonster->m_isrSounds; sound++)
|
||||||
|
{
|
||||||
|
if (strcmp(castMonster->m_srSoundList[sound].source, from) == 0)
|
||||||
|
{
|
||||||
|
// If found, use it
|
||||||
|
return castMonster->m_srSoundList[sound].destination;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If nothing is found stick to GSR if available
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int sound = 0; sound < numSounds; sound++)
|
||||||
|
{
|
||||||
|
if (strcmp(GSR[sound].source, from) == 0)
|
||||||
|
{
|
||||||
|
// If found, use that sound instead
|
||||||
|
return GSR[sound].destination;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing found, stick with default
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/dlls/globalreplace.h
Normal file
26
src/dlls/globalreplace.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef GLOBALREPLACE_H
|
||||||
|
#define GLOBALREPLACE_H
|
||||||
|
|
||||||
|
#define MAX_REPLACEMENTS 255
|
||||||
|
|
||||||
|
namespace REPLACER
|
||||||
|
{
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char source[128];
|
||||||
|
char destination[128];
|
||||||
|
} REPLACER;
|
||||||
|
|
||||||
|
void Init(void);
|
||||||
|
bool AddGlobalModel(const char *from, const char *to);
|
||||||
|
bool AddGlobalSound(const char *from, const char *to);
|
||||||
|
bool AddIndividualSound(edict_t *pMonster, const char *from, const char *to);
|
||||||
|
|
||||||
|
const char* FindModelReplacement( edict_t *pMonster, const char *from );
|
||||||
|
inline const char* FindModelReplacement( const char *from ) { return FindModelReplacement( NULL, from ); }
|
||||||
|
|
||||||
|
const char* FindSoundReplacement( edict_t *pMonster, const char *from );
|
||||||
|
inline const char* FindSoundReplacement( const char *from ) { return FindSoundReplacement( NULL, from ); }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
873
src/dlls/gonome.cpp
Normal file
873
src/dlls/gonome.cpp
Normal file
@@ -0,0 +1,873 @@
|
|||||||
|
// HUGE thanks to DrBeef for his hlsdk-xash3d-opfor repository!
|
||||||
|
|
||||||
|
/***
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* This product contains software technology licensed from Id
|
||||||
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use, distribution, and modification of this source code and/or resulting
|
||||||
|
* object code is restricted to non-commercial enhancements to products from
|
||||||
|
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||||
|
* without written permission from Valve LLC.
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Gonome.cpp
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
#include "monsters.h"
|
||||||
|
#include "schedule.h"
|
||||||
|
#include "animation.h"
|
||||||
|
#include "decals.h"
|
||||||
|
#include "nodes.h"
|
||||||
|
|
||||||
|
#define GONOME_MELEE_ATTACK_RADIUS 70
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
TASK_GONOME_GET_PATH_TO_ENEMY_CORPSE = LAST_COMMON_TASK + 1
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Monster's Anim Events Go Here
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
#define GONOME_AE_SLASH_RIGHT ( 1 )
|
||||||
|
#define GONOME_AE_SLASH_LEFT ( 2 )
|
||||||
|
#define GONOME_AE_SPIT ( 3 )
|
||||||
|
#define GONOME_AE_THROW ( 4 )
|
||||||
|
|
||||||
|
#define GONOME_AE_BITE1 ( 19 )
|
||||||
|
#define GONOME_AE_BITE2 ( 20 )
|
||||||
|
#define GONOME_AE_BITE3 ( 21 )
|
||||||
|
#define GONOME_AE_BITE4 ( 22 )
|
||||||
|
|
||||||
|
#define GONOME_SCRIPT_EVENT_SOUND ( 1011 )
|
||||||
|
|
||||||
|
void CGonomeGuts :: Spawn( void )
|
||||||
|
{
|
||||||
|
pev->movetype = MOVETYPE_FLY;
|
||||||
|
pev->classname = MAKE_STRING( "gonomeguts" );
|
||||||
|
|
||||||
|
pev->solid = SOLID_BBOX;
|
||||||
|
pev->rendermode = kRenderTransAlpha;
|
||||||
|
pev->renderamt = 255;
|
||||||
|
|
||||||
|
SET_MODEL( ENT( pev ), "sprites/bigspit.spr" );
|
||||||
|
pev->frame = 0;
|
||||||
|
pev->scale = 0.5;
|
||||||
|
pev->rendercolor.x = 255;
|
||||||
|
|
||||||
|
UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) );
|
||||||
|
|
||||||
|
m_maxFrame = (float)MODEL_FRAMES( pev->modelindex ) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGonomeGuts :: Animate( void )
|
||||||
|
{
|
||||||
|
pev->nextthink = gpGlobals->time + 0.1;
|
||||||
|
|
||||||
|
if ( pev->frame++ )
|
||||||
|
{
|
||||||
|
if ( pev->frame > m_maxFrame )
|
||||||
|
{
|
||||||
|
pev->frame = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
edict_t *CGonomeGuts :: Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity )
|
||||||
|
{
|
||||||
|
CGonomeGuts *pSpit = CreateClassPtr( (CGonomeGuts *)NULL );
|
||||||
|
|
||||||
|
if (pSpit == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pSpit->Spawn();
|
||||||
|
|
||||||
|
UTIL_SetOrigin( pSpit->pev, vecStart );
|
||||||
|
pSpit->pev->velocity = vecVelocity;
|
||||||
|
pSpit->pev->owner = ENT(pevOwner);
|
||||||
|
|
||||||
|
pSpit->SetThink ( &CGonomeGuts::Animate );
|
||||||
|
pSpit->pev->nextthink = gpGlobals->time + 0.1;
|
||||||
|
pSpit->SetTouch ( &CGonomeGuts::GutsTouch );
|
||||||
|
|
||||||
|
return pSpit->edict();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGonomeGuts :: GutsTouch( edict_t *pOther )
|
||||||
|
{
|
||||||
|
TraceResult tr;
|
||||||
|
int iPitch;
|
||||||
|
|
||||||
|
// splat sound
|
||||||
|
iPitch = RANDOM_FLOAT( 90, 110 );
|
||||||
|
|
||||||
|
EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "bullchicken/bc_acid1.wav", 1, ATTN_NORM, 0, iPitch );
|
||||||
|
|
||||||
|
switch( RANDOM_LONG( 0, 1 ) )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "bullchicken/bc_spithit1.wav", 1, ATTN_NORM, 0, iPitch );
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "bullchicken/bc_spithit2.wav", 1, ATTN_NORM, 0, iPitch );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !pOther->v.takedamage )
|
||||||
|
{
|
||||||
|
// make a splat on the wall
|
||||||
|
UTIL_TraceLine( pev->origin, pev->origin + pev->velocity * 10, dont_ignore_monsters, ENT( pev ), &tr );
|
||||||
|
UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED );
|
||||||
|
UTIL_BloodDrips( tr.vecEndPos, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, 35 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (UTIL_IsPlayer(pOther))
|
||||||
|
UTIL_TakeDamage( pOther, pev, VARS(pev->owner), gSkillData.gonomeDmgGuts, DMG_GENERIC );
|
||||||
|
else if (pOther->v.euser4 != NULL)
|
||||||
|
{
|
||||||
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||||
|
pMonster->TakeDamage ( pev, VARS(pev->owner), gSkillData.gonomeDmgGuts, DMG_GENERIC );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
UTIL_TakeDamageExternal( pOther, pev, VARS(pev->owner), gSkillData.gonomeDmgGuts, DMG_GENERIC );
|
||||||
|
}
|
||||||
|
|
||||||
|
SetThink( &CGonomeGuts::SUB_Remove );
|
||||||
|
pev->nextthink = gpGlobals->time;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char* CMGonome::pPainSounds[] = {
|
||||||
|
"gonome/gonome_pain1.wav",
|
||||||
|
"gonome/gonome_pain2.wav",
|
||||||
|
"gonome/gonome_pain3.wav",
|
||||||
|
"gonome/gonome_pain4.wav"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* CMGonome::pIdleSounds[] = {
|
||||||
|
"gonome/gonome_idle1.wav",
|
||||||
|
"gonome/gonome_idle2.wav",
|
||||||
|
"gonome/gonome_idle3.wav"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* CMGonome::pDeathSounds[] = {
|
||||||
|
"gonome/gonome_death2.wav",
|
||||||
|
"gonome/gonome_death3.wav",
|
||||||
|
"gonome/gonome_death4.wav"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* CMGonome::pAttackHitSounds[] =
|
||||||
|
{
|
||||||
|
"zombie/claw_strike1.wav",
|
||||||
|
"zombie/claw_strike2.wav",
|
||||||
|
"zombie/claw_strike3.wav",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* CMGonome::pAttackMissSounds[] =
|
||||||
|
{
|
||||||
|
"zombie/claw_miss1.wav",
|
||||||
|
"zombie/claw_miss2.wav",
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void CMGonome::Killed(entvars_t *pevAttacker, int iGib)
|
||||||
|
{
|
||||||
|
ClearGuts();
|
||||||
|
UnlockPlayer();
|
||||||
|
CMBaseMonster::Killed(pevAttacker, iGib);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMGonome::UnlockPlayer()
|
||||||
|
{
|
||||||
|
if (m_fPlayerLocked)
|
||||||
|
{
|
||||||
|
edict_t *player = 0;
|
||||||
|
if (m_lockedPlayer != 0 && UTIL_IsPlayer(m_lockedPlayer))
|
||||||
|
player = m_lockedPlayer;
|
||||||
|
else // if ehandle is empty for some reason just unlock the first player
|
||||||
|
player = UTIL_FindEntityByClassname(0, "player");
|
||||||
|
|
||||||
|
if (player)
|
||||||
|
player->v.flags &= ~FL_FROZEN;
|
||||||
|
|
||||||
|
m_lockedPlayer = 0;
|
||||||
|
m_fPlayerLocked = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CGonomeGuts* CMGonome::GetGonomeGuts(entvars_t *pevOwner, const Vector &pos)
|
||||||
|
{
|
||||||
|
if (m_pGonomeGuts)
|
||||||
|
return m_pGonomeGuts;
|
||||||
|
edict_t *pEdict = CGonomeGuts::Shoot( pevOwner, g_vecZero, g_vecZero );
|
||||||
|
CGonomeGuts *pGuts = GetClassPtr((CGonomeGuts*)VARS(pEdict));
|
||||||
|
pGuts->Spawn();
|
||||||
|
|
||||||
|
UTIL_SetOrigin( pGuts->pev, pos );
|
||||||
|
|
||||||
|
m_pGonomeGuts = pGuts;
|
||||||
|
return m_pGonomeGuts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMGonome::ClearGuts()
|
||||||
|
{
|
||||||
|
if (m_pGonomeGuts)
|
||||||
|
{
|
||||||
|
UTIL_Remove( m_pGonomeGuts->edict() );
|
||||||
|
m_pGonomeGuts = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMGonome::PainSound( void )
|
||||||
|
{
|
||||||
|
int pitch = 95 + RANDOM_LONG( 0, 9 );
|
||||||
|
|
||||||
|
if( RANDOM_LONG( 0, 5 ) < 2 )
|
||||||
|
EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), 1.0, ATTN_NORM, 0, pitch );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMGonome::DeathSound( void )
|
||||||
|
{
|
||||||
|
int pitch = 95 + RANDOM_LONG( 0, 9 );
|
||||||
|
|
||||||
|
EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), 1.0, ATTN_NORM, 0, pitch );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMGonome::IdleSound( void )
|
||||||
|
{
|
||||||
|
int pitch = 95 + RANDOM_LONG( 0, 9 );
|
||||||
|
|
||||||
|
// Play a random idle sound
|
||||||
|
EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), 1.0, ATTN_NORM, 0, pitch );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMGonome::AlertSound( void )
|
||||||
|
{
|
||||||
|
const int iPitch = RANDOM_LONG(0, 9) + 95;
|
||||||
|
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), 1, ATTN_NORM, 0, iPitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMGonome::SetActivity( Activity NewActivity )
|
||||||
|
{
|
||||||
|
Activity OldActivity = m_Activity;
|
||||||
|
int iSequence = ACTIVITY_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
if (NewActivity != ACT_RANGE_ATTACK1)
|
||||||
|
{
|
||||||
|
ClearGuts();
|
||||||
|
}
|
||||||
|
if (NewActivity == ACT_MELEE_ATTACK1 && m_hEnemy != 0)
|
||||||
|
{
|
||||||
|
// special melee animations
|
||||||
|
if ((pev->origin - m_hEnemy->v.origin).Length2D() >= 48 )
|
||||||
|
{
|
||||||
|
m_meleeAttack2 = false;
|
||||||
|
iSequence = LookupSequence("attack1");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_meleeAttack2 = true;
|
||||||
|
iSequence = LookupSequence("attack2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UnlockPlayer();
|
||||||
|
|
||||||
|
if (NewActivity == ACT_RUN && m_hEnemy != 0)
|
||||||
|
{
|
||||||
|
// special run animations
|
||||||
|
if ((pev->origin - m_hEnemy->v.origin).Length2D() <= 512 )
|
||||||
|
{
|
||||||
|
iSequence = LookupSequence("runshort");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iSequence = LookupSequence("runlong");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iSequence = LookupActivity(NewActivity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present
|
||||||
|
|
||||||
|
// In case someone calls this with something other than the ideal activity
|
||||||
|
m_IdealActivity = m_Activity;
|
||||||
|
|
||||||
|
// Set to the desired anim, or default anim if the desired is not present
|
||||||
|
if( iSequence > ACTIVITY_NOT_AVAILABLE )
|
||||||
|
{
|
||||||
|
if( pev->sequence != iSequence || !m_fSequenceLoops )
|
||||||
|
{
|
||||||
|
// don't reset frame between walk and run
|
||||||
|
if( !( OldActivity == ACT_WALK || OldActivity == ACT_RUN ) || !( NewActivity == ACT_WALK || NewActivity == ACT_RUN ) )
|
||||||
|
pev->frame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pev->sequence = iSequence; // Set to the reset anim (if it's there)
|
||||||
|
ResetSequenceInfo();
|
||||||
|
SetYawSpeed();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not available try to get default anim
|
||||||
|
ALERT( at_aiconsole, "%s has no sequence for act:%d\n", STRING( pev->classname ), NewActivity );
|
||||||
|
pev->sequence = 0; // Set to the reset anim (if it's there)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Classify - indicates this monster's place in the
|
||||||
|
// relationship table.
|
||||||
|
//=========================================================
|
||||||
|
int CMGonome::Classify(void)
|
||||||
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
|
return CLASS_ALIEN_MONSTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// TakeDamage - overridden for gonome so we can keep track
|
||||||
|
// of how much time has passed since it was last injured
|
||||||
|
//=========================================================
|
||||||
|
int CMGonome::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType)
|
||||||
|
{
|
||||||
|
// HACK HACK -- until we fix this.
|
||||||
|
if( IsAlive() )
|
||||||
|
PainSound();
|
||||||
|
return CMBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// CheckRangeAttack1
|
||||||
|
//=========================================================
|
||||||
|
BOOL CMGonome::CheckRangeAttack1(float flDot, float flDist)
|
||||||
|
{
|
||||||
|
if (flDist < 256)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (IsMoving() && flDist >= 512)
|
||||||
|
{
|
||||||
|
// squid will far too far behind if he stops running to spit at this distance from the enemy.
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flDist > 64 && flDist <= 784 && flDot >= 0.5 && gpGlobals->time >= m_flNextThrowTime)
|
||||||
|
{
|
||||||
|
if (m_hEnemy != 0)
|
||||||
|
{
|
||||||
|
if (fabs(pev->origin.z - m_hEnemy->v.origin.z) > 256)
|
||||||
|
{
|
||||||
|
// don't try to spit at someone up really high or down really low.
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsMoving())
|
||||||
|
{
|
||||||
|
// don't spit again for a long time, resume chasing enemy.
|
||||||
|
m_flNextThrowTime = gpGlobals->time + 5;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// not moving, so spit again pretty soon.
|
||||||
|
m_flNextThrowTime = gpGlobals->time + 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// CheckMeleeAttack2 - both gonome's melee attacks are ACT_MELEE_ATTACK1
|
||||||
|
//=========================================================
|
||||||
|
BOOL CMGonome::CheckMeleeAttack2(float flDot, float flDist)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// SetYawSpeed - allows each sequence to have a different
|
||||||
|
// turn rate associated with it.
|
||||||
|
//=========================================================
|
||||||
|
void CMGonome::SetYawSpeed( void )
|
||||||
|
{
|
||||||
|
pev->yaw_speed = 120;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// HandleAnimEvent - catches the monster-specific messages
|
||||||
|
// that occur when tagged animation frames are played.
|
||||||
|
//=========================================================
|
||||||
|
void CMGonome::HandleAnimEvent(MonsterEvent_t *pEvent)
|
||||||
|
{
|
||||||
|
switch (pEvent->event)
|
||||||
|
{
|
||||||
|
case GONOME_SCRIPT_EVENT_SOUND:
|
||||||
|
if (m_Activity != ACT_MELEE_ATTACK1)
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_BODY, pEvent->options, 1, ATTN_NORM);
|
||||||
|
break;
|
||||||
|
case GONOME_AE_SPIT:
|
||||||
|
{
|
||||||
|
Vector vecArmPos, vecArmAng;
|
||||||
|
GetAttachment(0, vecArmPos, vecArmAng);
|
||||||
|
|
||||||
|
if (GetGonomeGuts(pev, vecArmPos))
|
||||||
|
{
|
||||||
|
m_pGonomeGuts->pev->skin = entindex();
|
||||||
|
m_pGonomeGuts->pev->body = 1;
|
||||||
|
m_pGonomeGuts->pev->aiment = ENT(pev);
|
||||||
|
m_pGonomeGuts->pev->movetype = MOVETYPE_FOLLOW;
|
||||||
|
}
|
||||||
|
UTIL_BloodDrips( vecArmPos, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, 35 );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GONOME_AE_THROW:
|
||||||
|
{
|
||||||
|
UTIL_MakeVectors(pev->angles);
|
||||||
|
Vector vecArmPos, vecArmAng;
|
||||||
|
GetAttachment(0, vecArmPos, vecArmAng);
|
||||||
|
|
||||||
|
if (GetGonomeGuts(pev, vecArmPos))
|
||||||
|
{
|
||||||
|
Vector vecSpitDir;
|
||||||
|
|
||||||
|
Vector vecEnemyPosition;
|
||||||
|
if (m_hEnemy != 0)
|
||||||
|
vecEnemyPosition = (m_hEnemy->v.origin + m_hEnemy->v.view_ofs);
|
||||||
|
else
|
||||||
|
vecEnemyPosition = m_vecEnemyLKP;
|
||||||
|
vecSpitDir = (vecEnemyPosition - vecArmPos).Normalize();
|
||||||
|
|
||||||
|
vecSpitDir.x += RANDOM_FLOAT(-0.05, 0.05);
|
||||||
|
vecSpitDir.y += RANDOM_FLOAT(-0.05, 0.05);
|
||||||
|
vecSpitDir.z += RANDOM_FLOAT(-0.05, 0);
|
||||||
|
|
||||||
|
m_pGonomeGuts->pev->body = 0;
|
||||||
|
m_pGonomeGuts->pev->skin = 0;
|
||||||
|
m_pGonomeGuts->pev->owner = ENT( pev );
|
||||||
|
m_pGonomeGuts->pev->aiment = 0;
|
||||||
|
m_pGonomeGuts->pev->movetype = MOVETYPE_FLY;
|
||||||
|
m_pGonomeGuts->pev->velocity = vecSpitDir * 900;
|
||||||
|
m_pGonomeGuts->SetThink( &CGonomeGuts::Animate );
|
||||||
|
m_pGonomeGuts->pev->nextthink = gpGlobals->time + 0.1;
|
||||||
|
UTIL_SetOrigin(m_pGonomeGuts->pev, vecArmPos);
|
||||||
|
|
||||||
|
m_pGonomeGuts = 0;
|
||||||
|
}
|
||||||
|
UTIL_BloodDrips( vecArmPos, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, 35 );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GONOME_AE_SLASH_LEFT:
|
||||||
|
{
|
||||||
|
edict_t *pHurt = CheckTraceHullAttack(GONOME_MELEE_ATTACK_RADIUS, gSkillData.gonomeDmgOneSlash, DMG_SLASH);
|
||||||
|
if (pHurt)
|
||||||
|
{
|
||||||
|
if (FBitSet(pHurt->v.flags, FL_MONSTER|FL_CLIENT))
|
||||||
|
{
|
||||||
|
pHurt->v.punchangle.z = 9;
|
||||||
|
pHurt->v.punchangle.x = 5;
|
||||||
|
pHurt->v.velocity = pHurt->v.velocity + gpGlobals->v_right * 25;
|
||||||
|
}
|
||||||
|
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackHitSounds), 1, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackMissSounds), 1, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GONOME_AE_SLASH_RIGHT:
|
||||||
|
{
|
||||||
|
edict_t *pHurt = CheckTraceHullAttack(GONOME_MELEE_ATTACK_RADIUS, gSkillData.gonomeDmgOneSlash, DMG_SLASH);
|
||||||
|
if (pHurt)
|
||||||
|
{
|
||||||
|
if (FBitSet(pHurt->v.flags, FL_MONSTER|FL_CLIENT))
|
||||||
|
{
|
||||||
|
pHurt->v.punchangle.z = -9;
|
||||||
|
pHurt->v.punchangle.x = 5;
|
||||||
|
pHurt->v.velocity = pHurt->v.velocity + gpGlobals->v_right * -25;
|
||||||
|
}
|
||||||
|
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackHitSounds), 1, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackMissSounds), 1, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GONOME_AE_BITE1:
|
||||||
|
case GONOME_AE_BITE2:
|
||||||
|
case GONOME_AE_BITE3:
|
||||||
|
case GONOME_AE_BITE4:
|
||||||
|
{
|
||||||
|
int iPitch;
|
||||||
|
edict_t *pHurt = CheckTraceHullAttack(GONOME_MELEE_ATTACK_RADIUS, gSkillData.gonomeDmgOneBite, DMG_SLASH);
|
||||||
|
|
||||||
|
if (pHurt)
|
||||||
|
{
|
||||||
|
// croonchy bite sound
|
||||||
|
iPitch = RANDOM_FLOAT(90, 110);
|
||||||
|
switch (RANDOM_LONG(0, 1))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "bullchicken/bc_bite2.wav", 1, ATTN_NORM, 0, iPitch);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "bullchicken/bc_bite3.wav", 1, ATTN_NORM, 0, iPitch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FBitSet(pHurt->v.flags, FL_MONSTER|FL_CLIENT))
|
||||||
|
{
|
||||||
|
if (pEvent->event == GONOME_AE_BITE4)
|
||||||
|
{
|
||||||
|
pHurt->v.punchangle.x = 15;
|
||||||
|
pHurt->v.velocity = pHurt->v.velocity - gpGlobals->v_forward * 75;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pHurt->v.punchangle.x = 9;
|
||||||
|
pHurt->v.velocity = pHurt->v.velocity - gpGlobals->v_forward * 25;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// lock player
|
||||||
|
if (pEvent->event == GONOME_AE_BITE4)
|
||||||
|
{
|
||||||
|
UnlockPlayer();
|
||||||
|
}
|
||||||
|
else if (UTIL_IsPlayer( pHurt ) && UTIL_IsAlive( pHurt ))
|
||||||
|
{
|
||||||
|
if (!m_fPlayerLocked)
|
||||||
|
{
|
||||||
|
edict_t *player = pHurt;
|
||||||
|
player->v.flags |= FL_FROZEN;
|
||||||
|
m_lockedPlayer = player;
|
||||||
|
m_fPlayerLocked = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CMBaseMonster::HandleAnimEvent(pEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GONOME_FLINCH_DELAY 2
|
||||||
|
|
||||||
|
int CMGonome::IgnoreConditions( void )
|
||||||
|
{
|
||||||
|
int iIgnore = CMBaseMonster::IgnoreConditions();
|
||||||
|
|
||||||
|
if( m_Activity == ACT_MELEE_ATTACK1 )
|
||||||
|
{
|
||||||
|
if( m_flNextFlinch >= gpGlobals->time )
|
||||||
|
iIgnore |= ( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ( m_Activity == ACT_SMALL_FLINCH ) || ( m_Activity == ACT_BIG_FLINCH ) )
|
||||||
|
{
|
||||||
|
if( m_flNextFlinch < gpGlobals->time )
|
||||||
|
m_flNextFlinch = gpGlobals->time + GONOME_FLINCH_DELAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return iIgnore;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Spawn
|
||||||
|
//=========================================================
|
||||||
|
void CMGonome::Spawn()
|
||||||
|
{
|
||||||
|
Precache();
|
||||||
|
|
||||||
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/gonome.mdl"));
|
||||||
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
pev->movetype = MOVETYPE_STEP;
|
||||||
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
|
||||||
|
pev->effects = 0;
|
||||||
|
if (!pev->health) { pev->health = gSkillData.gonomeHealth; }
|
||||||
|
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
|
|
||||||
|
m_flNextThrowTime = gpGlobals->time;
|
||||||
|
|
||||||
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_gonome" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Gonome" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Precache - precaches all resources this monster needs
|
||||||
|
//=========================================================
|
||||||
|
void CMGonome::Precache()
|
||||||
|
{
|
||||||
|
PRECACHE_MODEL("models/gonome.mdl");
|
||||||
|
|
||||||
|
PRECACHE_MODEL("sprites/bigspit.spr");// spit projectile.
|
||||||
|
|
||||||
|
PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event
|
||||||
|
|
||||||
|
PRECACHE_SOUND("gonome/gonome_eat.wav");
|
||||||
|
PRECACHE_SOUND("gonome/gonome_jumpattack.wav");
|
||||||
|
PRECACHE_SOUND("gonome/gonome_melee1.wav");
|
||||||
|
PRECACHE_SOUND("gonome/gonome_melee2.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND_ARRAY(pIdleSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pPainSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pDeathSounds);
|
||||||
|
|
||||||
|
PRECACHE_SOUND("gonome/gonome_run.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("bullchicken/bc_acid1.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("bullchicken/bc_bite2.wav");
|
||||||
|
PRECACHE_SOUND("bullchicken/bc_bite3.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("bullchicken/bc_spithit1.wav");
|
||||||
|
PRECACHE_SOUND("bullchicken/bc_spithit2.wav");
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// GetSchedule
|
||||||
|
//=========================================================
|
||||||
|
Schedule_t *CMGonome::GetSchedule( void )
|
||||||
|
{
|
||||||
|
switch( m_MonsterState )
|
||||||
|
{
|
||||||
|
case MONSTERSTATE_COMBAT:
|
||||||
|
{
|
||||||
|
// dead enemy
|
||||||
|
if( HasConditions( bits_COND_ENEMY_DEAD ) )
|
||||||
|
{
|
||||||
|
// call base class, all code to handle dead enemies is centralized there.
|
||||||
|
return CMBaseMonster::GetSchedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( HasConditions( bits_COND_NEW_ENEMY ) )
|
||||||
|
{
|
||||||
|
return GetScheduleOfType( SCHED_WAKE_ANGRY );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) )
|
||||||
|
{
|
||||||
|
return GetScheduleOfType( SCHED_RANGE_ATTACK1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) )
|
||||||
|
{
|
||||||
|
return GetScheduleOfType( SCHED_MELEE_ATTACK1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( HasConditions( bits_COND_CAN_MELEE_ATTACK2 ) )
|
||||||
|
{
|
||||||
|
return GetScheduleOfType( SCHED_MELEE_ATTACK2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetScheduleOfType( SCHED_CHASE_ENEMY );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMBaseMonster::GetSchedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
// primary range attack
|
||||||
|
Task_t tlGonomeRangeAttack1[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, 0 },
|
||||||
|
{ TASK_FACE_IDEAL, (float)0 },
|
||||||
|
{ TASK_RANGE_ATTACK1, (float)0 },
|
||||||
|
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slGonomeRangeAttack1[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlGonomeRangeAttack1,
|
||||||
|
ARRAYSIZE( tlGonomeRangeAttack1 ),
|
||||||
|
bits_COND_NEW_ENEMY |
|
||||||
|
bits_COND_ENEMY_DEAD |
|
||||||
|
bits_COND_HEAVY_DAMAGE |
|
||||||
|
bits_COND_ENEMY_OCCLUDED |
|
||||||
|
bits_COND_NO_AMMO_LOADED,
|
||||||
|
0,
|
||||||
|
"Gonome Range Attack1"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Chase enemy schedule
|
||||||
|
Task_t tlGonomeChaseEnemy1[] =
|
||||||
|
{
|
||||||
|
{ TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK1 },// !!!OEM - this will stop nasty squid oscillation.
|
||||||
|
{ TASK_GET_PATH_TO_ENEMY, (float)0 },
|
||||||
|
{ TASK_RUN_PATH, (float)0 },
|
||||||
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slGonomeChaseEnemy[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlGonomeChaseEnemy1,
|
||||||
|
ARRAYSIZE( tlGonomeChaseEnemy1 ),
|
||||||
|
bits_COND_NEW_ENEMY |
|
||||||
|
bits_COND_ENEMY_DEAD |
|
||||||
|
bits_COND_SMELL_FOOD |
|
||||||
|
bits_COND_CAN_RANGE_ATTACK1 |
|
||||||
|
bits_COND_CAN_MELEE_ATTACK1 |
|
||||||
|
bits_COND_CAN_MELEE_ATTACK2 |
|
||||||
|
bits_COND_TASK_FAILED,
|
||||||
|
0,
|
||||||
|
"Gonome Chase Enemy"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// victory dance (eating body)
|
||||||
|
Task_t tlGonomeVictoryDance[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, (float)0 },
|
||||||
|
{ TASK_WAIT, (float)0.1 },
|
||||||
|
{ TASK_GONOME_GET_PATH_TO_ENEMY_CORPSE, (float)0 },
|
||||||
|
{ TASK_WALK_PATH, (float)0 },
|
||||||
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
|
||||||
|
{ TASK_FACE_ENEMY, (float)0 },
|
||||||
|
{ TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE },
|
||||||
|
{ TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE },
|
||||||
|
{ TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slGonomeVictoryDance[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlGonomeVictoryDance,
|
||||||
|
ARRAYSIZE( tlGonomeVictoryDance ),
|
||||||
|
bits_COND_NEW_ENEMY |
|
||||||
|
bits_COND_LIGHT_DAMAGE |
|
||||||
|
bits_COND_HEAVY_DAMAGE,
|
||||||
|
0,
|
||||||
|
"GonomeVictoryDance"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFINE_CUSTOM_SCHEDULES( CMGonome )
|
||||||
|
{
|
||||||
|
slGonomeRangeAttack1,
|
||||||
|
slGonomeChaseEnemy,
|
||||||
|
slGonomeVictoryDance,
|
||||||
|
};
|
||||||
|
|
||||||
|
IMPLEMENT_CUSTOM_SCHEDULES( CMGonome, CMBaseMonster )
|
||||||
|
|
||||||
|
Schedule_t* CMGonome::GetScheduleOfType(int Type)
|
||||||
|
{
|
||||||
|
switch ( Type )
|
||||||
|
{
|
||||||
|
case SCHED_RANGE_ATTACK1:
|
||||||
|
return &slGonomeRangeAttack1[0];
|
||||||
|
break;
|
||||||
|
case SCHED_CHASE_ENEMY:
|
||||||
|
return &slGonomeChaseEnemy[0];
|
||||||
|
break;
|
||||||
|
case SCHED_VICTORY_DANCE:
|
||||||
|
return &slGonomeVictoryDance[0];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return CMBaseMonster::GetScheduleOfType(Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMGonome::RunTask(Task_t *pTask)
|
||||||
|
{
|
||||||
|
// HACK to stop Gonome from playing attack sound twice
|
||||||
|
if (pTask->iTask == TASK_MELEE_ATTACK1)
|
||||||
|
{
|
||||||
|
if (!m_playedAttackSound)
|
||||||
|
{
|
||||||
|
const char* sample = NULL;
|
||||||
|
if (m_meleeAttack2)
|
||||||
|
{
|
||||||
|
sample = "gonome/gonome_melee2.wav";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sample = "gonome/gonome_melee1.wav";
|
||||||
|
}
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_BODY, sample, 1, ATTN_NORM);
|
||||||
|
m_playedAttackSound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_playedAttackSound = false;
|
||||||
|
}
|
||||||
|
CMBaseMonster::RunTask(pTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Start task - selects the correct activity and performs
|
||||||
|
// any necessary calculations to start the next task on the
|
||||||
|
// schedule.
|
||||||
|
//=========================================================
|
||||||
|
void CMGonome::StartTask(Task_t *pTask)
|
||||||
|
{
|
||||||
|
m_iTaskStatus = TASKSTATUS_RUNNING;
|
||||||
|
|
||||||
|
switch (pTask->iTask)
|
||||||
|
{
|
||||||
|
case TASK_GONOME_GET_PATH_TO_ENEMY_CORPSE:
|
||||||
|
{
|
||||||
|
UTIL_MakeVectors( pev->angles );
|
||||||
|
if( BuildRoute( m_vecEnemyLKP - gpGlobals->v_forward * 40, bits_MF_TO_LOCATION, NULL ) )
|
||||||
|
{
|
||||||
|
TaskComplete();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ALERT( at_aiconsole, "GonomeGetPathToEnemyCorpse failed!!\n" );
|
||||||
|
TaskFail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
CMBaseMonster::StartTask(pTask);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -215,14 +215,14 @@ void CMHAssassin :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/hassassin.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/hassassin.mdl"));
|
||||||
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
pev->movetype = MOVETYPE_STEP;
|
pev->movetype = MOVETYPE_STEP;
|
||||||
m_bloodColor = BLOOD_COLOR_RED;
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
|
||||||
pev->effects = 0;
|
pev->effects = 0;
|
||||||
pev->health = gSkillData.hassassinHealth;
|
if (!pev->health) { pev->health = gSkillData.hassassinHealth; }
|
||||||
m_flFieldOfView = VIEW_FIELD_WIDE; // indicates the width of this monster's forward view cone ( as a dotproduct result )
|
m_flFieldOfView = VIEW_FIELD_WIDE; // indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
m_MonsterState = MONSTERSTATE_NONE;
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
m_afCapability = bits_CAP_MELEE_ATTACK1 | bits_CAP_DOORS_GROUP;
|
m_afCapability = bits_CAP_MELEE_ATTACK1 | bits_CAP_DOORS_GROUP;
|
||||||
@@ -256,7 +256,7 @@ void CMHAssassin :: Precache()
|
|||||||
|
|
||||||
PRECACHE_SOUND("debris/beamstart1.wav");
|
PRECACHE_SOUND("debris/beamstart1.wav");
|
||||||
|
|
||||||
m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell
|
m_iShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ void CMHeadCrab :: HandleAnimEvent( MonsterEvent_t *pEvent )
|
|||||||
|
|
||||||
int iSound = RANDOM_LONG(0,2);
|
int iSound = RANDOM_LONG(0,2);
|
||||||
if ( iSound != 0 )
|
if ( iSound != 0 )
|
||||||
EMIT_SOUND_DYN( edict(), CHAN_VOICE, pAttackSounds[iSound], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
|
EMIT_SOUND_DYN( edict(), CHAN_VOICE, pAttackSounds[iSound], GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||||
|
|
||||||
pev->velocity = vecJumpDir;
|
pev->velocity = vecJumpDir;
|
||||||
m_flNextAttack = gpGlobals->time + 2;
|
m_flNextAttack = gpGlobals->time + 2;
|
||||||
@@ -247,14 +247,14 @@ void CMHeadCrab :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/headcrab.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/headcrab.mdl"));
|
||||||
UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24));
|
UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24));
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
pev->movetype = MOVETYPE_STEP;
|
pev->movetype = MOVETYPE_STEP;
|
||||||
m_bloodColor = BLOOD_COLOR_GREEN;
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
|
||||||
pev->effects = 0;
|
pev->effects = 0;
|
||||||
pev->health = gSkillData.headcrabHealth;
|
if (!pev->health) { pev->health = gSkillData.headcrabHealth; }
|
||||||
pev->view_ofs = Vector ( 0, 0, 20 );// position of the eyes relative to monster's origin.
|
pev->view_ofs = Vector ( 0, 0, 20 );// position of the eyes relative to monster's origin.
|
||||||
pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim?
|
pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim?
|
||||||
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
@@ -325,7 +325,7 @@ void CMHeadCrab :: LeapTouch ( edict_t *pOther )
|
|||||||
// Don't hit if back on ground
|
// Don't hit if back on ground
|
||||||
if ( !FBitSet( pev->flags, FL_ONGROUND ) )
|
if ( !FBitSet( pev->flags, FL_ONGROUND ) )
|
||||||
{
|
{
|
||||||
EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBiteSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
|
EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBiteSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||||
|
|
||||||
if (UTIL_IsPlayer(pOther))
|
if (UTIL_IsPlayer(pOther))
|
||||||
UTIL_TakeDamage( pOther, pev, pev, GetDamageAmount(), DMG_SLASH );
|
UTIL_TakeDamage( pOther, pev, pev, GetDamageAmount(), DMG_SLASH );
|
||||||
@@ -359,7 +359,7 @@ void CMHeadCrab :: StartTask ( Task_t *pTask )
|
|||||||
{
|
{
|
||||||
case TASK_RANGE_ATTACK1:
|
case TASK_RANGE_ATTACK1:
|
||||||
{
|
{
|
||||||
EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pAttackSounds[0], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
|
EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pAttackSounds[0], GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||||
m_IdealActivity = ACT_RANGE_ATTACK1;
|
m_IdealActivity = ACT_RANGE_ATTACK1;
|
||||||
SetTouch ( &CMHeadCrab::LeapTouch );
|
SetTouch ( &CMHeadCrab::LeapTouch );
|
||||||
break;
|
break;
|
||||||
@@ -415,7 +415,7 @@ int CMHeadCrab :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, f
|
|||||||
#define CRAB_ATTN_IDLE (float)1.5
|
#define CRAB_ATTN_IDLE (float)1.5
|
||||||
void CMHeadCrab :: IdleSound ( void )
|
void CMHeadCrab :: IdleSound ( void )
|
||||||
{
|
{
|
||||||
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
|
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -423,7 +423,7 @@ void CMHeadCrab :: IdleSound ( void )
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
void CMHeadCrab :: AlertSound ( void )
|
void CMHeadCrab :: AlertSound ( void )
|
||||||
{
|
{
|
||||||
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAlertSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
|
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAlertSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -431,7 +431,7 @@ void CMHeadCrab :: AlertSound ( void )
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
void CMHeadCrab :: PainSound ( void )
|
void CMHeadCrab :: PainSound ( void )
|
||||||
{
|
{
|
||||||
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
|
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -439,7 +439,7 @@ void CMHeadCrab :: PainSound ( void )
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
void CMHeadCrab :: DeathSound ( void )
|
void CMHeadCrab :: DeathSound ( void )
|
||||||
{
|
{
|
||||||
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
|
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch() );
|
||||||
}
|
}
|
||||||
|
|
||||||
Schedule_t* CMHeadCrab :: GetScheduleOfType ( int Type )
|
Schedule_t* CMHeadCrab :: GetScheduleOfType ( int Type )
|
||||||
@@ -461,12 +461,12 @@ Schedule_t* CMHeadCrab :: GetScheduleOfType ( int Type )
|
|||||||
void CMBabyCrab :: Spawn( void )
|
void CMBabyCrab :: Spawn( void )
|
||||||
{
|
{
|
||||||
CMHeadCrab::Spawn();
|
CMHeadCrab::Spawn();
|
||||||
SET_MODEL(ENT(pev), "models/baby_headcrab.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/baby_headcrab.mdl"));
|
||||||
pev->rendermode = kRenderTransTexture;
|
pev->rendermode = kRenderTransTexture;
|
||||||
pev->renderamt = 192;
|
pev->renderamt = 192;
|
||||||
UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24));
|
UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24));
|
||||||
|
|
||||||
pev->health = gSkillData.headcrabHealth * 0.25; // less health than full grown
|
if (!pev->health) { pev->health = gSkillData.headcrabHealth * 0.25; } // less health than full grown
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMBabyCrab :: Precache( void )
|
void CMBabyCrab :: Precache( void )
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ void CMHGrunt :: SpeakSentence( void )
|
|||||||
|
|
||||||
if (FOkToSpeak())
|
if (FOkToSpeak())
|
||||||
{
|
{
|
||||||
SENTENCEG_PlayRndSz( ENT(pev), pGruntSentences[ m_iSentence ], HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
|
SENTENCEG_PlayRndSz( ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? pGruntSentences[ m_iSentence ] : CMRGrunt::pRobotSentences[ m_iSentence ], HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
|
||||||
JustSpoke();
|
JustSpoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -546,21 +546,22 @@ void CMHGrunt :: IdleSound( void )
|
|||||||
{
|
{
|
||||||
if (FOkToSpeak() && (g_fGruntQuestion || RANDOM_LONG(0,1)))
|
if (FOkToSpeak() && (g_fGruntQuestion || RANDOM_LONG(0,1)))
|
||||||
{
|
{
|
||||||
|
// there has to be a better way than spamming ternary operators... -Giegue
|
||||||
if (!g_fGruntQuestion)
|
if (!g_fGruntQuestion)
|
||||||
{
|
{
|
||||||
// ask question or make statement
|
// ask question or make statement
|
||||||
switch (RANDOM_LONG(0,2))
|
switch (RANDOM_LONG(0,2))
|
||||||
{
|
{
|
||||||
case 0: // check in
|
case 0: // check in
|
||||||
SENTENCEG_PlayRndSz(ENT(pev), "HG_CHECK", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
SENTENCEG_PlayRndSz(ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_CHECK" : "RB_CHECK", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
||||||
g_fGruntQuestion = 1;
|
g_fGruntQuestion = 1;
|
||||||
break;
|
break;
|
||||||
case 1: // question
|
case 1: // question
|
||||||
SENTENCEG_PlayRndSz(ENT(pev), "HG_QUEST", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
SENTENCEG_PlayRndSz(ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_QUEST" : "RB_QUEST", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
||||||
g_fGruntQuestion = 2;
|
g_fGruntQuestion = 2;
|
||||||
break;
|
break;
|
||||||
case 2: // statement
|
case 2: // statement
|
||||||
SENTENCEG_PlayRndSz(ENT(pev), "HG_IDLE", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
SENTENCEG_PlayRndSz(ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_IDLE" : "RB_IDLE", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -569,10 +570,10 @@ void CMHGrunt :: IdleSound( void )
|
|||||||
switch (g_fGruntQuestion)
|
switch (g_fGruntQuestion)
|
||||||
{
|
{
|
||||||
case 1: // check in
|
case 1: // check in
|
||||||
SENTENCEG_PlayRndSz(ENT(pev), "HG_CLEAR", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
SENTENCEG_PlayRndSz(ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_CLEAR" : "RB_CLEAR", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
||||||
break;
|
break;
|
||||||
case 2: // question
|
case 2: // question
|
||||||
SENTENCEG_PlayRndSz(ENT(pev), "HG_ANSWER", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
SENTENCEG_PlayRndSz(ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_ANSWER" : "RB_ANSWER", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
g_fGruntQuestion = 0;
|
g_fGruntQuestion = 0;
|
||||||
@@ -798,8 +799,10 @@ void CMHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent )
|
|||||||
else if (pHurt->v.euser4 != NULL)
|
else if (pHurt->v.euser4 != NULL)
|
||||||
{
|
{
|
||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pHurt));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pHurt));
|
||||||
pMonster->TakeDamage( pev, pev, gSkillData.hgruntDmgKick, DMG_CLUB );
|
pMonster->TakeDamage(pev, pev, gSkillData.hgruntDmgKick, DMG_CLUB);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
UTIL_TakeDamageExternal(pHurt, pev, pev, gSkillData.hgruntDmgKick, DMG_CLUB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -808,7 +811,7 @@ void CMHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent )
|
|||||||
{
|
{
|
||||||
if ( FOkToSpeak() )
|
if ( FOkToSpeak() )
|
||||||
{
|
{
|
||||||
SENTENCEG_PlayRndSz(ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
|
SENTENCEG_PlayRndSz(ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_ALERT" : "RB_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
|
||||||
JustSpoke();
|
JustSpoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -827,14 +830,14 @@ void CMHGrunt :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/hgrunt.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/hgrunt.mdl"));
|
||||||
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
pev->movetype = MOVETYPE_STEP;
|
pev->movetype = MOVETYPE_STEP;
|
||||||
m_bloodColor = BLOOD_COLOR_RED;
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
|
||||||
pev->effects = 0;
|
pev->effects = 0;
|
||||||
pev->health = gSkillData.hgruntHealth;
|
if (!pev->health) { pev->health = gSkillData.hgruntHealth; }
|
||||||
m_flFieldOfView = VIEW_FIELD_FULL; // indicates the width of this monster's forward view cone ( as a dotproduct result )
|
m_flFieldOfView = VIEW_FIELD_FULL; // indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
m_MonsterState = MONSTERSTATE_NONE;
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
m_flNextGrenadeCheck = gpGlobals->time + 1;
|
m_flNextGrenadeCheck = gpGlobals->time + 1;
|
||||||
@@ -937,8 +940,8 @@ void CMHGrunt :: Precache()
|
|||||||
else
|
else
|
||||||
m_voicePitch = 100;
|
m_voicePitch = 100;
|
||||||
|
|
||||||
m_iBrassShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell
|
m_iBrassShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell
|
||||||
m_iShotgunShell = PRECACHE_MODEL ("models/shotgunshell.mdl");
|
m_iShotgunShell = PRECACHE_MODELINDEX("models/shotgunshell.mdl");
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -1673,6 +1676,37 @@ Schedule_t slGruntRepelLand[] =
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Chase enemy failure schedule
|
||||||
|
//=========================================================
|
||||||
|
Task_t tlGruntChaseEnemyFailed[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, (float)0 },
|
||||||
|
{ TASK_WAIT, (float)0.2 },
|
||||||
|
{ TASK_FIND_COVER_FROM_ENEMY, (float)0 },
|
||||||
|
{ TASK_RUN_PATH, (float)0 },
|
||||||
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
|
||||||
|
{ TASK_REMEMBER, (float)bits_MEMORY_INCOVER },
|
||||||
|
// { TASK_TURN_LEFT, (float)179 },
|
||||||
|
{ TASK_FACE_ENEMY, (float)0 },
|
||||||
|
{ TASK_WAIT, (float)1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slGruntChaseEnemyFailed[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlGruntChaseEnemyFailed,
|
||||||
|
ARRAYSIZE ( tlGruntChaseEnemyFailed ),
|
||||||
|
bits_COND_NEW_ENEMY |
|
||||||
|
bits_COND_CAN_RANGE_ATTACK1 |
|
||||||
|
bits_COND_CAN_MELEE_ATTACK1 |
|
||||||
|
bits_COND_CAN_RANGE_ATTACK2 |
|
||||||
|
bits_COND_CAN_MELEE_ATTACK2 |
|
||||||
|
bits_COND_HEAR_SOUND,
|
||||||
|
0,
|
||||||
|
"GruntChaseEnemyFailed"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
DEFINE_CUSTOM_SCHEDULES( CMHGrunt )
|
DEFINE_CUSTOM_SCHEDULES( CMHGrunt )
|
||||||
{
|
{
|
||||||
@@ -1697,6 +1731,7 @@ DEFINE_CUSTOM_SCHEDULES( CMHGrunt )
|
|||||||
slGruntRepel,
|
slGruntRepel,
|
||||||
slGruntRepelAttack,
|
slGruntRepelAttack,
|
||||||
slGruntRepelLand,
|
slGruntRepelLand,
|
||||||
|
slGruntChaseEnemyFailed,
|
||||||
};
|
};
|
||||||
|
|
||||||
IMPLEMENT_CUSTOM_SCHEDULES( CMHGrunt, CMBaseMonster );
|
IMPLEMENT_CUSTOM_SCHEDULES( CMHGrunt, CMBaseMonster );
|
||||||
@@ -1852,6 +1887,8 @@ Schedule_t *CMHGrunt :: GetSchedule( void )
|
|||||||
// new enemy
|
// new enemy
|
||||||
if ( HasConditions(bits_COND_NEW_ENEMY) )
|
if ( HasConditions(bits_COND_NEW_ENEMY) )
|
||||||
{
|
{
|
||||||
|
// none of this should take place as CSquadMonster functions were completely stripped. -Giegue
|
||||||
|
/*
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
//!!!KELLY - the leader of a squad of grunts has just seen the player or a
|
//!!!KELLY - the leader of a squad of grunts has just seen the player or a
|
||||||
@@ -1867,14 +1904,14 @@ Schedule_t *CMHGrunt :: GetSchedule( void )
|
|||||||
if ((m_hEnemy != NULL) && UTIL_IsPlayer(m_hEnemy))
|
if ((m_hEnemy != NULL) && UTIL_IsPlayer(m_hEnemy))
|
||||||
// player
|
// player
|
||||||
SENTENCEG_PlayRndSz( ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
|
SENTENCEG_PlayRndSz( ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
|
||||||
/*jlb
|
|
||||||
else if ((m_hEnemy != NULL) &&
|
else if ((m_hEnemy != NULL) &&
|
||||||
(m_hEnemy->Classify() != CLASS_PLAYER_ALLY) &&
|
(m_hEnemy->Classify() != CLASS_PLAYER_ALLY) &&
|
||||||
(m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE) &&
|
(m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE) &&
|
||||||
(m_hEnemy->Classify() != CLASS_MACHINE))
|
(m_hEnemy->Classify() != CLASS_MACHINE))
|
||||||
// monster
|
// monster
|
||||||
SENTENCEG_PlayRndSz( ENT(pev), "HG_MONST", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
|
SENTENCEG_PlayRndSz( ENT(pev), "HG_MONST", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
|
||||||
jlb*/
|
|
||||||
JustSpoke();
|
JustSpoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1888,6 +1925,7 @@ jlb*/
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
// no ammo
|
// no ammo
|
||||||
else if ( HasConditions ( bits_COND_NO_AMMO_LOADED ) )
|
else if ( HasConditions ( bits_COND_NO_AMMO_LOADED ) )
|
||||||
@@ -1913,9 +1951,9 @@ jlb*/
|
|||||||
//!!!KELLY - this grunt was hit and is going to run to cover.
|
//!!!KELLY - this grunt was hit and is going to run to cover.
|
||||||
if (FOkToSpeak()) // && RANDOM_LONG(0,1))
|
if (FOkToSpeak()) // && RANDOM_LONG(0,1))
|
||||||
{
|
{
|
||||||
//SENTENCEG_PlayRndSz( ENT(pev), "HG_COVER", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
|
SENTENCEG_PlayRndSz( ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_COVER" : "RB_COVER", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
|
||||||
m_iSentence = HGRUNT_SENT_COVER;
|
m_iSentence = HGRUNT_SENT_COVER;
|
||||||
//JustSpoke();
|
JustSpoke();
|
||||||
}
|
}
|
||||||
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
|
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
|
||||||
}
|
}
|
||||||
@@ -1939,6 +1977,10 @@ jlb*/
|
|||||||
// can shoot
|
// can shoot
|
||||||
else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
|
else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
|
||||||
{
|
{
|
||||||
|
// lack of CSquadMonster functionality makes hgrunt behave erraticaly as is removes
|
||||||
|
// core conditions to make them attack (OccupySlot). -Giegue
|
||||||
|
|
||||||
|
// check if a grenade can be thrown, otherwise force weapon fire.
|
||||||
if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) )
|
if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) )
|
||||||
{
|
{
|
||||||
// throw a grenade if can and no engage slots are available
|
// throw a grenade if can and no engage slots are available
|
||||||
@@ -1946,24 +1988,34 @@ jlb*/
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
return GetScheduleOfType( SCHED_RANGE_ATTACK1 );
|
||||||
|
|
||||||
// hide!
|
// hide!
|
||||||
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
|
//return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// can't see enemy
|
// can't see enemy
|
||||||
else if ( HasConditions( bits_COND_ENEMY_OCCLUDED ) )
|
else if ( HasConditions( bits_COND_ENEMY_OCCLUDED ) )
|
||||||
{
|
{
|
||||||
|
// missing CSquadMonster functions means that the monster will stand still if its enemy is out of sight
|
||||||
|
// AND if it is impossible to throw a grenade. force it to chase the enemy if attack isn't possible
|
||||||
|
// -Giegue
|
||||||
if ( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) )
|
if ( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) )
|
||||||
{
|
{
|
||||||
//!!!KELLY - this grunt is about to throw or fire a grenade at the player. Great place for "fire in the hole" "frag out" etc
|
//!!!KELLY - this grunt is about to throw or fire a grenade at the player. Great place for "fire in the hole" "frag out" etc
|
||||||
if (FOkToSpeak())
|
if (FOkToSpeak())
|
||||||
{
|
{
|
||||||
SENTENCEG_PlayRndSz( ENT(pev), "HG_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
|
SENTENCEG_PlayRndSz( ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_THROW" : "RB_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
|
||||||
JustSpoke();
|
JustSpoke();
|
||||||
}
|
}
|
||||||
return GetScheduleOfType( SCHED_RANGE_ATTACK2 );
|
return GetScheduleOfType( SCHED_RANGE_ATTACK2 );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
return GetScheduleOfType( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE );
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
else
|
||||||
{
|
{
|
||||||
//!!!KELLY - grunt is going to stay put for a couple seconds to see if
|
//!!!KELLY - grunt is going to stay put for a couple seconds to see if
|
||||||
// the enemy wanders back out into the open, or approaches the
|
// the enemy wanders back out into the open, or approaches the
|
||||||
@@ -1975,6 +2027,7 @@ jlb*/
|
|||||||
}
|
}
|
||||||
return GetScheduleOfType( SCHED_STANDOFF );
|
return GetScheduleOfType( SCHED_STANDOFF );
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( HasConditions( bits_COND_SEE_ENEMY ) && !HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
|
if ( HasConditions( bits_COND_SEE_ENEMY ) && !HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
|
||||||
@@ -2109,6 +2162,11 @@ Schedule_t* CMHGrunt :: GetScheduleOfType ( int Type )
|
|||||||
{
|
{
|
||||||
return &slGruntRepelLand[ 0 ];
|
return &slGruntRepelLand[ 0 ];
|
||||||
}
|
}
|
||||||
|
case SCHED_CHASE_ENEMY_FAILED:
|
||||||
|
{
|
||||||
|
// add missing schedule from squadmonster.cpp
|
||||||
|
return &slGruntChaseEnemyFailed[ 0 ];
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
return CMBaseMonster :: GetScheduleOfType ( Type );
|
return CMBaseMonster :: GetScheduleOfType ( Type );
|
||||||
|
|||||||
@@ -104,8 +104,8 @@ void CMHornet :: Precache()
|
|||||||
PRECACHE_SOUND( "hornet/ag_hornethit2.wav" );
|
PRECACHE_SOUND( "hornet/ag_hornethit2.wav" );
|
||||||
PRECACHE_SOUND( "hornet/ag_hornethit3.wav" );
|
PRECACHE_SOUND( "hornet/ag_hornethit3.wav" );
|
||||||
|
|
||||||
iHornetPuff = PRECACHE_MODEL( "sprites/muz1.spr" );
|
iHornetPuff = PRECACHE_MODELINDEX( "sprites/muz1.spr" );
|
||||||
iHornetTrail = PRECACHE_MODEL("sprites/laserbeam.spr");
|
iHornetTrail = PRECACHE_MODELINDEX("sprites/laserbeam.spr");
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -126,23 +126,17 @@ int CMHornet::IRelationship ( CMBaseEntity *pTarget )
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMHornet::Classify ( void )
|
int CMHornet::Classify ( void )
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
if ( pev->owner && pev->owner->v.flags & FL_CLIENT)
|
|
||||||
{
|
|
||||||
return CLASS_PLAYER_BIOWEAPON;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CLASS_ALIEN_BIOWEAPON;
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Ensure classify is consistent with the owner, in the event
|
// Ensure classify is consistent with the owner, in the event
|
||||||
// it's classification was overriden.
|
// it's classification was overriden.
|
||||||
if ( pev->owner == NULL )
|
if (UTIL_IsValidEntity(pev->owner))
|
||||||
return CLASS_ALIEN_BIOWEAPON;
|
{
|
||||||
|
|
||||||
// Ain't this going to make the hornets code "slow"?
|
|
||||||
CMBaseMonster *pOwner = GetClassPtr((CMBaseMonster *)VARS(pev->owner));
|
CMBaseMonster *pOwner = GetClassPtr((CMBaseMonster *)VARS(pev->owner));
|
||||||
|
if (pOwner)
|
||||||
return pOwner->Classify();
|
return pOwner->Classify();
|
||||||
|
else
|
||||||
|
return pev->owner->v.iuser4;
|
||||||
|
}
|
||||||
|
return CLASS_ALIEN_BIOWEAPON;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -326,11 +320,10 @@ void CMHornet :: TrackTouch ( edict_t *pOther )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// is this NOT a player and IS a monster?
|
// is this NOT a player and IS a monster?
|
||||||
if (!UTIL_IsPlayer(pOther) && (pOther->v.euser4 != NULL))
|
if (!UTIL_IsPlayer(pOther) && (pOther->v.flags & FL_MONSTER))
|
||||||
{
|
{
|
||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||||
|
if ( pMonster != NULL && IRelationship( pMonster ) <= R_NO || IRelationshipByClass( pOther->v.iuser4 ) <= R_NO )
|
||||||
if ( IRelationship( pMonster ) <= R_NO )
|
|
||||||
{
|
{
|
||||||
// hit something we don't want to hurt, so turn around.
|
// hit something we don't want to hurt, so turn around.
|
||||||
|
|
||||||
@@ -373,6 +366,8 @@ void CMHornet::DieTouch ( edict_t *pOther )
|
|||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||||
pMonster->TakeDamage( pev, VARS( pev->owner ), pev->dmg, DMG_BULLET );
|
pMonster->TakeDamage( pev, VARS( pev->owner ), pev->dmg, DMG_BULLET );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
UTIL_TakeDamageExternal( pOther, pev, VARS( pev->owner ), pev->dmg, DMG_BULLET );
|
||||||
}
|
}
|
||||||
|
|
||||||
pev->modelindex = 0;// so will disappear for the 0.1 secs we wait until NEXTTHINK gets rid
|
pev->modelindex = 0;// so will disappear for the 0.1 secs we wait until NEXTTHINK gets rid
|
||||||
|
|||||||
@@ -267,14 +267,14 @@ void CMHoundeye :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/houndeye.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/houndeye.mdl"));
|
||||||
UTIL_SetSize(pev, Vector ( -16, -16, 0 ), Vector ( 16, 16, 36 ) );
|
UTIL_SetSize(pev, Vector ( -16, -16, 0 ), Vector ( 16, 16, 36 ) );
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
pev->movetype = MOVETYPE_STEP;
|
pev->movetype = MOVETYPE_STEP;
|
||||||
m_bloodColor = BLOOD_COLOR_YELLOW;
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
|
||||||
pev->effects = 0;
|
pev->effects = 0;
|
||||||
pev->health = gSkillData.houndeyeHealth;
|
if (!pev->health) { pev->health = gSkillData.houndeyeHealth; }
|
||||||
pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim?
|
pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim?
|
||||||
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
m_MonsterState = MONSTERSTATE_NONE;
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
@@ -326,7 +326,7 @@ void CMHoundeye :: Precache()
|
|||||||
PRECACHE_SOUND("houndeye/he_blast2.wav");
|
PRECACHE_SOUND("houndeye/he_blast2.wav");
|
||||||
PRECACHE_SOUND("houndeye/he_blast3.wav");
|
PRECACHE_SOUND("houndeye/he_blast3.wav");
|
||||||
|
|
||||||
m_iSpriteTexture = PRECACHE_MODEL( "sprites/shockwave.spr" );
|
m_iSpriteTexture = PRECACHE_MODELINDEX( "sprites/shockwave.spr" );
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -524,7 +524,8 @@ void CMHoundeye :: SonicAttack ( void )
|
|||||||
{
|
{
|
||||||
if ( pEntity->v.takedamage != DAMAGE_NO )
|
if ( pEntity->v.takedamage != DAMAGE_NO )
|
||||||
{
|
{
|
||||||
if ( strcmp(STRING(pEntity->v.model), "models/houndeye.mdl") != 0 )
|
// don't compare by model because a mapper might change it
|
||||||
|
if ( strcmp(STRING(pEntity->v.classname), "monster_houndeye") != 0 )
|
||||||
{// houndeyes don't hurt other houndeyes with their attack
|
{// houndeyes don't hurt other houndeyes with their attack
|
||||||
|
|
||||||
// houndeyes do FULL damage if the ent in question is visible. Half damage otherwise.
|
// houndeyes do FULL damage if the ent in question is visible. Half damage otherwise.
|
||||||
@@ -565,6 +566,8 @@ void CMHoundeye :: SonicAttack ( void )
|
|||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
|
||||||
pMonster->TakeDamage( pev, pev, flAdjustedDamage, DMG_SONIC | DMG_ALWAYSGIB );
|
pMonster->TakeDamage( pev, pev, flAdjustedDamage, DMG_SONIC | DMG_ALWAYSGIB );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
UTIL_TakeDamageExternal( pEntity, pev, pev, flAdjustedDamage, DMG_SONIC | DMG_ALWAYSGIB );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
813
src/dlls/hwgrunt.cpp
Normal file
813
src/dlls/hwgrunt.cpp
Normal file
@@ -0,0 +1,813 @@
|
|||||||
|
/***
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* This product contains software technology licensed from Id
|
||||||
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This source code contains proprietary and confidential information of
|
||||||
|
* Valve LLC and its suppliers. Access to this code is restricted to
|
||||||
|
* persons who have executed a written SDK license with Valve. Any access,
|
||||||
|
* use or distribution of this code by or to any unlicensed person is illegal.
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
//=========================================================
|
||||||
|
// Heavy Weapons Grunt
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "plane.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
#include "monsters.h"
|
||||||
|
#include "schedule.h"
|
||||||
|
#include "animation.h"
|
||||||
|
#include "weapons.h"
|
||||||
|
#include "cmtalkmonster.h"
|
||||||
|
#include "effects.h"
|
||||||
|
#include "customentity.h"
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// monster-specific DEFINE's
|
||||||
|
//=========================================================
|
||||||
|
// Weapon flags
|
||||||
|
#define HWGRUNT_MINIGUN 0
|
||||||
|
|
||||||
|
#define GUN_GROUP 1
|
||||||
|
|
||||||
|
// Gun values
|
||||||
|
#define GUN_MINIGUN 0
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// monster-specific schedule types
|
||||||
|
//=========================================================
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE = LAST_COMMON_SCHEDULE + 1,// move to a location to set up an attack against the enemy.
|
||||||
|
SCHED_HWGRUNT_REPEL,
|
||||||
|
SCHED_HWGRUNT_REPEL_LAND,
|
||||||
|
SCHED_HWGRUNT_WAIT_FACE_ENEMY,
|
||||||
|
SCHED_HWGRUNT_TAKECOVER_FAILED,// force analysis of conditions and pick the best possible schedule to recover from failure.
|
||||||
|
SCHED_HWGRUNT_ELOF_FAIL,
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// monster-specific conditions
|
||||||
|
//=========================================================
|
||||||
|
#define bits_MEMORY_HWGRUNT_SPINUP ( bits_MEMORY_CUSTOM1 )
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Monster's Anim Events Go Here
|
||||||
|
//=========================================================
|
||||||
|
#define HWGRUNT_AE_DEATH ( 11 )
|
||||||
|
#define HWGRUNT_AE_MINIGUN ( 5001 )
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Classify - indicates this monster's place in the
|
||||||
|
// relationship table.
|
||||||
|
//=========================================================
|
||||||
|
int CMHWGrunt::Classify(void)
|
||||||
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
|
return CLASS_HUMAN_MILITARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// CheckRangeAttack1 - HWGrunt doesn't care about melee
|
||||||
|
//=========================================================
|
||||||
|
BOOL CMHWGrunt :: CheckRangeAttack1 ( float flDot, float flDist )
|
||||||
|
{
|
||||||
|
if ( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 2048 && flDot >= 0.5 )
|
||||||
|
{
|
||||||
|
TraceResult tr;
|
||||||
|
|
||||||
|
Vector vecSrc = GetGunPosition();
|
||||||
|
|
||||||
|
// verify that a bullet fired from the gun will hit the enemy before the world.
|
||||||
|
UTIL_TraceLine( vecSrc, UTIL_BodyTarget(m_hEnemy, vecSrc), ignore_monsters, ignore_glass, ENT(pev), &tr);
|
||||||
|
|
||||||
|
if ( tr.flFraction == 1.0 )
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// CheckMeleeAttack1 - HWGrunt does not kick
|
||||||
|
//=========================================================
|
||||||
|
BOOL CMHWGrunt :: CheckMeleeAttack1 ( float flDot, float flDist )
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// CheckRangeAttack2 - HWGrunt has no grenades
|
||||||
|
//=========================================================
|
||||||
|
BOOL CMHWGrunt :: CheckRangeAttack2 ( float flDot, float flDist )
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Shoot
|
||||||
|
//=========================================================
|
||||||
|
void CMHWGrunt::Minigun(void)
|
||||||
|
{
|
||||||
|
if (m_hEnemy == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector vecShootOrigin = GetGunPosition();
|
||||||
|
Vector vecShootDir = ShootAtEnemy(vecShootOrigin);
|
||||||
|
|
||||||
|
FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_10DEGREES, 2048, BULLET_MONSTER_12MM); // shoot +-5 degrees
|
||||||
|
|
||||||
|
pev->effects |= EF_MUZZLEFLASH;
|
||||||
|
|
||||||
|
// Minigunners have infinite ammo
|
||||||
|
//m_cAmmoLoaded--;// take away a bullet!
|
||||||
|
|
||||||
|
Vector angDir = UTIL_VecToAngles(vecShootDir);
|
||||||
|
SetBlending(0, angDir.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// TraceAttack - hwgrunts do not wear helmets
|
||||||
|
//=========================================================
|
||||||
|
void CMHWGrunt :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
|
||||||
|
{
|
||||||
|
CMBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// TakeDamage - overridden for hwgrunts.
|
||||||
|
// They are meant to be aggresive, never take cover.
|
||||||
|
//=========================================================
|
||||||
|
int CMHWGrunt :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
||||||
|
{
|
||||||
|
return CMBaseMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType );
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// HandleAnimEvent - catches the monster-specific messages
|
||||||
|
// that occur when tagged animation frames are played.
|
||||||
|
//=========================================================
|
||||||
|
void CMHWGrunt::HandleAnimEvent(MonsterEvent_t *pEvent)
|
||||||
|
{
|
||||||
|
switch (pEvent->event)
|
||||||
|
{
|
||||||
|
case HWGRUNT_AE_DEATH:
|
||||||
|
break; // don't get rid of gun
|
||||||
|
|
||||||
|
case HWGRUNT_AE_MINIGUN:
|
||||||
|
{
|
||||||
|
// Sven Co-op uses a modified hassault/hw_gun4.wav for it's fire sound
|
||||||
|
Minigun();
|
||||||
|
|
||||||
|
// We don't want looping WAVs. Pick a different sound and change pitch on it
|
||||||
|
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "hassault/hw_shoot1.wav", 1, ATTN_NORM, 0, PITCH_NORM + RANDOM_LONG(-5,5));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CMHGrunt::HandleAnimEvent(pEvent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Spawn
|
||||||
|
//=========================================================
|
||||||
|
void CMHWGrunt::Spawn()
|
||||||
|
{
|
||||||
|
Precache();
|
||||||
|
|
||||||
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/hwgrunt.mdl"));
|
||||||
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
pev->movetype = MOVETYPE_STEP;
|
||||||
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
|
||||||
|
pev->effects = 0;
|
||||||
|
if (!pev->health) { pev->health = gSkillData.hwgruntHealth; }
|
||||||
|
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
|
//m_flNextGrenadeCheck = gpGlobals->time + 1;
|
||||||
|
m_flNextPainTime = gpGlobals->time;
|
||||||
|
//m_flMinigunSpinTime = 0; // be able to spin up/down minigun right away
|
||||||
|
m_iSentence = -1;
|
||||||
|
m_fStanding = TRUE;
|
||||||
|
|
||||||
|
//m_afCapability = bits_CAP_SQUAD | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
|
||||||
|
m_afCapability = bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
|
||||||
|
|
||||||
|
//m_fEnemyEluded = FALSE;
|
||||||
|
m_fFirstEncounter = FALSE;// false because hwgrunt does not send signals of any kind
|
||||||
|
|
||||||
|
m_HackedGunPos = Vector(0, 0, 55);
|
||||||
|
|
||||||
|
// Don't setup pev->weapons, always minigun if not specified
|
||||||
|
/*
|
||||||
|
if (FBitSet(pev->weapons, HWGRUNT_MINIGUN))
|
||||||
|
{
|
||||||
|
SetBodygroup(GUN_GROUP, GUN_MINIGUN);
|
||||||
|
m_cClipSize = 1;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
m_cAmmoLoaded = 99;
|
||||||
|
m_cClipSize = 99;
|
||||||
|
|
||||||
|
CMTalkMonster::g_talkWaitTime = 0;
|
||||||
|
|
||||||
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_hwgrunt" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Heavy Weapons Grunt" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Precache - precaches all resources this monster needs
|
||||||
|
//=========================================================
|
||||||
|
void CMHWGrunt::Precache()
|
||||||
|
{
|
||||||
|
PRECACHE_MODEL("models/hwgrunt.mdl");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("hassault/hw_shoot1.wav");
|
||||||
|
PRECACHE_SOUND("hassault/hw_spinup.wav");
|
||||||
|
PRECACHE_SOUND("hassault/hw_spindown.wav");
|
||||||
|
|
||||||
|
// get voice pitch
|
||||||
|
m_voicePitch = 95 + RANDOM_LONG(0, 3); // slighly lower than normal grunt
|
||||||
|
|
||||||
|
CMHGrunt hgrunt;
|
||||||
|
hgrunt.Precache();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// AI Schedules Specific to this monster
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Fail
|
||||||
|
//=========================================================
|
||||||
|
Task_t tlHWGruntFail[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, 0 },
|
||||||
|
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
|
||||||
|
{ TASK_WAIT, (float)2 },
|
||||||
|
{ TASK_WAIT_PVS, (float)0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slHWGruntFail[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlHWGruntFail,
|
||||||
|
ARRAYSIZE ( tlHWGruntFail ),
|
||||||
|
bits_COND_CAN_RANGE_ATTACK1,
|
||||||
|
0,
|
||||||
|
"HWGrunt Fail"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Combat Fail
|
||||||
|
//=========================================================
|
||||||
|
Task_t tlHWGruntCombatFail[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, 0 },
|
||||||
|
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
|
||||||
|
{ TASK_WAIT_FACE_ENEMY, (float)2 },
|
||||||
|
{ TASK_WAIT_PVS, (float)0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slHWGruntCombatFail[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlHWGruntCombatFail,
|
||||||
|
ARRAYSIZE ( tlHWGruntCombatFail ),
|
||||||
|
bits_COND_CAN_RANGE_ATTACK1,
|
||||||
|
0,
|
||||||
|
"HWGrunt Combat Fail"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Not really victory dance
|
||||||
|
//=========================================================
|
||||||
|
Task_t tlHWGruntVictoryDance[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, (float)0 },
|
||||||
|
{ TASK_FACE_ENEMY, (float)0 },
|
||||||
|
{ TASK_WAIT, (float)1.5 },
|
||||||
|
{ TASK_GET_PATH_TO_ENEMY_CORPSE, (float)0 },
|
||||||
|
{ TASK_WALK_PATH, (float)0 },
|
||||||
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
|
||||||
|
{ TASK_FACE_ENEMY, (float)0 },
|
||||||
|
// { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slHWGruntVictoryDance[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlHWGruntVictoryDance,
|
||||||
|
ARRAYSIZE ( tlHWGruntVictoryDance ),
|
||||||
|
bits_COND_NEW_ENEMY |
|
||||||
|
bits_COND_LIGHT_DAMAGE |
|
||||||
|
bits_COND_HEAVY_DAMAGE,
|
||||||
|
0,
|
||||||
|
"HWGrunt Victory Dance"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Establish line of fire - move to a position that allows
|
||||||
|
// the grunt to attack.
|
||||||
|
//=========================================================
|
||||||
|
Task_t tlHWGruntEstablishLineOfFire[] =
|
||||||
|
{
|
||||||
|
{ TASK_SET_FAIL_SCHEDULE, (float)SCHED_HWGRUNT_ELOF_FAIL },
|
||||||
|
{ TASK_GET_PATH_TO_ENEMY, (float)0 },
|
||||||
|
// { TASK_GRUNT_SPEAK_SENTENCE,(float)0 },
|
||||||
|
{ TASK_RUN_PATH, (float)0 },
|
||||||
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slHWGruntEstablishLineOfFire[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlHWGruntEstablishLineOfFire,
|
||||||
|
ARRAYSIZE ( tlHWGruntEstablishLineOfFire ),
|
||||||
|
bits_COND_NEW_ENEMY |
|
||||||
|
bits_COND_ENEMY_DEAD |
|
||||||
|
bits_COND_CAN_RANGE_ATTACK1 |
|
||||||
|
bits_COND_HEAR_SOUND,
|
||||||
|
0,
|
||||||
|
"HWGrunt Establish Line Of Fire"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// wait in cover - we don't allow danger or the ability to
|
||||||
|
// attack to break a grunt's run to cover schedule, but when
|
||||||
|
// a grunt is in cover, we do want them to attack if they can.
|
||||||
|
//=========================================================
|
||||||
|
Task_t tlHWGruntWaitInCover[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, (float)0 },
|
||||||
|
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
|
||||||
|
{ TASK_WAIT_FACE_ENEMY, (float)1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slHWGruntWaitInCover[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlHWGruntWaitInCover,
|
||||||
|
ARRAYSIZE ( tlHWGruntWaitInCover ),
|
||||||
|
bits_COND_NEW_ENEMY |
|
||||||
|
bits_COND_HEAR_SOUND |
|
||||||
|
bits_COND_CAN_RANGE_ATTACK1,
|
||||||
|
0,
|
||||||
|
"HWGrunt Wait In Cover"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// run to cover.
|
||||||
|
//=========================================================
|
||||||
|
Task_t tlHWGruntTakeCover[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, (float)0 },
|
||||||
|
{ TASK_SET_FAIL_SCHEDULE, (float)SCHED_HWGRUNT_TAKECOVER_FAILED },
|
||||||
|
{ TASK_WAIT, (float)0.2 },
|
||||||
|
{ TASK_FIND_COVER_FROM_ENEMY, (float)0 },
|
||||||
|
// { TASK_GRUNT_SPEAK_SENTENCE, (float)0 },
|
||||||
|
{ TASK_RUN_PATH, (float)0 },
|
||||||
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
|
||||||
|
{ TASK_REMEMBER, (float)bits_MEMORY_INCOVER },
|
||||||
|
{ TASK_SET_SCHEDULE, (float)SCHED_HWGRUNT_WAIT_FACE_ENEMY },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slHWGruntTakeCover[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlHWGruntTakeCover,
|
||||||
|
ARRAYSIZE ( tlHWGruntTakeCover ),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
"HWGrunt Take Cover"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// minigun spinup
|
||||||
|
//=========================================================
|
||||||
|
Task_t tlHWGruntMinigunSpinUp[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, (float)0 },
|
||||||
|
{ TASK_SET_ACTIVITY, (float)ACT_THREAT_DISPLAY },
|
||||||
|
{ TASK_WAIT_FACE_ENEMY, (float)1 },
|
||||||
|
{ TASK_REMEMBER, (float)bits_MEMORY_HWGRUNT_SPINUP },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slHWGruntMinigunSpinUp[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlHWGruntMinigunSpinUp,
|
||||||
|
ARRAYSIZE ( tlHWGruntMinigunSpinUp ),
|
||||||
|
0, // nothing should interrupt this
|
||||||
|
0,
|
||||||
|
"HWGrunt Minigun Spin Up"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// minigun attack
|
||||||
|
//=========================================================
|
||||||
|
Task_t tlHWGruntMinigunAttack[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, (float)0 },
|
||||||
|
{ TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_RANGE_ATTACK1 },
|
||||||
|
{ TASK_RANGE_ATTACK1, (float)0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slHWGruntMinigunAttack[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlHWGruntMinigunAttack,
|
||||||
|
ARRAYSIZE ( tlHWGruntMinigunAttack ),
|
||||||
|
bits_COND_NEW_ENEMY |
|
||||||
|
bits_COND_ENEMY_DEAD |
|
||||||
|
bits_COND_ENEMY_OCCLUDED |
|
||||||
|
bits_COND_HEAR_SOUND,
|
||||||
|
0,
|
||||||
|
"HWGrunt Minigun Attack"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// repel
|
||||||
|
//=========================================================
|
||||||
|
Task_t tlHWGruntRepel[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, (float)0 },
|
||||||
|
{ TASK_FACE_IDEAL, (float)0 },
|
||||||
|
{ TASK_PLAY_SEQUENCE, (float)ACT_GLIDE },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slHWGruntRepel[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlHWGruntRepel,
|
||||||
|
ARRAYSIZE ( tlHWGruntRepel ),
|
||||||
|
bits_COND_SEE_ENEMY |
|
||||||
|
bits_COND_NEW_ENEMY |
|
||||||
|
bits_COND_LIGHT_DAMAGE |
|
||||||
|
bits_COND_HEAVY_DAMAGE |
|
||||||
|
bits_COND_HEAR_SOUND,
|
||||||
|
0,
|
||||||
|
"HWGrunt Repel"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// repel land
|
||||||
|
//=========================================================
|
||||||
|
Task_t tlHWGruntRepelLand[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, (float)0 },
|
||||||
|
{ TASK_PLAY_SEQUENCE, (float)ACT_LAND },
|
||||||
|
{ TASK_GET_PATH_TO_LASTPOSITION, (float)0 },
|
||||||
|
{ TASK_RUN_PATH, (float)0 },
|
||||||
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
|
||||||
|
{ TASK_CLEAR_LASTPOSITION, (float)0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slHWGruntRepelLand[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlHWGruntRepelLand,
|
||||||
|
ARRAYSIZE ( tlHWGruntRepelLand ),
|
||||||
|
bits_COND_SEE_ENEMY |
|
||||||
|
bits_COND_NEW_ENEMY |
|
||||||
|
bits_COND_LIGHT_DAMAGE |
|
||||||
|
bits_COND_HEAVY_DAMAGE |
|
||||||
|
bits_COND_HEAR_SOUND,
|
||||||
|
0,
|
||||||
|
"HWGrunt Repel Land"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Chase enemy failure
|
||||||
|
//=========================================================
|
||||||
|
Task_t tlHWGruntChaseEnemyFailed[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, (float)0 },
|
||||||
|
{ TASK_WAIT, (float)0.2 },
|
||||||
|
{ TASK_FIND_COVER_FROM_ENEMY, (float)0 },
|
||||||
|
{ TASK_RUN_PATH, (float)0 },
|
||||||
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
|
||||||
|
{ TASK_REMEMBER, (float)bits_MEMORY_INCOVER },
|
||||||
|
// { TASK_TURN_LEFT, (float)179 },
|
||||||
|
{ TASK_FACE_ENEMY, (float)0 },
|
||||||
|
{ TASK_WAIT, (float)1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slHWGruntChaseEnemyFailed[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlHWGruntChaseEnemyFailed,
|
||||||
|
ARRAYSIZE ( tlHWGruntChaseEnemyFailed ),
|
||||||
|
bits_COND_NEW_ENEMY |
|
||||||
|
bits_COND_CAN_RANGE_ATTACK1 |
|
||||||
|
bits_COND_HEAR_SOUND,
|
||||||
|
0,
|
||||||
|
"HWGrunt Chase Enemy Failed"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
DEFINE_CUSTOM_SCHEDULES( CMHWGrunt )
|
||||||
|
{
|
||||||
|
slHWGruntFail,
|
||||||
|
slHWGruntCombatFail,
|
||||||
|
slHWGruntVictoryDance,
|
||||||
|
slHWGruntEstablishLineOfFire,
|
||||||
|
slHWGruntWaitInCover,
|
||||||
|
slHWGruntTakeCover,
|
||||||
|
slHWGruntMinigunSpinUp,
|
||||||
|
slHWGruntMinigunAttack,
|
||||||
|
slHWGruntRepel,
|
||||||
|
slHWGruntRepelLand,
|
||||||
|
slHWGruntChaseEnemyFailed,
|
||||||
|
};
|
||||||
|
|
||||||
|
IMPLEMENT_CUSTOM_SCHEDULES( CMHWGrunt, CMBaseMonster );
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// SetActivity
|
||||||
|
//=========================================================
|
||||||
|
void CMHWGrunt :: SetActivity ( Activity NewActivity )
|
||||||
|
{
|
||||||
|
int iSequence = ACTIVITY_NOT_AVAILABLE;
|
||||||
|
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||||
|
|
||||||
|
switch ( NewActivity )
|
||||||
|
{
|
||||||
|
case ACT_RANGE_ATTACK1:
|
||||||
|
iSequence = LookupSequence( "attack" );
|
||||||
|
break;
|
||||||
|
case ACT_RUN:
|
||||||
|
iSequence = LookupSequence( "run" );
|
||||||
|
break;
|
||||||
|
case ACT_WALK:
|
||||||
|
iSequence = LookupSequence( "creeping_walk" );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
iSequence = LookupActivity( NewActivity );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present
|
||||||
|
|
||||||
|
// Set to the desired anim, or default anim if the desired is not present
|
||||||
|
if ( iSequence > ACTIVITY_NOT_AVAILABLE )
|
||||||
|
{
|
||||||
|
if ( pev->sequence != iSequence || !m_fSequenceLoops )
|
||||||
|
{
|
||||||
|
pev->frame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pev->sequence = iSequence; // Set to the reset anim (if it's there)
|
||||||
|
ResetSequenceInfo( );
|
||||||
|
SetYawSpeed();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not available try to get default anim
|
||||||
|
ALERT ( at_console, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity );
|
||||||
|
pev->sequence = 0; // Set to the reset anim (if it's there)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Get Schedule!
|
||||||
|
//=========================================================
|
||||||
|
Schedule_t *CMHWGrunt :: GetSchedule( void )
|
||||||
|
{
|
||||||
|
// clear old sentence
|
||||||
|
m_iSentence = -1; // we don't care about sounds for now.
|
||||||
|
|
||||||
|
// flying? If PRONE, barnacle has me. IF not, it's assumed I am rapelling.
|
||||||
|
if ( pev->movetype == MOVETYPE_FLY && m_MonsterState != MONSTERSTATE_PRONE )
|
||||||
|
{
|
||||||
|
if (pev->flags & FL_ONGROUND)
|
||||||
|
{
|
||||||
|
// just landed
|
||||||
|
pev->movetype = MOVETYPE_STEP;
|
||||||
|
return GetScheduleOfType ( SCHED_HWGRUNT_REPEL_LAND );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// can not attack while holding a minigun in rapel
|
||||||
|
return GetScheduleOfType ( SCHED_HWGRUNT_REPEL );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( m_MonsterState )
|
||||||
|
{
|
||||||
|
case MONSTERSTATE_COMBAT:
|
||||||
|
{
|
||||||
|
// dead enemy
|
||||||
|
if ( HasConditions( bits_COND_ENEMY_DEAD ) )
|
||||||
|
{
|
||||||
|
// was attacking, spin down
|
||||||
|
if ( HasMemory( bits_MEMORY_HWGRUNT_SPINUP ) )
|
||||||
|
{
|
||||||
|
Forget( bits_MEMORY_HWGRUNT_SPINUP );
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_ITEM, "hassault/hw_spindown.wav", 0.8, ATTN_NORM);
|
||||||
|
}
|
||||||
|
|
||||||
|
// call base class, all code to handle dead enemies is centralized there.
|
||||||
|
return CMBaseMonster :: GetSchedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
// new enemy
|
||||||
|
if ( HasConditions(bits_COND_NEW_ENEMY) )
|
||||||
|
{
|
||||||
|
// none of this should take place as CSquadMonster functions were completely stripped. -Giegue
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
{
|
||||||
|
//!!!KELLY - the leader of a squad of grunts has just seen the player or a
|
||||||
|
// monster and has made it the squad's enemy. You
|
||||||
|
// can check pev->flags for FL_CLIENT to determine whether this is the player
|
||||||
|
// or a monster. He's going to immediately start
|
||||||
|
// firing, though. If you'd like, we can make an alternate "first sight"
|
||||||
|
// schedule where the leader plays a handsign anim
|
||||||
|
// that gives us enough time to hear a short sentence or spoken command
|
||||||
|
// before he starts pluggin away.
|
||||||
|
if (FOkToSpeak())// && RANDOM_LONG(0,1))
|
||||||
|
{
|
||||||
|
if ((m_hEnemy != NULL) && UTIL_IsPlayer(m_hEnemy))
|
||||||
|
// player
|
||||||
|
SENTENCEG_PlayRndSz( ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
|
||||||
|
|
||||||
|
else if ((m_hEnemy != NULL) &&
|
||||||
|
(m_hEnemy->Classify() != CLASS_PLAYER_ALLY) &&
|
||||||
|
(m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE) &&
|
||||||
|
(m_hEnemy->Classify() != CLASS_MACHINE))
|
||||||
|
// monster
|
||||||
|
SENTENCEG_PlayRndSz( ENT(pev), "HG_MONST", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
|
||||||
|
|
||||||
|
JustSpoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
|
||||||
|
{
|
||||||
|
return GetScheduleOfType ( SCHED_GRUNT_SUPPRESS );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GetScheduleOfType ( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// damaged just a little
|
||||||
|
else if ( HasConditions( bits_COND_LIGHT_DAMAGE ) )
|
||||||
|
{
|
||||||
|
// we don't want the monster to take cover when hurt while attacking, clear this
|
||||||
|
ClearConditions( bits_COND_LIGHT_DAMAGE );
|
||||||
|
}
|
||||||
|
// can shoot
|
||||||
|
else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
|
||||||
|
{
|
||||||
|
// can fire? shoot. destroy without a care
|
||||||
|
return GetScheduleOfType( SCHED_RANGE_ATTACK1 );
|
||||||
|
}
|
||||||
|
// can't see enemy
|
||||||
|
else if ( HasConditions( bits_COND_ENEMY_OCCLUDED ) )
|
||||||
|
{
|
||||||
|
// do sound
|
||||||
|
if ( HasMemory( bits_MEMORY_HWGRUNT_SPINUP ) )
|
||||||
|
{
|
||||||
|
Forget( bits_MEMORY_HWGRUNT_SPINUP );
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_ITEM, "hassault/hw_spindown.wav", 0.8, ATTN_NORM);
|
||||||
|
}
|
||||||
|
|
||||||
|
// then go kamikaze and chase the enemy
|
||||||
|
return GetScheduleOfType( SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( HasConditions( bits_COND_SEE_ENEMY ) && !HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
|
||||||
|
{
|
||||||
|
return GetScheduleOfType( SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no special cases here, call the base class
|
||||||
|
return CMBaseMonster :: GetSchedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
//=========================================================
|
||||||
|
Schedule_t* CMHWGrunt :: GetScheduleOfType ( int Type )
|
||||||
|
{
|
||||||
|
switch ( Type )
|
||||||
|
{
|
||||||
|
case SCHED_TAKE_COVER_FROM_ENEMY:
|
||||||
|
{
|
||||||
|
return &slHWGruntTakeCover[ 0 ];
|
||||||
|
}
|
||||||
|
case SCHED_HWGRUNT_TAKECOVER_FAILED:
|
||||||
|
{
|
||||||
|
if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) )
|
||||||
|
{
|
||||||
|
return GetScheduleOfType( SCHED_RANGE_ATTACK1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetScheduleOfType ( SCHED_FAIL );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SCHED_HWGRUNT_ELOF_FAIL:
|
||||||
|
{
|
||||||
|
// unable to move to a position that allows attacking the enemy.
|
||||||
|
return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE:
|
||||||
|
{
|
||||||
|
return &slHWGruntEstablishLineOfFire[ 0 ];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SCHED_RANGE_ATTACK1:
|
||||||
|
{
|
||||||
|
// minigun should spin up first
|
||||||
|
if ( !HasMemory( bits_MEMORY_HWGRUNT_SPINUP ) )
|
||||||
|
{
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "hassault/hw_spinup.wav", 0.8, ATTN_NORM);
|
||||||
|
return &slHWGruntMinigunSpinUp[ 0 ];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return &slHWGruntMinigunAttack[ 0 ];
|
||||||
|
}
|
||||||
|
case SCHED_HWGRUNT_WAIT_FACE_ENEMY:
|
||||||
|
{
|
||||||
|
return &slHWGruntWaitInCover[ 0 ];
|
||||||
|
}
|
||||||
|
case SCHED_VICTORY_DANCE:
|
||||||
|
{
|
||||||
|
return &slHWGruntVictoryDance[ 0 ];
|
||||||
|
}
|
||||||
|
case SCHED_FAIL:
|
||||||
|
{
|
||||||
|
if ( m_hEnemy != NULL )
|
||||||
|
{
|
||||||
|
// has an enemy, so pick a different default fail schedule most likely to help recover.
|
||||||
|
return &slHWGruntCombatFail[ 0 ];
|
||||||
|
}
|
||||||
|
|
||||||
|
return &slHWGruntFail[ 0 ];
|
||||||
|
}
|
||||||
|
case SCHED_HWGRUNT_REPEL:
|
||||||
|
{
|
||||||
|
if (pev->velocity.z > -128)
|
||||||
|
pev->velocity.z -= 32;
|
||||||
|
return &slHWGruntRepel[ 0 ];
|
||||||
|
}
|
||||||
|
case SCHED_HWGRUNT_REPEL_LAND:
|
||||||
|
{
|
||||||
|
return &slHWGruntRepelLand[ 0 ];
|
||||||
|
}
|
||||||
|
case SCHED_CHASE_ENEMY_FAILED:
|
||||||
|
{
|
||||||
|
// add missing schedule from squadmonster.cpp
|
||||||
|
return &slHWGruntChaseEnemyFailed[ 0 ];
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return CMBaseMonster :: GetScheduleOfType ( Type );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -168,6 +168,12 @@ void CMISlave::Killed( entvars_t *pevAttacker, int iGib )
|
|||||||
CMBaseMonster::Killed( pevAttacker, iGib );
|
CMBaseMonster::Killed( pevAttacker, iGib );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMISlave::UpdateOnRemove()
|
||||||
|
{
|
||||||
|
CMBaseMonster::UpdateOnRemove();
|
||||||
|
ClearBeams();
|
||||||
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
// SetYawSpeed - allows each sequence to have a different
|
// SetYawSpeed - allows each sequence to have a different
|
||||||
// turn rate associated with it.
|
// turn rate associated with it.
|
||||||
@@ -416,14 +422,14 @@ void CMISlave :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/islave.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/islave.mdl"));
|
||||||
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
pev->movetype = MOVETYPE_STEP;
|
pev->movetype = MOVETYPE_STEP;
|
||||||
m_bloodColor = BLOOD_COLOR_GREEN;
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
|
||||||
pev->effects = 0;
|
pev->effects = 0;
|
||||||
pev->health = gSkillData.slaveHealth;
|
if (!pev->health) { pev->health = gSkillData.slaveHealth; }
|
||||||
pev->view_ofs = Vector ( 0, 0, 64 );// position of the eyes relative to monster's origin.
|
pev->view_ofs = Vector ( 0, 0, 64 );// position of the eyes relative to monster's origin.
|
||||||
m_flFieldOfView = 0.5;
|
m_flFieldOfView = 0.5;
|
||||||
m_MonsterState = MONSTERSTATE_NONE;
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
@@ -451,8 +457,6 @@ void CMISlave :: Spawn()
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
void CMISlave :: Precache()
|
void CMISlave :: Precache()
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
PRECACHE_MODEL("models/islave.mdl");
|
PRECACHE_MODEL("models/islave.mdl");
|
||||||
PRECACHE_MODEL("sprites/lgtning.spr");
|
PRECACHE_MODEL("sprites/lgtning.spr");
|
||||||
PRECACHE_SOUND("debris/zap1.wav");
|
PRECACHE_SOUND("debris/zap1.wav");
|
||||||
@@ -463,17 +467,10 @@ void CMISlave :: Precache()
|
|||||||
PRECACHE_SOUND("headcrab/hc_headbite.wav");
|
PRECACHE_SOUND("headcrab/hc_headbite.wav");
|
||||||
PRECACHE_SOUND("weapons/cbar_miss1.wav");
|
PRECACHE_SOUND("weapons/cbar_miss1.wav");
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
|
PRECACHE_SOUND_ARRAY(pAttackHitSounds);
|
||||||
PRECACHE_SOUND((char *)pAttackHitSounds[i]);
|
PRECACHE_SOUND_ARRAY(pAttackMissSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pPainSounds);
|
||||||
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
|
PRECACHE_SOUND_ARRAY(pDeathSounds);
|
||||||
PRECACHE_SOUND((char *)pAttackMissSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pPainSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pDeathSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pDeathSounds[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -737,6 +734,8 @@ void CMISlave :: ZapBeam( int side )
|
|||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
|
||||||
pMonster->TraceAttack( pev, gSkillData.slaveDmgZap, vecAim, &tr, DMG_SHOCK );
|
pMonster->TraceAttack( pev, gSkillData.slaveDmgZap, vecAim, &tr, DMG_SHOCK );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
UTIL_TraceAttack( pEntity, pev, gSkillData.slaveDmgZap, vecAim, &tr, DMG_SHOCK );
|
||||||
}
|
}
|
||||||
|
|
||||||
UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) );
|
UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) );
|
||||||
|
|||||||
442
src/dlls/massn.cpp
Normal file
442
src/dlls/massn.cpp
Normal file
@@ -0,0 +1,442 @@
|
|||||||
|
// HUGE thanks to DrBeef for his hlsdk-xash3d-opfor repository!
|
||||||
|
|
||||||
|
/***
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* This product contains software technology licensed from Id
|
||||||
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This source code contains proprietary and confidential information of
|
||||||
|
* Valve LLC and its suppliers. Access to this code is restricted to
|
||||||
|
* persons who have executed a written SDK license with Valve. Any access,
|
||||||
|
* use or distribution of this code by or to any unlicensed person is illegal.
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
//=========================================================
|
||||||
|
// Black Ops - Male Assassin
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "plane.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
#include "monsters.h"
|
||||||
|
#include "schedule.h"
|
||||||
|
#include "animation.h"
|
||||||
|
#include "weapons.h"
|
||||||
|
#include "cmtalkmonster.h"
|
||||||
|
#include "effects.h"
|
||||||
|
#include "customentity.h"
|
||||||
|
|
||||||
|
extern cvar_t *monster_default_maxrange;
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// monster-specific DEFINE's
|
||||||
|
//=========================================================
|
||||||
|
#define MASSN_CLIP_SIZE 36 // how many bullets in a clip? - NOTE: 3 round burst sound, so keep as 3 * x!
|
||||||
|
|
||||||
|
// Weapon flags
|
||||||
|
#define MASSN_9MMAR (1 << 0)
|
||||||
|
#define MASSN_HANDGRENADE (1 << 1)
|
||||||
|
#define MASSN_GRENADELAUNCHER (1 << 2)
|
||||||
|
#define MASSN_SNIPERRIFLE (1 << 3)
|
||||||
|
|
||||||
|
// Body groups.
|
||||||
|
#define HEAD_GROUP 1
|
||||||
|
#define GUN_GROUP 2
|
||||||
|
|
||||||
|
// Head values
|
||||||
|
#define HEAD_WHITE 0
|
||||||
|
#define HEAD_BLACK 1
|
||||||
|
#define HEAD_GOGGLES 2
|
||||||
|
|
||||||
|
// Gun values
|
||||||
|
#define GUN_MP5 0
|
||||||
|
#define GUN_SNIPERRIFLE 1
|
||||||
|
#define GUN_NONE 2
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Monster's Anim Events Go Here
|
||||||
|
//=========================================================
|
||||||
|
#define MASSN_AE_KICK ( 3 )
|
||||||
|
#define MASSN_AE_BURST1 ( 4 )
|
||||||
|
#define MASSN_AE_BURST2 ( 5 )
|
||||||
|
#define MASSN_AE_BURST3 ( 6 )
|
||||||
|
#define MASSN_AE_CAUGHT_ENEMY ( 10 ) // grunt established sight with an enemy (player only) that had previously eluded the squad.
|
||||||
|
#define MASSN_AE_DROP_GUN ( 11 ) // grunt (probably dead) is dropping his mp5.
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Override a few behaviours to make this grunt silent
|
||||||
|
//=========================================================
|
||||||
|
BOOL CMMassn::FOkToSpeak(void)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMMassn::IdleSound(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMMassn::PainSound(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMMassn::DeathSound(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Classify - indicates this monster's place in the
|
||||||
|
// relationship table.
|
||||||
|
//=========================================================
|
||||||
|
int CMMassn::Classify(void)
|
||||||
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
|
return CLASS_HUMAN_MILITARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Shoot
|
||||||
|
//=========================================================
|
||||||
|
void CMMassn::Sniperrifle(void)
|
||||||
|
{
|
||||||
|
if (m_hEnemy == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector vecShootOrigin = GetGunPosition();
|
||||||
|
Vector vecShootDir = ShootAtEnemy(vecShootOrigin);
|
||||||
|
|
||||||
|
UTIL_MakeVectors(pev->angles);
|
||||||
|
|
||||||
|
Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40, 90) + gpGlobals->v_up * RANDOM_FLOAT(75, 200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40);
|
||||||
|
EjectBrass(vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iBrassShell, TE_BOUNCE_SHELL);
|
||||||
|
FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_1DEGREES, 2048, BULLET_MONSTER_762, 0); // shoot +-7.5 degrees
|
||||||
|
|
||||||
|
pev->effects |= EF_MUZZLEFLASH;
|
||||||
|
|
||||||
|
m_cAmmoLoaded--;// take away a bullet!
|
||||||
|
|
||||||
|
Vector angDir = UTIL_VecToAngles(vecShootDir);
|
||||||
|
SetBlending(0, angDir.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// HandleAnimEvent - catches the monster-specific messages
|
||||||
|
// that occur when tagged animation frames are played.
|
||||||
|
//=========================================================
|
||||||
|
void CMMassn::HandleAnimEvent(MonsterEvent_t *pEvent)
|
||||||
|
{
|
||||||
|
Vector vecShootDir;
|
||||||
|
Vector vecShootOrigin;
|
||||||
|
|
||||||
|
switch (pEvent->event)
|
||||||
|
{
|
||||||
|
case MASSN_AE_DROP_GUN:
|
||||||
|
{
|
||||||
|
Vector vecGunPos;
|
||||||
|
Vector vecGunAngles;
|
||||||
|
|
||||||
|
GetAttachment(0, vecGunPos, vecGunAngles);
|
||||||
|
|
||||||
|
// switch to body group with no gun.
|
||||||
|
SetBodygroup(GUN_GROUP, GUN_NONE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case MASSN_AE_BURST1:
|
||||||
|
{
|
||||||
|
if (FBitSet(pev->weapons, MASSN_9MMAR))
|
||||||
|
{
|
||||||
|
Shoot();
|
||||||
|
|
||||||
|
// the first round of the three round burst plays the sound and puts a sound in the world sound list.
|
||||||
|
if (RANDOM_LONG(0, 1))
|
||||||
|
{
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "hgrunt/gr_mgun1.wav", 1, ATTN_NORM);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "hgrunt/gr_mgun2.wav", 1, ATTN_NORM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (FBitSet(pev->weapons, MASSN_SNIPERRIFLE))
|
||||||
|
{
|
||||||
|
Sniperrifle();
|
||||||
|
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/sniper_fire.wav", 1, ATTN_NORM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MASSN_AE_BURST2:
|
||||||
|
case MASSN_AE_BURST3:
|
||||||
|
Shoot();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MASSN_AE_KICK:
|
||||||
|
{
|
||||||
|
edict_t *pHurt = Kick();
|
||||||
|
|
||||||
|
if (pHurt)
|
||||||
|
{
|
||||||
|
// SOUND HERE!
|
||||||
|
UTIL_MakeVectors(pev->angles);
|
||||||
|
pHurt->v.punchangle.x = 15;
|
||||||
|
pHurt->v.velocity = pHurt->v.velocity + gpGlobals->v_forward * 100 + gpGlobals->v_up * 50;
|
||||||
|
if (UTIL_IsPlayer(pHurt))
|
||||||
|
UTIL_TakeDamage( pHurt, pev, pev, gSkillData.massnDmgKick, DMG_CLUB );
|
||||||
|
else if (pHurt->v.euser4 != NULL)
|
||||||
|
{
|
||||||
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pHurt));
|
||||||
|
pMonster->TakeDamage( pev, pev, gSkillData.massnDmgKick, DMG_CLUB );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
UTIL_TakeDamageExternal( pHurt, pev, pev, gSkillData.massnDmgKick, DMG_CLUB );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MASSN_AE_CAUGHT_ENEMY:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CMHGrunt::HandleAnimEvent(pEvent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Spawn
|
||||||
|
//=========================================================
|
||||||
|
void CMMassn::Spawn()
|
||||||
|
{
|
||||||
|
Precache();
|
||||||
|
|
||||||
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/massn.mdl"));
|
||||||
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
pev->movetype = MOVETYPE_STEP;
|
||||||
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
|
||||||
|
pev->effects = 0;
|
||||||
|
if (!pev->health) { pev->health = gSkillData.massnHealth; }
|
||||||
|
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
|
m_flNextGrenadeCheck = gpGlobals->time + 1;
|
||||||
|
m_flNextPainTime = gpGlobals->time;
|
||||||
|
m_iSentence = -1;
|
||||||
|
|
||||||
|
//m_afCapability = bits_CAP_SQUAD | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
|
||||||
|
m_afCapability = bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
|
||||||
|
|
||||||
|
//m_fEnemyEluded = FALSE;
|
||||||
|
m_fFirstEncounter = TRUE;// this is true when the grunt spawns, because he hasn't encountered an enemy yet.
|
||||||
|
|
||||||
|
m_HackedGunPos = Vector(0, 0, 55);
|
||||||
|
|
||||||
|
if (pev->weapons == 0)
|
||||||
|
{
|
||||||
|
// weapons not specified, randomize
|
||||||
|
switch ( RANDOM_LONG( 0, 2 ) )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
pev->weapons = MASSN_9MMAR | MASSN_HANDGRENADE;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
pev->weapons = MASSN_9MMAR | MASSN_GRENADELAUNCHER;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pev->weapons = MASSN_SNIPERRIFLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FBitSet(pev->weapons, MASSN_SNIPERRIFLE))
|
||||||
|
{
|
||||||
|
SetBodygroup(GUN_GROUP, GUN_SNIPERRIFLE);
|
||||||
|
m_cClipSize = 5;
|
||||||
|
|
||||||
|
// if no attack range set, set 2x default
|
||||||
|
if (!m_flDistLook)
|
||||||
|
m_flDistLook = monster_default_maxrange->value * 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_cClipSize = MASSN_CLIP_SIZE;
|
||||||
|
}
|
||||||
|
m_cAmmoLoaded = m_cClipSize;
|
||||||
|
|
||||||
|
if (RANDOM_LONG(0, 99) < 80)
|
||||||
|
pev->skin = 0; // light skin
|
||||||
|
else
|
||||||
|
pev->skin = 1; // dark skin
|
||||||
|
|
||||||
|
CMTalkMonster::g_talkWaitTime = 0;
|
||||||
|
|
||||||
|
MonsterInit();
|
||||||
|
if (FBitSet(pev->weapons, MASSN_SNIPERRIFLE))
|
||||||
|
{
|
||||||
|
// override for snipers
|
||||||
|
m_flDistTooFar = m_flDistLook / 1.33;
|
||||||
|
}
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_male_assassin" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Male Assassin" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Precache - precaches all resources this monster needs
|
||||||
|
//=========================================================
|
||||||
|
void CMMassn::Precache()
|
||||||
|
{
|
||||||
|
PRECACHE_MODEL("models/massn.mdl");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("hgrunt/gr_mgun1.wav");
|
||||||
|
PRECACHE_SOUND("hgrunt/gr_mgun2.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("hgrunt/gr_reload1.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("weapons/glauncher.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("weapons/sniper_bolt1.wav");
|
||||||
|
PRECACHE_SOUND("weapons/sniper_fire.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event
|
||||||
|
|
||||||
|
// get voice pitch
|
||||||
|
if (RANDOM_LONG(0, 1))
|
||||||
|
m_voicePitch = 109 + RANDOM_LONG(0, 7);
|
||||||
|
else
|
||||||
|
m_voicePitch = 100;
|
||||||
|
|
||||||
|
m_iBrassShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Chase enemy failure schedule
|
||||||
|
//=========================================================
|
||||||
|
Task_t tlMassnSniperAttack[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, (float)0 },
|
||||||
|
{ TASK_SET_ACTIVITY, (float)ACT_IDLE_ANGRY },
|
||||||
|
{ TASK_WAIT_FACE_ENEMY , (float)1 },
|
||||||
|
{ TASK_SET_ACTIVITY, (float)ACT_RANGE_ATTACK1 },
|
||||||
|
{ TASK_WAIT_FACE_ENEMY, (float)1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slMassnSniperAttack[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlMassnSniperAttack,
|
||||||
|
ARRAYSIZE ( tlMassnSniperAttack ),
|
||||||
|
bits_COND_HEAR_SOUND,
|
||||||
|
0,
|
||||||
|
"MassnSniperAttack"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFINE_CUSTOM_SCHEDULES( CMMassn )
|
||||||
|
{
|
||||||
|
slMassnSniperAttack,
|
||||||
|
};
|
||||||
|
|
||||||
|
IMPLEMENT_CUSTOM_SCHEDULES( CMMassn, CMHGrunt );
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// SetActivity
|
||||||
|
//=========================================================
|
||||||
|
void CMMassn :: SetActivity ( Activity NewActivity )
|
||||||
|
{
|
||||||
|
int iSequence = ACTIVITY_NOT_AVAILABLE;
|
||||||
|
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||||
|
|
||||||
|
switch ( NewActivity )
|
||||||
|
{
|
||||||
|
case ACT_RANGE_ATTACK1:
|
||||||
|
// shooting standing or shooting crouched
|
||||||
|
if (FBitSet( pev->weapons, MASSN_SNIPERRIFLE))
|
||||||
|
{
|
||||||
|
// Always standing
|
||||||
|
iSequence = LookupSequence( "standing_m40a1" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( m_fStanding )
|
||||||
|
{
|
||||||
|
// get aimable sequence
|
||||||
|
iSequence = LookupSequence( "standing_mp5" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// get crouching shoot
|
||||||
|
iSequence = LookupSequence( "crouching_mp5" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
CMHGrunt::SetActivity(NewActivity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present
|
||||||
|
|
||||||
|
// Set to the desired anim, or default anim if the desired is not present
|
||||||
|
if ( iSequence > ACTIVITY_NOT_AVAILABLE )
|
||||||
|
{
|
||||||
|
if ( pev->sequence != iSequence || !m_fSequenceLoops )
|
||||||
|
{
|
||||||
|
pev->frame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pev->sequence = iSequence; // Set to the reset anim (if it's there)
|
||||||
|
ResetSequenceInfo( );
|
||||||
|
SetYawSpeed();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not available try to get default anim
|
||||||
|
ALERT ( at_console, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity );
|
||||||
|
pev->sequence = 0; // Set to the reset anim (if it's there)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// GetScheduleOfType - Override schedule for sniper attack
|
||||||
|
//=========================================================
|
||||||
|
Schedule_t* CMMassn :: GetScheduleOfType ( int Type )
|
||||||
|
{
|
||||||
|
switch ( Type )
|
||||||
|
{
|
||||||
|
case SCHED_RANGE_ATTACK1:
|
||||||
|
{
|
||||||
|
if (FBitSet(pev->weapons, MASSN_SNIPERRIFLE))
|
||||||
|
{
|
||||||
|
// sniper attack is always standing
|
||||||
|
m_fStanding = TRUE;
|
||||||
|
return &slMassnSniperAttack[ 0 ];
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMHGrunt :: GetScheduleOfType ( Type );
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return CMHGrunt :: GetScheduleOfType ( Type );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,7 +48,7 @@ static META_FUNCTIONS gMetaFunctionTable =
|
|||||||
GetEntityAPI2_Post, // pfnGetEntityAPI2_Post META; called after game DLL
|
GetEntityAPI2_Post, // pfnGetEntityAPI2_Post META; called after game DLL
|
||||||
NULL, // pfnGetNewDLLFunctions HL SDK2; called before game DLL
|
NULL, // pfnGetNewDLLFunctions HL SDK2; called before game DLL
|
||||||
NULL, // pfnGetNewDLLFunctions_Post META; called after game DLL
|
NULL, // pfnGetNewDLLFunctions_Post META; called after game DLL
|
||||||
GetEngineFunctions, // pfnGetEngineFunctions META; called before HL engine
|
NULL, // pfnGetEngineFunctions META; called before HL engine
|
||||||
GetEngineFunctions_Post, // pfnGetEngineFunctions_Post META; called after HL engine
|
GetEngineFunctions_Post, // pfnGetEngineFunctions_Post META; called after HL engine
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -56,8 +56,8 @@ static META_FUNCTIONS gMetaFunctionTable =
|
|||||||
plugin_info_t Plugin_info = {
|
plugin_info_t Plugin_info = {
|
||||||
META_INTERFACE_VERSION, // interface version
|
META_INTERFACE_VERSION, // interface version
|
||||||
"MonsterMod", // name
|
"MonsterMod", // name
|
||||||
"2.0", // version
|
"4.0", // version
|
||||||
"03/06/2020", // date in DD/MM/YYYY format
|
"14/07/2023", // date in DD/MM/YYYY format
|
||||||
"botman, Rick90, Giegue", // original authors + recreation by...
|
"botman, Rick90, Giegue", // original authors + recreation by...
|
||||||
"https://github.com/JulianR0/monstermod-redo", // url
|
"https://github.com/JulianR0/monstermod-redo", // url
|
||||||
"MONSTER", // logtag
|
"MONSTER", // logtag
|
||||||
@@ -87,6 +87,16 @@ cvar_t init_monster_show_deaths = {"monster_show_deaths", "1", FCVAR_EXTDLL, 0,
|
|||||||
cvar_t *monster_show_deaths = NULL;
|
cvar_t *monster_show_deaths = NULL;
|
||||||
cvar_t init_monster_show_info = {"monster_show_info", "1", FCVAR_EXTDLL, 0, NULL};
|
cvar_t init_monster_show_info = {"monster_show_info", "1", FCVAR_EXTDLL, 0, NULL};
|
||||||
cvar_t *monster_show_info = NULL;
|
cvar_t *monster_show_info = NULL;
|
||||||
|
cvar_t init_monster_turn_coeficient = {"monster_turn_coeficient", "1.75", FCVAR_EXTDLL, 0, NULL};
|
||||||
|
cvar_t *monster_turn_coeficient = NULL;
|
||||||
|
cvar_t init_monster_entity_config = {"monster_entity_config", "1", FCVAR_EXTDLL, 0, NULL};
|
||||||
|
cvar_t *monster_entity_config = NULL;
|
||||||
|
cvar_t init_globalmodellist = {"monster_gmr", "", FCVAR_EXTDLL, 0, NULL};
|
||||||
|
cvar_t *globalmodellist = NULL;
|
||||||
|
cvar_t init_globalsoundlist = {"monster_gsr", "", FCVAR_EXTDLL, 0, NULL};
|
||||||
|
cvar_t *globalsoundlist = NULL;
|
||||||
|
cvar_t init_monster_default_maxrange = {"monster_default_maxrange", "2048", FCVAR_EXTDLL, 0, NULL};
|
||||||
|
cvar_t *monster_default_maxrange = NULL;
|
||||||
|
|
||||||
|
|
||||||
// Metamod requesting info about this plugin:
|
// Metamod requesting info about this plugin:
|
||||||
@@ -146,6 +156,20 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m
|
|||||||
CVAR_REGISTER(&init_monster_show_info);
|
CVAR_REGISTER(&init_monster_show_info);
|
||||||
monster_show_info = CVAR_GET_POINTER("monster_show_info");
|
monster_show_info = CVAR_GET_POINTER("monster_show_info");
|
||||||
|
|
||||||
|
CVAR_REGISTER(&init_monster_turn_coeficient);
|
||||||
|
monster_turn_coeficient = CVAR_GET_POINTER("monster_turn_coeficient");
|
||||||
|
|
||||||
|
CVAR_REGISTER(&init_monster_entity_config);
|
||||||
|
monster_entity_config = CVAR_GET_POINTER("monster_entity_config");
|
||||||
|
|
||||||
|
CVAR_REGISTER(&init_globalmodellist);
|
||||||
|
globalmodellist = CVAR_GET_POINTER("monster_gmr");
|
||||||
|
CVAR_REGISTER(&init_globalsoundlist);
|
||||||
|
globalsoundlist = CVAR_GET_POINTER("monster_gsr");
|
||||||
|
|
||||||
|
CVAR_REGISTER(&init_monster_default_maxrange);
|
||||||
|
monster_default_maxrange = CVAR_GET_POINTER("monster_default_maxrange");
|
||||||
|
|
||||||
return(TRUE);
|
return(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,14 @@
|
|||||||
#include "meta_api.h"
|
#include "meta_api.h"
|
||||||
|
|
||||||
#include "monster_plugin.h"
|
#include "monster_plugin.h"
|
||||||
|
#include "ripent.h"
|
||||||
|
#include "globalreplace.h"
|
||||||
|
|
||||||
extern cvar_t *dllapi_log;
|
extern cvar_t *dllapi_log;
|
||||||
|
extern cvar_t *monster_entity_config;
|
||||||
|
|
||||||
|
extern cvar_t *globalmodellist;
|
||||||
|
extern cvar_t *globalsoundlist;
|
||||||
|
|
||||||
extern monster_type_t monster_types[];
|
extern monster_type_t monster_types[];
|
||||||
extern int monster_spawn_count;
|
extern int monster_spawn_count;
|
||||||
@@ -62,6 +68,83 @@ bool get_input(FILE *fp, char *input)
|
|||||||
return FALSE; // no input found
|
return FALSE; // no input found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void scan_monster_sound(FILE *fp, edict_t *pMonster )
|
||||||
|
{
|
||||||
|
char input[1024];
|
||||||
|
|
||||||
|
while (get_input(fp, input))
|
||||||
|
{
|
||||||
|
// might slip through
|
||||||
|
if (strlen(input) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char *source = strtok(input, " \t");
|
||||||
|
char *destination = strtok(NULL, " \t");
|
||||||
|
|
||||||
|
// Remove all quotes
|
||||||
|
char parse[128] = {0};
|
||||||
|
int skip;
|
||||||
|
|
||||||
|
// source
|
||||||
|
skip = 0;
|
||||||
|
for (unsigned i = 0; i < strlen(source); i++)
|
||||||
|
{
|
||||||
|
if (source[i] == '"')
|
||||||
|
{
|
||||||
|
skip++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
parse[i-skip] = source[i];
|
||||||
|
}
|
||||||
|
parse[strlen(parse)] = '\0';
|
||||||
|
strcpy(source, parse);
|
||||||
|
|
||||||
|
// destination
|
||||||
|
memset(parse, 0, sizeof(parse));
|
||||||
|
skip = 0;
|
||||||
|
for (unsigned i = 0; i < strlen(destination); i++)
|
||||||
|
{
|
||||||
|
if (destination[i] == '"')
|
||||||
|
{
|
||||||
|
skip++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
parse[i-skip] = destination[i];
|
||||||
|
}
|
||||||
|
parse[strlen(parse)] = '\0';
|
||||||
|
strcpy(destination, parse);
|
||||||
|
|
||||||
|
if ( pMonster )
|
||||||
|
REPLACER::AddIndividualSound( pMonster, source, destination );
|
||||||
|
else
|
||||||
|
PRECACHE_SOUND2(destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_monster_sound(edict_t *pMonster, char *fileName)
|
||||||
|
{
|
||||||
|
char game_dir[256];
|
||||||
|
FILE *fp = NULL;
|
||||||
|
|
||||||
|
// find the directory name of the currently running MOD...
|
||||||
|
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
||||||
|
|
||||||
|
char srPath[192];
|
||||||
|
|
||||||
|
// SC soundlist path starts from sound/MAPNAME
|
||||||
|
sprintf(srPath, "%s/sound/%s/%s", game_dir, STRING(gpGlobals->mapname), fileName);
|
||||||
|
if (access(srPath, 0) == 0)
|
||||||
|
{
|
||||||
|
if ((fp = fopen(srPath, "r")) != NULL)
|
||||||
|
{
|
||||||
|
scan_monster_sound(fp, pMonster);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void scan_monster_cfg(FILE *fp)
|
void scan_monster_cfg(FILE *fp)
|
||||||
{
|
{
|
||||||
// Let's make a full rework of this. -Giegue
|
// Let's make a full rework of this. -Giegue
|
||||||
@@ -94,7 +177,7 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
// Now that I think about it this looks slow and bad code >.>
|
// Now that I think about it this looks slow and bad code >.>
|
||||||
|
|
||||||
// A match is found. What is this?
|
// A match is found. What is this?
|
||||||
if (strncmp(monster_types[mIndex].name, "monster", 7) == 0)
|
if (strncmp(monster_types[mIndex].name, "monster_", 8) == 0)
|
||||||
{
|
{
|
||||||
// It's a monster, add it to the list
|
// It's a monster, add it to the list
|
||||||
if (monster_spawn_count == MAX_MONSTERS)
|
if (monster_spawn_count == MAX_MONSTERS)
|
||||||
@@ -110,6 +193,67 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
monster = TRUE;
|
monster = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcmp(monster_types[mIndex].name, "monstermaker") == 0 || strcmp(monster_types[mIndex].name, "squadmaker") == 0)
|
||||||
|
{
|
||||||
|
// A monster spawner, add it to the list
|
||||||
|
if (monster_spawn_count == MAX_MONSTERS)
|
||||||
|
{
|
||||||
|
// error.exe
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: can't add monstermaker, reached MAX_MONSTERS!");
|
||||||
|
badent = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
monster_spawnpoint[monster_spawn_count].monster = 32; // monstermaker index is fixed at 32
|
||||||
|
monster_types[32].need_to_precache = TRUE;
|
||||||
|
monster = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(monster_types[mIndex].name, "ambient_music") == 0)
|
||||||
|
{
|
||||||
|
// TODO - Extra entities should go towards a separate counter like nodes
|
||||||
|
if (monster_spawn_count == MAX_MONSTERS)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: can't add ambient_music, reached MAX_MONSTERS!");
|
||||||
|
badent = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
monster_spawnpoint[monster_spawn_count].monster = mIndex;
|
||||||
|
monster_types[mIndex].need_to_precache = TRUE;
|
||||||
|
monster = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(monster_types[mIndex].name, "trigger_setcvar") == 0)
|
||||||
|
{
|
||||||
|
if (monster_spawn_count == MAX_MONSTERS)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: can't add ambient_music, reached MAX_MONSTERS!");
|
||||||
|
badent = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
monster_spawnpoint[monster_spawn_count].monster = mIndex;
|
||||||
|
monster_types[mIndex].need_to_precache = TRUE;
|
||||||
|
monster = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(monster_types[mIndex].name, "env_xenmaker") == 0)
|
||||||
|
{
|
||||||
|
// A monster spawner, add it to the list
|
||||||
|
if (monster_spawn_count == MAX_MONSTERS)
|
||||||
|
{
|
||||||
|
// error.exe
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: can't add monstermaker, reached MAX_MONSTERS!");
|
||||||
|
badent = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
monster_spawnpoint[monster_spawn_count].monster = mIndex;
|
||||||
|
monster_types[mIndex].need_to_precache = TRUE;
|
||||||
|
monster = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (strcmp(monster_types[mIndex].name, "info_node") == 0)
|
else if (strcmp(monster_types[mIndex].name, "info_node") == 0)
|
||||||
{
|
{
|
||||||
// Normal node
|
// Normal node
|
||||||
@@ -142,7 +286,7 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
}
|
}
|
||||||
if (monster_types[mIndex].name[0] == 0)
|
if (monster_types[mIndex].name[0] == 0)
|
||||||
{
|
{
|
||||||
LOG_MESSAGE(PLID, "ERROR: unknown classname: %s", input); // print conflictive line
|
LOG_MESSAGE(PLID, "ERROR: unknown classname: %s", data[kvd_index-1].value); // print conflictive line
|
||||||
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!");
|
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!");
|
||||||
badent = TRUE;
|
badent = TRUE;
|
||||||
}
|
}
|
||||||
@@ -150,8 +294,8 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// What are you doing?!
|
// What are you doing?!
|
||||||
LOG_MESSAGE(PLID, "ERROR: BAD ENTITY STRUCTURE! Last line was %s", input); // print conflictive line
|
LOG_MESSAGE(PLID, "ERROR: BAD ENTITY STRUCTURE! Last line was %s", data[kvd_index-1].key); // print conflictive line
|
||||||
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!");
|
LOG_MESSAGE(PLID, "ERROR: classname MUST be the last entry of the entity!" );
|
||||||
badent = TRUE;
|
badent = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,23 +336,6 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
node_spawnpoint[node_spawn_count].origin[2] = z;
|
node_spawnpoint[node_spawn_count].origin[2] = z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strcmp(data[i].key, "delay") == 0)
|
|
||||||
{
|
|
||||||
// ToDo: Remove this keyvalue.
|
|
||||||
// Monsters spawned directly should not respawn.
|
|
||||||
if (monster)
|
|
||||||
{
|
|
||||||
if (sscanf(data[i].value, "%f", &x) != 1)
|
|
||||||
{
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: invalid delay: %s", input); // print conflictive line
|
|
||||||
|
|
||||||
// default to 30 seconds
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: entity respawn frequency will be set to 30 seconds");
|
|
||||||
x = 30;
|
|
||||||
}
|
|
||||||
monster_spawnpoint[monster_spawn_count].delay = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(data[i].key, "angles") == 0)
|
else if (strcmp(data[i].key, "angles") == 0)
|
||||||
{
|
{
|
||||||
if (monster)
|
if (monster)
|
||||||
@@ -241,6 +368,94 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
monster_spawnpoint[monster_spawn_count].spawnflags = x;
|
monster_spawnpoint[monster_spawn_count].spawnflags = x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcmp(data[i].key, "model") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// only applicable for normal monsters
|
||||||
|
if (strcmp(data[kvd_index-1].value, "monstermaker") != 0 && strcmp(data[kvd_index-1].value, "squadmaker") != 0)
|
||||||
|
{
|
||||||
|
// precache the custom model here
|
||||||
|
PRECACHE_MODEL( data[i].value );
|
||||||
|
|
||||||
|
// the entity will need the keyvalue
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(data[i].key, "soundlist") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// file handling, string must not be empty
|
||||||
|
if (strlen(data[i].value))
|
||||||
|
{
|
||||||
|
// process and precache the replacement sounds
|
||||||
|
process_monster_sound( NULL, data[i].value );
|
||||||
|
|
||||||
|
// the entity will need the keyvalue
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(data[i].key, "new_model") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// only applicable for monstermaker entity
|
||||||
|
if (strcmp(data[kvd_index-1].value, "monstermaker") == 0 || strcmp(data[kvd_index-1].value, "squadmaker") == 0)
|
||||||
|
{
|
||||||
|
// precache the custom model
|
||||||
|
PRECACHE_MODEL( data[i].value );
|
||||||
|
|
||||||
|
// the entity will need the keyvalue as well
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(data[i].key, "monstertype") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// this keyvalue is only valid for monstermaker entities
|
||||||
|
if (strcmp(data[kvd_index - 1].value, "monstermaker") == 0 || strcmp(data[kvd_index - 1].value, "squadmaker") == 0 || strcmp(data[kvd_index - 1].value, "env_xenmaker") == 0)
|
||||||
|
{
|
||||||
|
// process the entity precache here
|
||||||
|
int mIndex;
|
||||||
|
for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
|
||||||
|
{
|
||||||
|
if (strcmp(data[i].value, monster_types[mIndex].name) == 0)
|
||||||
|
{
|
||||||
|
monster_types[mIndex].need_to_precache = TRUE;
|
||||||
|
break; // only one monster at a time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pass the keyvalue to the entity
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(data[i].key, "message") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// only applicable for ambient_music
|
||||||
|
if (strcmp(data[kvd_index - 1].value, "ambient_music") == 0)
|
||||||
|
{
|
||||||
|
// precache the sound here
|
||||||
|
PRECACHE_GENERIC(data[i].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// common pev-field, an entity might need it
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We do not know this keyvalue, but an specific entity might use it.
|
// We do not know this keyvalue, but an specific entity might use it.
|
||||||
@@ -255,8 +470,7 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
|
|
||||||
if (monster)
|
if (monster)
|
||||||
{
|
{
|
||||||
// Init monster
|
// Spawn right away
|
||||||
monster_spawnpoint[monster_spawn_count].respawn_time = gpGlobals->time + 0.1; // spawn (nearly) right away
|
|
||||||
monster_spawnpoint[monster_spawn_count].need_to_respawn = TRUE;
|
monster_spawnpoint[monster_spawn_count].need_to_respawn = TRUE;
|
||||||
monster_spawn_count++;
|
monster_spawn_count++;
|
||||||
}
|
}
|
||||||
@@ -282,7 +496,7 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
// Bruteforce to remove quotes
|
// Bruteforce to remove quotes
|
||||||
char parse[66] = {0};
|
char parse[66] = {0};
|
||||||
int skip = 0;
|
int skip = 0;
|
||||||
for (int i = 0; i < strlen(input); i++)
|
for (unsigned i = 0; i < strlen(input); i++)
|
||||||
{
|
{
|
||||||
if (input[i] == '"')
|
if (input[i] == '"')
|
||||||
{
|
{
|
||||||
@@ -317,53 +531,564 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_monster_cfg(void)
|
void scan_monster_bsp(void)
|
||||||
|
{
|
||||||
|
// TODO: code duplication galore! optimize this for T5 milestone. -Giegue
|
||||||
|
epair_t *kv_pair;
|
||||||
|
pKVD data[MAX_KEYVALUES];
|
||||||
|
|
||||||
|
int kvd_index;
|
||||||
|
bool use_monstermod_explicit;
|
||||||
|
bool use_monstermod;
|
||||||
|
|
||||||
|
int classname_kvdI, mIndex;
|
||||||
|
float x, y, z;
|
||||||
|
bool badent, monster, node;
|
||||||
|
|
||||||
|
// go through all entities
|
||||||
|
for (int ent = 1; ent < num_entities; ent++)
|
||||||
|
{
|
||||||
|
kv_pair = entities[ent].epairs;
|
||||||
|
|
||||||
|
kvd_index = 0;
|
||||||
|
use_monstermod_explicit = false;
|
||||||
|
use_monstermod = true;
|
||||||
|
|
||||||
|
classname_kvdI = 0;
|
||||||
|
badent = monster = node = false;
|
||||||
|
|
||||||
|
// examine all keys
|
||||||
|
while (kv_pair != NULL)
|
||||||
|
{
|
||||||
|
// entities cannot be this big!
|
||||||
|
if (kvd_index >= MAX_KEYVALUES)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "WARNING: can't process entity #%i - too many keyvalues", ent);
|
||||||
|
use_monstermod = false;
|
||||||
|
use_monstermod_explicit = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(kv_pair->key, "classname") == 0)
|
||||||
|
{
|
||||||
|
// the entity we are trying to spawn could already exist within the game
|
||||||
|
// use the engine's CREATE_NAMED_ENTITY to see if it's valid or not
|
||||||
|
edict_t *existsGAME = CREATE_NAMED_ENTITY( MAKE_STRING( kv_pair->value ) );
|
||||||
|
if ( !FNullEnt( existsGAME ) )
|
||||||
|
{
|
||||||
|
// this entity already exists and we should ignore it
|
||||||
|
|
||||||
|
// use REMOVE_ENTITY instead of UTIL_Remove!
|
||||||
|
// UTIL_Remove sets FL_KILLME to remove the entity on the next frame, that won't do.
|
||||||
|
// REMOVE_ENTITY instead removes it instantly, which is needed to prevent server crashes
|
||||||
|
// due to "ED_Alloc: no free edicts" error.
|
||||||
|
|
||||||
|
REMOVE_ENTITY( existsGAME ); // get rid of the temporary entity
|
||||||
|
use_monstermod = false; // stick with game entity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(kv_pair->key, "use_monstermod") == 0)
|
||||||
|
{
|
||||||
|
if (atoi(kv_pair->value) == 1)
|
||||||
|
{
|
||||||
|
// The extra plugin must be available to handle the old entity!
|
||||||
|
if (CVAR_GET_FLOAT("_hl_explicit"))
|
||||||
|
{
|
||||||
|
// EXPLICITY requested to use monstermod for this entity
|
||||||
|
use_monstermod_explicit = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LOG_MESSAGE(PLID, "WARNING: can't explicity add entity #%i - add-on plugin unavailable", ent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(data[kvd_index].key, kv_pair->key);
|
||||||
|
strcpy(data[kvd_index].value, kv_pair->value);
|
||||||
|
|
||||||
|
kvd_index++;
|
||||||
|
kv_pair = kv_pair->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// spawn a monstermod entity?
|
||||||
|
if (use_monstermod_explicit || use_monstermod)
|
||||||
|
{
|
||||||
|
// find classname keyvalue
|
||||||
|
for (int i = 0; i < kvd_index; i++)
|
||||||
|
{
|
||||||
|
if (strcmp(data[i].key, "classname") == 0)
|
||||||
|
{
|
||||||
|
for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
|
||||||
|
{
|
||||||
|
if (strcmp(data[i].value, monster_types[mIndex].name) == 0)
|
||||||
|
{
|
||||||
|
// Match found, check if it's a node
|
||||||
|
if (strcmp(monster_types[mIndex].name, "info_node") == 0)
|
||||||
|
{
|
||||||
|
// Normal node
|
||||||
|
if (node_spawn_count == MAX_NODES)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: can't add node, reached MAX_NODES!");
|
||||||
|
badent = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
node = true;
|
||||||
|
}
|
||||||
|
else if (strcmp(monster_types[mIndex].name, "info_node_air") == 0)
|
||||||
|
{
|
||||||
|
// Aerial node
|
||||||
|
if (node_spawn_count == MAX_NODES)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: can't add node, reached MAX_NODES!");
|
||||||
|
badent = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node_spawnpoint[node_spawn_count].is_air_node = true;
|
||||||
|
node = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Assume it's a monster and add it to the list
|
||||||
|
// (Extra entities are built as CMBaseMonster)
|
||||||
|
if (monster_spawn_count == MAX_MONSTERS)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: can't add entity, reached MAX_MONSTERS!");
|
||||||
|
badent = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Aliases
|
||||||
|
if (strcmp(monster_types[mIndex].name, "squadmaker") == 0)
|
||||||
|
mIndex = 32; // monstermaker
|
||||||
|
|
||||||
|
monster_spawnpoint[monster_spawn_count].monster = mIndex;
|
||||||
|
monster_types[mIndex].need_to_precache = true;
|
||||||
|
monster = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
classname_kvdI = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (monster_types[mIndex].name[0] == 0)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "unknown classname: %s", data[i].value);
|
||||||
|
badent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!badent)
|
||||||
|
{
|
||||||
|
// Make room for entity-specific keyvalues.
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// Can I use malloc/calloc again or you are going to crash cuz you feel like it? >.>
|
||||||
|
monster_spawnpoint[monster_spawn_count].keyvalue = (pKVD*)calloc(MAX_KEYVALUES, sizeof(*monster_spawnpoint[monster_spawn_count].keyvalue));
|
||||||
|
}
|
||||||
|
|
||||||
|
// process entity keyvalues
|
||||||
|
for (int i = 0; i < kvd_index; i++)
|
||||||
|
{
|
||||||
|
// duplicates are overwritten
|
||||||
|
if (strcmp(data[i].key, "origin") == 0)
|
||||||
|
{
|
||||||
|
if (sscanf(data[i].value, "%f %f %f", &x, &y, &z) != 3)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: invalid origin: %s", data[i].value); // print conflictive line
|
||||||
|
|
||||||
|
// reset origin to g_vecZero
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: entity will spawn at 0 0 0");
|
||||||
|
x = y = z = 0;
|
||||||
|
}
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
monster_spawnpoint[monster_spawn_count].origin[0] = x;
|
||||||
|
monster_spawnpoint[monster_spawn_count].origin[1] = y;
|
||||||
|
monster_spawnpoint[monster_spawn_count].origin[2] = z;
|
||||||
|
}
|
||||||
|
else if (node)
|
||||||
|
{
|
||||||
|
node_spawnpoint[node_spawn_count].origin[0] = x;
|
||||||
|
node_spawnpoint[node_spawn_count].origin[1] = y;
|
||||||
|
node_spawnpoint[node_spawn_count].origin[2] = z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(data[i].key, "angles") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
if (sscanf(data[i].value, "%f %f %f", &x, &y, &z) != 3)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: invalid angles: %s", data[i].value); // print conflictive line
|
||||||
|
|
||||||
|
// reset angles to g_vecZero
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: entity angles will be set to 0 0 0");
|
||||||
|
x = y = z = 0;
|
||||||
|
}
|
||||||
|
monster_spawnpoint[monster_spawn_count].angles[0] = x;
|
||||||
|
monster_spawnpoint[monster_spawn_count].angles[1] = y;
|
||||||
|
monster_spawnpoint[monster_spawn_count].angles[2] = z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(data[i].key, "spawnflags") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
if (sscanf(data[i].value, "%f", &x) != 1)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: invalid spawnflags: %s", data[i].value); // print conflictive line
|
||||||
|
|
||||||
|
// default to no spawnflags
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: entity spawnflags will be set to none (0)");
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
monster_spawnpoint[monster_spawn_count].spawnflags = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(data[i].key, "model") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// only applicable for normal monsters
|
||||||
|
if (strcmp(data[classname_kvdI].value, "monstermaker") != 0 && strcmp(data[classname_kvdI].value, "squadmaker") != 0)
|
||||||
|
{
|
||||||
|
// precache the custom model here
|
||||||
|
PRECACHE_MODEL( data[i].value );
|
||||||
|
|
||||||
|
// the entity will need the keyvalue
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(data[i].key, "soundlist") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// file handling, string must not be empty
|
||||||
|
if (strlen(data[i].value))
|
||||||
|
{
|
||||||
|
// process and precache the replacement sounds
|
||||||
|
process_monster_sound( NULL, data[i].value );
|
||||||
|
|
||||||
|
// the entity will need the keyvalue
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(data[i].key, "new_model") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// only applicable for monstermaker entity
|
||||||
|
if (strcmp(data[classname_kvdI].value, "monstermaker") == 0 || strcmp(data[classname_kvdI].value, "squadmaker") == 0)
|
||||||
|
{
|
||||||
|
// precache the custom model
|
||||||
|
PRECACHE_MODEL( data[i].value );
|
||||||
|
|
||||||
|
// the entity will need the keyvalue as well
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(data[i].key, "monstertype") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// this keyvalue is only valid for monstermaker entity
|
||||||
|
if (strcmp(data[classname_kvdI].value, "monstermaker") == 0 || strcmp(data[classname_kvdI].value, "squadmaker") == 0 || strcmp(data[classname_kvdI].value, "env_xenmaker") == 0)
|
||||||
|
{
|
||||||
|
// process the entity precache here
|
||||||
|
for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
|
||||||
|
{
|
||||||
|
if (strcmp(data[i].value, monster_types[mIndex].name) == 0)
|
||||||
|
{
|
||||||
|
monster_types[mIndex].need_to_precache = TRUE;
|
||||||
|
break; // only one monster at a time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pass the keyvalue to the entity
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(data[i].key, "message") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// only applicable for ambient_music
|
||||||
|
if (strcmp(data[classname_kvdI].value, "ambient_music") == 0)
|
||||||
|
{
|
||||||
|
// precache the sound here
|
||||||
|
PRECACHE_GENERIC(data[i].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// common pev-field, an entity might need it
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We do not know this keyvalue, but an specific entity might use it.
|
||||||
|
// Save it for later
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
|
||||||
|
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// Spawn right away
|
||||||
|
monster_spawnpoint[monster_spawn_count].need_to_respawn = TRUE;
|
||||||
|
monster_spawn_count++;
|
||||||
|
}
|
||||||
|
else if (node)
|
||||||
|
{
|
||||||
|
// Increase node count
|
||||||
|
node_spawn_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log on? Print all the entities that were added
|
||||||
|
if (dllapi_log->value)
|
||||||
|
{
|
||||||
|
// Classname only, or we will flood the server!
|
||||||
|
LOG_CONSOLE(PLID, "[DEBUG] Added entity: %s", data[classname_kvdI].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scan_extra_cfg(FILE *fp)
|
||||||
|
{
|
||||||
|
char input[1024];
|
||||||
|
|
||||||
|
while (get_input(fp, input))
|
||||||
|
{
|
||||||
|
char *cmd = strtok(input, " ");
|
||||||
|
char *value = strtok(NULL, " ");
|
||||||
|
if (value == NULL)
|
||||||
|
continue; // command with no value, skip
|
||||||
|
|
||||||
|
// Remove all quotes from "value"
|
||||||
|
char parse[128] = {0};
|
||||||
|
int skip = 0;
|
||||||
|
for (unsigned i = 0; i < strlen(value); i++)
|
||||||
|
{
|
||||||
|
if (value[i] == '"')
|
||||||
|
{
|
||||||
|
skip++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
parse[i-skip] = value[i];
|
||||||
|
}
|
||||||
|
parse[strlen(parse)] = '\0';
|
||||||
|
strcpy(value, parse);
|
||||||
|
|
||||||
|
if (strcmp(cmd, "globalmodellist") == 0)
|
||||||
|
{
|
||||||
|
// ugh...
|
||||||
|
//globalmodellist->string = value;
|
||||||
|
CVAR_SET_STRING( "monster_gmr", value );
|
||||||
|
|
||||||
|
// Verbose if logging is enabled
|
||||||
|
if (dllapi_log->value)
|
||||||
|
LOG_CONSOLE(PLID, "[DEBUG] Using global model replacement file: %s", value);
|
||||||
|
}
|
||||||
|
if (strcmp(cmd, "globalsoundlist") == 0)
|
||||||
|
{
|
||||||
|
//globalsoundlist->string = value;
|
||||||
|
CVAR_SET_STRING( "monster_gsr", value );
|
||||||
|
|
||||||
|
// Verbose if logging is enabled
|
||||||
|
if (dllapi_log->value)
|
||||||
|
LOG_CONSOLE(PLID, "[DEBUG] Using global sound replacement file: %s", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scan_monster_replace(FILE *fp, bool toGSR )
|
||||||
|
{
|
||||||
|
char input[1024];
|
||||||
|
|
||||||
|
while (get_input(fp, input))
|
||||||
|
{
|
||||||
|
// might slip through
|
||||||
|
if (strlen(input) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char *source = strtok(input, " \t");
|
||||||
|
char *destination = strtok(NULL, " \t");
|
||||||
|
|
||||||
|
// Remove all quotes
|
||||||
|
char parse[128] = {0};
|
||||||
|
int skip;
|
||||||
|
|
||||||
|
// source
|
||||||
|
skip = 0;
|
||||||
|
for (unsigned i = 0; i < strlen(source); i++)
|
||||||
|
{
|
||||||
|
if (source[i] == '"')
|
||||||
|
{
|
||||||
|
skip++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
parse[i-skip] = source[i];
|
||||||
|
}
|
||||||
|
parse[strlen(parse)] = '\0';
|
||||||
|
strcpy(source, parse);
|
||||||
|
|
||||||
|
// destination
|
||||||
|
memset(parse, 0, sizeof(parse));
|
||||||
|
skip = 0;
|
||||||
|
for (unsigned i = 0; i < strlen(destination); i++)
|
||||||
|
{
|
||||||
|
if (destination[i] == '"')
|
||||||
|
{
|
||||||
|
skip++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
parse[i-skip] = destination[i];
|
||||||
|
}
|
||||||
|
parse[strlen(parse)] = '\0';
|
||||||
|
strcpy(destination, parse);
|
||||||
|
|
||||||
|
if ( toGSR )
|
||||||
|
REPLACER::AddGlobalSound( source, destination );
|
||||||
|
else
|
||||||
|
REPLACER::AddGlobalModel( source, destination );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool process_monster_cfg(void)
|
||||||
{
|
{
|
||||||
char game_dir[256];
|
char game_dir[256];
|
||||||
char filename[256];
|
char BSPfilename[256]; // to read ents directly from BSP
|
||||||
|
char CFGfilename[256]; // read ents from MAPNAME_monster.cfg file
|
||||||
|
char EXTfilename[256]; // extra map configs from MAPNAME.cfg
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
bool status = FALSE; // no error
|
|
||||||
|
|
||||||
monster_spawn_count = 0;
|
monster_spawn_count = 0;
|
||||||
|
node_spawn_count = 0;
|
||||||
|
|
||||||
// find the directory name of the currently running MOD...
|
// find the directory name of the currently running MOD...
|
||||||
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
||||||
|
|
||||||
strcpy(filename, game_dir);
|
// build route...
|
||||||
#ifdef __linux__
|
strcpy(CFGfilename, game_dir);
|
||||||
strcat(filename, "/maps/");
|
strcat(CFGfilename, "/maps/");
|
||||||
#else
|
strcat(CFGfilename, STRING(gpGlobals->mapname));
|
||||||
strcat(filename, "\\maps\\");
|
strcpy(BSPfilename, CFGfilename);
|
||||||
#endif
|
strcpy(EXTfilename, CFGfilename);
|
||||||
strcat(filename, STRING(gpGlobals->mapname));
|
|
||||||
strcat(filename, "_monster.cfg");
|
|
||||||
|
|
||||||
|
strcat(BSPfilename, ".bsp");
|
||||||
|
strcat(CFGfilename, "_monster.cfg");
|
||||||
|
strcat(EXTfilename, ".cfg");
|
||||||
|
|
||||||
|
// process config files?
|
||||||
|
// -1 = don't process monster config, dynamic spawns only
|
||||||
|
// 0 = read entities from BSP file
|
||||||
|
// 1 = read entities from CFG file
|
||||||
|
// 2 = read entities from both, BSP first, then CFG file
|
||||||
|
if (monster_entity_config->value >= 0)
|
||||||
|
{
|
||||||
|
// read from bsp? (mode 0 or 2)
|
||||||
|
if (monster_entity_config->value != 1)
|
||||||
|
{
|
||||||
|
LoadBSPFile(BSPfilename);
|
||||||
|
ParseEntities();
|
||||||
|
|
||||||
|
scan_monster_bsp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// read from cfg? (mode 1 or 2)
|
||||||
|
if (monster_entity_config->value > 0)
|
||||||
|
{
|
||||||
// check if the map specific filename exists...
|
// check if the map specific filename exists...
|
||||||
if (access(filename, 0) == 0)
|
if (access(CFGfilename, 0) == 0)
|
||||||
{
|
{
|
||||||
if (dllapi_log->value)
|
if (dllapi_log->value)
|
||||||
{
|
{
|
||||||
//META_CONS("[MONSTER] Processing config file=%s", filename);
|
//META_CONS("[MONSTER] Processing config file=%s", filename);
|
||||||
LOG_MESSAGE(PLID, "Processing config file=%s", filename);
|
LOG_MESSAGE(PLID, "Processing config file '%s'", CFGfilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fp = fopen(filename, "r")) == NULL)
|
if ((fp = fopen(CFGfilename, "r")) == NULL)
|
||||||
{
|
{
|
||||||
//META_CONS("[MONSTER] ERROR: Could not open \"%s\"!", filename);
|
//META_CONS("[MONSTER] ERROR: Could not open \"%s\"!", filename);
|
||||||
LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\" file!", filename);
|
LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\" file!", CFGfilename);
|
||||||
|
return TRUE; // error
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scan_monster_cfg(fp);
|
scan_monster_cfg(fp);
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
/* The code is only getting worse from here, I have to finish T4 quickly
|
||||||
|
* so I can move into making actual clean and optimized code for the final tier...
|
||||||
|
* -Giegue */
|
||||||
|
|
||||||
|
// extra map configs
|
||||||
|
if (access(EXTfilename, 0) == 0)
|
||||||
|
{
|
||||||
|
// first read configs
|
||||||
|
if ((fp = fopen(EXTfilename, "r")) != NULL)
|
||||||
|
{
|
||||||
|
scan_extra_cfg(fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// then process them here
|
||||||
|
if (strlen(globalmodellist->string))
|
||||||
|
{
|
||||||
|
char gmrPath[192];
|
||||||
|
|
||||||
|
// SC globalmodellist path starts from models/MAPNAME
|
||||||
|
sprintf(gmrPath, "%s/models/%s/%s", game_dir, STRING(gpGlobals->mapname), globalmodellist->string);
|
||||||
|
|
||||||
|
if (access(gmrPath, 0) == 0)
|
||||||
|
{
|
||||||
|
if ((fp = fopen(gmrPath, "r")) != NULL)
|
||||||
|
{
|
||||||
|
scan_monster_replace(fp, false);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (strlen(globalsoundlist->string))
|
||||||
|
{
|
||||||
|
char gsrPath[192];
|
||||||
|
|
||||||
|
// SC globalsoundlist path starts from sound/MAPNAME
|
||||||
|
sprintf(gsrPath, "%s/sound/%s/%s", game_dir, STRING(gpGlobals->mapname), globalsoundlist->string);
|
||||||
|
|
||||||
|
if (access(gsrPath, 0) == 0)
|
||||||
|
{
|
||||||
|
if ((fp = fopen(gsrPath, "r")) != NULL)
|
||||||
|
{
|
||||||
|
scan_monster_replace(fp, true);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE; // all ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool scan_monster_precache_cfg(FILE *fp)
|
bool scan_monster_precache_cfg(FILE *fp)
|
||||||
{
|
{
|
||||||
char input[1024];
|
char input[1024];
|
||||||
|
|||||||
@@ -1,378 +0,0 @@
|
|||||||
# Microsoft Developer Studio Project File - Name="monster_mm" - Package Owner=<4>
|
|
||||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
|
||||||
# ** DO NOT EDIT **
|
|
||||||
|
|
||||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
|
||||||
|
|
||||||
CFG=monster_mm - Win32 Debug
|
|
||||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
|
||||||
!MESSAGE use the Export Makefile command and run
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "monster_mm.mak".
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE You can specify a configuration when running NMAKE
|
|
||||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "monster_mm.mak" CFG="monster_mm - Win32 Debug"
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE Possible choices for configuration are:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE "monster_mm - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
|
||||||
!MESSAGE "monster_mm - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
|
||||||
!MESSAGE
|
|
||||||
|
|
||||||
# Begin Project
|
|
||||||
# PROP AllowPerConfigDependencies 0
|
|
||||||
# PROP Scc_ProjName ""
|
|
||||||
# PROP Scc_LocalPath ""
|
|
||||||
CPP=cl.exe
|
|
||||||
MTL=midl.exe
|
|
||||||
RSC=rc.exe
|
|
||||||
|
|
||||||
!IF "$(CFG)" == "monster_mm - Win32 Release"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 0
|
|
||||||
# PROP BASE Output_Dir "Release"
|
|
||||||
# PROP BASE Intermediate_Dir "Release"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 0
|
|
||||||
# PROP Output_Dir "Release"
|
|
||||||
# PROP Intermediate_Dir "Release"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "monster_mm_EXPORTS" /YX /FD /c
|
|
||||||
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\dlls" /I "..\common" /I "..\engine" /I "..\pm_shared" /I "..\..\metamod" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "monster_mm_EXPORTS" /D strcasecmp=stricmp /D strncasecmp=_strnicmp /FD /c
|
|
||||||
# SUBTRACT CPP /YX
|
|
||||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
|
||||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
|
||||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
|
||||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
|
||||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /def:".\monster_mm.def"
|
|
||||||
# Begin Custom Build - Copying to DLL folder
|
|
||||||
TargetPath=.\Release\monster_mm.dll
|
|
||||||
TargetName=monster_mm
|
|
||||||
InputPath=.\Release\monster_mm.dll
|
|
||||||
SOURCE="$(InputPath)"
|
|
||||||
|
|
||||||
"$(TargetName)" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
|
|
||||||
copy $(TargetPath) D:\Half-Life\valve\dlls
|
|
||||||
copy $(TargetPath) D:\Half-Life\tfc\dlls
|
|
||||||
copy $(TargetPath) D:\Half-Life\cstrike\dlls
|
|
||||||
copy $(TargetPath) D:\Half-Life\dmc\dlls
|
|
||||||
copy $(TargetPath) D:\Half-Life\dod\dlls
|
|
||||||
copy $(TargetPath) D:\Half-Life\firearms\dlls
|
|
||||||
copy $(TargetPath) D:\Half-Life\frontline\dlls
|
|
||||||
|
|
||||||
# End Custom Build
|
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "monster_mm - Win32 Debug"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 1
|
|
||||||
# PROP BASE Output_Dir "Debug"
|
|
||||||
# PROP BASE Intermediate_Dir "Debug"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 1
|
|
||||||
# PROP Output_Dir "Debug"
|
|
||||||
# PROP Intermediate_Dir "Debug"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "monster_mm_EXPORTS" /YX /FD /GZ /c
|
|
||||||
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\dlls" /I "..\common" /I "..\engine" /I "..\pm_shared" /I "..\..\metamod" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "monster_mm_EXPORTS" /D strcasecmp=stricmp /D strncasecmp=_strnicmp /FD /GZ /c
|
|
||||||
# SUBTRACT CPP /YX
|
|
||||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
|
||||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
|
||||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
|
||||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
|
||||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /def:".\monster_mm.def" /pdbtype:sept
|
|
||||||
# Begin Custom Build - Copying to DLL folder
|
|
||||||
TargetPath=.\Debug\monster_mm.dll
|
|
||||||
TargetName=monster_mm
|
|
||||||
InputPath=.\Debug\monster_mm.dll
|
|
||||||
SOURCE="$(InputPath)"
|
|
||||||
|
|
||||||
"$(TargetName)" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
|
|
||||||
copy $(TargetPath) D:\Half-Life\valve\dlls
|
|
||||||
copy $(TargetPath) D:\Half-Life\tfc\dlls
|
|
||||||
copy $(TargetPath) D:\Half-Life\cstrike\dlls
|
|
||||||
copy $(TargetPath) D:\Half-Life\dmc\dlls
|
|
||||||
copy $(TargetPath) D:\Half-Life\dod\dlls
|
|
||||||
copy $(TargetPath) D:\Half-Life\firearms\dlls
|
|
||||||
copy $(TargetPath) D:\Half-Life\frontline\dlls
|
|
||||||
copy $(TargetPath) D:\Half-Life\gearbox\dlls
|
|
||||||
|
|
||||||
# End Custom Build
|
|
||||||
|
|
||||||
!ENDIF
|
|
||||||
|
|
||||||
# Begin Target
|
|
||||||
|
|
||||||
# Name "monster_mm - Win32 Release"
|
|
||||||
# Name "monster_mm - Win32 Debug"
|
|
||||||
# Begin Group "Source Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\agrunt.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\AI_BaseNPC_Schedule.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\animating.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\animation.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\apache.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\barney.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\bigmomma.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\bullsquid.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\cmbase.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\combat.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\controller.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\defaultai.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\dllapi.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\effects.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\flyingmonster.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\ggrenade.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\h_ai.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\h_export.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\hassassin.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\headcrab.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\hgrunt.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\hornet.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\houndeye.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\islave.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\monster_api.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\monster_config.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\monsters.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\monsterstate.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\nodes.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\scientist.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\skill.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\sound.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\squeakgrenade.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\subs.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\talkmonster.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\util.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\weapons.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\zombie.cpp
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Header Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\activity.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\animation.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\cdll_dll.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\cmbase.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\cmbasemonster.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\cmflyingmonster.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\cmtalkmonster.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\decals.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\doors.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\effects.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\enginecallback.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\explode.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\extdll.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\func_break.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\monster_plugin.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\monsters.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\nodes.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\schedule.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\skill.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\util.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\vector.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\weapons.h
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Resource Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
|
||||||
# End Group
|
|
||||||
# End Target
|
|
||||||
# End Project
|
|
||||||
25
src/dlls/monster_mm.sln
Normal file
25
src/dlls/monster_mm.sln
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 15.0.28307.1433
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "monster_mm", "monster_mm.vcxproj", "{E4F36B30-6406-4D6E-90F6-DE34744D2434}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{E4F36B30-6406-4D6E-90F6-DE34744D2434}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{E4F36B30-6406-4D6E-90F6-DE34744D2434}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{E4F36B30-6406-4D6E-90F6-DE34744D2434}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{E4F36B30-6406-4D6E-90F6-DE34744D2434}.Release|x86.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {32C2F544-BCE4-4787-9C16-F85467CD69DA}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
230
src/dlls/monster_mm.vcxproj
Normal file
230
src/dlls/monster_mm.vcxproj
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{E4F36B30-6406-4D6E-90F6-DE34744D2434}</ProjectGuid>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseOfMfc>false</UseOfMfc>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v141_xp</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseOfMfc>false</UseOfMfc>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<PlatformToolset>v141_xp</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||||
|
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</OutDir>
|
||||||
|
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</IntDir>
|
||||||
|
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
|
||||||
|
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</OutDir>
|
||||||
|
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</IntDir>
|
||||||
|
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
|
||||||
|
<PostBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</PostBuildEventUseInBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Midl>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<MkTypLibCompatible>true</MkTypLibCompatible>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<TargetEnvironment>Win32</TargetEnvironment>
|
||||||
|
<TypeLibraryName>.\Debug/monster_mm.tlb</TypeLibraryName>
|
||||||
|
</Midl>
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>..\dlls;..\common;..\engine;..\pm_shared;..\metamod;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;monster_mm_EXPORTS;strcasecmp=stricmp;strncasecmp=_strnicmp;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
<PrecompiledHeaderOutputFile>.\Debug/monster_mm.pch</PrecompiledHeaderOutputFile>
|
||||||
|
<AssemblerListingLocation>.\Debug/</AssemblerListingLocation>
|
||||||
|
<ObjectFileName>.\Debug/</ObjectFileName>
|
||||||
|
<ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||||
|
<CompileAs>Default</CompileAs>
|
||||||
|
</ClCompile>
|
||||||
|
<ResourceCompile>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Culture>0x0409</Culture>
|
||||||
|
</ResourceCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<AdditionalDependencies>odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<OutputFile>.\Debug/monster_mm.dll</OutputFile>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<ModuleDefinitionFile>.\monster_mm.def</ModuleDefinitionFile>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<ProgramDatabaseFile>.\Debug/monster_mm.pdb</ProgramDatabaseFile>
|
||||||
|
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||||
|
<DataExecutionPrevention>
|
||||||
|
</DataExecutionPrevention>
|
||||||
|
<ImportLibrary>.\Debug/monster_mm.lib</ImportLibrary>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Midl>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<MkTypLibCompatible>true</MkTypLibCompatible>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<TargetEnvironment>Win32</TargetEnvironment>
|
||||||
|
<TypeLibraryName>.\Release/monster_mm.tlb</TypeLibraryName>
|
||||||
|
</Midl>
|
||||||
|
<ClCompile>
|
||||||
|
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||||
|
<AdditionalIncludeDirectories>..\dlls;..\common;..\engine;..\pm_shared;..\metamod;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;monster_mm_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<PrecompiledHeaderOutputFile>.\Release/monster_mm.pch</PrecompiledHeaderOutputFile>
|
||||||
|
<AssemblerListingLocation>.\Release/</AssemblerListingLocation>
|
||||||
|
<ObjectFileName>.\Release/</ObjectFileName>
|
||||||
|
<ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<CompileAs>Default</CompileAs>
|
||||||
|
</ClCompile>
|
||||||
|
<ResourceCompile>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Culture>0x0409</Culture>
|
||||||
|
</ResourceCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<AdditionalDependencies>odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<OutputFile>.\Release/monster_mm.dll</OutputFile>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<ModuleDefinitionFile>.\monster_mm.def</ModuleDefinitionFile>
|
||||||
|
<ProgramDatabaseFile>.\Release/monster_mm.pdb</ProgramDatabaseFile>
|
||||||
|
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||||
|
<DataExecutionPrevention>
|
||||||
|
</DataExecutionPrevention>
|
||||||
|
<ImportLibrary>.\Release/monster_mm.lib</ImportLibrary>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="agrunt.cpp" />
|
||||||
|
<ClCompile Include="AI_BaseNPC_Schedule.cpp" />
|
||||||
|
<ClCompile Include="animating.cpp" />
|
||||||
|
<ClCompile Include="animation.cpp" />
|
||||||
|
<ClCompile Include="apache.cpp" />
|
||||||
|
<ClCompile Include="barney.cpp" />
|
||||||
|
<ClCompile Include="bigmomma.cpp" />
|
||||||
|
<ClCompile Include="bullsquid.cpp" />
|
||||||
|
<ClCompile Include="cmbase.cpp" />
|
||||||
|
<ClCompile Include="combat.cpp" />
|
||||||
|
<ClCompile Include="controller.cpp" />
|
||||||
|
<ClCompile Include="defaultai.cpp" />
|
||||||
|
<ClCompile Include="dllapi.cpp" />
|
||||||
|
<ClCompile Include="effects.cpp" />
|
||||||
|
<ClCompile Include="explode.cpp" />
|
||||||
|
<ClCompile Include="flyingmonster.cpp" />
|
||||||
|
<ClCompile Include="gargantua.cpp" />
|
||||||
|
<ClCompile Include="ggrenade.cpp" />
|
||||||
|
<ClCompile Include="globalreplace.cpp" />
|
||||||
|
<ClCompile Include="gonome.cpp" />
|
||||||
|
<ClCompile Include="h_ai.cpp" />
|
||||||
|
<ClCompile Include="h_export.cpp" />
|
||||||
|
<ClCompile Include="hassassin.cpp" />
|
||||||
|
<ClCompile Include="headcrab.cpp" />
|
||||||
|
<ClCompile Include="hgrunt.cpp" />
|
||||||
|
<ClCompile Include="hornet.cpp" />
|
||||||
|
<ClCompile Include="houndeye.cpp" />
|
||||||
|
<ClCompile Include="hwgrunt.cpp" />
|
||||||
|
<ClCompile Include="islave.cpp" />
|
||||||
|
<ClCompile Include="massn.cpp" />
|
||||||
|
<ClCompile Include="monster_api.cpp" />
|
||||||
|
<ClCompile Include="monster_config.cpp" />
|
||||||
|
<ClCompile Include="monstermaker.cpp" />
|
||||||
|
<ClCompile Include="monsters.cpp" />
|
||||||
|
<ClCompile Include="monsterstate.cpp" />
|
||||||
|
<ClCompile Include="music.cpp" />
|
||||||
|
<ClCompile Include="nodes.cpp" />
|
||||||
|
<ClCompile Include="otis.cpp" />
|
||||||
|
<ClCompile Include="pitdrone.cpp" />
|
||||||
|
<ClCompile Include="rgrunt.cpp" />
|
||||||
|
<ClCompile Include="ripent.cpp" />
|
||||||
|
<ClCompile Include="scientist.cpp" />
|
||||||
|
<ClCompile Include="setcvar.cpp" />
|
||||||
|
<ClCompile Include="shock.cpp" />
|
||||||
|
<ClCompile Include="shockroach.cpp" />
|
||||||
|
<ClCompile Include="skill.cpp" />
|
||||||
|
<ClCompile Include="sound.cpp" />
|
||||||
|
<ClCompile Include="sporegrenade.cpp" />
|
||||||
|
<ClCompile Include="squeakgrenade.cpp" />
|
||||||
|
<ClCompile Include="strooper.cpp" />
|
||||||
|
<ClCompile Include="stukabat.cpp" />
|
||||||
|
<ClCompile Include="subs.cpp" />
|
||||||
|
<ClCompile Include="talkmonster.cpp" />
|
||||||
|
<ClCompile Include="turret.cpp" />
|
||||||
|
<ClCompile Include="util.cpp" />
|
||||||
|
<ClCompile Include="voltigore.cpp" />
|
||||||
|
<ClCompile Include="weapons.cpp" />
|
||||||
|
<ClCompile Include="xenmaker.cpp" />
|
||||||
|
<ClCompile Include="zombie.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="activity.h" />
|
||||||
|
<ClInclude Include="activitymap.h" />
|
||||||
|
<ClInclude Include="animation.h" />
|
||||||
|
<ClInclude Include="cdll_dll.h" />
|
||||||
|
<ClInclude Include="cmbase.h" />
|
||||||
|
<ClInclude Include="cmbaseextra.h" />
|
||||||
|
<ClInclude Include="cmbasemonster.h" />
|
||||||
|
<ClInclude Include="cmflyingmonster.h" />
|
||||||
|
<ClInclude Include="cmtalkmonster.h" />
|
||||||
|
<ClInclude Include="decals.h" />
|
||||||
|
<ClInclude Include="defaultai.h" />
|
||||||
|
<ClInclude Include="doors.h" />
|
||||||
|
<ClInclude Include="effects.h" />
|
||||||
|
<ClInclude Include="enginecallback.h" />
|
||||||
|
<ClInclude Include="explode.h" />
|
||||||
|
<ClInclude Include="extdll.h" />
|
||||||
|
<ClInclude Include="func_break.h" />
|
||||||
|
<ClInclude Include="globalreplace.h" />
|
||||||
|
<ClInclude Include="hornet.h" />
|
||||||
|
<ClInclude Include="monster_plugin.h" />
|
||||||
|
<ClInclude Include="monsterevent.h" />
|
||||||
|
<ClInclude Include="monsters.h" />
|
||||||
|
<ClInclude Include="nodes.h" />
|
||||||
|
<ClInclude Include="plane.h" />
|
||||||
|
<ClInclude Include="ripent.h" />
|
||||||
|
<ClInclude Include="schedule.h" />
|
||||||
|
<ClInclude Include="shock.h" />
|
||||||
|
<ClInclude Include="skill.h" />
|
||||||
|
<ClInclude Include="util.h" />
|
||||||
|
<ClInclude Include="vector.h" />
|
||||||
|
<ClInclude Include="weapons.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
291
src/dlls/monster_mm.vcxproj.filters
Normal file
291
src/dlls/monster_mm.vcxproj.filters
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{c6c9a5d3-53c7-4dda-a7f7-a278343d08f6}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{7a512719-d6e9-4695-acde-c7239717ece9}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hpp;hxx;hm;inl</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{af74e8b8-3ee2-4d62-b8cb-fa3952c4afed}</UniqueIdentifier>
|
||||||
|
<Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="agrunt.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="AI_BaseNPC_Schedule.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="animating.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="animation.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="apache.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="barney.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="bigmomma.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="bullsquid.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="cmbase.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="combat.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="controller.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="defaultai.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="dllapi.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="effects.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="explode.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="flyingmonster.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="gargantua.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ggrenade.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="gonome.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="h_ai.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="h_export.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hassassin.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="headcrab.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hgrunt.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hornet.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="houndeye.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hwgrunt.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="islave.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="massn.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="monster_api.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="monster_config.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="monstermaker.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="monsters.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="monsterstate.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="nodes.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="otis.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="pitdrone.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="rgrunt.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="scientist.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="shock.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="shockroach.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="skill.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="sound.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="sporegrenade.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="squeakgrenade.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="strooper.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="stukabat.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="subs.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="talkmonster.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="turret.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="util.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="voltigore.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="weapons.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="zombie.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ripent.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="music.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="globalreplace.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="xenmaker.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="setcvar.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="activity.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="activitymap.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="animation.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="cdll_dll.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="cmbase.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="cmbaseextra.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="cmbasemonster.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="cmflyingmonster.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="cmtalkmonster.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="decals.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="defaultai.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="doors.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="effects.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="enginecallback.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="explode.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="extdll.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="func_break.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="hornet.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="monster_plugin.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="monsterevent.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="monsters.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="nodes.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="plane.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="schedule.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="shock.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="skill.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="util.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="vector.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="weapons.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="ripent.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="globalreplace.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -5,11 +5,11 @@
|
|||||||
#ifndef MONSTER_PLUGIN_H
|
#ifndef MONSTER_PLUGIN_H
|
||||||
#define MONSTER_PLUGIN_H
|
#define MONSTER_PLUGIN_H
|
||||||
|
|
||||||
typedef struct pKVD
|
typedef struct
|
||||||
{
|
{
|
||||||
char key[33];
|
char key[33];
|
||||||
char value[33];
|
char value[481];
|
||||||
};
|
} pKVD;
|
||||||
|
|
||||||
#define MAX_KEYVALUES 32
|
#define MAX_KEYVALUES 32
|
||||||
|
|
||||||
@@ -27,26 +27,23 @@ typedef struct
|
|||||||
int monster_index;
|
int monster_index;
|
||||||
edict_t *monster_pent;
|
edict_t *monster_pent;
|
||||||
bool killed;
|
bool killed;
|
||||||
int respawn_index;
|
|
||||||
CMBaseMonster *pMonster;
|
CMBaseMonster *pMonster;
|
||||||
} monster_t;
|
} monster_t;
|
||||||
|
|
||||||
#define MAX_MONSTER_ENTS 400 // increased from 200 so it can hold non-monster entities
|
#define MAX_MONSTER_ENTS 768
|
||||||
|
|
||||||
extern monster_t monsters[MAX_MONSTER_ENTS];
|
extern monster_t monsters[MAX_MONSTER_ENTS];
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Vector origin;
|
Vector origin;
|
||||||
Vector angles;
|
Vector angles;
|
||||||
float delay;
|
|
||||||
unsigned char monster;
|
unsigned char monster;
|
||||||
int spawnflags;
|
int spawnflags;
|
||||||
pKVD *keyvalue;
|
pKVD *keyvalue;
|
||||||
float respawn_time;
|
|
||||||
bool need_to_respawn;
|
bool need_to_respawn;
|
||||||
} monster_spawnpoint_t;
|
} monster_spawnpoint_t;
|
||||||
|
|
||||||
#define MAX_MONSTERS 100
|
#define MAX_MONSTERS 384
|
||||||
extern monster_spawnpoint_t monster_spawnpoint[MAX_MONSTERS];
|
extern monster_spawnpoint_t monster_spawnpoint[MAX_MONSTERS];
|
||||||
|
|
||||||
// this is here to store if a node we want to spawn is an ordinary one, or a flying one
|
// this is here to store if a node we want to spawn is an ordinary one, or a flying one
|
||||||
|
|||||||
366
src/dlls/monstermaker.cpp
Normal file
366
src/dlls/monstermaker.cpp
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
/***
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* This product contains software technology licensed from Id
|
||||||
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use, distribution, and modification of this source code and/or resulting
|
||||||
|
* object code is restricted to non-commercial enhancements to products from
|
||||||
|
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||||
|
* without written permission from Valve LLC.
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
//=========================================================
|
||||||
|
// Monster Maker - this is an entity that creates monsters
|
||||||
|
// in the game.
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
#include "cmbaseextra.h"
|
||||||
|
#include "monsters.h"
|
||||||
|
|
||||||
|
// Monstermaker spawnflags
|
||||||
|
#define SF_MONSTERMAKER_START_ON 1 // start active ( if has targetname )
|
||||||
|
#define SF_MONSTERMAKER_CYCLIC 4 // drop one monster every time fired.
|
||||||
|
#define SF_MONSTERMAKER_MONSTERCLIP 8 // Children are blocked by monsterclip
|
||||||
|
#define SF_MONSTERMAKER_PRISONER 16 // children won't attack or be attacked
|
||||||
|
|
||||||
|
extern monster_type_t monster_types[];
|
||||||
|
extern edict_t* spawn_monster(int monster_type, Vector origin, Vector angles, int spawnflags, pKVD *keyvalue);
|
||||||
|
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
void CMMonsterMaker :: KeyValue( KeyValueData *pkvd )
|
||||||
|
{
|
||||||
|
if ( FStrEq(pkvd->szKeyName, "monstercount") )
|
||||||
|
{
|
||||||
|
m_cNumMonsters = atoi(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if ( FStrEq(pkvd->szKeyName, "m_imaxlivechildren") )
|
||||||
|
{
|
||||||
|
m_iMaxLiveChildren = atoi(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if ( FStrEq(pkvd->szKeyName, "monstertype") )
|
||||||
|
{
|
||||||
|
// Process monster_index
|
||||||
|
int mIndex;
|
||||||
|
for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
|
||||||
|
{
|
||||||
|
if (strcmp(pkvd->szValue, monster_types[mIndex].name) == 0)
|
||||||
|
{
|
||||||
|
m_iMonsterIndex = mIndex;
|
||||||
|
break; // grab the first entry we find
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (monster_types[mIndex].name[0] == 0)
|
||||||
|
{
|
||||||
|
ALERT ( at_logged, "[MONSTER] MonsterMaker - %s is not a valid monster type!\n", pkvd->szValue );
|
||||||
|
m_iMonsterIndex = -1;
|
||||||
|
}
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if ( FStrEq(pkvd->szKeyName, "new_model") )
|
||||||
|
{
|
||||||
|
m_iszCustomModel = ALLOC_STRING(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if ( FStrEq(pkvd->szKeyName, "bloodcolor") )
|
||||||
|
{
|
||||||
|
m_iMonsterBlood = atoi(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if ( FStrEq(pkvd->szKeyName, "respawn_as_playerally") )
|
||||||
|
{
|
||||||
|
if (atoi(pkvd->szValue))
|
||||||
|
m_iClassifyOverride = CLASS_PLAYER_ALLY;
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
// These are to keep consistency with Sven Co-op's squadmaker entity.
|
||||||
|
// CMBaseMonster::KeyValue will process TriggerCondition/TriggerTarget
|
||||||
|
// keyvalues in the same way.
|
||||||
|
else if ( FStrEq(pkvd->szKeyName, "trigger_condition") )
|
||||||
|
{
|
||||||
|
m_iTriggerCondition = atoi(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if ( FStrEq(pkvd->szKeyName, "trigger_target") )
|
||||||
|
{
|
||||||
|
m_iszTriggerTarget = ALLOC_STRING(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CMBaseMonster::KeyValue( pkvd );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CMMonsterMaker :: Spawn( )
|
||||||
|
{
|
||||||
|
// likely omitted keyvalue, but it could truly be an alien grunt spawn
|
||||||
|
if ( m_iMonsterIndex == 0 )
|
||||||
|
{
|
||||||
|
if ( !monster_types[0].need_to_precache )
|
||||||
|
{
|
||||||
|
// monstertype was not defined
|
||||||
|
ALERT ( at_logged, "[MONSTER] Spawned a monstermaker entity without a monstertype! targetname: \"%s\"\n", STRING(pev->targetname) );
|
||||||
|
m_iMonsterIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pev->solid = SOLID_NOT;
|
||||||
|
|
||||||
|
m_cLiveChildren = 0;
|
||||||
|
Precache();
|
||||||
|
if ( !FStringNull ( pev->targetname ) )
|
||||||
|
{
|
||||||
|
if ( pev->spawnflags & SF_MONSTERMAKER_CYCLIC )
|
||||||
|
{
|
||||||
|
SetUse ( &CMMonsterMaker::CyclicUse );// drop one monster each time we fire
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetUse ( &CMMonsterMaker::ToggleUse );// so can be turned on/off
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( FBitSet ( pev->spawnflags, SF_MONSTERMAKER_START_ON ) )
|
||||||
|
{// start making monsters as soon as monstermaker spawns
|
||||||
|
m_fActive = TRUE;
|
||||||
|
SetThink ( &CMMonsterMaker::MakerThink );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{// wait to be activated.
|
||||||
|
m_fActive = FALSE;
|
||||||
|
SetThink ( &CMMonsterMaker::SUB_DoNothing );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{// no targetname, just start.
|
||||||
|
pev->nextthink = gpGlobals->time + m_flDelay;
|
||||||
|
m_fActive = TRUE;
|
||||||
|
SetThink ( &CMMonsterMaker::MakerThink );
|
||||||
|
}
|
||||||
|
|
||||||
|
// always fade
|
||||||
|
m_fFadeChildren = TRUE;
|
||||||
|
|
||||||
|
m_flGround = 0;
|
||||||
|
pev->classname = MAKE_STRING("monstermaker");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMMonsterMaker :: Precache( void )
|
||||||
|
{
|
||||||
|
CMBaseMonster::Precache();
|
||||||
|
// choosen monster is auto-precached
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// MakeMonster- this is the code that drops the monster
|
||||||
|
//=========================================================
|
||||||
|
void CMMonsterMaker::MakeMonster( void )
|
||||||
|
{
|
||||||
|
// monstermaker incorrectly setup or intentionally empty
|
||||||
|
if ( m_iMonsterIndex == -1 )
|
||||||
|
{
|
||||||
|
ALERT ( at_console, "[MONSTER] NULL Ent in MonsterMaker!\n" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
edict_t *pent;
|
||||||
|
pKVD keyvalue[MAX_KEYVALUES];
|
||||||
|
int createSF = SF_MONSTER_FALL_TO_GROUND;
|
||||||
|
|
||||||
|
if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren )
|
||||||
|
{// not allowed to make a new one yet. Too many live ones out right now.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !m_flGround )
|
||||||
|
{
|
||||||
|
// set altitude. Now that I'm activated, any breakables, etc should be out from under me.
|
||||||
|
TraceResult tr;
|
||||||
|
|
||||||
|
UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0, 0, 2048 ), ignore_monsters, ENT(pev), &tr );
|
||||||
|
m_flGround = tr.vecEndPos.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector mins = pev->origin - Vector( 34, 34, 0 );
|
||||||
|
Vector maxs = pev->origin + Vector( 34, 34, 0 );
|
||||||
|
maxs.z = pev->origin.z;
|
||||||
|
mins.z = m_flGround;
|
||||||
|
|
||||||
|
edict_t *pList[2];
|
||||||
|
int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_CLIENT|FL_MONSTER );
|
||||||
|
if ( count )
|
||||||
|
{
|
||||||
|
// don't build a stack of monsters!
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should children hit monsterclip brushes?
|
||||||
|
if ( pev->spawnflags & SF_MONSTERMAKER_MONSTERCLIP )
|
||||||
|
createSF |= SF_MONSTER_HITMONSTERCLIP;
|
||||||
|
|
||||||
|
// Should children be prisoner entities?
|
||||||
|
if (pev->spawnflags & SF_MONSTERMAKER_PRISONER)
|
||||||
|
createSF |= SF_MONSTER_PRISONER;
|
||||||
|
|
||||||
|
/* KEYVALUES */
|
||||||
|
// Monster is to have a custom model?
|
||||||
|
if ( !FStringNull( m_iszCustomModel ) )
|
||||||
|
{
|
||||||
|
// setup model keyvalue
|
||||||
|
strcpy(keyvalue[0].key, "model");
|
||||||
|
strcpy(keyvalue[0].value, STRING( m_iszCustomModel ));
|
||||||
|
}
|
||||||
|
// Override monster blood color?
|
||||||
|
if ( m_iMonsterBlood )
|
||||||
|
{
|
||||||
|
// setup blood keyvalue
|
||||||
|
strcpy(keyvalue[1].key, "bloodcolor");
|
||||||
|
sprintf(keyvalue[1].value, "%i", m_iMonsterBlood);
|
||||||
|
}
|
||||||
|
// Trigger conditions set?
|
||||||
|
if ( !FStringNull( m_iszTriggerTarget ) )
|
||||||
|
{
|
||||||
|
// setup trigger keyvalues
|
||||||
|
strcpy(keyvalue[2].key, "TriggerCondition");
|
||||||
|
sprintf(keyvalue[2].value, "%i", m_iTriggerCondition);
|
||||||
|
strcpy(keyvalue[3].key, "TriggerTarget");
|
||||||
|
strcpy(keyvalue[3].value, STRING( m_iszTriggerTarget ));
|
||||||
|
}
|
||||||
|
// Weapons (For hgrunt/massn/rgrunt/etc...)
|
||||||
|
if ( pev->weapons )
|
||||||
|
{
|
||||||
|
strcpy(keyvalue[4].key, "weapons");
|
||||||
|
sprintf(keyvalue[4].value, "%i", pev->weapons);
|
||||||
|
}
|
||||||
|
// Monster's Name
|
||||||
|
if ( !FStringNull( m_szMonsterName ) )
|
||||||
|
{
|
||||||
|
strcpy(keyvalue[5].key, "displayname");
|
||||||
|
strcpy(keyvalue[5].value, STRING( m_szMonsterName ));
|
||||||
|
}
|
||||||
|
// Classify override
|
||||||
|
if ( m_iClassifyOverride )
|
||||||
|
{
|
||||||
|
strcpy(keyvalue[6].key, "classify");
|
||||||
|
sprintf(keyvalue[6].value, "%i", m_iClassifyOverride);
|
||||||
|
}
|
||||||
|
// Custom health
|
||||||
|
if (pev->health)
|
||||||
|
{
|
||||||
|
strcpy(keyvalue[7].key, "health");
|
||||||
|
sprintf(keyvalue[7].value, "%f", pev->health);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to spawn monster
|
||||||
|
pent = spawn_monster(m_iMonsterIndex, pev->origin, pev->angles, createSF, keyvalue);
|
||||||
|
if ( pent == NULL )
|
||||||
|
{
|
||||||
|
ALERT ( at_console, "[MONSTER] MonsterMaker - failed to spawn monster! targetname: \"%s\"\n", STRING(pev->targetname) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If I have a target, fire!
|
||||||
|
if ( !FStringNull ( pev->target ) )
|
||||||
|
{
|
||||||
|
// delay already overloaded for this entity, so can't call SUB_UseTargets()
|
||||||
|
FireTargets( STRING(pev->target), this->edict(), this->edict(), USE_TOGGLE, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
pent->v.owner = edict();
|
||||||
|
|
||||||
|
if ( !FStringNull( pev->netname ) )
|
||||||
|
{
|
||||||
|
// if I have a netname (overloaded), give the child monster that name as a targetname
|
||||||
|
pent->v.targetname = pev->netname;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass parent's rendering effects to child
|
||||||
|
pent->v.rendermode = pev->rendermode;
|
||||||
|
pent->v.renderfx = pev->renderfx;
|
||||||
|
pent->v.renderamt = pev->renderamt;
|
||||||
|
pent->v.rendercolor = pev->rendercolor;
|
||||||
|
|
||||||
|
// Soundlist isn't "exactly" a keyvalue so pass it here
|
||||||
|
if (m_srSoundList != NULL)
|
||||||
|
{
|
||||||
|
// it needs to be allocated first
|
||||||
|
CMBaseMonster *pChild = GetClassPtr((CMBaseMonster *)VARS(pent));
|
||||||
|
pChild->m_srSoundList = (REPLACER::REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*pChild->m_srSoundList));
|
||||||
|
|
||||||
|
memcpy(pChild->m_srSoundList, m_srSoundList, m_isrSounds * sizeof(*pChild->m_srSoundList));
|
||||||
|
pChild->m_isrSounds = m_isrSounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_cLiveChildren++;// count this monster
|
||||||
|
m_cNumMonsters--;
|
||||||
|
|
||||||
|
if ( m_cNumMonsters == 0 )
|
||||||
|
{
|
||||||
|
// Disable this forever. Don't kill it because it still gets death notices
|
||||||
|
SetThink( NULL );
|
||||||
|
SetUse( NULL );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// CyclicUse - drops one monster from the monstermaker
|
||||||
|
// each time we call this.
|
||||||
|
//=========================================================
|
||||||
|
void CMMonsterMaker::CyclicUse ( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value )
|
||||||
|
{
|
||||||
|
MakeMonster();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// ToggleUse - activates/deactivates the monster maker
|
||||||
|
//=========================================================
|
||||||
|
void CMMonsterMaker :: ToggleUse ( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value )
|
||||||
|
{
|
||||||
|
if ( !ShouldToggle( useType, m_fActive ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( m_fActive )
|
||||||
|
{
|
||||||
|
m_fActive = FALSE;
|
||||||
|
SetThink ( NULL );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_fActive = TRUE;
|
||||||
|
SetThink ( &CMMonsterMaker::MakerThink );
|
||||||
|
}
|
||||||
|
|
||||||
|
pev->nextthink = gpGlobals->time;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// MakerThink - creates a new monster every so often
|
||||||
|
//=========================================================
|
||||||
|
void CMMonsterMaker :: MakerThink ( void )
|
||||||
|
{
|
||||||
|
pev->nextthink = gpGlobals->time + m_flDelay;
|
||||||
|
|
||||||
|
MakeMonster();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
//=========================================================
|
||||||
|
void CMMonsterMaker :: DeathNotice ( entvars_t *pevChild )
|
||||||
|
{
|
||||||
|
// ok, we've gotten the deathnotice from our child, now clear out its owner if we don't want it to fade.
|
||||||
|
m_cLiveChildren--;
|
||||||
|
|
||||||
|
if ( !m_fFadeChildren )
|
||||||
|
{
|
||||||
|
pevChild->owner = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,7 +39,10 @@ extern DLL_GLOBAL BOOL g_fDrawLines;
|
|||||||
|
|
||||||
extern CGraph WorldGraph;// the world node graph
|
extern CGraph WorldGraph;// the world node graph
|
||||||
|
|
||||||
|
extern cvar_t *monster_turn_coeficient;
|
||||||
|
extern cvar_t *monster_default_maxrange;
|
||||||
|
|
||||||
|
extern void process_monster_sound(edict_t *pMonster, char *fileName);
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
// Eat - makes a monster full for a little while.
|
// Eat - makes a monster full for a little while.
|
||||||
@@ -137,17 +140,14 @@ void CMBaseMonster :: Look ( int iDistance )
|
|||||||
{
|
{
|
||||||
pSightEnt = pList[i];
|
pSightEnt = pList[i];
|
||||||
// !!!temporarily only considering other monsters and clients, don't see prisoners
|
// !!!temporarily only considering other monsters and clients, don't see prisoners
|
||||||
if ( pSightEnt != this->edict() &&
|
if ( pSightEnt != this->edict() && !FBitSet( pSightEnt->v.spawnflags, SF_MONSTER_PRISONER ) && pSightEnt->v.health > 0 )
|
||||||
!FBitSet( pSightEnt->v.spawnflags, SF_MONSTER_PRISONER ) &&
|
|
||||||
pSightEnt->v.health > 0 )
|
|
||||||
{
|
{
|
||||||
// is this a player AND are they alive?
|
// is this a player AND are they alive?
|
||||||
if (UTIL_IsPlayer(pSightEnt) && UTIL_IsAlive(pSightEnt))
|
if (UTIL_IsPlayer(pSightEnt) && UTIL_IsAlive(pSightEnt))
|
||||||
{
|
{
|
||||||
// the looker will want to consider this entity
|
// the looker will want to consider this entity
|
||||||
// don't check anything else about an entity that can't be seen.
|
// don't check anything else about an entity that can't be seen.
|
||||||
if ( UTIL_FInViewCone( pSightEnt, ENT(pev), m_flFieldOfView ) &&
|
if ( UTIL_FInViewCone( pSightEnt, ENT(pev), m_flFieldOfView ) && !FBitSet( pSightEnt->v.flags, FL_NOTARGET ) && UTIL_FVisible( pSightEnt, ENT(pev) ) )
|
||||||
!FBitSet( pSightEnt->v.flags, FL_NOTARGET ) && UTIL_FVisible( pSightEnt, ENT(pev) ) )
|
|
||||||
{
|
{
|
||||||
m_edictList[m_edictList_count] = pSightEnt;
|
m_edictList[m_edictList_count] = pSightEnt;
|
||||||
m_edictList_count++;
|
m_edictList_count++;
|
||||||
@@ -170,12 +170,12 @@ void CMBaseMonster :: Look ( int iDistance )
|
|||||||
}
|
}
|
||||||
else if (pSightEnt->v.euser4 != NULL)
|
else if (pSightEnt->v.euser4 != NULL)
|
||||||
{
|
{
|
||||||
|
/* MonsterMod monster looking at another MonsterMod monster */
|
||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pSightEnt));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pSightEnt));
|
||||||
|
|
||||||
// the looker will want to consider this entity
|
// the looker will want to consider this entity
|
||||||
// don't check anything else about an entity that can't be seen, or an entity that you don't care about.
|
// don't check anything else about an entity that can't be seen, or an entity that you don't care about.
|
||||||
if ( IRelationship( pMonster ) != R_NO && UTIL_FInViewCone( pSightEnt, ENT(pev), m_flFieldOfView ) &&
|
if ( IRelationship( pMonster ) != R_NO && UTIL_FInViewCone( pSightEnt, ENT(pev), m_flFieldOfView ) && !FBitSet( pSightEnt->v.flags, FL_NOTARGET ) && UTIL_FVisible( pSightEnt, ENT(pev) ) )
|
||||||
!FBitSet( pSightEnt->v.flags, FL_NOTARGET ) && UTIL_FVisible( pSightEnt, ENT(pev) ) )
|
|
||||||
{
|
{
|
||||||
m_edictList[m_edictList_count] = pSightEnt;
|
m_edictList[m_edictList_count] = pSightEnt;
|
||||||
m_edictList_count++;
|
m_edictList_count++;
|
||||||
@@ -210,6 +210,47 @@ void CMBaseMonster :: Look ( int iDistance )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* MonsterMod monster looking at a NON-MonsterMod monster */
|
||||||
|
|
||||||
|
// the looker will want to consider this entity
|
||||||
|
// don't check anything else about an entity that can't be seen, or an entity that you don't care about.
|
||||||
|
if ( IRelationship( pSightEnt->v.iuser4 ) != R_NO && UTIL_FInViewCone( pSightEnt, ENT(pev), m_flFieldOfView ) && !FBitSet( pSightEnt->v.flags, FL_NOTARGET ) && UTIL_FVisible( pSightEnt, ENT(pev) ) )
|
||||||
|
{
|
||||||
|
m_edictList[m_edictList_count] = pSightEnt;
|
||||||
|
m_edictList_count++;
|
||||||
|
|
||||||
|
if ( pSightEnt == m_hEnemy )
|
||||||
|
{
|
||||||
|
// we know this ent is visible, so if it also happens to be our enemy, store that now.
|
||||||
|
iSighted |= bits_COND_SEE_ENEMY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't add the Enemy's relationship to the conditions. We only want to worry about conditions when
|
||||||
|
// we see monsters other than the Enemy.
|
||||||
|
switch ( IRelationship ( pSightEnt->v.iuser4 ) )
|
||||||
|
{
|
||||||
|
case R_NM:
|
||||||
|
iSighted |= bits_COND_SEE_NEMESIS;
|
||||||
|
break;
|
||||||
|
case R_HT:
|
||||||
|
iSighted |= bits_COND_SEE_HATE;
|
||||||
|
break;
|
||||||
|
case R_DL:
|
||||||
|
iSighted |= bits_COND_SEE_DISLIKE;
|
||||||
|
break;
|
||||||
|
case R_FR:
|
||||||
|
iSighted |= bits_COND_SEE_FEAR;
|
||||||
|
break;
|
||||||
|
case R_AL:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ALERT ( at_aiconsole, "%s can't assess %s\n", STRING(pev->classname), STRING(pSightEnt->v.classname ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1514,7 +1555,7 @@ void CMBaseMonster :: Move ( float flInterval )
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//jlb TaskFail();
|
TaskFail();
|
||||||
ALERT( at_aiconsole, "%s Failed to move (%d)!\n", STRING(pev->classname), HasMemory( bits_MEMORY_MOVE_FAILED ) );
|
ALERT( at_aiconsole, "%s Failed to move (%d)!\n", STRING(pev->classname), HasMemory( bits_MEMORY_MOVE_FAILED ) );
|
||||||
//ALERT( at_aiconsole, "%f, %f, %f\n", pev->origin.z, (pev->origin + (vecDir * flCheckDist)).z, m_Route[m_iRouteIndex].vecLocation.z );
|
//ALERT( at_aiconsole, "%f, %f, %f\n", pev->origin.z, (pev->origin + (vecDir * flCheckDist)).z, m_Route[m_iRouteIndex].vecLocation.z );
|
||||||
}
|
}
|
||||||
@@ -1623,8 +1664,9 @@ void CMBaseMonster :: MonsterInit ( void )
|
|||||||
for (int i=0; i < MAX_OLD_ENEMIES; i++)
|
for (int i=0; i < MAX_OLD_ENEMIES; i++)
|
||||||
m_hOldEnemy[ i ] = NULL;
|
m_hOldEnemy[ i ] = NULL;
|
||||||
|
|
||||||
m_flDistTooFar = 1024.0;
|
if (!m_flDistLook)
|
||||||
m_flDistLook = 2048.0;
|
m_flDistLook = monster_default_maxrange->value;
|
||||||
|
m_flDistTooFar = m_flDistLook / 2; // always 50%
|
||||||
|
|
||||||
// set eye position
|
// set eye position
|
||||||
SetEyePosition();
|
SetEyePosition();
|
||||||
@@ -1743,6 +1785,9 @@ void CMBaseMonster :: StartMonster ( void )
|
|||||||
SetActivity( ACT_IDLE );
|
SetActivity( ACT_IDLE );
|
||||||
ChangeSchedule( GetScheduleOfType( SCHED_WAIT_TRIGGER ) );
|
ChangeSchedule( GetScheduleOfType( SCHED_WAIT_TRIGGER ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Notify normal game engine of monster classify
|
||||||
|
pev->iuser4 = Classify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1785,25 +1830,35 @@ int CMBaseMonster::TaskIsRunning( void )
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMBaseMonster::IRelationship ( CMBaseEntity *pTarget )
|
int CMBaseMonster::IRelationship ( CMBaseEntity *pTarget )
|
||||||
{
|
{
|
||||||
static int iEnemy[14][14] =
|
return IRelationshipByClass( pTarget->Classify() );
|
||||||
{ // NONE MACH PLYR HPASS HMIL AMIL APASS AMONST APREY APRED INSECT PLRALY PBWPN ABWPN
|
}
|
||||||
/*NONE*/ { R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO },
|
int CMBaseMonster::IRelationship ( int iTargetClass )
|
||||||
/*MACHINE*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_DL, R_DL },
|
{
|
||||||
/*PLAYER*/ { R_NO ,R_DL ,R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_DL, R_DL },
|
return IRelationshipByClass( iTargetClass );
|
||||||
/*HUMANPASSIVE*/{ R_NO ,R_NO ,R_AL ,R_AL ,R_HT ,R_FR ,R_NO ,R_HT ,R_DL ,R_FR ,R_NO ,R_AL, R_NO, R_NO },
|
}
|
||||||
/*HUMANMILITAR*/{ R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_HT ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_HT, R_NO, R_NO },
|
int CMBaseMonster::IRelationshipByClass ( int iClass )
|
||||||
/*ALIENMILITAR*/{ R_NO ,R_DL ,R_HT ,R_DL ,R_HT ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO },
|
{
|
||||||
/*ALIENPASSIVE*/{ R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO },
|
static int iEnemy[16][16] =
|
||||||
/*ALIENMONSTER*/{ R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO },
|
{ // NONE MACH PLYR HPASS HMIL AMIL APASS AMONST APREY APRED INSECT PLRALY PBWPN ABWPN RXPIT RXSHK
|
||||||
/*ALIENPREY */{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_FR ,R_NO ,R_DL, R_NO, R_NO },
|
/*NONE*/ { R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO, R_NO, R_NO },
|
||||||
/*ALIENPREDATO*/{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_DL, R_NO, R_NO },
|
/*MACHINE*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_DL, R_DL, R_DL, R_DL },
|
||||||
/*INSECT*/ { R_FR ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR, R_NO, R_NO },
|
/*PLAYER*/ { R_NO ,R_DL ,R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_DL, R_DL, R_DL, R_DL },
|
||||||
/*PLAYERALLY*/ { R_NO ,R_DL ,R_AL ,R_AL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_NO, R_NO },
|
/*HUMANPASSIVE*/{ R_NO ,R_FR ,R_AL ,R_AL ,R_HT ,R_DL ,R_DL ,R_HT ,R_DL ,R_DL ,R_NO ,R_AL, R_NO, R_NO, R_FR, R_FR },
|
||||||
/*PBIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_NO, R_DL },
|
/*HUMANMILITAR*/{ R_NO ,R_NO ,R_DL ,R_DL ,R_AL ,R_HT ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_NO, R_NO, R_HT, R_HT },
|
||||||
/*ABIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_AL ,R_NO ,R_DL ,R_DL ,R_NO ,R_NO ,R_DL, R_DL, R_NO }
|
/*ALIENMILITAR*/{ R_NO ,R_DL ,R_DL ,R_DL ,R_HT ,R_AL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO, R_DL, R_HT },
|
||||||
|
/*ALIENPASSIVE*/{ R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO, R_NO, R_NO },
|
||||||
|
/*ALIENMONSTER*/{ R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO, R_NO, R_NO },
|
||||||
|
/*ALIENPREY */{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_FR ,R_NO ,R_DL, R_NO, R_NO, R_FR, R_NO },
|
||||||
|
/*ALIENPREDATO*/{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_HT ,R_NO ,R_NO ,R_DL, R_NO, R_NO, R_DL, R_DL },
|
||||||
|
/*INSECT*/ { R_NO ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR, R_NO, R_NO, R_NO, R_NO },
|
||||||
|
/*PLAYERALLY*/ { R_NO ,R_DL ,R_AL ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_NO, R_NO, R_DL, R_DL },
|
||||||
|
/*PBIOWEAPON*/ { R_NO ,R_NO ,R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_NO, R_DL, R_DL, R_DL },
|
||||||
|
/*ABIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_AL ,R_NO ,R_DL ,R_DL ,R_NO ,R_NO ,R_DL, R_DL, R_NO, R_DL, R_DL },
|
||||||
|
/*RXPITDRONE*/ { R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL ,R_DL ,R_NO ,R_DL, R_NO, R_NO, R_AL, R_AL },
|
||||||
|
/*RXSHOCKTRP*/ { R_NO ,R_DL ,R_HT ,R_DL ,R_HT ,R_HT ,R_DL ,R_NO ,R_NO ,R_DL ,R_NO ,R_DL, R_NO, R_NO, R_AL, R_AL }
|
||||||
};
|
};
|
||||||
|
|
||||||
return iEnemy[ Classify() ][ pTarget->Classify() ];
|
return iEnemy[ Classify() ][ iClass ];
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -2034,21 +2089,35 @@ edict_t *CMBaseMonster :: BestVisibleEnemy ( void )
|
|||||||
if ( UTIL_IsPlayer(pEnt) )
|
if ( UTIL_IsPlayer(pEnt) )
|
||||||
{
|
{
|
||||||
// it's a player...
|
// it's a player...
|
||||||
|
if ( UTIL_IsAlive(pEnt) )
|
||||||
|
{
|
||||||
|
// repeat2
|
||||||
|
if ( IRelationshipByClass( CLASS_PLAYER ) > iBestRelationship )
|
||||||
|
{
|
||||||
|
iBestRelationship = IRelationshipByClass( CLASS_PLAYER );
|
||||||
|
iNearest = ( pEnt->v.origin - pev->origin ).Length();
|
||||||
|
pReturn = pEnt;
|
||||||
|
}
|
||||||
|
else if ( IRelationshipByClass( CLASS_PLAYER ) == iBestRelationship )
|
||||||
|
{
|
||||||
iDist = ( pEnt->v.origin - pev->origin ).Length();
|
iDist = ( pEnt->v.origin - pev->origin ).Length();
|
||||||
|
|
||||||
if ( iDist <= iNearest )
|
if ( iDist <= iNearest )
|
||||||
{
|
{
|
||||||
iNearest = iDist;
|
iNearest = iDist;
|
||||||
iBestRelationship = R_NM; // player is always nemsis
|
iBestRelationship = IRelationshipByClass( CLASS_PLAYER );
|
||||||
pReturn = pEnt;
|
pReturn = pEnt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (pEnt->v.euser4 != NULL)
|
else if (pEnt->v.euser4 != NULL)
|
||||||
{
|
{
|
||||||
|
// it's a monstermod monster...
|
||||||
CMBaseMonster *pNextEnt = GetClassPtr((CMBaseMonster *)VARS(pEnt));
|
CMBaseMonster *pNextEnt = GetClassPtr((CMBaseMonster *)VARS(pEnt));
|
||||||
if ( pNextEnt->IsAlive() )
|
if ( pNextEnt->IsAlive() )
|
||||||
{
|
{
|
||||||
if ( IRelationship( pNextEnt) > iBestRelationship )
|
if ( IRelationship( pNextEnt ) > iBestRelationship )
|
||||||
{
|
{
|
||||||
// this entity is disliked MORE than the entity that we
|
// this entity is disliked MORE than the entity that we
|
||||||
// currently think is the best visible enemy. No need to do
|
// currently think is the best visible enemy. No need to do
|
||||||
@@ -2057,7 +2126,7 @@ edict_t *CMBaseMonster :: BestVisibleEnemy ( void )
|
|||||||
iNearest = ( pNextEnt->pev->origin - pev->origin ).Length();
|
iNearest = ( pNextEnt->pev->origin - pev->origin ).Length();
|
||||||
pReturn = pEnt;
|
pReturn = pEnt;
|
||||||
}
|
}
|
||||||
else if ( IRelationship( pNextEnt) == iBestRelationship )
|
else if ( IRelationship( pNextEnt ) == iBestRelationship )
|
||||||
{
|
{
|
||||||
// this entity is disliked just as much as the entity that
|
// this entity is disliked just as much as the entity that
|
||||||
// we currently think is the best visible enemy, so we only
|
// we currently think is the best visible enemy, so we only
|
||||||
@@ -2073,6 +2142,31 @@ edict_t *CMBaseMonster :: BestVisibleEnemy ( void )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// it's a normal game entity...
|
||||||
|
if ( UTIL_IsAlive(pEnt) )
|
||||||
|
{
|
||||||
|
//repeat3
|
||||||
|
if ( IRelationship( pEnt->v.iuser4 ) > iBestRelationship )
|
||||||
|
{
|
||||||
|
iBestRelationship = IRelationship( pEnt->v.iuser4 );
|
||||||
|
iNearest = ( pEnt->v.origin - pev->origin ).Length();
|
||||||
|
pReturn = pEnt;
|
||||||
|
}
|
||||||
|
else if ( IRelationship( pEnt->v.iuser4 ) == iBestRelationship )
|
||||||
|
{
|
||||||
|
iDist = ( pEnt->v.origin - pev->origin ).Length();
|
||||||
|
|
||||||
|
if ( iDist <= iNearest )
|
||||||
|
{
|
||||||
|
iNearest = iDist;
|
||||||
|
iBestRelationship = IRelationship( pEnt->v.iuser4 );
|
||||||
|
pReturn = pEnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
edictList_index++;
|
edictList_index++;
|
||||||
}
|
}
|
||||||
@@ -2144,7 +2238,22 @@ float CMBaseMonster::ChangeYaw ( int yawSpeed )
|
|||||||
ideal = pev->ideal_yaw;
|
ideal = pev->ideal_yaw;
|
||||||
if (current != ideal)
|
if (current != ideal)
|
||||||
{
|
{
|
||||||
speed = (float)yawSpeed * gpGlobals->frametime * 10;
|
// -SamVanheer
|
||||||
|
if ( m_flLastYawTime == 0 )
|
||||||
|
{
|
||||||
|
m_flLastYawTime = gpGlobals->time - gpGlobals->frametime;
|
||||||
|
}
|
||||||
|
|
||||||
|
float delta = gpGlobals->time - m_flLastYawTime;
|
||||||
|
if ( delta > 0.25 )
|
||||||
|
delta = 0.25;
|
||||||
|
|
||||||
|
// let server operators modify the multiplier coeficient -Giegue
|
||||||
|
float multiplier = monster_turn_coeficient->value;
|
||||||
|
if ( multiplier < 0.1 || multiplier > 10.0 )
|
||||||
|
multiplier = 1.75;
|
||||||
|
|
||||||
|
speed = (float)yawSpeed * delta * multiplier;
|
||||||
move = ideal - current;
|
move = ideal - current;
|
||||||
|
|
||||||
if (ideal > current)
|
if (ideal > current)
|
||||||
@@ -2519,6 +2628,36 @@ void CMBaseMonster :: KeyValue( KeyValueData *pkvd )
|
|||||||
m_iClassifyOverride = atoi( pkvd->szValue );
|
m_iClassifyOverride = atoi( pkvd->szValue );
|
||||||
pkvd->fHandled = TRUE;
|
pkvd->fHandled = TRUE;
|
||||||
}
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "bloodcolor"))
|
||||||
|
{
|
||||||
|
switch ( atoi( pkvd->szValue ) )
|
||||||
|
{
|
||||||
|
case -1: m_bloodColor = DONT_BLEED; break;
|
||||||
|
case 1: m_bloodColor = BLOOD_COLOR_RED; break;
|
||||||
|
case 2: m_bloodColor = BLOOD_COLOR_YELLOW; break;
|
||||||
|
case 3: m_bloodColor = BLOOD_COLOR_BLUE; break;
|
||||||
|
case 4: m_bloodColor = BLOOD_COLOR_PINK; break;
|
||||||
|
case 5: m_bloodColor = BLOOD_COLOR_WHITE; break;
|
||||||
|
case 6: m_bloodColor = BLOOD_COLOR_ORANGE; break;
|
||||||
|
case 7: m_bloodColor = BLOOD_COLOR_BLACK; break;
|
||||||
|
case 8: m_bloodColor = BLOOD_COLOR_GREEN; break;
|
||||||
|
default: m_bloodColor = 0; break; // Invalid, set default
|
||||||
|
}
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "soundlist"))
|
||||||
|
{
|
||||||
|
if (strlen( pkvd->szValue ))
|
||||||
|
{
|
||||||
|
process_monster_sound(edict(), pkvd->szValue);
|
||||||
|
}
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "attackrange"))
|
||||||
|
{
|
||||||
|
m_flDistLook = atof(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CMBaseToggle::KeyValue( pkvd );
|
CMBaseToggle::KeyValue( pkvd );
|
||||||
@@ -2882,9 +3021,14 @@ BOOL CMBaseMonster :: GetEnemy ( void )
|
|||||||
if (HasConditions(bits_COND_SEE_CLIENT) && (m_hEnemy == NULL))
|
if (HasConditions(bits_COND_SEE_CLIENT) && (m_hEnemy == NULL))
|
||||||
{
|
{
|
||||||
m_hEnemy = BestVisibleEnemy();
|
m_hEnemy = BestVisibleEnemy();
|
||||||
|
|
||||||
|
// the player we've just seen might not always be our enemy
|
||||||
|
if ( m_hEnemy != NULL )
|
||||||
|
{
|
||||||
m_hTargetEnt = m_hEnemy;
|
m_hTargetEnt = m_hEnemy;
|
||||||
m_vecEnemyLKP = m_hEnemy->v.origin;
|
m_vecEnemyLKP = m_hEnemy->v.origin;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// remember old enemies
|
// remember old enemies
|
||||||
if (m_hEnemy == NULL && PopEnemy( ))
|
if (m_hEnemy == NULL && PopEnemy( ))
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ public:
|
|||||||
virtual int ObjectCaps( void ) { return (CMBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; }
|
virtual int ObjectCaps( void ) { return (CMBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; }
|
||||||
static void SpawnHeadGib( entvars_t *pevVictim );
|
static void SpawnHeadGib( entvars_t *pevVictim );
|
||||||
static void SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human );
|
static void SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human );
|
||||||
|
static void SpawnRandomGibs( entvars_t *pevVictim, int cGibs, const char *pGibModel, int human );
|
||||||
static void SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs );
|
static void SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs );
|
||||||
|
|
||||||
int m_bloodColor;
|
int m_bloodColor;
|
||||||
|
|||||||
61
src/dlls/music.cpp
Normal file
61
src/dlls/music.cpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
//=========================================================
|
||||||
|
// Ambient Music - when triggered, it will play an mp3
|
||||||
|
// music file locally to players, looped or once.
|
||||||
|
//=========================================================
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
#include "cmbaseextra.h"
|
||||||
|
|
||||||
|
// spawnflags
|
||||||
|
#define SF_MUSIC_LOOP 2 // music will loop instead of playing once.
|
||||||
|
#define SF_MUSIC_ACTIVATOR_ONLY 4 // only play to the one that activates this entity.
|
||||||
|
|
||||||
|
void CMAmbientMusic::KeyValue(KeyValueData *pkvd)
|
||||||
|
{
|
||||||
|
CMBaseMonster::KeyValue(pkvd);
|
||||||
|
}
|
||||||
|
void CMAmbientMusic::Spawn()
|
||||||
|
{
|
||||||
|
pev->solid = SOLID_NOT;
|
||||||
|
SetUse(&CMAmbientMusic::MusicUse);
|
||||||
|
pev->classname = MAKE_STRING("ambient_music");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMAmbientMusic::MusicUse(edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value)
|
||||||
|
{
|
||||||
|
// no music
|
||||||
|
if (FStringNull(pev->message))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// not a player (if not to everyone)
|
||||||
|
if (pev->spawnflags & SF_MUSIC_ACTIVATOR_ONLY && !UTIL_IsPlayer(pActivator))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pev->spawnflags & SF_MUSIC_ACTIVATOR_ONLY)
|
||||||
|
MESSAGE_BEGIN(MSG_ONE, SVC_STUFFTEXT, NULL, pActivator);
|
||||||
|
else
|
||||||
|
MESSAGE_BEGIN(MSG_ALL, SVC_STUFFTEXT);
|
||||||
|
|
||||||
|
// triggering off
|
||||||
|
if (useType == USE_OFF || m_fPlaying && useType != USE_ON)
|
||||||
|
{
|
||||||
|
WRITE_STRING("mp3 stop\n");
|
||||||
|
m_fPlaying = FALSE;
|
||||||
|
}
|
||||||
|
else // USE_ON / USE_TOGGLE
|
||||||
|
{
|
||||||
|
char szPath[256];
|
||||||
|
|
||||||
|
if (pev->spawnflags & SF_MUSIC_LOOP)
|
||||||
|
sprintf(szPath, "mp3 loop %s\n", STRING(pev->message));
|
||||||
|
else
|
||||||
|
sprintf(szPath, "mp3 play %s\n", STRING(pev->message));
|
||||||
|
|
||||||
|
WRITE_STRING(szPath);
|
||||||
|
m_fPlaying = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
MESSAGE_END();
|
||||||
|
}
|
||||||
@@ -25,12 +25,12 @@
|
|||||||
#include "animation.h"
|
#include "animation.h"
|
||||||
#include "doors.h"
|
#include "doors.h"
|
||||||
|
|
||||||
//#if !defined ( _WIN32 )
|
#if !defined ( _WIN32 )
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h> // mkdir
|
#include <unistd.h> // mkdir
|
||||||
//#endif
|
#endif
|
||||||
|
|
||||||
#define HULL_STEP_SIZE 16// how far the test hull moves on each step
|
#define HULL_STEP_SIZE 16// how far the test hull moves on each step
|
||||||
#define NODE_HEIGHT 8 // how high to lift nodes off the ground after we drop them all (make stair/ramp mapping easier)
|
#define NODE_HEIGHT 8 // how high to lift nodes off the ground after we drop them all (make stair/ramp mapping easier)
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
// to help eliminate node clutter by level designers, this is used to cap how many other nodes
|
// to help eliminate node clutter by level designers, this is used to cap how many other nodes
|
||||||
// any given node is allowed to 'see' in the first stage of graph creation "LinkVisibleNodes()".
|
// any given node is allowed to 'see' in the first stage of graph creation "LinkVisibleNodes()".
|
||||||
#define MAX_NODE_INITIAL_LINKS 128
|
#define MAX_NODE_INITIAL_LINKS 128
|
||||||
#define MAX_NODES 1024
|
//#define MAX_NODES 1024 // already defined in monster_plugin.h
|
||||||
|
|
||||||
Vector VecBModelOrigin( entvars_t* pevBModel );
|
Vector VecBModelOrigin( entvars_t* pevBModel );
|
||||||
|
|
||||||
@@ -212,6 +212,10 @@ entvars_t* CGraph :: LinkEntForLink ( CLink *pLink, CNode *pNode )
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, NODEQUERY queryType )
|
int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, NODEQUERY queryType )
|
||||||
{
|
{
|
||||||
|
// NULL pointers are becoming a nightmare... -Giegue
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
#if 0
|
||||||
edict_t *pentWorld;
|
edict_t *pentWorld;
|
||||||
CMBaseEntity *pDoor;
|
CMBaseEntity *pDoor;
|
||||||
TraceResult tr;
|
TraceResult tr;
|
||||||
@@ -282,6 +286,7 @@ int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, N
|
|||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@@ -1278,7 +1283,7 @@ int CGraph :: LinkVisibleNodes ( CLink *pLinkPool, FILE *file, int *piBadNode )
|
|||||||
fprintf ( file, " Entity on connection: %s, name: %s Model: %s", STRING( VARS( pTraceEnt )->classname ), STRING ( VARS( pTraceEnt )->targetname ), STRING ( VARS(tr.pHit)->model ) );
|
fprintf ( file, " Entity on connection: %s, name: %s Model: %s", STRING( VARS( pTraceEnt )->classname ), STRING ( VARS( pTraceEnt )->targetname ), STRING ( VARS(tr.pHit)->model ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf ( file, "\n", j );
|
fprintf ( file, "\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
pLinkPool [ cTotalLinks ].m_iDestNode = j;
|
pLinkPool [ cTotalLinks ].m_iDestNode = j;
|
||||||
@@ -1889,17 +1894,17 @@ void CTestHull :: BuildNodeGraph( void )
|
|||||||
switch ( hull )
|
switch ( hull )
|
||||||
{
|
{
|
||||||
case NODE_SMALL_HULL: // if this hull can't fit, nothing can, so drop the connection
|
case NODE_SMALL_HULL: // if this hull can't fit, nothing can, so drop the connection
|
||||||
fprintf ( file, "NODE_SMALL_HULL step %f\n", step );
|
fprintf ( file, "NODE_SMALL_HULL step %i\n", step );
|
||||||
pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~(bits_LINK_SMALL_HULL | bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL);
|
pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~(bits_LINK_SMALL_HULL | bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL);
|
||||||
fSkipRemainingHulls = TRUE;// don't bother checking larger hulls
|
fSkipRemainingHulls = TRUE;// don't bother checking larger hulls
|
||||||
break;
|
break;
|
||||||
case NODE_HUMAN_HULL:
|
case NODE_HUMAN_HULL:
|
||||||
fprintf ( file, "NODE_HUMAN_HULL step %f\n", step );
|
fprintf ( file, "NODE_HUMAN_HULL step %i\n", step );
|
||||||
pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~(bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL);
|
pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~(bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL);
|
||||||
fSkipRemainingHulls = TRUE;// don't bother checking larger hulls
|
fSkipRemainingHulls = TRUE;// don't bother checking larger hulls
|
||||||
break;
|
break;
|
||||||
case NODE_LARGE_HULL:
|
case NODE_LARGE_HULL:
|
||||||
fprintf ( file, "NODE_LARGE_HULL step %f\n", step );
|
fprintf ( file, "NODE_LARGE_HULL step %i\n", step );
|
||||||
pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~bits_LINK_LARGE_HULL;
|
pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~bits_LINK_LARGE_HULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3437,7 +3442,7 @@ void CGraph :: TestRoutingTables( void )
|
|||||||
#endif
|
#endif
|
||||||
ALERT(at_aiconsole, "Routing is inconsistent!!!\n");
|
ALERT(at_aiconsole, "Routing is inconsistent!!!\n");
|
||||||
ALERT(at_aiconsole, "(%d to %d |%d/%d)1:", iFrom, iTo, iHull, iCap);
|
ALERT(at_aiconsole, "(%d to %d |%d/%d)1:", iFrom, iTo, iHull, iCap);
|
||||||
for (int i = 0; i < cPathSize1; i++)
|
for (i = 0; i < cPathSize1; i++)
|
||||||
{
|
{
|
||||||
ALERT(at_aiconsole, "%d ", pMyPath[i]);
|
ALERT(at_aiconsole, "%d ", pMyPath[i]);
|
||||||
}
|
}
|
||||||
|
|||||||
329
src/dlls/otis.cpp
Normal file
329
src/dlls/otis.cpp
Normal file
@@ -0,0 +1,329 @@
|
|||||||
|
// HUGE thanks to DrBeef for his hlsdk-xash3d-opfor repository!
|
||||||
|
|
||||||
|
/***
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* This product contains software technology licensed from Id
|
||||||
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This source code contains proprietary and confidential information of
|
||||||
|
* Valve LLC and its suppliers. Access to this code is restricted to
|
||||||
|
* persons who have executed a written SDK license with Valve. Any access,
|
||||||
|
* use or distribution of this code by or to any unlicensed person is illegal.
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
//=========================================================
|
||||||
|
// monster template
|
||||||
|
//=========================================================
|
||||||
|
// UNDONE: Holster weapon?
|
||||||
|
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
#include "monsters.h"
|
||||||
|
#include "schedule.h"
|
||||||
|
#include "defaultai.h"
|
||||||
|
#include "weapons.h"
|
||||||
|
|
||||||
|
#define NUM_OTIS_HEADS 2 // heads available for otis model
|
||||||
|
|
||||||
|
#define GUN_GROUP 1
|
||||||
|
#define HEAD_GROUP 2
|
||||||
|
|
||||||
|
#define HEAD_HAIR 0
|
||||||
|
#define HEAD_BALD 1
|
||||||
|
|
||||||
|
#define GUN_NONE 0
|
||||||
|
#define GUN_EAGLE 1
|
||||||
|
#define GUN_DONUT 2
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Monster's Anim Events Go Here
|
||||||
|
//=========================================================
|
||||||
|
// first flag is Otis dying for scripted sequences?
|
||||||
|
#define OTIS_AE_DRAW ( 2 )
|
||||||
|
#define OTIS_AE_SHOOT ( 3 )
|
||||||
|
#define OTIS_AE_HOLSTER ( 4 )
|
||||||
|
|
||||||
|
#define OTIS_BODY_GUNHOLSTERED 0
|
||||||
|
#define OTIS_BODY_GUNDRAWN 1
|
||||||
|
#define OTIS_BODY_DONUT 2
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// ALertSound - otis says "Freeze!"
|
||||||
|
//=========================================================
|
||||||
|
void CMOtis::AlertSound(void)
|
||||||
|
{
|
||||||
|
if (m_hEnemy != 0)
|
||||||
|
{
|
||||||
|
if (FOkToSpeak())
|
||||||
|
{
|
||||||
|
PlaySentence("OT_ATTACK", RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// BarneyFirePistol - shoots one round from the pistol at
|
||||||
|
// the enemy otis is facing.
|
||||||
|
//=========================================================
|
||||||
|
void CMOtis::BarneyFirePistol(void)
|
||||||
|
{
|
||||||
|
Vector vecShootOrigin;
|
||||||
|
|
||||||
|
UTIL_MakeVectors(pev->angles);
|
||||||
|
vecShootOrigin = pev->origin + Vector(0, 0, 55);
|
||||||
|
Vector vecShootDir = ShootAtEnemy(vecShootOrigin);
|
||||||
|
|
||||||
|
Vector angDir = UTIL_VecToAngles(vecShootDir);
|
||||||
|
SetBlending(0, angDir.x);
|
||||||
|
pev->effects = EF_MUZZLEFLASH;
|
||||||
|
|
||||||
|
FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, BULLET_MONSTER_357);
|
||||||
|
|
||||||
|
int pitchShift = RANDOM_LONG(0, 20);
|
||||||
|
|
||||||
|
// Only shift about half the time
|
||||||
|
if (pitchShift > 10)
|
||||||
|
pitchShift = 0;
|
||||||
|
else
|
||||||
|
pitchShift -= 5;
|
||||||
|
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "weapons/desert_eagle_fire.wav", 1, ATTN_NORM, 0, 100 + pitchShift);
|
||||||
|
|
||||||
|
// UNDONE: Reload?
|
||||||
|
m_cAmmoLoaded--;// take away a bullet!
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// HandleAnimEvent - catches the monster-specific messages
|
||||||
|
// that occur when tagged animation frames are played.
|
||||||
|
//
|
||||||
|
// Returns number of events handled, 0 if none.
|
||||||
|
//=========================================================
|
||||||
|
void CMOtis::HandleAnimEvent(MonsterEvent_t *pEvent)
|
||||||
|
{
|
||||||
|
switch (pEvent->event)
|
||||||
|
{
|
||||||
|
case OTIS_AE_SHOOT:
|
||||||
|
BarneyFirePistol();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OTIS_AE_DRAW:
|
||||||
|
// otis' bodygroup switches here so he can pull gun from holster
|
||||||
|
// pev->body = OTIS_BODY_GUNDRAWN;
|
||||||
|
SetBodygroup( GUN_GROUP, GUN_EAGLE );
|
||||||
|
m_fGunDrawn = TRUE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OTIS_AE_HOLSTER:
|
||||||
|
// change bodygroup to replace gun in holster
|
||||||
|
// pev->body = OTIS_BODY_GUNHOLSTERED;
|
||||||
|
SetBodygroup( GUN_GROUP, GUN_NONE );
|
||||||
|
m_fGunDrawn = FALSE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CMBarney::HandleAnimEvent(pEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Spawn
|
||||||
|
//=========================================================
|
||||||
|
void CMOtis::Spawn()
|
||||||
|
{
|
||||||
|
Precache();
|
||||||
|
|
||||||
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/otis.mdl"));
|
||||||
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
pev->movetype = MOVETYPE_STEP;
|
||||||
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
|
||||||
|
if (!pev->health) { pev->health = gSkillData.otisHealth; }
|
||||||
|
pev->view_ofs = Vector(0, 0, 50);// position of the eyes relative to monster's origin.
|
||||||
|
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
|
||||||
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
|
|
||||||
|
pev->body = 0; // gun in holster
|
||||||
|
m_fGunDrawn = FALSE;
|
||||||
|
|
||||||
|
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
|
||||||
|
|
||||||
|
// Make sure hands are white.
|
||||||
|
pev->skin = 0;
|
||||||
|
|
||||||
|
// Select a random head.
|
||||||
|
if (head == -1)
|
||||||
|
{
|
||||||
|
SetBodygroup(HEAD_GROUP, RANDOM_LONG(0, NUM_OTIS_HEADS - 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetBodygroup(HEAD_GROUP, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bodystate == -1)
|
||||||
|
{
|
||||||
|
SetBodygroup(GUN_GROUP, RANDOM_LONG(OTIS_BODY_GUNHOLSTERED, OTIS_BODY_GUNDRAWN)); // don't random donut
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetBodygroup(GUN_GROUP, bodystate);
|
||||||
|
}
|
||||||
|
|
||||||
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_otis" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Otis" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Precache - precaches all resources this monster needs
|
||||||
|
//=========================================================
|
||||||
|
void CMOtis::Precache()
|
||||||
|
{
|
||||||
|
PRECACHE_MODEL("models/otis.mdl");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("weapons/desert_eagle_fire.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("barney/ba_pain1.wav");
|
||||||
|
PRECACHE_SOUND("barney/ba_pain2.wav");
|
||||||
|
PRECACHE_SOUND("barney/ba_pain3.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("barney/ba_die1.wav");
|
||||||
|
PRECACHE_SOUND("barney/ba_die2.wav");
|
||||||
|
PRECACHE_SOUND("barney/ba_die3.wav");
|
||||||
|
|
||||||
|
// every new otis must call this, otherwise
|
||||||
|
// when a level is loaded, nobody will talk (time is reset to 0)
|
||||||
|
TalkInit();
|
||||||
|
CMTalkMonster::Precache();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init talk data
|
||||||
|
void CMOtis::TalkInit()
|
||||||
|
{
|
||||||
|
CMTalkMonster::TalkInit();
|
||||||
|
|
||||||
|
// scientists speach group names (group names are in sentences.txt)
|
||||||
|
|
||||||
|
m_szGrp[TLK_ANSWER] = "OT_ANSWER";
|
||||||
|
m_szGrp[TLK_QUESTION] = "OT_QUESTION";
|
||||||
|
m_szGrp[TLK_IDLE] = "OT_IDLE";
|
||||||
|
m_szGrp[TLK_STARE] = "OT_STARE";
|
||||||
|
m_szGrp[TLK_USE] = "OT_OK";
|
||||||
|
m_szGrp[TLK_UNUSE] = "OT_WAIT";
|
||||||
|
m_szGrp[TLK_STOP] = "OT_STOP";
|
||||||
|
|
||||||
|
m_szGrp[TLK_NOSHOOT] = "OT_SCARED";
|
||||||
|
m_szGrp[TLK_HELLO] = "OT_HELLO";
|
||||||
|
|
||||||
|
m_szGrp[TLK_PLHURT1] = "!OT_CUREA";
|
||||||
|
m_szGrp[TLK_PLHURT2] = "!OT_CUREB";
|
||||||
|
m_szGrp[TLK_PLHURT3] = "!OT_CUREC";
|
||||||
|
|
||||||
|
m_szGrp[TLK_PHELLO] = NULL;
|
||||||
|
m_szGrp[TLK_PIDLE] = NULL;
|
||||||
|
m_szGrp[TLK_PQUESTION] = NULL;
|
||||||
|
|
||||||
|
m_szGrp[TLK_SMELL] = "OT_SMELL";
|
||||||
|
|
||||||
|
m_szGrp[TLK_WOUND] = "OT_WOUND";
|
||||||
|
m_szGrp[TLK_MORTAL] = "OT_MORTAL";
|
||||||
|
|
||||||
|
// get voice for head - just one otis voice for now
|
||||||
|
m_voicePitch = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CMOtis::TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType)
|
||||||
|
{
|
||||||
|
// make sure friends talk about it if player hurts talkmonsters...
|
||||||
|
int ret = CMTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType);
|
||||||
|
if (!IsAlive() || pev->deadflag == DEAD_DYING)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (m_MonsterState != MONSTERSTATE_PRONE && (pevAttacker->flags & FL_CLIENT))
|
||||||
|
{
|
||||||
|
// This is a heurstic to determine if the player intended to harm me
|
||||||
|
// If I have an enemy, we can't establish intent (may just be crossfire)
|
||||||
|
if ( ( m_hEnemy != NULL ) && UTIL_IsPlayer(m_hEnemy) )
|
||||||
|
{
|
||||||
|
Remember( bits_MEMORY_PROVOKED );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMOtis::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
|
||||||
|
{
|
||||||
|
switch (ptr->iHitgroup)
|
||||||
|
{
|
||||||
|
case HITGROUP_CHEST:
|
||||||
|
case HITGROUP_STOMACH:
|
||||||
|
if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST))
|
||||||
|
{
|
||||||
|
flDamage = flDamage / 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 10: // Otis wears no helmet, so do not prevent taking headshot damage.
|
||||||
|
// always a head shot
|
||||||
|
ptr->iHitgroup = HITGROUP_HEAD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CMTalkMonster::TraceAttack(pevAttacker, flDamage, vecDir, ptr, bitsDamageType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CMOtis::Killed(entvars_t *pevAttacker, int iGib)
|
||||||
|
{
|
||||||
|
if (GetBodygroup(GUN_GROUP) != OTIS_BODY_GUNHOLSTERED)
|
||||||
|
{
|
||||||
|
// drop the gun!
|
||||||
|
SetBodygroup(GUN_GROUP, OTIS_BODY_GUNHOLSTERED);
|
||||||
|
}
|
||||||
|
|
||||||
|
CMTalkMonster::Killed(pevAttacker, iGib);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// AI Schedules Specific to this monster
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// GetSchedule - Decides which type of schedule best suits
|
||||||
|
// the monster's current state and conditions. Then calls
|
||||||
|
// monster's member function to get a pointer to a schedule
|
||||||
|
// of the proper type.
|
||||||
|
//=========================================================
|
||||||
|
Schedule_t *CMOtis::GetSchedule(void)
|
||||||
|
{
|
||||||
|
if (HasConditions(bits_COND_ENEMY_DEAD) && FOkToSpeak())
|
||||||
|
{
|
||||||
|
PlaySentence("OT_KILL", 4, VOL_NORM, ATTN_NORM);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMBarney::GetSchedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMOtis::KeyValue(KeyValueData *pkvd)
|
||||||
|
{
|
||||||
|
if (FStrEq(pkvd->szKeyName, "head"))
|
||||||
|
{
|
||||||
|
head = atoi(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CMBarney::KeyValue(pkvd);
|
||||||
|
}
|
||||||
1072
src/dlls/pitdrone.cpp
Normal file
1072
src/dlls/pitdrone.cpp
Normal file
File diff suppressed because it is too large
Load Diff
423
src/dlls/rgrunt.cpp
Normal file
423
src/dlls/rgrunt.cpp
Normal file
@@ -0,0 +1,423 @@
|
|||||||
|
/***
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* This product contains software technology licensed from Id
|
||||||
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This source code contains proprietary and confidential information of
|
||||||
|
* Valve LLC and its suppliers. Access to this code is restricted to
|
||||||
|
* persons who have executed a written SDK license with Valve. Any access,
|
||||||
|
* use or distribution of this code by or to any unlicensed person is illegal.
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
//=========================================================
|
||||||
|
// Robo Grunt
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "plane.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
#include "monsters.h"
|
||||||
|
#include "schedule.h"
|
||||||
|
#include "animation.h"
|
||||||
|
#include "weapons.h"
|
||||||
|
#include "cmtalkmonster.h"
|
||||||
|
#include "effects.h"
|
||||||
|
#include "explode.h"
|
||||||
|
#include "customentity.h"
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// monster-specific DEFINE's
|
||||||
|
//=========================================================
|
||||||
|
#define RGRUNT_CLIP_SIZE 36 // how many bullets in a clip? - NOTE: 3 round burst sound, so keep as 3 * x!
|
||||||
|
|
||||||
|
// Weapon flags
|
||||||
|
#define RGRUNT_9MMAR (1 << 0)
|
||||||
|
#define RGRUNT_HANDGRENADE (1 << 1)
|
||||||
|
#define RGRUNT_GRENADELAUNCHER (1 << 2)
|
||||||
|
#define RGRUNT_SHOTGUN (1 << 3)
|
||||||
|
|
||||||
|
// Body groups
|
||||||
|
#define GUN_GROUP 2
|
||||||
|
|
||||||
|
// Gun values
|
||||||
|
#define GUN_MP5 0
|
||||||
|
#define GUN_SHOTGUN 1
|
||||||
|
#define GUN_NONE 2
|
||||||
|
|
||||||
|
// How many sparks to emit when low on health
|
||||||
|
#define RGRUNT_MAX_SPARKS 5
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// This sound is muted for Robo Grunts
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::PainSound(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a gross hack: RGRUNT inherits from HGRUNT, so...
|
||||||
|
// to avoid duplicating code, I'm going to define it here
|
||||||
|
// then use it in hgrunt whenever speech is needed. -Giegue
|
||||||
|
const char *CMRGrunt::pRobotSentences[] =
|
||||||
|
{
|
||||||
|
"RB_GREN", // Sven Co-op uses "RB_" for rgrunt sentences
|
||||||
|
"RB_ALERT",
|
||||||
|
"RB_MONSTER",
|
||||||
|
"RB_COVER",
|
||||||
|
"RB_THROW",
|
||||||
|
"RB_CHARGE",
|
||||||
|
"RB_TAUNT",
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// DeathSound
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::DeathSound(void)
|
||||||
|
{
|
||||||
|
switch ( RANDOM_LONG(0,1) )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
EMIT_SOUND( ENT(pev), CHAN_VOICE, "turret/tu_die.wav", 1, ATTN_IDLE );
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
EMIT_SOUND( ENT(pev), CHAN_VOICE, "turret/tu_die2.wav", 1, ATTN_IDLE );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use this spot to activate the explosion
|
||||||
|
int duration = RANDOM_LONG( 3, 9 );
|
||||||
|
|
||||||
|
/* Smoke effect */
|
||||||
|
// variable smoke balls
|
||||||
|
// 1.7X normal size
|
||||||
|
// 0 radial distribution
|
||||||
|
// instant start
|
||||||
|
SmokeCreate( pev->origin, duration * 7, 17, 0, 0 );
|
||||||
|
|
||||||
|
// "Gib"
|
||||||
|
pev->nextthink = gpGlobals->time + duration;
|
||||||
|
SetThink( &CMRGrunt::StartGib );
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Classify - indicates this monster's place in the
|
||||||
|
// relationship table.
|
||||||
|
//=========================================================
|
||||||
|
int CMRGrunt::Classify(void)
|
||||||
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
|
return CLASS_HUMAN_MILITARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Killed - Explode a few seconds after death
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::Killed(entvars_t *pevAttacker, int iGib)
|
||||||
|
{
|
||||||
|
// Turn off electricity
|
||||||
|
if ( m_flActiveDischarge != 0 )
|
||||||
|
{
|
||||||
|
pev->renderfx = kRenderFxNone;
|
||||||
|
m_flActiveDischarge = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disallow this monster to fade away, need to keep it around for the explosion
|
||||||
|
pev->owner = 0;
|
||||||
|
pev->spawnflags &= ~SF_MONSTER_FADECORPSE;
|
||||||
|
pev->solid = SOLID_NOT; // stop interacting with the world
|
||||||
|
|
||||||
|
CMBaseMonster::Killed(pevAttacker, iGib);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMRGrunt::StartGib(void)
|
||||||
|
{
|
||||||
|
// derp
|
||||||
|
GibMonster();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// GibMonster - Boom!
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::GibMonster()
|
||||||
|
{
|
||||||
|
// Don't call this more times than needed
|
||||||
|
if ( pev->iuser1 != 0 )
|
||||||
|
return;
|
||||||
|
pev->iuser1 = 1;
|
||||||
|
|
||||||
|
Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5;
|
||||||
|
|
||||||
|
// Explosion
|
||||||
|
ExplosionCreate( vecSpot, g_vecZero, ENT(pev), 128, 0, 0 );
|
||||||
|
|
||||||
|
// Wreckage
|
||||||
|
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot );
|
||||||
|
WRITE_BYTE( TE_BREAKMODEL );
|
||||||
|
|
||||||
|
// position
|
||||||
|
WRITE_COORD( vecSpot.x );
|
||||||
|
WRITE_COORD( vecSpot.y );
|
||||||
|
WRITE_COORD( vecSpot.z );
|
||||||
|
|
||||||
|
// size
|
||||||
|
WRITE_COORD( 96 );
|
||||||
|
WRITE_COORD( 96 );
|
||||||
|
WRITE_COORD( 16 );
|
||||||
|
|
||||||
|
// velocity
|
||||||
|
WRITE_COORD( 0 );
|
||||||
|
WRITE_COORD( 0 );
|
||||||
|
WRITE_COORD( 30 );
|
||||||
|
|
||||||
|
// randomization
|
||||||
|
WRITE_BYTE( 15 );
|
||||||
|
|
||||||
|
// Model
|
||||||
|
WRITE_SHORT( m_iBodyGibs ); //model id#
|
||||||
|
|
||||||
|
// # of shards
|
||||||
|
WRITE_BYTE( 35 );
|
||||||
|
|
||||||
|
// duration
|
||||||
|
WRITE_BYTE( 100 );// 5.0 seconds
|
||||||
|
|
||||||
|
// flags
|
||||||
|
WRITE_BYTE( BREAK_METAL );
|
||||||
|
MESSAGE_END();
|
||||||
|
|
||||||
|
SetThink( &CMBaseEntity::SUB_Remove );
|
||||||
|
pev->nextthink = gpGlobals->time;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// RunAI - Robo Grunt emits sparks when its low on health.
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::RunAI(void)
|
||||||
|
{
|
||||||
|
CMBaseMonster::RunAI();
|
||||||
|
|
||||||
|
if ( pev->health <= ( pev->max_health / 10 ) ) // below 10% health
|
||||||
|
{
|
||||||
|
// Spark ON
|
||||||
|
if ( gpGlobals->time > m_flNextSpark )
|
||||||
|
{
|
||||||
|
// Code looks familiar? It's CBaseButton::DoSpark
|
||||||
|
for ( int spark_num = 0; spark_num < RGRUNT_MAX_SPARKS; spark_num++ )
|
||||||
|
{
|
||||||
|
Vector tmp = pev->origin + (pev->mins + pev->maxs) * 0.5; // grab center
|
||||||
|
tmp.x += RANDOM_FLOAT( -( pev->size.x / 2 ), pev->size.x / 2); // then randomize
|
||||||
|
tmp.y += RANDOM_FLOAT( -( pev->size.y / 2 ), pev->size.y / 2);
|
||||||
|
tmp.z += RANDOM_FLOAT( -( pev->size.z / 2 ), pev->size.z / 2);
|
||||||
|
UTIL_Sparks( tmp );
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( (int)(RANDOM_FLOAT(0,1) * 6) )
|
||||||
|
{
|
||||||
|
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark1.wav", 0.6, ATTN_NORM); break;
|
||||||
|
case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark2.wav", 0.6, ATTN_NORM); break;
|
||||||
|
case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark3.wav", 0.6, ATTN_NORM); break;
|
||||||
|
case 3: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark4.wav", 0.6, ATTN_NORM); break;
|
||||||
|
case 4: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark5.wav", 0.6, ATTN_NORM); break;
|
||||||
|
case 5: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", 0.6, ATTN_NORM); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_flNextSpark = gpGlobals->time + 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Glow/Hurt ON
|
||||||
|
if ( gpGlobals->time > m_flNextDischarge )
|
||||||
|
{
|
||||||
|
// Turn on the electric glow
|
||||||
|
pev->renderfx = kRenderFxGlowShell;
|
||||||
|
pev->rendercolor = Vector( 100, 150, 250 ); // r, g, b
|
||||||
|
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_BODY, "debris/beamstart14.wav", 0.8, ATTN_NORM);
|
||||||
|
|
||||||
|
// Sustain the electricity for this long
|
||||||
|
m_flActiveDischarge = gpGlobals->time + RANDOM_FLOAT( 0.3, 0.6 );
|
||||||
|
|
||||||
|
// Discharge again in...
|
||||||
|
m_flNextDischarge = gpGlobals->time + RANDOM_FLOAT( 0.9, 2.7 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Glow/Hurt OFF
|
||||||
|
if ( gpGlobals->time > m_flActiveDischarge )
|
||||||
|
{
|
||||||
|
// Turn off electricity
|
||||||
|
pev->renderfx = kRenderFxNone;
|
||||||
|
m_flActiveDischarge = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// SparkTouch - Hurt players who come too close to it
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::SparkTouch( edict_t *pOther )
|
||||||
|
{
|
||||||
|
// No electricity, no harm
|
||||||
|
if ( m_flActiveDischarge == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Only affect players
|
||||||
|
if ( UTIL_IsPlayer( pOther ) )
|
||||||
|
{
|
||||||
|
// Because of Touch(), players are going to be hurt every server frame.
|
||||||
|
// Don't be bullshit like Sven Co-op, set the damage REALLY LOW.
|
||||||
|
UTIL_TakeDamage( pOther, pev, pev, 1, DMG_SHOCK );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// TraceAttack - Override for robo grunt
|
||||||
|
// Emit ricochet sparks if getting hurt from bullets
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
|
||||||
|
{
|
||||||
|
// Absorb damage and emit ricochet if bullets or melee attacks are used
|
||||||
|
if ( bitsDamageType & ( DMG_BULLET | DMG_SLASH | DMG_CLUB ) )
|
||||||
|
{
|
||||||
|
if ( RANDOM_LONG( 0, 100 ) < 20 )
|
||||||
|
{
|
||||||
|
UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 0.5, 1.5 ) );
|
||||||
|
// EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, pRicSounds[ RANDOM_LONG(0,ARRAYSIZE(pRicSounds)-1) ], 1.0, ATTN_NORM, 0, PITCH_NORM );
|
||||||
|
}
|
||||||
|
flDamage *= (1.00f - gSkillData.rgruntArmor); // cut damage
|
||||||
|
}
|
||||||
|
// Lower protection against explosions
|
||||||
|
else if ( bitsDamageType & DMG_BLAST )
|
||||||
|
flDamage *= (1.00f - (gSkillData.rgruntArmor / 2.00f)); // 50% less protection
|
||||||
|
// No protection at all against other types of damages
|
||||||
|
|
||||||
|
CMBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// TakeDamage - Robo Grunts should not take cover as soon
|
||||||
|
// as they take damage.
|
||||||
|
//=========================================================
|
||||||
|
int CMRGrunt::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
||||||
|
{
|
||||||
|
return CMBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Spawn
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::Spawn()
|
||||||
|
{
|
||||||
|
Precache();
|
||||||
|
|
||||||
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/rgrunt.mdl"));
|
||||||
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
pev->movetype = MOVETYPE_STEP;
|
||||||
|
m_bloodColor = DONT_BLEED;
|
||||||
|
pev->effects = 0;
|
||||||
|
if (!pev->health) { pev->health = gSkillData.rgruntHealth; }
|
||||||
|
pev->max_health = pev->health; // to determine when sparks should be emitted
|
||||||
|
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
|
m_flNextGrenadeCheck = gpGlobals->time + 1;
|
||||||
|
m_flNextPainTime = gpGlobals->time;
|
||||||
|
m_flNextSpark = gpGlobals->time; // when to emit sparks again
|
||||||
|
m_flNextDischarge = gpGlobals->time; // when electric shell should activate
|
||||||
|
m_flActiveDischarge = 0; // how long to sustain the electricity
|
||||||
|
m_iSentence = -1;
|
||||||
|
|
||||||
|
//m_afCapability = bits_CAP_SQUAD | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
|
||||||
|
m_afCapability = bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
|
||||||
|
|
||||||
|
//m_fEnemyEluded = FALSE;
|
||||||
|
m_fFirstEncounter = TRUE;// this is true when the grunt spawns, because he hasn't encountered an enemy yet.
|
||||||
|
|
||||||
|
m_HackedGunPos = Vector(0, 0, 55);
|
||||||
|
|
||||||
|
if (pev->weapons == 0)
|
||||||
|
{
|
||||||
|
// weapons not specified, randomize
|
||||||
|
switch(RANDOM_LONG(0, 2))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
pev->weapons = RGRUNT_9MMAR | RGRUNT_HANDGRENADE;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
pev->weapons = RGRUNT_SHOTGUN;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pev->weapons = RGRUNT_9MMAR | RGRUNT_GRENADELAUNCHER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FBitSet(pev->weapons, RGRUNT_SHOTGUN))
|
||||||
|
{
|
||||||
|
SetBodygroup(GUN_GROUP, GUN_SHOTGUN);
|
||||||
|
m_cClipSize = 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_cClipSize = RGRUNT_CLIP_SIZE;
|
||||||
|
}
|
||||||
|
m_cAmmoLoaded = m_cClipSize;
|
||||||
|
|
||||||
|
CMTalkMonster::g_talkWaitTime = 0;
|
||||||
|
|
||||||
|
MonsterInit();
|
||||||
|
|
||||||
|
SetTouch( &CMRGrunt::SparkTouch );
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_robogrunt" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Robo Grunt" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Precache - precaches all resources this monster needs
|
||||||
|
//=========================================================
|
||||||
|
void CMRGrunt::Precache()
|
||||||
|
{
|
||||||
|
PRECACHE_MODEL("models/rgrunt.mdl");
|
||||||
|
|
||||||
|
m_iBodyGibs = PRECACHE_MODELINDEX( "models/metalplategibs_green.mdl" );
|
||||||
|
|
||||||
|
PRECACHE_SOUND("hgrunt/gr_mgun1.wav");
|
||||||
|
PRECACHE_SOUND("hgrunt/gr_mgun2.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("turret/tu_die.wav");
|
||||||
|
PRECACHE_SOUND("turret/tu_die2.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("buttons/spark1.wav");
|
||||||
|
PRECACHE_SOUND("buttons/spark2.wav");
|
||||||
|
PRECACHE_SOUND("buttons/spark3.wav");
|
||||||
|
PRECACHE_SOUND("buttons/spark4.wav");
|
||||||
|
PRECACHE_SOUND("buttons/spark5.wav");
|
||||||
|
PRECACHE_SOUND("buttons/spark6.wav");
|
||||||
|
PRECACHE_SOUND("debris/beamstart14.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("hgrunt/gr_reload1.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("weapons/glauncher.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("weapons/sbarrel1.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event
|
||||||
|
|
||||||
|
// get voice pitch
|
||||||
|
m_voicePitch = 115; // always the same
|
||||||
|
|
||||||
|
m_iBrassShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell
|
||||||
|
}
|
||||||
456
src/dlls/ripent.cpp
Normal file
456
src/dlls/ripent.cpp
Normal file
@@ -0,0 +1,456 @@
|
|||||||
|
/***
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* This product contains software technology licensed from Id
|
||||||
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
|
||||||
|
// this is a stripped down "bspfile.c" file containing only entity data similar
|
||||||
|
// to using a ripent tool to read ents from a bsp, hence the name.
|
||||||
|
// -Giegue
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "ripent.h"
|
||||||
|
#include "meta_api.h"
|
||||||
|
|
||||||
|
#if defined linux
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
int entdatasize;
|
||||||
|
char dentdata[MAX_MAP_ENTSTRING];
|
||||||
|
|
||||||
|
int num_entities;
|
||||||
|
entity_t entities[MAX_MAP_ENTITIES];
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
dheader_t *header;
|
||||||
|
|
||||||
|
int CopyLump(int lump, void *dest, int size)
|
||||||
|
{
|
||||||
|
int length, ofs;
|
||||||
|
|
||||||
|
length = header->lumps[lump].filelen;
|
||||||
|
ofs = header->lumps[lump].fileofs;
|
||||||
|
|
||||||
|
if (length % size)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "LoadBSPFile: odd lump size");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dest, (byte *)header + ofs, length);
|
||||||
|
|
||||||
|
return length / size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
LoadBSPFile
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void LoadBSPFile(char *filename)
|
||||||
|
{
|
||||||
|
//int i;
|
||||||
|
|
||||||
|
// reset these values
|
||||||
|
entdatasize = 0;
|
||||||
|
num_entities = 0;
|
||||||
|
memset(dentdata, 0, sizeof(dentdata));
|
||||||
|
memset(entities, 0, sizeof(entities));
|
||||||
|
|
||||||
|
//
|
||||||
|
// load the file header
|
||||||
|
//
|
||||||
|
if (LoadFile(filename, (void **)&header) == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// UNDONE: there is no need to swap it...? -Giegue
|
||||||
|
// swap the header
|
||||||
|
/*for (i = 0; i < sizeof(dheader_t) / 4; i++)
|
||||||
|
((int *)header)[i] = LittleLong(((int *)header)[i]);*/
|
||||||
|
|
||||||
|
// game will not load the BSP if it's invalid.
|
||||||
|
// so if this is called, it means something went really wrong loading it
|
||||||
|
if (header->version != BSPVERSION)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "%s is version %i, not %i", filename, header->version, BSPVERSION);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
entdatasize = CopyLump(LUMP_ENTITIES, dentdata, 1);
|
||||||
|
|
||||||
|
free(header); // everything has been copied out
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
ParseEpair
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
epair_t *ParseEpair(void)
|
||||||
|
{
|
||||||
|
epair_t *e;
|
||||||
|
|
||||||
|
e = (epair_t*)malloc(sizeof(epair_t));
|
||||||
|
memset(e, 0, sizeof(epair_t));
|
||||||
|
|
||||||
|
if (strlen(token) >= MAX_KEY - 1)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ParseEpar: token key too long");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
e->key = copystring(token);
|
||||||
|
GetToken(false);
|
||||||
|
if (strlen(token) >= MAX_VALUE - 1)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ParseEpar: token value too long");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
e->value = copystring(token);
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
ParseEntity
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
bool ParseEntity(void)
|
||||||
|
{
|
||||||
|
epair_t *e;
|
||||||
|
entity_t *mapent;
|
||||||
|
|
||||||
|
if (!GetToken(true))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (strcmp(token, "{"))
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ParseEntity: { not found");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_entities == MAX_MAP_ENTITIES)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "num_entities == MAX_MAP_ENTITIES");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapent = &entities[num_entities];
|
||||||
|
num_entities++;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!GetToken(true))
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ParseEntity: EOF without closing brace");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!strcmp(token, "}"))
|
||||||
|
break;
|
||||||
|
e = ParseEpair();
|
||||||
|
e->next = mapent->epairs;
|
||||||
|
mapent->epairs = e;
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
ParseEntities
|
||||||
|
|
||||||
|
Parses the dentdata string into entities
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void ParseEntities(void)
|
||||||
|
{
|
||||||
|
num_entities = 0;
|
||||||
|
ParseFromMemory(dentdata, entdatasize);
|
||||||
|
|
||||||
|
while (ParseEntity())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --
|
||||||
|
/* MERGE cmdlib.c AND scriplib.c INTO ripent.cpp */
|
||||||
|
/* Only add needed functions. */
|
||||||
|
// --
|
||||||
|
|
||||||
|
// -- cmdlib.c --
|
||||||
|
char qdir[1024] = { '\0' };
|
||||||
|
int LoadFile(char *filename, void **bufferptr)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
int length;
|
||||||
|
void *buffer;
|
||||||
|
|
||||||
|
f = SafeOpenRead(filename);
|
||||||
|
if (f == NULL)
|
||||||
|
return -1; // error
|
||||||
|
|
||||||
|
#if defined (_WIN32)
|
||||||
|
length = filelength(fileno(f));
|
||||||
|
#else
|
||||||
|
struct stat st; stat(filename, &st);
|
||||||
|
length = st.st_size;
|
||||||
|
#endif
|
||||||
|
buffer = malloc(length + 1);
|
||||||
|
((char *)buffer)[length] = 0;
|
||||||
|
SafeRead(f, buffer, length);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
*bufferptr = buffer;
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
int LittleLong(int l)
|
||||||
|
{
|
||||||
|
byte b1, b2, b3, b4;
|
||||||
|
|
||||||
|
b1 = l & 255;
|
||||||
|
b2 = (l >> 8) & 255;
|
||||||
|
b3 = (l >> 16) & 255;
|
||||||
|
b4 = (l >> 24) & 255;
|
||||||
|
|
||||||
|
return ((int)b1 << 24) + ((int)b2 << 16) + ((int)b3 << 8) + b4;
|
||||||
|
}
|
||||||
|
char *copystring(char *s)
|
||||||
|
{
|
||||||
|
char *b;
|
||||||
|
b = (char*)malloc(strlen(s) + 1);
|
||||||
|
strcpy(b, s);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *SafeOpenRead(char *filename)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
f = fopen(filename, "rb");
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "Error opening %s: %s", filename, strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
void SafeRead(FILE *f, void *buffer, int count)
|
||||||
|
{
|
||||||
|
if (fread(buffer, 1, count, f) != (size_t)count)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "File read failure");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char *ExpandPath(char *path)
|
||||||
|
{
|
||||||
|
char *psz;
|
||||||
|
static char full[1024];
|
||||||
|
if (!qdir)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "ExpandPath called without qdir set");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (path[0] == '/' || path[0] == '\\' || path[1] == ':')
|
||||||
|
return path;
|
||||||
|
psz = strstr(path, qdir);
|
||||||
|
if (psz)
|
||||||
|
strcpy(full, path);
|
||||||
|
else
|
||||||
|
sprintf(full, "%s%s", qdir, path);
|
||||||
|
|
||||||
|
return full;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- scriplib.c --
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char filename[1024];
|
||||||
|
char *buffer, *script_p, *end_p;
|
||||||
|
int line;
|
||||||
|
} script_t;
|
||||||
|
|
||||||
|
#define MAX_INCLUDES 8
|
||||||
|
script_t scriptstack[MAX_INCLUDES];
|
||||||
|
script_t *script;
|
||||||
|
int scriptline;
|
||||||
|
|
||||||
|
char token[MAXTOKEN];
|
||||||
|
bool endofscript;
|
||||||
|
bool tokenready; // only true if UnGetToken was just called
|
||||||
|
|
||||||
|
void ParseFromMemory(char *buffer, int size)
|
||||||
|
{
|
||||||
|
script = scriptstack;
|
||||||
|
script++;
|
||||||
|
if (script == &scriptstack[MAX_INCLUDES])
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "script file exceeded MAX_INCLUDES");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strcpy(script->filename, "memory buffer");
|
||||||
|
|
||||||
|
script->buffer = buffer;
|
||||||
|
script->line = 1;
|
||||||
|
script->script_p = script->buffer;
|
||||||
|
script->end_p = script->buffer + size;
|
||||||
|
|
||||||
|
endofscript = false;
|
||||||
|
tokenready = false;
|
||||||
|
}
|
||||||
|
bool EndOfScript(bool crossline)
|
||||||
|
{
|
||||||
|
if (!crossline)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "Line %i is incomplete", scriptline);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(script->filename, "memory buffer"))
|
||||||
|
{
|
||||||
|
endofscript = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(script->buffer);
|
||||||
|
if (script == scriptstack + 1)
|
||||||
|
{
|
||||||
|
endofscript = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
script--;
|
||||||
|
scriptline = script->line;
|
||||||
|
//printf("returning to %s\n", script->filename);
|
||||||
|
return GetToken(crossline);
|
||||||
|
}
|
||||||
|
void AddScriptToStack(char *filename)
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
|
||||||
|
script++;
|
||||||
|
if (script == &scriptstack[MAX_INCLUDES])
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "script file exceeded MAX_INCLUDES");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strcpy(script->filename, ExpandPath(filename));
|
||||||
|
|
||||||
|
size = LoadFile(script->filename, (void **)&script->buffer);
|
||||||
|
|
||||||
|
//printf("entering %s\n", script->filename);
|
||||||
|
|
||||||
|
script->line = 1;
|
||||||
|
|
||||||
|
script->script_p = script->buffer;
|
||||||
|
script->end_p = script->buffer + size;
|
||||||
|
}
|
||||||
|
bool GetToken(bool crossline)
|
||||||
|
{
|
||||||
|
char *token_p;
|
||||||
|
|
||||||
|
if (tokenready) // is a token allready waiting?
|
||||||
|
{
|
||||||
|
tokenready = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (script->script_p >= script->end_p)
|
||||||
|
return EndOfScript(crossline);
|
||||||
|
|
||||||
|
//
|
||||||
|
// skip space
|
||||||
|
//
|
||||||
|
skipspace:
|
||||||
|
while (*script->script_p <= 32)
|
||||||
|
{
|
||||||
|
if (script->script_p >= script->end_p)
|
||||||
|
return EndOfScript(crossline);
|
||||||
|
if (*script->script_p++ == '\n')
|
||||||
|
{
|
||||||
|
if (!crossline)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "Line %i is incomplete", scriptline);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
scriptline = script->line++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (script->script_p >= script->end_p)
|
||||||
|
return EndOfScript(crossline);
|
||||||
|
|
||||||
|
if (*script->script_p == ';' || *script->script_p == '#' || // semicolon and # is comment field
|
||||||
|
(*script->script_p == '/' && *((script->script_p) + 1) == '/')) // also make // a comment field
|
||||||
|
{
|
||||||
|
if (!crossline)
|
||||||
|
{
|
||||||
|
LOG_MESSAGE(PLID, "Line %i is incomplete", scriptline);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (*script->script_p++ != '\n')
|
||||||
|
if (script->script_p >= script->end_p)
|
||||||
|
return EndOfScript(crossline);
|
||||||
|
goto skipspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// copy token
|
||||||
|
//
|
||||||
|
token_p = token;
|
||||||
|
|
||||||
|
if (*script->script_p == '"')
|
||||||
|
{
|
||||||
|
// quoted token
|
||||||
|
script->script_p++;
|
||||||
|
while (*script->script_p != '"')
|
||||||
|
{
|
||||||
|
*token_p++ = *script->script_p++;
|
||||||
|
if (script->script_p == script->end_p)
|
||||||
|
break;
|
||||||
|
if (token_p == &token[MAXTOKEN])
|
||||||
|
{
|
||||||
|
// if the server does not crash before this happens, then monstermod will.
|
||||||
|
// simulate a fatal error and be verbose on why it happens.
|
||||||
|
ALERT(at_logged, "FATAL ERROR (shutting down): ReadEntsFromBSP: Line %i is too long (length > %i).", scriptline, MAXTOKEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
script->script_p++;
|
||||||
|
}
|
||||||
|
else // regular token
|
||||||
|
while (*script->script_p > 32 && *script->script_p != ';')
|
||||||
|
{
|
||||||
|
*token_p++ = *script->script_p++;
|
||||||
|
if (script->script_p == script->end_p)
|
||||||
|
break;
|
||||||
|
if (token_p == &token[MAXTOKEN])
|
||||||
|
{
|
||||||
|
// ditto
|
||||||
|
ALERT(at_logged, "FATAL ERROR (shutting down): ReadEntsFromBSP: Line %i is too long (length > %i).", scriptline, MAXTOKEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*token_p = 0;
|
||||||
|
|
||||||
|
if (!strcmp(token, "$include"))
|
||||||
|
{
|
||||||
|
GetToken(false);
|
||||||
|
AddScriptToStack(token);
|
||||||
|
return GetToken(crossline);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
97
src/dlls/ripent.h
Normal file
97
src/dlls/ripent.h
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
/***
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* This product contains software technology licensed from Id
|
||||||
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
|
||||||
|
// this is a stripped down "bspfile.h". contains only entity data similar
|
||||||
|
// to using a ripent tool to read ents from a bsp, hence the name.
|
||||||
|
// -Giegue
|
||||||
|
#include "extdll.h"
|
||||||
|
|
||||||
|
// upper design bounds
|
||||||
|
// some ents are info holders for compiler tools (also -num_edicts is customizable)
|
||||||
|
#define MAX_MAP_ENTITIES 2048
|
||||||
|
#define MAX_MAP_ENTSTRING (128*2048)
|
||||||
|
|
||||||
|
// key / value pair sizes
|
||||||
|
|
||||||
|
#define MAX_KEY 32
|
||||||
|
#define MAX_VALUE 1024
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
#define BSPVERSION 30
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int fileofs, filelen;
|
||||||
|
} lump_t;
|
||||||
|
|
||||||
|
#define LUMP_ENTITIES 0
|
||||||
|
|
||||||
|
#define HEADER_LUMPS 15
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int version;
|
||||||
|
lump_t lumps[HEADER_LUMPS];
|
||||||
|
} dheader_t;
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
// the utilities get to be lazy and just use large static arrays
|
||||||
|
|
||||||
|
extern int entdatasize;
|
||||||
|
extern char dentdata[MAX_MAP_ENTSTRING];
|
||||||
|
|
||||||
|
void LoadBSPFile(char *filename);
|
||||||
|
|
||||||
|
//===============
|
||||||
|
|
||||||
|
typedef struct epair_s
|
||||||
|
{
|
||||||
|
struct epair_s *next;
|
||||||
|
char *key;
|
||||||
|
char *value;
|
||||||
|
} epair_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
vec3_t origin;
|
||||||
|
int firstbrush;
|
||||||
|
int numbrushes;
|
||||||
|
epair_t *epairs;
|
||||||
|
} entity_t;
|
||||||
|
|
||||||
|
extern int num_entities;
|
||||||
|
extern entity_t entities[MAX_MAP_ENTITIES];
|
||||||
|
|
||||||
|
void ParseEntities(void);
|
||||||
|
|
||||||
|
epair_t *ParseEpair(void);
|
||||||
|
|
||||||
|
// --
|
||||||
|
/* MERGE cmdlib.h AND scriplib.h INTO ripent.h */
|
||||||
|
/* Only add needed functions. */
|
||||||
|
// --
|
||||||
|
|
||||||
|
// -- cmdlib.h --
|
||||||
|
int LoadFile(char *filename, void **bufferptr);
|
||||||
|
int LittleLong(int l);
|
||||||
|
char *copystring(char *s);
|
||||||
|
|
||||||
|
FILE *SafeOpenRead(char *filename);
|
||||||
|
void SafeRead(FILE *f, void *buffer, int count);
|
||||||
|
char *ExpandPath(char *path); // from scripts
|
||||||
|
|
||||||
|
// -- scriplib.h --
|
||||||
|
#define MAXTOKEN 4096
|
||||||
|
|
||||||
|
extern char token[MAXTOKEN];
|
||||||
|
bool GetToken(bool crossline);
|
||||||
|
void ParseFromMemory(char *buffer, int size);
|
||||||
@@ -596,13 +596,13 @@ void CMScientist :: Spawn( void )
|
|||||||
// when a level is loaded, nobody will talk (time is reset to 0)
|
// when a level is loaded, nobody will talk (time is reset to 0)
|
||||||
TalkInit();
|
TalkInit();
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/scientist.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/scientist.mdl"));
|
||||||
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
pev->movetype = MOVETYPE_STEP;
|
pev->movetype = MOVETYPE_STEP;
|
||||||
m_bloodColor = BLOOD_COLOR_RED;
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
|
||||||
pev->health = gSkillData.scientistHealth;
|
if (!pev->health) { pev->health = gSkillData.scientistHealth; }
|
||||||
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
|
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
|
||||||
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so scientists will notice player and say hello
|
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so scientists will notice player and say hello
|
||||||
m_MonsterState = MONSTERSTATE_NONE;
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
|
|||||||
68
src/dlls/setcvar.cpp
Normal file
68
src/dlls/setcvar.cpp
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
//=========================================================
|
||||||
|
// Set CVar - trigger_setcvar from Sven Co-op.
|
||||||
|
// Change a map CVar when triggered.
|
||||||
|
//=========================================================
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
#include "cmbaseextra.h"
|
||||||
|
|
||||||
|
#define MAX_CVARS 10
|
||||||
|
|
||||||
|
// list of CVars that can be modified by this entity
|
||||||
|
char *cvar_list[MAX_CVARS]
|
||||||
|
{
|
||||||
|
"mp_falldamage",
|
||||||
|
"mp_flashlight",
|
||||||
|
"mp_fraglimit",
|
||||||
|
"mp_timelimit",
|
||||||
|
"mp_weaponstay",
|
||||||
|
"sv_accelerate",
|
||||||
|
"sv_airaccelerate"
|
||||||
|
"sv_friction",
|
||||||
|
"sv_gravity",
|
||||||
|
"sv_maxspeed"
|
||||||
|
}; // quite lame compared to SC, but many CVars don't exist in vanilla HL
|
||||||
|
|
||||||
|
void CMSetCVar::KeyValue(KeyValueData *pkvd)
|
||||||
|
{
|
||||||
|
if (FStrEq(pkvd->szKeyName, "m_iszCVarToChange"))
|
||||||
|
{
|
||||||
|
for (int index = 0; index < MAX_CVARS; index++)
|
||||||
|
{
|
||||||
|
if (strcmp(pkvd->szValue, cvar_list[index]) == 0)
|
||||||
|
{
|
||||||
|
m_iszCVarToChange = ALLOC_STRING(pkvd->szValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (FStringNull(m_iszCVarToChange))
|
||||||
|
{
|
||||||
|
ALERT(at_console, "trigger_setcvar - can't change CVar \"%s\". not supported!\n", pkvd->szValue);
|
||||||
|
}
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CMBaseMonster::KeyValue(pkvd);
|
||||||
|
}
|
||||||
|
void CMSetCVar::Spawn()
|
||||||
|
{
|
||||||
|
pev->solid = SOLID_NOT;
|
||||||
|
SetUse(&CMSetCVar::ActUse);
|
||||||
|
pev->classname = MAKE_STRING("trigger_setcvar");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMSetCVar::ActUse(edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value)
|
||||||
|
{
|
||||||
|
// nothing to change
|
||||||
|
if (FStringNull(m_iszCVarToChange))
|
||||||
|
return;
|
||||||
|
|
||||||
|
CVAR_SET_FLOAT(STRING(m_iszCVarToChange), atof(STRING(pev->message)));
|
||||||
|
|
||||||
|
if (!FStringNull(pev->netname))
|
||||||
|
{
|
||||||
|
FireTargets(STRING(pev->netname), pActivator, this->edict(), USE_TOGGLE, 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
235
src/dlls/shock.cpp
Normal file
235
src/dlls/shock.cpp
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
// HUGE thanks to DrBeef for his hlsdk-xash3d-opfor repository!
|
||||||
|
|
||||||
|
/***
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* This product contains software technology licensed from Id
|
||||||
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This source code contains proprietary and confidential information of
|
||||||
|
* Valve LLC and its suppliers. Access to this code is restricted to
|
||||||
|
* persons who have executed a written SDK license with Valve. Any access,
|
||||||
|
* use or distribution of this code by or to any unlicensed person is illegal.
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
//=========================================================
|
||||||
|
// shock - projectile shot from shockrifles.
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
#include "monsters.h"
|
||||||
|
#include "schedule.h"
|
||||||
|
#include "effects.h"
|
||||||
|
#include "decals.h"
|
||||||
|
#include "weapons.h"
|
||||||
|
#include "customentity.h"
|
||||||
|
#include "shock.h"
|
||||||
|
|
||||||
|
|
||||||
|
void CMShock::Spawn()
|
||||||
|
{
|
||||||
|
Precache();
|
||||||
|
|
||||||
|
pev->movetype = MOVETYPE_FLY;
|
||||||
|
pev->solid = SOLID_BBOX;
|
||||||
|
pev->classname = MAKE_STRING("shock_beam");
|
||||||
|
SET_MODEL(ENT(pev), "models/shock_effect.mdl");
|
||||||
|
UTIL_SetOrigin(pev, pev->origin);
|
||||||
|
pev->dmg = gSkillData.monDmgShockroach;
|
||||||
|
UTIL_SetSize(pev, Vector(-4, -4, -4), Vector(4, 4, 4));
|
||||||
|
|
||||||
|
CreateEffects();
|
||||||
|
SetThink( &CMShock::FlyThink );
|
||||||
|
pev->nextthink = gpGlobals->time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMShock::Precache()
|
||||||
|
{
|
||||||
|
PRECACHE_MODEL("sprites/flare3.spr");
|
||||||
|
PRECACHE_MODEL("sprites/lgtning.spr");
|
||||||
|
PRECACHE_MODEL("models/shock_effect.mdl");
|
||||||
|
PRECACHE_SOUND("weapons/shock_impact.wav");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMShock::FlyThink()
|
||||||
|
{
|
||||||
|
if (pev->waterlevel == 3)
|
||||||
|
{
|
||||||
|
entvars_t *pevOwner = VARS(pev->owner);
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/shock_impact.wav", VOL_NORM, ATTN_NORM);
|
||||||
|
RadiusDamage(pev->origin, pev, pevOwner ? pevOwner : pev, pev->dmg * 3, 144, CLASS_NONE, DMG_SHOCK | DMG_ALWAYSGIB );
|
||||||
|
ClearEffects();
|
||||||
|
SetThink( &CMBaseEntity::SUB_Remove );
|
||||||
|
pev->nextthink = gpGlobals->time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pev->nextthink = gpGlobals->time + 0.05;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
edict_t *CMShock::Shoot(entvars_t *pevOwner, const Vector angles, const Vector vecStart, const Vector vecVelocity)
|
||||||
|
{
|
||||||
|
CMShock *pShock = CreateClassPtr((CMShock *)NULL);
|
||||||
|
|
||||||
|
if (pShock == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
UTIL_SetOrigin(pShock->pev, vecStart);
|
||||||
|
pShock->Spawn();
|
||||||
|
|
||||||
|
pShock->pev->velocity = vecVelocity;
|
||||||
|
pShock->pev->owner = ENT(pevOwner);
|
||||||
|
pShock->pev->angles = angles;
|
||||||
|
|
||||||
|
pShock->pev->nextthink = gpGlobals->time;
|
||||||
|
|
||||||
|
return pShock->edict();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMShock::Touch(edict_t *pOther)
|
||||||
|
{
|
||||||
|
// Do not collide with the owner.
|
||||||
|
if (pOther == pev->owner)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TraceResult tr = UTIL_GetGlobalTrace( );
|
||||||
|
|
||||||
|
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
||||||
|
WRITE_BYTE(TE_DLIGHT);
|
||||||
|
WRITE_COORD(pev->origin.x); // X
|
||||||
|
WRITE_COORD(pev->origin.y); // Y
|
||||||
|
WRITE_COORD(pev->origin.z); // Z
|
||||||
|
WRITE_BYTE( 8 ); // radius * 0.1
|
||||||
|
WRITE_BYTE( 0 ); // r
|
||||||
|
WRITE_BYTE( 255 ); // g
|
||||||
|
WRITE_BYTE( 255 ); // b
|
||||||
|
WRITE_BYTE( 10 ); // time * 10
|
||||||
|
WRITE_BYTE( 10 ); // decay * 0.1
|
||||||
|
MESSAGE_END( );
|
||||||
|
|
||||||
|
ClearEffects();
|
||||||
|
if (!pOther->v.takedamage)
|
||||||
|
{
|
||||||
|
// make a splat on the wall
|
||||||
|
const int baseDecal = DECAL_SCORCH1;
|
||||||
|
UTIL_DecalTrace(&tr, baseDecal + RANDOM_LONG(0, 1));
|
||||||
|
|
||||||
|
int iContents = UTIL_PointContents(pev->origin);
|
||||||
|
|
||||||
|
// Create sparks
|
||||||
|
if (iContents != CONTENTS_WATER)
|
||||||
|
{
|
||||||
|
UTIL_Sparks(tr.vecEndPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int damageType = DMG_SHOCK;
|
||||||
|
ClearMultiDamage();
|
||||||
|
entvars_t *pevOwner = VARS(pev->owner);
|
||||||
|
entvars_t *pevAttacker = pevOwner ? pevOwner : pev;
|
||||||
|
|
||||||
|
if ( UTIL_IsPlayer( pOther ) )
|
||||||
|
UTIL_TraceAttack( pOther, pevAttacker, pev->dmg, pev->velocity.Normalize(), &tr, damageType );
|
||||||
|
else if ( pOther->v.euser4 != NULL )
|
||||||
|
{
|
||||||
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||||
|
pMonster->TraceAttack( pevAttacker, pev->dmg, pev->velocity.Normalize(), &tr, damageType );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
UTIL_TraceAttack( pOther, pevAttacker, pev->dmg, pev->velocity.Normalize(), &tr, damageType );
|
||||||
|
|
||||||
|
ApplyMultiDamage(pev, pevAttacker);
|
||||||
|
}
|
||||||
|
|
||||||
|
// splat sound
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/shock_impact.wav", VOL_NORM, ATTN_NORM);
|
||||||
|
|
||||||
|
pev->modelindex = 0;
|
||||||
|
pev->solid = SOLID_NOT;
|
||||||
|
SetThink( &CMBaseEntity::SUB_Remove );
|
||||||
|
pev->nextthink = gpGlobals->time + 0.01; // let the sound play
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMShock::CreateEffects()
|
||||||
|
{
|
||||||
|
m_pSprite = CMSprite::SpriteCreate( "sprites/flare3.spr", pev->origin, FALSE );
|
||||||
|
m_pSprite->SetAttachment( edict(), 0 );
|
||||||
|
m_pSprite->pev->scale = 0.35;
|
||||||
|
m_pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 170, kRenderFxNoDissipation );
|
||||||
|
//m_pSprite->pev->spawnflags |= SF_SPRITE_TEMPORARY;
|
||||||
|
//m_pSprite->pev->flags |= FL_SKIPLOCALHOST;
|
||||||
|
|
||||||
|
m_pBeam = CMBeam::BeamCreate( "sprites/lgtning.spr", 30 );
|
||||||
|
|
||||||
|
if (m_pBeam)
|
||||||
|
{
|
||||||
|
m_pBeam->EntsInit( entindex(), entindex() );
|
||||||
|
m_pBeam->SetStartAttachment( 1 );
|
||||||
|
m_pBeam->SetEndAttachment( 2 );
|
||||||
|
m_pBeam->SetBrightness( 180 );
|
||||||
|
m_pBeam->SetScrollRate( 10 );
|
||||||
|
m_pBeam->SetNoise( 0 );
|
||||||
|
m_pBeam->SetFlags( BEAM_FSHADEOUT );
|
||||||
|
m_pBeam->SetColor( 0, 255, 255 );
|
||||||
|
//m_pBeam->pev->spawnflags = SF_BEAM_TEMPORARY;
|
||||||
|
m_pBeam->RelinkBeam();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ALERT(at_console, "Could not create shockbeam beam!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pNoise = CMBeam::BeamCreate( "sprites/lgtning.spr", 30 );
|
||||||
|
|
||||||
|
if (m_pNoise)
|
||||||
|
{
|
||||||
|
m_pNoise->EntsInit( entindex(), entindex() );
|
||||||
|
m_pNoise->SetStartAttachment( 1 );
|
||||||
|
m_pNoise->SetEndAttachment( 2 );
|
||||||
|
m_pNoise->SetBrightness( 180 );
|
||||||
|
m_pNoise->SetScrollRate( 30 );
|
||||||
|
m_pNoise->SetNoise( 30 );
|
||||||
|
m_pNoise->SetFlags( BEAM_FSHADEOUT );
|
||||||
|
m_pNoise->SetColor( 255, 255, 173 );
|
||||||
|
//m_pNoise->pev->spawnflags = SF_BEAM_TEMPORARY;
|
||||||
|
m_pNoise->RelinkBeam();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ALERT(at_console, "Could not create shockbeam noise!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMShock::ClearEffects()
|
||||||
|
{
|
||||||
|
if (m_pBeam)
|
||||||
|
{
|
||||||
|
UTIL_Remove( m_pBeam->edict() );
|
||||||
|
m_pBeam = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pNoise)
|
||||||
|
{
|
||||||
|
UTIL_Remove( m_pNoise->edict() );
|
||||||
|
m_pNoise = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pSprite)
|
||||||
|
{
|
||||||
|
UTIL_Remove( m_pSprite->edict() );
|
||||||
|
m_pSprite = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMShock::UpdateOnRemove()
|
||||||
|
{
|
||||||
|
CMBaseAnimating::UpdateOnRemove();
|
||||||
|
ClearEffects();
|
||||||
|
}
|
||||||
25
src/dlls/shock.h
Normal file
25
src/dlls/shock.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef SHOCKBEAM_H
|
||||||
|
#define SHOCKBEAM_H
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Shockrifle projectile
|
||||||
|
//=========================================================
|
||||||
|
class CMShock : public CMBaseAnimating
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Spawn(void);
|
||||||
|
void Precache(void);
|
||||||
|
|
||||||
|
static edict_t *Shoot(entvars_t *pevOwner, const Vector angles, const Vector vecStart, const Vector vecVelocity);
|
||||||
|
void Touch(edict_t *pOther);
|
||||||
|
void EXPORT FlyThink();
|
||||||
|
|
||||||
|
void CreateEffects();
|
||||||
|
void ClearEffects();
|
||||||
|
void UpdateOnRemove();
|
||||||
|
|
||||||
|
CMBeam *m_pBeam;
|
||||||
|
CMBeam *m_pNoise;
|
||||||
|
CMSprite *m_pSprite;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
246
src/dlls/shockroach.cpp
Normal file
246
src/dlls/shockroach.cpp
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
// HUGE thanks to DrBeef for his hlsdk-xash3d-opfor repository!
|
||||||
|
|
||||||
|
/***
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* This product contains software technology licensed from Id
|
||||||
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This source code contains proprietary and confidential information of
|
||||||
|
* Valve LLC and its suppliers. Access to this code is restricted to
|
||||||
|
* persons who have executed a written SDK license with Valve. Any access,
|
||||||
|
* use or distribution of this code by or to any unlicensed person is illegal.
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
//=========================================================
|
||||||
|
// shockroach.cpp
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
#include "monsters.h"
|
||||||
|
#include "schedule.h"
|
||||||
|
#include "weapons.h"
|
||||||
|
|
||||||
|
#define SR_AE_JUMPATTACK ( 2 )
|
||||||
|
|
||||||
|
const char *CMShockRoach::pIdleSounds[] =
|
||||||
|
{
|
||||||
|
"shockroach/shock_idle1.wav",
|
||||||
|
"shockroach/shock_idle2.wav",
|
||||||
|
"shockroach/shock_idle3.wav",
|
||||||
|
};
|
||||||
|
const char *CMShockRoach::pAlertSounds[] =
|
||||||
|
{
|
||||||
|
"shockroach/shock_angry.wav",
|
||||||
|
};
|
||||||
|
const char *CMShockRoach::pPainSounds[] =
|
||||||
|
{
|
||||||
|
"shockroach/shock_flinch.wav",
|
||||||
|
};
|
||||||
|
const char *CMShockRoach::pAttackSounds[] =
|
||||||
|
{
|
||||||
|
"shockroach/shock_jump1.wav",
|
||||||
|
"shockroach/shock_jump2.wav",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *CMShockRoach::pDeathSounds[] =
|
||||||
|
{
|
||||||
|
"shockroach/shock_die.wav",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *CMShockRoach::pBiteSounds[] =
|
||||||
|
{
|
||||||
|
"shockroach/shock_bite.wav",
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Spawn
|
||||||
|
//=========================================================
|
||||||
|
void CMShockRoach::Spawn()
|
||||||
|
{
|
||||||
|
Precache();
|
||||||
|
|
||||||
|
SET_MODEL(ENT(pev), "models/w_shock_rifle.mdl");
|
||||||
|
UTIL_SetOrigin(pev, pev->origin);
|
||||||
|
|
||||||
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
pev->movetype = MOVETYPE_FLY;
|
||||||
|
m_bloodColor = BLOOD_COLOR_YELLOW;
|
||||||
|
|
||||||
|
pev->effects = 0;
|
||||||
|
pev->health = gSkillData.roachHealth;
|
||||||
|
pev->view_ofs = Vector(0, 0, 20);// position of the eyes relative to monster's origin.
|
||||||
|
pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim?
|
||||||
|
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
|
|
||||||
|
m_fRoachSolid = 0;
|
||||||
|
m_flBirthTime = gpGlobals->time;
|
||||||
|
|
||||||
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_shockroach" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Shock Roach" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Precache - precaches all resources this monster needs
|
||||||
|
//=========================================================
|
||||||
|
void CMShockRoach::Precache()
|
||||||
|
{
|
||||||
|
PRECACHE_SOUND_ARRAY(pIdleSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pAlertSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pPainSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pAttackSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pDeathSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pBiteSounds);
|
||||||
|
|
||||||
|
PRECACHE_SOUND("shockroach/shock_walk.wav");
|
||||||
|
|
||||||
|
PRECACHE_MODEL("models/w_shock_rifle.mdl");
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// LeapTouch - this is the headcrab's touch function when it
|
||||||
|
// is in the air
|
||||||
|
//=========================================================
|
||||||
|
void CMShockRoach::LeapTouch(edict_t *pOther)
|
||||||
|
{
|
||||||
|
if (!pOther->v.takedamage)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't hit if back on ground
|
||||||
|
if (!FBitSet(pev->flags, FL_ONGROUND))
|
||||||
|
{
|
||||||
|
EMIT_SOUND_DYN(edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBiteSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch());
|
||||||
|
|
||||||
|
if (UTIL_IsPlayer(pOther))
|
||||||
|
UTIL_TakeDamage( pOther, pev, pev, GetDamageAmount(), DMG_SLASH );
|
||||||
|
else if (pOther->v.euser4 != NULL)
|
||||||
|
{
|
||||||
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||||
|
pMonster->TakeDamage( pev, pev, GetDamageAmount(), DMG_SLASH );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
UTIL_TakeDamageExternal( pOther, pev, pev, GetDamageAmount(), DMG_SLASH );
|
||||||
|
}
|
||||||
|
|
||||||
|
SetTouch(NULL);
|
||||||
|
}
|
||||||
|
//=========================================================
|
||||||
|
// PrescheduleThink
|
||||||
|
//=========================================================
|
||||||
|
void CMShockRoach::MonsterThink(void)
|
||||||
|
{
|
||||||
|
float lifeTime = (gpGlobals->time - m_flBirthTime);
|
||||||
|
if (lifeTime >= 0.2)
|
||||||
|
{
|
||||||
|
pev->movetype = MOVETYPE_STEP;
|
||||||
|
}
|
||||||
|
if (!m_fRoachSolid && lifeTime >= 2.0 ) {
|
||||||
|
m_fRoachSolid = TRUE;
|
||||||
|
UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 4));
|
||||||
|
}
|
||||||
|
if (lifeTime >= gSkillData.roachLifespan)
|
||||||
|
{
|
||||||
|
pev->health = -1;
|
||||||
|
Killed(pev, 0);
|
||||||
|
//return; // it still needs to think
|
||||||
|
}
|
||||||
|
|
||||||
|
CMHeadCrab::MonsterThink();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// IdleSound
|
||||||
|
//=========================================================
|
||||||
|
void CMShockRoach::IdleSound(void)
|
||||||
|
{
|
||||||
|
EMIT_SOUND_DYN(edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch());
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// AlertSound
|
||||||
|
//=========================================================
|
||||||
|
void CMShockRoach::AlertSound(void)
|
||||||
|
{
|
||||||
|
EMIT_SOUND_DYN(edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAlertSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch());
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// AlertSound
|
||||||
|
//=========================================================
|
||||||
|
void CMShockRoach::PainSound(void)
|
||||||
|
{
|
||||||
|
EMIT_SOUND_DYN(edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch());
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// DeathSound
|
||||||
|
//=========================================================
|
||||||
|
void CMShockRoach::DeathSound(void)
|
||||||
|
{
|
||||||
|
EMIT_SOUND_DYN(edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CMShockRoach::StartTask(Task_t *pTask)
|
||||||
|
{
|
||||||
|
m_iTaskStatus = TASKSTATUS_RUNNING;
|
||||||
|
|
||||||
|
switch (pTask->iTask)
|
||||||
|
{
|
||||||
|
case TASK_RANGE_ATTACK1:
|
||||||
|
{
|
||||||
|
m_IdealActivity = ACT_RANGE_ATTACK1;
|
||||||
|
SetTouch(&CMShockRoach::LeapTouch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
CMHeadCrab::StartTask(pTask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int CMShockRoach::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
||||||
|
{
|
||||||
|
if ( gpGlobals->time - m_flBirthTime < 2.0 )
|
||||||
|
flDamage = 0.0;
|
||||||
|
// Skip headcrab's TakeDamage to avoid unwanted immunity to acid.
|
||||||
|
return CMBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// HandleAnimEvent - catches the monster-specific messages
|
||||||
|
// that occur when tagged animation frames are played.
|
||||||
|
//=========================================================
|
||||||
|
void CMShockRoach::HandleAnimEvent(MonsterEvent_t *pEvent)
|
||||||
|
{
|
||||||
|
CMHeadCrab::HandleAnimEvent(pEvent);
|
||||||
|
|
||||||
|
switch (pEvent->event)
|
||||||
|
{
|
||||||
|
case SR_AE_JUMPATTACK:
|
||||||
|
{
|
||||||
|
// Overwrite attack noise
|
||||||
|
AttackSound();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMShockRoach::AttackSound()
|
||||||
|
{
|
||||||
|
EMIT_SOUND_DYN(edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAttackSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch());
|
||||||
|
}
|
||||||
@@ -72,11 +72,47 @@ skill_cfg_t skill_cfg[] = {
|
|||||||
{"sk_turret_health", &gSkillData.turretHealth},
|
{"sk_turret_health", &gSkillData.turretHealth},
|
||||||
{"sk_miniturret_health", &gSkillData.miniturretHealth},
|
{"sk_miniturret_health", &gSkillData.miniturretHealth},
|
||||||
{"sk_sentry_health", &gSkillData.sentryHealth},
|
{"sk_sentry_health", &gSkillData.sentryHealth},
|
||||||
|
{"sk_gonome_health", &gSkillData.gonomeHealth},
|
||||||
|
{"sk_gonome_dmg_guts", &gSkillData.gonomeDmgGuts},
|
||||||
|
{"sk_gonome_dmg_one_slash", &gSkillData.gonomeDmgOneSlash},
|
||||||
|
{"sk_gonome_dmg_one_bite", &gSkillData.gonomeDmgOneBite},
|
||||||
|
{"sk_massassin_health", &gSkillData.massnHealth},
|
||||||
|
{"sk_massassin_kick", &gSkillData.massnDmgKick},
|
||||||
|
{"sk_otis_health", &gSkillData.otisHealth},
|
||||||
|
{"sk_pitdrone_health", &gSkillData.pitdroneHealth},
|
||||||
|
{"sk_pitdrone_dmg_spit", &gSkillData.pitdroneDmgSpit},
|
||||||
|
{"sk_pitdrone_dmg_whip", &gSkillData.pitdroneDmgWhip},
|
||||||
|
{"sk_pitdrone_dmg_bite", &gSkillData.pitdroneDmgBite},
|
||||||
|
{"sk_shockroach_health", &gSkillData.roachHealth},
|
||||||
|
{"sk_shockroach_lifespan", &gSkillData.roachLifespan},
|
||||||
|
{"sk_shocktrooper_health", &gSkillData.strooperHealth},
|
||||||
|
{"sk_shocktrooper_kick", &gSkillData.strooperDmgKick},
|
||||||
|
{"sk_shocktrooper_maxcharge", &gSkillData.strooperMaxCharge},
|
||||||
|
{"sk_shocktrooper_rchgspeed", &gSkillData.strooperRchgSpeed},
|
||||||
|
{"sk_voltigore_health", &gSkillData.voltigoreHealth},
|
||||||
|
{"sk_voltigore_dmg_beam", &gSkillData.voltigoreDmgBeam},
|
||||||
|
{"sk_voltigore_dmg_punch", &gSkillData.voltigoreDmgPunch},
|
||||||
|
{"sk_babyvoltigore_health", &gSkillData.babyVoltigoreHealth},
|
||||||
|
{"sk_babyvoltigore_dmg_punch", &gSkillData.babyVoltigoreDmgPunch},
|
||||||
|
{"sk_babygarg_health", &gSkillData.babygargHealth},
|
||||||
|
{"sk_babygarg_dmg_slash", &gSkillData.babygargDmgSlash},
|
||||||
|
{"sk_babygarg_dmg_fire", &gSkillData.babygargDmgFire},
|
||||||
|
{"sk_babygarg_dmg_stomp", &gSkillData.babygargDmgStomp},
|
||||||
|
{"sk_hwgrunt_health", &gSkillData.hwgruntHealth},
|
||||||
|
{"sk_rgrunt_health", &gSkillData.rgruntHealth},
|
||||||
|
{"sk_rgrunt_armor", &gSkillData.rgruntArmor},
|
||||||
|
{"sk_stukabat_health", &gSkillData.stukabatHealth},
|
||||||
|
{"sk_stukabat_dmg_bite", &gSkillData.stukabatDmgBite},
|
||||||
|
{"sk_stukabat_speed", &gSkillData.stukabatSpeed},
|
||||||
{"sk_12mm_bullet", &gSkillData.monDmg9MM},
|
{"sk_12mm_bullet", &gSkillData.monDmg9MM},
|
||||||
{"sk_9mmAR_bullet", &gSkillData.monDmgMP5},
|
{"sk_9mmAR_bullet", &gSkillData.monDmgMP5},
|
||||||
{"sk_9mm_bullet", &gSkillData.monDmg12MM},
|
{"sk_9mm_bullet", &gSkillData.monDmg12MM},
|
||||||
{"sk_9mmAR_grenade", &gSkillData.monDmgM203Grenade},
|
{"sk_9mmAR_grenade", &gSkillData.monDmgM203Grenade},
|
||||||
|
{"sk_762_bullet", &gSkillData.monDmg762},
|
||||||
|
{"sk_357_bullet", &gSkillData.monDmg357},
|
||||||
{"sk_hornet_dmg", &gSkillData.monDmgHornet},
|
{"sk_hornet_dmg", &gSkillData.monDmgHornet},
|
||||||
|
{"sk_shock_dmg", &gSkillData.monDmgShockroach},
|
||||||
|
{"sk_spore_dmg", &gSkillData.monDmgSpore},
|
||||||
{"", NULL}
|
{"", NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -212,15 +248,78 @@ void monster_skill_init(void)
|
|||||||
// Sentry
|
// Sentry
|
||||||
gSkillData.sentryHealth = 40.0f;
|
gSkillData.sentryHealth = 40.0f;
|
||||||
|
|
||||||
|
// Gonome
|
||||||
|
gSkillData.gonomeHealth = 85.0f;
|
||||||
|
gSkillData.gonomeDmgGuts = 10.0f;
|
||||||
|
gSkillData.gonomeDmgOneSlash = 20.0f;
|
||||||
|
gSkillData.gonomeDmgOneBite = 14.0f;
|
||||||
|
|
||||||
|
// Male Assassin
|
||||||
|
gSkillData.massnHealth = 50.0f;
|
||||||
|
gSkillData.massnDmgKick = 25.0f;
|
||||||
|
|
||||||
|
// Otis
|
||||||
|
gSkillData.otisHealth = 35.0f;
|
||||||
|
|
||||||
|
// Pit Drone
|
||||||
|
gSkillData.pitdroneHealth = 40.0f;
|
||||||
|
gSkillData.pitdroneDmgSpit = 10.0f;
|
||||||
|
gSkillData.pitdroneDmgWhip = 35.0f;
|
||||||
|
gSkillData.pitdroneDmgBite = 25.0f;
|
||||||
|
|
||||||
|
// Shock Roach
|
||||||
|
gSkillData.roachHealth = 10.0f;
|
||||||
|
gSkillData.roachLifespan = 10.0f;
|
||||||
|
|
||||||
|
// Shock Trooper
|
||||||
|
gSkillData.strooperHealth = 50.0f;
|
||||||
|
gSkillData.strooperDmgKick = 10.0f;
|
||||||
|
gSkillData.strooperMaxCharge = 8.0f;
|
||||||
|
gSkillData.strooperRchgSpeed = 1.0f;
|
||||||
|
|
||||||
|
// Voltigore
|
||||||
|
gSkillData.voltigoreHealth = 320.0f;
|
||||||
|
gSkillData.voltigoreDmgBeam = 50.0f;
|
||||||
|
gSkillData.voltigoreDmgPunch = 40.0f;
|
||||||
|
|
||||||
|
// Baby Voltigore
|
||||||
|
gSkillData.babyVoltigoreHealth = 60.0f;
|
||||||
|
gSkillData.babyVoltigoreDmgPunch = 15.0f;
|
||||||
|
|
||||||
|
// Baby Gargantua
|
||||||
|
gSkillData.babygargHealth = 640.0f;
|
||||||
|
gSkillData.babygargDmgSlash = 24.0f;
|
||||||
|
gSkillData.babygargDmgFire = 4.0f;
|
||||||
|
gSkillData.babygargDmgStomp = 80.0f;
|
||||||
|
|
||||||
|
// Heavy Weapons Grunt
|
||||||
|
gSkillData.hwgruntHealth = 60.0f;
|
||||||
|
|
||||||
|
// Robo Grunt
|
||||||
|
gSkillData.rgruntHealth = 50.0f;
|
||||||
|
gSkillData.rgruntArmor = 0.75f;
|
||||||
|
|
||||||
|
// Stukabat
|
||||||
|
gSkillData.stukabatHealth = 80.0f;
|
||||||
|
gSkillData.stukabatDmgBite = 12.0f;
|
||||||
|
gSkillData.stukabatSpeed = 400.0f;
|
||||||
|
|
||||||
// MONSTER WEAPONS
|
// MONSTER WEAPONS
|
||||||
gSkillData.monDmg9MM = 5.0f;
|
gSkillData.monDmg9MM = 5.0f;
|
||||||
gSkillData.monDmgMP5 = 4.0f;
|
gSkillData.monDmgMP5 = 4.0f;
|
||||||
gSkillData.monDmg12MM = 10.0f;
|
gSkillData.monDmg12MM = 10.0f;
|
||||||
gSkillData.monDmgM203Grenade = 100.0f;
|
gSkillData.monDmgM203Grenade = 100.0f;
|
||||||
|
gSkillData.monDmg762 = 100.0f;
|
||||||
|
gSkillData.monDmg357 = 40.0f;
|
||||||
|
|
||||||
// HORNET
|
// HORNET
|
||||||
gSkillData.monDmgHornet = 5.0f;
|
gSkillData.monDmgHornet = 5.0f;
|
||||||
|
|
||||||
|
// SHOCK ROACH
|
||||||
|
gSkillData.monDmgShockroach = 15.0f;
|
||||||
|
|
||||||
|
// SPORE GRENADE
|
||||||
|
gSkillData.monDmgSpore = 50.0f;
|
||||||
|
|
||||||
// find the directory name of the currently running MOD...
|
// find the directory name of the currently running MOD...
|
||||||
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
||||||
|
|||||||
@@ -86,13 +86,65 @@ struct skilldata_t
|
|||||||
float miniturretHealth;
|
float miniturretHealth;
|
||||||
float sentryHealth;
|
float sentryHealth;
|
||||||
|
|
||||||
|
|
||||||
|
//OP4 monsters
|
||||||
|
float gonomeHealth;
|
||||||
|
float gonomeDmgGuts;
|
||||||
|
float gonomeDmgOneSlash;
|
||||||
|
float gonomeDmgOneBite;
|
||||||
|
|
||||||
|
float massnHealth;
|
||||||
|
float massnDmgKick;
|
||||||
|
|
||||||
|
float otisHealth;
|
||||||
|
|
||||||
|
float pitdroneHealth;
|
||||||
|
float pitdroneDmgSpit;
|
||||||
|
float pitdroneDmgWhip;
|
||||||
|
float pitdroneDmgBite;
|
||||||
|
|
||||||
|
float roachHealth;
|
||||||
|
float roachLifespan;
|
||||||
|
|
||||||
|
float strooperHealth;
|
||||||
|
float strooperDmgKick;
|
||||||
|
float strooperMaxCharge;
|
||||||
|
float strooperRchgSpeed;
|
||||||
|
|
||||||
|
float voltigoreHealth;
|
||||||
|
float voltigoreDmgBeam;
|
||||||
|
float voltigoreDmgPunch;
|
||||||
|
|
||||||
|
float babyVoltigoreHealth;
|
||||||
|
float babyVoltigoreDmgPunch;
|
||||||
|
|
||||||
|
|
||||||
|
//SC monsters
|
||||||
|
float babygargHealth;
|
||||||
|
float babygargDmgSlash;
|
||||||
|
float babygargDmgFire;
|
||||||
|
float babygargDmgStomp;
|
||||||
|
|
||||||
|
float hwgruntHealth;
|
||||||
|
|
||||||
|
float rgruntHealth;
|
||||||
|
float rgruntArmor;
|
||||||
|
|
||||||
|
float stukabatHealth;
|
||||||
|
float stukabatDmgBite;
|
||||||
|
float stukabatSpeed;
|
||||||
|
|
||||||
// weapons shared by monsters
|
// weapons shared by monsters
|
||||||
float monDmg9MM;
|
float monDmg9MM;
|
||||||
float monDmgMP5;
|
float monDmgMP5;
|
||||||
float monDmg12MM;
|
float monDmg12MM;
|
||||||
float monDmgM203Grenade;
|
float monDmgM203Grenade;
|
||||||
|
float monDmg762;
|
||||||
|
float monDmg357;
|
||||||
|
|
||||||
float monDmgHornet;
|
float monDmgHornet;
|
||||||
|
float monDmgShockroach;
|
||||||
|
float monDmgSpore;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern DLL_GLOBAL skilldata_t gSkillData;
|
extern DLL_GLOBAL skilldata_t gSkillData;
|
||||||
|
|||||||
@@ -540,8 +540,7 @@ int SENTENCEG_Lookup(const char *sample, char *sentencenum)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation,
|
void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch)
|
||||||
int flags, int pitch)
|
|
||||||
{
|
{
|
||||||
if (sample && *sample == '!')
|
if (sample && *sample == '!')
|
||||||
{
|
{
|
||||||
@@ -552,7 +551,7 @@ void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volu
|
|||||||
ALERT( at_aiconsole, "Unable to find %s in sentences.txt\n", sample );
|
ALERT( at_aiconsole, "Unable to find %s in sentences.txt\n", sample );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
EMIT_SOUND_DYN2(entity, channel, sample, volume, attenuation, flags, pitch);
|
EMIT_SOUND_DYN2(entity, channel, REPLACER::FindSoundReplacement( entity, sample ), volume, attenuation, flags, pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
// play a specific sentence over the HEV suit speaker - just pass player entity, and !sentencename
|
// play a specific sentence over the HEV suit speaker - just pass player entity, and !sentencename
|
||||||
|
|||||||
353
src/dlls/sporegrenade.cpp
Normal file
353
src/dlls/sporegrenade.cpp
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
// HUGE thanks to DrBeef for his hlsdk-xash3d-opfor repository!
|
||||||
|
|
||||||
|
/***
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* This product contains software technology licensed from Id
|
||||||
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use, distribution, and modification of this source code and/or resulting
|
||||||
|
* object code is restricted to non-commercial enhancements to products from
|
||||||
|
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||||
|
* without written permission from Valve LLC.
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
|
||||||
|
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
#include "monsters.h"
|
||||||
|
#include "weapons.h"
|
||||||
|
#include "decals.h"
|
||||||
|
#include "explode.h"
|
||||||
|
|
||||||
|
int gSporeExplode, gSporeExplodeC;
|
||||||
|
|
||||||
|
void CMSporeGrenade::Precache()
|
||||||
|
{
|
||||||
|
PRECACHE_MODEL("models/spore.mdl");
|
||||||
|
PRECACHE_MODEL("sprites/glow02.spr");
|
||||||
|
g_sModelIndexTinySpit = PRECACHE_MODELINDEX("sprites/tinyspit.spr");
|
||||||
|
gSporeExplode = PRECACHE_MODELINDEX("sprites/spore_exp_01.spr");
|
||||||
|
gSporeExplodeC = PRECACHE_MODELINDEX("sprites/spore_exp_c_01.spr");
|
||||||
|
PRECACHE_SOUND("weapons/splauncher_bounce.wav");
|
||||||
|
PRECACHE_SOUND("weapons/splauncher_impact.wav");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMSporeGrenade::Explode(TraceResult *pTrace)
|
||||||
|
{
|
||||||
|
if (m_hOwner == NULL)
|
||||||
|
pev->owner = NULL;
|
||||||
|
|
||||||
|
pev->solid = SOLID_NOT;// intangible
|
||||||
|
pev->takedamage = DAMAGE_NO;
|
||||||
|
|
||||||
|
// Pull out of the wall a bit
|
||||||
|
if (pTrace->flFraction != 1.0)
|
||||||
|
{
|
||||||
|
pev->origin = pTrace->vecEndPos + (pTrace->vecPlaneNormal * (pev->dmg - 24) * 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector vecSpraySpot = pTrace->vecEndPos;
|
||||||
|
float flSpraySpeed = RANDOM_LONG(10, 15);
|
||||||
|
|
||||||
|
// If the trace is pointing up, then place
|
||||||
|
// spawn position a few units higher.
|
||||||
|
if (pTrace->vecPlaneNormal.z > 0)
|
||||||
|
{
|
||||||
|
vecSpraySpot = vecSpraySpot + (pTrace->vecPlaneNormal * 8);
|
||||||
|
flSpraySpeed *= 2; // Double the speed to make them fly higher
|
||||||
|
// in the air.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn small particles at the explosion origin.
|
||||||
|
SpawnExplosionParticles(
|
||||||
|
vecSpraySpot, // position
|
||||||
|
pTrace->vecPlaneNormal, // direction
|
||||||
|
g_sModelIndexTinySpit, // modelindex
|
||||||
|
RANDOM_LONG(40, 50), // count
|
||||||
|
flSpraySpeed, // speed
|
||||||
|
RANDOM_FLOAT(600, 640)); // noise
|
||||||
|
|
||||||
|
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
|
||||||
|
WRITE_BYTE( TE_SPRITE );
|
||||||
|
WRITE_COORD( pev->origin.x );
|
||||||
|
WRITE_COORD( pev->origin.y );
|
||||||
|
WRITE_COORD( pev->origin.z );
|
||||||
|
WRITE_SHORT( RANDOM_LONG( 0, 1 ) ? gSporeExplode : gSporeExplodeC );
|
||||||
|
WRITE_BYTE( 25 ); // scale * 10
|
||||||
|
WRITE_BYTE( 155 ); // framerate
|
||||||
|
MESSAGE_END();
|
||||||
|
|
||||||
|
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
||||||
|
WRITE_BYTE(TE_DLIGHT);
|
||||||
|
WRITE_COORD( pev->origin.x ); // X
|
||||||
|
WRITE_COORD( pev->origin.y ); // Y
|
||||||
|
WRITE_COORD( pev->origin.z ); // Z
|
||||||
|
WRITE_BYTE( 12 ); // radius * 0.1
|
||||||
|
WRITE_BYTE( 0 ); // r
|
||||||
|
WRITE_BYTE( 180 ); // g
|
||||||
|
WRITE_BYTE( 0 ); // b
|
||||||
|
WRITE_BYTE( 20 ); // time * 10
|
||||||
|
WRITE_BYTE( 20 ); // decay * 0.1
|
||||||
|
MESSAGE_END( );
|
||||||
|
|
||||||
|
// Play explode sound.
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/splauncher_impact.wav", 1, ATTN_NORM);
|
||||||
|
|
||||||
|
entvars_t *pevOwner;
|
||||||
|
if (pev->owner)
|
||||||
|
pevOwner = VARS(pev->owner);
|
||||||
|
else
|
||||||
|
pevOwner = NULL;
|
||||||
|
|
||||||
|
pev->owner = NULL; // can't traceline attack owner if this is set
|
||||||
|
|
||||||
|
RadiusDamage(pev, pevOwner, pev->dmg, CLASS_NONE, DMG_BLAST | DMG_POISON);
|
||||||
|
|
||||||
|
// Place a decal on the surface that was hit.
|
||||||
|
UTIL_DecalTrace(pTrace, DECAL_SPIT1 + RANDOM_LONG(0, 1));
|
||||||
|
|
||||||
|
UpdateOnRemove();
|
||||||
|
UTIL_Remove( this->edict() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMSporeGrenade::Detonate()
|
||||||
|
{
|
||||||
|
TraceResult tr;
|
||||||
|
Vector vecSpot = pev->origin + Vector(0, 0, 8);
|
||||||
|
UTIL_TraceLine(vecSpot, vecSpot + Vector(0, 0, -40), ignore_monsters, ENT(pev), &tr);
|
||||||
|
|
||||||
|
Explode(&tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CMSporeGrenade::BounceSound()
|
||||||
|
{
|
||||||
|
if (m_hOwner == NULL)
|
||||||
|
pev->owner = NULL;
|
||||||
|
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/splauncher_bounce.wav", 0.25, ATTN_NORM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMSporeGrenade::TumbleThink()
|
||||||
|
{
|
||||||
|
if (!IsInWorld())
|
||||||
|
{
|
||||||
|
UpdateOnRemove();
|
||||||
|
UTIL_Remove( this->edict() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pev->nextthink = gpGlobals->time + 0.1;
|
||||||
|
|
||||||
|
if (pev->dmgtime <= gpGlobals->time)
|
||||||
|
{
|
||||||
|
SetThink(&CMSporeGrenade::Detonate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn particles.
|
||||||
|
SpawnTrailParticles(
|
||||||
|
pev->origin, // position
|
||||||
|
-pev->velocity.Normalize(), // dir
|
||||||
|
g_sModelIndexTinySpit, // modelindex
|
||||||
|
RANDOM_LONG( 2, 4 ), // count
|
||||||
|
RANDOM_FLOAT(10, 15), // speed
|
||||||
|
RANDOM_FLOAT(2, 3) * 100); // noise ( client will divide by 100 )
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Contact grenade, explode when it touches something
|
||||||
|
//
|
||||||
|
void CMSporeGrenade::ExplodeTouch(edict_t *pOther)
|
||||||
|
{
|
||||||
|
TraceResult tr;
|
||||||
|
Vector vecSpot;// trace starts here!
|
||||||
|
|
||||||
|
pev->enemy = pOther;
|
||||||
|
|
||||||
|
vecSpot = pev->origin - pev->velocity.Normalize() * 32;
|
||||||
|
UTIL_TraceLine(vecSpot, vecSpot + pev->velocity.Normalize() * 64, ignore_monsters, ENT(pev), &tr);
|
||||||
|
|
||||||
|
Explode(&tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMSporeGrenade::DangerSoundThink()
|
||||||
|
{
|
||||||
|
if (!IsInWorld())
|
||||||
|
{
|
||||||
|
UpdateOnRemove();
|
||||||
|
UTIL_Remove( this->edict() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pev->nextthink = gpGlobals->time + 0.2;
|
||||||
|
|
||||||
|
// Spawn particles.
|
||||||
|
SpawnTrailParticles(
|
||||||
|
pev->origin, // position
|
||||||
|
-pev->velocity.Normalize(), // dir
|
||||||
|
g_sModelIndexTinySpit, // modelindex
|
||||||
|
RANDOM_LONG( 5, 10), // count
|
||||||
|
RANDOM_FLOAT(10, 15), // speed
|
||||||
|
RANDOM_FLOAT(2, 3) * 100); // noise ( client will divide by 100 )
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMSporeGrenade::BounceTouch(edict_t *pOther)
|
||||||
|
{
|
||||||
|
if ( !pOther->v.takedamage )
|
||||||
|
{
|
||||||
|
if (!(pev->flags & FL_ONGROUND)) {
|
||||||
|
if (pev->dmg_save < gpGlobals->time) {
|
||||||
|
BounceSound();
|
||||||
|
pev->dmg_save = gpGlobals->time + 0.1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pev->velocity = pev->velocity * 0.9;
|
||||||
|
}
|
||||||
|
if (pev->flags & FL_SWIM)
|
||||||
|
{
|
||||||
|
pev->velocity = pev->velocity * 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TraceResult tr = UTIL_GetGlobalTrace();
|
||||||
|
Explode(&tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMSporeGrenade::Spawn()
|
||||||
|
{
|
||||||
|
Precache();
|
||||||
|
pev->classname = MAKE_STRING("spore");
|
||||||
|
pev->movetype = MOVETYPE_BOUNCE;
|
||||||
|
|
||||||
|
pev->solid = SOLID_BBOX;
|
||||||
|
|
||||||
|
SET_MODEL(ENT(pev), "models/spore.mdl");
|
||||||
|
UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0));
|
||||||
|
|
||||||
|
//pev->gravity = 0.5;
|
||||||
|
|
||||||
|
pev->dmg = gSkillData.monDmgSpore;
|
||||||
|
|
||||||
|
m_pSporeGlow = CMSprite::SpriteCreate("sprites/glow02.spr", pev->origin, FALSE);
|
||||||
|
|
||||||
|
if (m_pSporeGlow)
|
||||||
|
{
|
||||||
|
m_pSporeGlow->SetTransparency(kRenderGlow, 150, 158, 19, 155, kRenderFxNoDissipation);
|
||||||
|
m_pSporeGlow->SetAttachment(edict(), 0);
|
||||||
|
m_pSporeGlow->SetScale(.75f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CMSporeGrenade* CMSporeGrenade::ShootTimed(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, bool ai)
|
||||||
|
{
|
||||||
|
CMSporeGrenade *pGrenade = CreateClassPtr((CMSporeGrenade *)NULL);
|
||||||
|
|
||||||
|
if (pGrenade == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
UTIL_SetOrigin(pGrenade->pev, vecStart);
|
||||||
|
pGrenade->Spawn();
|
||||||
|
pGrenade->pev->velocity = vecVelocity;
|
||||||
|
pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity);
|
||||||
|
pGrenade->pev->owner = ENT(pevOwner);
|
||||||
|
pGrenade->m_hOwner = ENT(pevOwner);
|
||||||
|
|
||||||
|
pGrenade->SetTouch(&CMSporeGrenade::BounceTouch); // Bounce if touched
|
||||||
|
|
||||||
|
float lifetime = 2.0;
|
||||||
|
if (ai) {
|
||||||
|
lifetime = 4.0;
|
||||||
|
pGrenade->pev->gravity = 0.5;
|
||||||
|
pGrenade->pev->friction = 0.9;
|
||||||
|
}
|
||||||
|
pGrenade->pev->dmgtime = gpGlobals->time + lifetime;
|
||||||
|
pGrenade->SetThink(&CMSporeGrenade::TumbleThink);
|
||||||
|
pGrenade->pev->nextthink = gpGlobals->time + 0.1;
|
||||||
|
if (lifetime < 0.1)
|
||||||
|
{
|
||||||
|
pGrenade->pev->nextthink = gpGlobals->time;
|
||||||
|
pGrenade->pev->velocity = Vector(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pGrenade;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMSporeGrenade *CMSporeGrenade::ShootContact(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity)
|
||||||
|
{
|
||||||
|
CMSporeGrenade *pGrenade = CreateClassPtr((CMSporeGrenade *)NULL);
|
||||||
|
|
||||||
|
if (pGrenade == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
UTIL_SetOrigin(pGrenade->pev, vecStart);
|
||||||
|
pGrenade->Spawn();
|
||||||
|
pGrenade->pev->movetype = MOVETYPE_FLY;
|
||||||
|
pGrenade->pev->velocity = vecVelocity;
|
||||||
|
pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity);
|
||||||
|
pGrenade->pev->owner = ENT(pevOwner);
|
||||||
|
pGrenade->m_hOwner = ENT(pevOwner);
|
||||||
|
|
||||||
|
// make monsters afraid of it while in the air
|
||||||
|
pGrenade->SetThink(&CMSporeGrenade::DangerSoundThink);
|
||||||
|
pGrenade->pev->nextthink = gpGlobals->time;
|
||||||
|
|
||||||
|
// Explode on contact
|
||||||
|
pGrenade->SetTouch(&CMSporeGrenade::ExplodeTouch);
|
||||||
|
|
||||||
|
pGrenade->pev->gravity = 0.5;
|
||||||
|
pGrenade->pev->friction = 0.7;
|
||||||
|
|
||||||
|
return pGrenade;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMSporeGrenade::SpawnTrailParticles(const Vector& origin, const Vector& direction, int modelindex, int count, float speed, float noise)
|
||||||
|
{
|
||||||
|
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, origin);
|
||||||
|
WRITE_BYTE(TE_SPRITE_SPRAY);
|
||||||
|
WRITE_COORD(origin.x); // pos
|
||||||
|
WRITE_COORD(origin.y);
|
||||||
|
WRITE_COORD(origin.z);
|
||||||
|
WRITE_COORD(direction.x); // dir
|
||||||
|
WRITE_COORD(direction.y);
|
||||||
|
WRITE_COORD(direction.z);
|
||||||
|
WRITE_SHORT(modelindex); // model
|
||||||
|
WRITE_BYTE(count); // count
|
||||||
|
WRITE_BYTE(speed); // speed
|
||||||
|
WRITE_BYTE(noise); // noise ( client will divide by 100 )
|
||||||
|
MESSAGE_END();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMSporeGrenade::SpawnExplosionParticles(const Vector& origin, const Vector& direction, int modelindex, int count, float speed, float noise)
|
||||||
|
{
|
||||||
|
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, origin);
|
||||||
|
WRITE_BYTE(TE_SPRITE_SPRAY);
|
||||||
|
WRITE_COORD(origin.x); // pos
|
||||||
|
WRITE_COORD(origin.y);
|
||||||
|
WRITE_COORD(origin.z);
|
||||||
|
WRITE_COORD(direction.x); // dir
|
||||||
|
WRITE_COORD(direction.y);
|
||||||
|
WRITE_COORD(direction.z);
|
||||||
|
WRITE_SHORT(modelindex); // model
|
||||||
|
WRITE_BYTE(count); // count
|
||||||
|
WRITE_BYTE(speed); // speed
|
||||||
|
WRITE_BYTE(noise); // noise ( client will divide by 100 )
|
||||||
|
MESSAGE_END();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMSporeGrenade::UpdateOnRemove()
|
||||||
|
{
|
||||||
|
CMBaseMonster::UpdateOnRemove();
|
||||||
|
if (m_pSporeGlow)
|
||||||
|
{
|
||||||
|
UTIL_Remove(m_pSporeGlow->edict());
|
||||||
|
m_pSporeGlow = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -302,6 +302,8 @@ void CMSqueakGrenade::SuperBounceTouch( edict_t *pOther )
|
|||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||||
pMonster->TraceAttack(pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH );
|
pMonster->TraceAttack(pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
UTIL_TraceAttack(pOther, pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH );
|
||||||
|
|
||||||
ApplyMultiDamage( pev, pev );
|
ApplyMultiDamage( pev, pev );
|
||||||
|
|
||||||
|
|||||||
898
src/dlls/strooper.cpp
Normal file
898
src/dlls/strooper.cpp
Normal file
@@ -0,0 +1,898 @@
|
|||||||
|
// HUGE thanks to DrBeef for his hlsdk-xash3d-opfor repository!
|
||||||
|
|
||||||
|
/***
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* This product contains software technology licensed from Id
|
||||||
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This source code contains proprietary and confidential information of
|
||||||
|
* Valve LLC and its suppliers. Access to this code is restricted to
|
||||||
|
* persons who have executed a written SDK license with Valve. Any access,
|
||||||
|
* use or distribution of this code by or to any unlicensed person is illegal.
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
//=========================================================
|
||||||
|
// shocktrooper
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "plane.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
#include "monsters.h"
|
||||||
|
#include "schedule.h"
|
||||||
|
#include "animation.h"
|
||||||
|
#include "weapons.h"
|
||||||
|
#include "cmtalkmonster.h"
|
||||||
|
#include "effects.h"
|
||||||
|
#include "customentity.h"
|
||||||
|
#include "shock.h"
|
||||||
|
|
||||||
|
int g_fStrooperQuestion; // true if an idle grunt asked a question. Cleared when someone answers.
|
||||||
|
|
||||||
|
extern Schedule_t slGruntTakeCover[];
|
||||||
|
extern Schedule_t slGruntGrenadeCover[];
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// monster-specific DEFINE's
|
||||||
|
//=========================================================
|
||||||
|
#define STROOPER_CLIP_SIZE 10 // how many bullets in a clip? - NOTE: 3 round burst sound, so keep as 3 * x!
|
||||||
|
#define STROOPER_VOL 0.35 // volume of grunt sounds
|
||||||
|
#define STROOPER_ATTN ATTN_NORM // attenutation of grunt sentences
|
||||||
|
#define STROOPER_LIMP_HEALTH 20
|
||||||
|
#define STROOPER_DMG_HEADSHOT ( DMG_BULLET | DMG_CLUB ) // damage types that can kill a grunt with a single headshot.
|
||||||
|
#define STROOPER_NUM_HEADS 2 // how many grunt heads are there?
|
||||||
|
#define STROOPER_MINIMUM_HEADSHOT_DAMAGE 15 // must do at least this much damage in one shot to head to score a headshot kill
|
||||||
|
#define STROOPER_SENTENCE_VOLUME (float)0.35 // volume of grunt sentences
|
||||||
|
#define STROOPER_MUZZLEFLASH "sprites/muzzle_shock.spr"
|
||||||
|
|
||||||
|
#define STROOPER_SHOCKRIFLE (1 << 0)
|
||||||
|
#define STROOPER_HANDGRENADE (1 << 1)
|
||||||
|
|
||||||
|
#define GUN_GROUP 1
|
||||||
|
#define GUN_SHOCKRIFLE 0
|
||||||
|
#define GUN_NONE 1
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Monster's Anim Events Go Here
|
||||||
|
//=========================================================
|
||||||
|
#define STROOPER_AE_RELOAD ( 2 )
|
||||||
|
#define STROOPER_AE_KICK ( 3 )
|
||||||
|
#define STROOPER_AE_BURST1 ( 4 )
|
||||||
|
#define STROOPER_AE_BURST2 ( 5 )
|
||||||
|
#define STROOPER_AE_BURST3 ( 6 )
|
||||||
|
#define STROOPER_AE_GREN_TOSS ( 7 )
|
||||||
|
#define STROOPER_AE_GREN_LAUNCH ( 8 )
|
||||||
|
#define STROOPER_AE_GREN_DROP ( 9 )
|
||||||
|
#define STROOPER_AE_CAUGHT_ENEMY ( 10 ) // shocktrooper established sight with an enemy (player only) that had previously eluded the squad.
|
||||||
|
#define STROOPER_AE_DROP_GUN ( 11 ) // shocktrooper (probably dead) is dropping his shockrifle.
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// monster-specific schedule types
|
||||||
|
//=========================================================
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SCHED_STROOPER_SUPPRESS = LAST_COMMON_SCHEDULE + 1,
|
||||||
|
SCHED_STROOPER_ESTABLISH_LINE_OF_FIRE,// move to a location to set up an attack against the enemy. (usually when a friendly is in the way).
|
||||||
|
SCHED_STROOPER_COVER_AND_RELOAD,
|
||||||
|
SCHED_STROOPER_SWEEP,
|
||||||
|
SCHED_STROOPER_FOUND_ENEMY,
|
||||||
|
SCHED_STROOPER_REPEL,
|
||||||
|
SCHED_STROOPER_REPEL_ATTACK,
|
||||||
|
SCHED_STROOPER_REPEL_LAND,
|
||||||
|
SCHED_STROOPER_WAIT_FACE_ENEMY,
|
||||||
|
SCHED_STROOPER_TAKECOVER_FAILED,// special schedule type that forces analysis of conditions and picks the best possible schedule to recover from this type of failure.
|
||||||
|
SCHED_STROOPER_ELOF_FAIL,
|
||||||
|
};
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// monster-specific tasks
|
||||||
|
//=========================================================
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
TASK_STROOPER_FACE_TOSS_DIR = LAST_COMMON_TASK + 1,
|
||||||
|
TASK_STROOPER_SPEAK_SENTENCE,
|
||||||
|
TASK_STROOPER_CHECK_FIRE,
|
||||||
|
};
|
||||||
|
|
||||||
|
int iStrooperMuzzleFlash;
|
||||||
|
|
||||||
|
const char *CMStrooper::pGruntSentences[] =
|
||||||
|
{
|
||||||
|
"ST_GREN", // grenade scared grunt
|
||||||
|
"ST_ALERT", // sees player
|
||||||
|
"ST_MONST", // sees monster
|
||||||
|
"ST_COVER", // running to cover
|
||||||
|
"ST_THROW", // about to throw grenade
|
||||||
|
"ST_CHARGE", // running out to get the enemy
|
||||||
|
"ST_TAUNT", // say rude things
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
STROOPER_SENT_NONE = -1,
|
||||||
|
STROOPER_SENT_GREN = 0,
|
||||||
|
STROOPER_SENT_ALERT,
|
||||||
|
STROOPER_SENT_MONSTER,
|
||||||
|
STROOPER_SENT_COVER,
|
||||||
|
STROOPER_SENT_THROW,
|
||||||
|
STROOPER_SENT_CHARGE,
|
||||||
|
STROOPER_SENT_TAUNT,
|
||||||
|
} STROOPER_SENTENCE_TYPES;
|
||||||
|
|
||||||
|
void CMStrooper::SpeakSentence()
|
||||||
|
{
|
||||||
|
if( m_iSentence == STROOPER_SENT_NONE )
|
||||||
|
{
|
||||||
|
// no sentence cued up.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( FOkToSpeak() )
|
||||||
|
{
|
||||||
|
SENTENCEG_PlayRndSz( ENT( pev ), pGruntSentences[m_iSentence], STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch );
|
||||||
|
JustSpoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STROOPER_GIB_COUNT 8
|
||||||
|
//=========================================================
|
||||||
|
// GibMonster - make gun fly through the air.
|
||||||
|
//=========================================================
|
||||||
|
void CMStrooper::GibMonster()
|
||||||
|
{
|
||||||
|
if (GetBodygroup(GUN_GROUP) != GUN_NONE)
|
||||||
|
{
|
||||||
|
DropShockRoach(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "common/bodysplat.wav", 1, ATTN_NORM );
|
||||||
|
|
||||||
|
if( CVAR_GET_FLOAT( "violence_agibs" ) != 0 ) // Should never get here, but someone might call it directly
|
||||||
|
{
|
||||||
|
CMGib::SpawnRandomGibs( pev, STROOPER_GIB_COUNT, "models/strooper_gibs.mdl", 0 ); // Throw alien gibs
|
||||||
|
}
|
||||||
|
SetThink( &CMBaseEntity::SUB_Remove );
|
||||||
|
pev->nextthink = gpGlobals->time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMStrooper::IdleSound()
|
||||||
|
{
|
||||||
|
if (FOkToSpeak() && (g_fStrooperQuestion || RANDOM_LONG(0, 1)))
|
||||||
|
{
|
||||||
|
if (!g_fStrooperQuestion)
|
||||||
|
{
|
||||||
|
// ask question or make statement
|
||||||
|
switch (RANDOM_LONG(0, 2))
|
||||||
|
{
|
||||||
|
case 0: // check in
|
||||||
|
SENTENCEG_PlayRndSz(ENT(pev), "ST_CHECK", STROOPER_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
||||||
|
g_fStrooperQuestion = 1;
|
||||||
|
break;
|
||||||
|
case 1: // question
|
||||||
|
SENTENCEG_PlayRndSz(ENT(pev), "ST_QUEST", STROOPER_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
||||||
|
g_fStrooperQuestion = 2;
|
||||||
|
break;
|
||||||
|
case 2: // statement
|
||||||
|
SENTENCEG_PlayRndSz(ENT(pev), "ST_IDLE", STROOPER_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (g_fStrooperQuestion)
|
||||||
|
{
|
||||||
|
case 1: // check in
|
||||||
|
SENTENCEG_PlayRndSz(ENT(pev), "ST_CLEAR", STROOPER_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
||||||
|
break;
|
||||||
|
case 2: // question
|
||||||
|
SENTENCEG_PlayRndSz(ENT(pev), "ST_ANSWER", STROOPER_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
g_fStrooperQuestion = 0;
|
||||||
|
}
|
||||||
|
JustSpoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Classify - indicates this monster's place in the
|
||||||
|
// relationship table.
|
||||||
|
//=========================================================
|
||||||
|
int CMStrooper::Classify()
|
||||||
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
|
return CLASS_RACEX_SHOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CMStrooper::CheckRangeAttack1(float flDot, float flDist)
|
||||||
|
{
|
||||||
|
return (m_cAmmoLoaded >= 1) && CMHGrunt::CheckRangeAttack1(flDot, flDist);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CMStrooper::CheckRangeAttack2( float flDot, float flDist )
|
||||||
|
{
|
||||||
|
if( !FBitSet( pev->weapons, STROOPER_HANDGRENADE ) )
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return CMHGrunt::CheckRangeAttack2(flDot, flDist);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// HandleAnimEvent - catches the monster-specific messages
|
||||||
|
// that occur when tagged animation frames are played.
|
||||||
|
//=========================================================
|
||||||
|
void CMStrooper::HandleAnimEvent(MonsterEvent_t *pEvent)
|
||||||
|
{
|
||||||
|
switch (pEvent->event)
|
||||||
|
{
|
||||||
|
case STROOPER_AE_DROP_GUN:
|
||||||
|
{
|
||||||
|
if (GetBodygroup(GUN_GROUP) != GUN_NONE)
|
||||||
|
{
|
||||||
|
DropShockRoach(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STROOPER_AE_RELOAD:
|
||||||
|
m_cAmmoLoaded = m_cClipSize;
|
||||||
|
ClearConditions(bits_COND_NO_AMMO_LOADED);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STROOPER_AE_GREN_TOSS:
|
||||||
|
{
|
||||||
|
UTIL_MakeVectors(pev->angles);
|
||||||
|
// CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 34 + Vector (0, 0, 32), m_vecTossVelocity, 3.5 );
|
||||||
|
CMSporeGrenade::ShootTimed(pev, pev->origin + Vector(0,0,98), m_vecTossVelocity, 3.5);
|
||||||
|
|
||||||
|
m_fThrowGrenade = FALSE;
|
||||||
|
m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown.
|
||||||
|
// !!!LATER - when in a group, only try to throw grenade if ordered.
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STROOPER_AE_GREN_LAUNCH:
|
||||||
|
case STROOPER_AE_GREN_DROP:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STROOPER_AE_BURST1:
|
||||||
|
{
|
||||||
|
if (m_hEnemy)
|
||||||
|
{
|
||||||
|
Vector vecGunPos;
|
||||||
|
Vector vecGunAngles;
|
||||||
|
|
||||||
|
GetAttachment(0, vecGunPos, vecGunAngles);
|
||||||
|
|
||||||
|
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecGunPos );
|
||||||
|
WRITE_BYTE( TE_SPRITE );
|
||||||
|
WRITE_COORD( vecGunPos.x ); // pos
|
||||||
|
WRITE_COORD( vecGunPos.y );
|
||||||
|
WRITE_COORD( vecGunPos.z );
|
||||||
|
WRITE_SHORT( iStrooperMuzzleFlash ); // model
|
||||||
|
WRITE_BYTE( 4 ); // size * 10
|
||||||
|
WRITE_BYTE( 128 ); // brightness
|
||||||
|
MESSAGE_END();
|
||||||
|
|
||||||
|
UTIL_MakeVectors(pev->angles);
|
||||||
|
Vector vecShootOrigin = vecGunPos + gpGlobals->v_forward * 32;
|
||||||
|
Vector vecShootDir = ShootAtEnemy( vecShootOrigin );
|
||||||
|
vecGunAngles = UTIL_VecToAngles( vecShootDir );
|
||||||
|
vecGunAngles.z += RANDOM_FLOAT( -0.05, 0 );
|
||||||
|
|
||||||
|
Vector vecVelocity = vecShootDir * 2000;
|
||||||
|
|
||||||
|
edict_t *pShock = CMShock::Shoot( pev, vecGunAngles, vecShootOrigin, vecVelocity );
|
||||||
|
if (pShock != NULL)
|
||||||
|
{
|
||||||
|
m_cAmmoLoaded--;
|
||||||
|
SetBlending( 0, vecGunAngles.x );
|
||||||
|
|
||||||
|
// Play fire sound.
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/shock_fire.wav", 1, ATTN_NORM);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ALERT( at_console, "Cannot create shock_beam!\n" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STROOPER_AE_KICK:
|
||||||
|
{
|
||||||
|
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "zombie/claw_miss2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM + RANDOM_LONG( -5, 5 ) );
|
||||||
|
edict_t *pHurt = Kick();
|
||||||
|
|
||||||
|
if (pHurt)
|
||||||
|
{
|
||||||
|
// SOUND HERE!
|
||||||
|
UTIL_MakeVectors(pev->angles);
|
||||||
|
pHurt->v.punchangle.x = 15;
|
||||||
|
pHurt->v.punchangle.z = (m_fRightClaw) ? -10 : 10;
|
||||||
|
pHurt->v.velocity = pHurt->v.velocity + gpGlobals->v_forward * 100 + gpGlobals->v_up * 50;
|
||||||
|
|
||||||
|
if ( UTIL_IsPlayer( pHurt ) )
|
||||||
|
UTIL_TakeDamage( pHurt, pev, pev, gSkillData.strooperDmgKick, DMG_CLUB );
|
||||||
|
else if ( pHurt->v.euser4 != NULL )
|
||||||
|
{
|
||||||
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pHurt));
|
||||||
|
pMonster->TakeDamage( pev, pev, gSkillData.strooperDmgKick, DMG_CLUB );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
UTIL_TakeDamageExternal( pHurt, pev, pev, gSkillData.strooperDmgKick, DMG_CLUB );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fRightClaw = !m_fRightClaw;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STROOPER_AE_CAUGHT_ENEMY:
|
||||||
|
{
|
||||||
|
if (FOkToSpeak())
|
||||||
|
{
|
||||||
|
SENTENCEG_PlayRndSz(ENT(pev), "ST_ALERT", STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch);
|
||||||
|
JustSpoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
CMHGrunt::HandleAnimEvent(pEvent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Spawn
|
||||||
|
//=========================================================
|
||||||
|
void CMStrooper::Spawn()
|
||||||
|
{
|
||||||
|
Precache();
|
||||||
|
|
||||||
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/strooper.mdl"));
|
||||||
|
UTIL_SetSize( pev, Vector(-24, -24, 0), Vector(24, 24, 72) );
|
||||||
|
|
||||||
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
pev->movetype = MOVETYPE_STEP;
|
||||||
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
|
||||||
|
pev->effects = 0;
|
||||||
|
if (!pev->health) { pev->health = gSkillData.strooperHealth; }
|
||||||
|
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
|
m_flNextGrenadeCheck = gpGlobals->time + 1;
|
||||||
|
m_flNextPainTime = gpGlobals->time;
|
||||||
|
m_iSentence = STROOPER_SENT_NONE;
|
||||||
|
|
||||||
|
m_afCapability = bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
|
||||||
|
|
||||||
|
//m_fEnemyEluded = FALSE;
|
||||||
|
m_fFirstEncounter = TRUE;// this is true when the grunt spawns, because he hasn't encountered an enemy yet.
|
||||||
|
|
||||||
|
m_HackedGunPos = Vector(0, 0, 55);
|
||||||
|
|
||||||
|
if (pev->weapons == 0)
|
||||||
|
{
|
||||||
|
// initialize to original values
|
||||||
|
pev->weapons = STROOPER_SHOCKRIFLE | STROOPER_HANDGRENADE;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_cClipSize = gSkillData.strooperMaxCharge;
|
||||||
|
|
||||||
|
m_cAmmoLoaded = m_cClipSize;
|
||||||
|
|
||||||
|
m_fRightClaw = FALSE;
|
||||||
|
|
||||||
|
CMTalkMonster::g_talkWaitTime = 0;
|
||||||
|
m_rechargeTime = gpGlobals->time + gSkillData.strooperRchgSpeed;
|
||||||
|
m_blinkTime = gpGlobals->time + RANDOM_FLOAT(3.0f, 7.0f);
|
||||||
|
|
||||||
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_shocktrooper" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Shock Trooper" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMStrooper::MonsterThink()
|
||||||
|
{
|
||||||
|
if (m_cAmmoLoaded < m_cClipSize)
|
||||||
|
{
|
||||||
|
if (m_rechargeTime < gpGlobals->time)
|
||||||
|
{
|
||||||
|
m_cAmmoLoaded++;
|
||||||
|
m_rechargeTime = gpGlobals->time + gSkillData.strooperRchgSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_blinkTime <= gpGlobals->time && pev->skin == 0) {
|
||||||
|
pev->skin = 1;
|
||||||
|
m_blinkTime = gpGlobals->time + RANDOM_FLOAT(3.0f, 7.0f);
|
||||||
|
m_eyeChangeTime = gpGlobals->time + 0.1;
|
||||||
|
}
|
||||||
|
if (pev->skin != 0) {
|
||||||
|
if (m_eyeChangeTime <= gpGlobals->time) {
|
||||||
|
m_eyeChangeTime = gpGlobals->time + 0.1;
|
||||||
|
pev->skin++;
|
||||||
|
if (pev->skin > 3) {
|
||||||
|
pev->skin = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CMHGrunt::MonsterThink();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Precache - precaches all resources this monster needs
|
||||||
|
//=========================================================
|
||||||
|
void CMStrooper::Precache()
|
||||||
|
{
|
||||||
|
PRECACHE_MODEL("models/strooper.mdl");
|
||||||
|
PRECACHE_MODEL("models/strooper_gibs.mdl");
|
||||||
|
iStrooperMuzzleFlash = PRECACHE_MODELINDEX(STROOPER_MUZZLEFLASH);
|
||||||
|
PRECACHE_SOUND("shocktrooper/shock_trooper_attack.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("shocktrooper/shock_trooper_die1.wav");
|
||||||
|
PRECACHE_SOUND("shocktrooper/shock_trooper_die2.wav");
|
||||||
|
PRECACHE_SOUND("shocktrooper/shock_trooper_die3.wav");
|
||||||
|
PRECACHE_SOUND("shocktrooper/shock_trooper_die4.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("shocktrooper/shock_trooper_pain1.wav");
|
||||||
|
PRECACHE_SOUND("shocktrooper/shock_trooper_pain2.wav");
|
||||||
|
PRECACHE_SOUND("shocktrooper/shock_trooper_pain3.wav");
|
||||||
|
PRECACHE_SOUND("shocktrooper/shock_trooper_pain4.wav");
|
||||||
|
PRECACHE_SOUND("shocktrooper/shock_trooper_pain5.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("weapons/shock_fire.wav");
|
||||||
|
PRECACHE_SOUND("weapons/shock_impact.wav");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event
|
||||||
|
|
||||||
|
// shock_beam
|
||||||
|
CMShock shock;
|
||||||
|
shock.Precache();
|
||||||
|
|
||||||
|
// spore
|
||||||
|
CMSporeGrenade spore;
|
||||||
|
spore.Precache();
|
||||||
|
|
||||||
|
// shockroach
|
||||||
|
CMShockRoach shockroach;
|
||||||
|
shockroach.Precache();
|
||||||
|
|
||||||
|
// get voice pitch
|
||||||
|
if (RANDOM_LONG(0, 1))
|
||||||
|
m_voicePitch = 109 + RANDOM_LONG(0, 7);
|
||||||
|
else
|
||||||
|
m_voicePitch = 100;
|
||||||
|
|
||||||
|
m_iBrassShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// PainSound
|
||||||
|
//=========================================================
|
||||||
|
void CMStrooper::PainSound()
|
||||||
|
{
|
||||||
|
if (gpGlobals->time > m_flNextPainTime)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
if (RANDOM_LONG(0, 99) < 5)
|
||||||
|
{
|
||||||
|
// pain sentences are rare
|
||||||
|
if (FOkToSpeak())
|
||||||
|
{
|
||||||
|
SENTENCEG_PlayRndSz(ENT(pev), "HG_PAIN", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, PITCH_NORM);
|
||||||
|
JustSpoke();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
switch (RANDOM_LONG(0, 4))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_pain1.wav", 1, ATTN_NORM);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_pain2.wav", 1, ATTN_NORM);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_pain3.wav", 1, ATTN_NORM);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_pain4.wav", 1, ATTN_NORM);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_pain5.wav", 1, ATTN_NORM);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_flNextPainTime = gpGlobals->time + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// DeathSound
|
||||||
|
//=========================================================
|
||||||
|
void CMStrooper::DeathSound()
|
||||||
|
{
|
||||||
|
switch (RANDOM_LONG(0, 3))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_die1.wav", 1, ATTN_IDLE);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_die2.wav", 1, ATTN_IDLE);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_die3.wav", 1, ATTN_IDLE);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "shocktrooper/shock_trooper_die4.wav", 1, ATTN_IDLE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// TraceAttack - reimplemented in shock trooper because they never have helmets
|
||||||
|
//=========================================================
|
||||||
|
void CMStrooper::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
|
||||||
|
{
|
||||||
|
CMBaseMonster::TraceAttack(pevAttacker, flDamage, vecDir, ptr, bitsDamageType);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMStrooper::DropShockRoach(bool gibbed)
|
||||||
|
{
|
||||||
|
Vector vecGunPos;
|
||||||
|
Vector vecGunAngles;
|
||||||
|
|
||||||
|
GetAttachment(0, vecGunPos, vecGunAngles);
|
||||||
|
SetBodygroup(GUN_GROUP, GUN_NONE);
|
||||||
|
|
||||||
|
Vector vecDropAngles;
|
||||||
|
|
||||||
|
// Remove any pitch.
|
||||||
|
vecDropAngles.x = 0;
|
||||||
|
vecDropAngles.y = vecGunAngles.y;
|
||||||
|
vecDropAngles.z = 0;
|
||||||
|
|
||||||
|
Vector vecPos = pev->origin;
|
||||||
|
if (gibbed)
|
||||||
|
vecPos.z += 32;
|
||||||
|
else
|
||||||
|
vecPos.z += 48;
|
||||||
|
|
||||||
|
// now spawn a shockroach.
|
||||||
|
//CBaseEntity* roach = CBaseEntity::Create( "monster_shockroach", vecPos, vecDropAngles );
|
||||||
|
CMShockRoach *roach = CreateClassPtr((CMShockRoach *)NULL);
|
||||||
|
if (roach != NULL)
|
||||||
|
{
|
||||||
|
UTIL_SetOrigin(roach->pev, vecPos);
|
||||||
|
roach->pev->angles = vecDropAngles;
|
||||||
|
|
||||||
|
roach->Spawn();
|
||||||
|
|
||||||
|
if (ShouldFadeOnDeath())
|
||||||
|
roach->pev->spawnflags |= SF_MONSTER_FADECORPSE;
|
||||||
|
if (gibbed)
|
||||||
|
{
|
||||||
|
roach->pev->velocity = Vector(RANDOM_FLOAT(-100.0f, 100.0f), RANDOM_FLOAT(-100.0f, 100.0f), RANDOM_FLOAT(200.0f, 300.0f));
|
||||||
|
roach->pev->avelocity = Vector(0, RANDOM_FLOAT(200.0f, 300.0f), 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
roach->pev->velocity = Vector(RANDOM_FLOAT(-20.0f, 20.0f) , RANDOM_FLOAT(-20.0f, 20.0f), RANDOM_FLOAT(20.0f, 30.0f));
|
||||||
|
roach->pev->avelocity = Vector(0, RANDOM_FLOAT(20.0f, 40.0f), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// SetActivity
|
||||||
|
//=========================================================
|
||||||
|
void CMStrooper::SetActivity(Activity NewActivity)
|
||||||
|
{
|
||||||
|
int iSequence = ACTIVITY_NOT_AVAILABLE;
|
||||||
|
void *pmodel = GET_MODEL_PTR(ENT(pev));
|
||||||
|
|
||||||
|
switch (NewActivity)
|
||||||
|
{
|
||||||
|
case ACT_RANGE_ATTACK1:
|
||||||
|
// shocktrooper is either shooting standing or shooting crouched
|
||||||
|
if (m_fStanding)
|
||||||
|
{
|
||||||
|
// get aimable sequence
|
||||||
|
iSequence = LookupSequence("standing_mp5");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// get crouching shoot
|
||||||
|
iSequence = LookupSequence("crouching_mp5");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ACT_RANGE_ATTACK2:
|
||||||
|
// shocktrooper is going to throw a grenade.
|
||||||
|
|
||||||
|
// get toss anim
|
||||||
|
iSequence = LookupSequence("throwgrenade");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACT_RUN:
|
||||||
|
if (pev->health <= STROOPER_LIMP_HEALTH)
|
||||||
|
{
|
||||||
|
// limp!
|
||||||
|
iSequence = LookupActivity(ACT_RUN_HURT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iSequence = LookupActivity(NewActivity);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ACT_WALK:
|
||||||
|
if (pev->health <= STROOPER_LIMP_HEALTH)
|
||||||
|
{
|
||||||
|
// limp!
|
||||||
|
iSequence = LookupActivity(ACT_WALK_HURT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iSequence = LookupActivity(NewActivity);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ACT_IDLE:
|
||||||
|
if (m_MonsterState == MONSTERSTATE_COMBAT)
|
||||||
|
{
|
||||||
|
NewActivity = ACT_IDLE_ANGRY;
|
||||||
|
}
|
||||||
|
iSequence = LookupActivity(NewActivity);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
iSequence = LookupActivity(NewActivity);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present
|
||||||
|
|
||||||
|
// Set to the desired anim, or default anim if the desired is not present
|
||||||
|
if (iSequence > ACTIVITY_NOT_AVAILABLE)
|
||||||
|
{
|
||||||
|
if (pev->sequence != iSequence || !m_fSequenceLoops)
|
||||||
|
{
|
||||||
|
pev->frame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pev->sequence = iSequence; // Set to the reset anim (if it's there)
|
||||||
|
ResetSequenceInfo();
|
||||||
|
SetYawSpeed();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not available try to get default anim
|
||||||
|
ALERT(at_console, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity);
|
||||||
|
pev->sequence = 0; // Set to the reset anim (if it's there)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Get Schedule!
|
||||||
|
//=========================================================
|
||||||
|
Schedule_t *CMStrooper::GetSchedule(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
// clear old sentence
|
||||||
|
m_iSentence = STROOPER_SENT_NONE;
|
||||||
|
|
||||||
|
// flying? If PRONE, barnacle has me. IF not, it's assumed I am rapelling.
|
||||||
|
if (pev->movetype == MOVETYPE_FLY && m_MonsterState != MONSTERSTATE_PRONE)
|
||||||
|
{
|
||||||
|
if (pev->flags & FL_ONGROUND)
|
||||||
|
{
|
||||||
|
// just landed
|
||||||
|
pev->movetype = MOVETYPE_STEP;
|
||||||
|
return GetScheduleOfType(SCHED_STROOPER_REPEL_LAND);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// repel down a rope,
|
||||||
|
if (m_MonsterState == MONSTERSTATE_COMBAT)
|
||||||
|
return GetScheduleOfType(SCHED_STROOPER_REPEL_ATTACK);
|
||||||
|
else
|
||||||
|
return GetScheduleOfType(SCHED_STROOPER_REPEL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_MonsterState)
|
||||||
|
{
|
||||||
|
case MONSTERSTATE_COMBAT:
|
||||||
|
{
|
||||||
|
// dead enemy
|
||||||
|
if (HasConditions(bits_COND_ENEMY_DEAD))
|
||||||
|
{
|
||||||
|
// call base class, all code to handle dead enemies is centralized there.
|
||||||
|
return CMBaseMonster::GetSchedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
// new enemy
|
||||||
|
if (HasConditions(bits_COND_NEW_ENEMY))
|
||||||
|
{
|
||||||
|
// pretty much a copypaste of hgrunt and so the same issues. -Giegue
|
||||||
|
/*
|
||||||
|
//!!!KELLY - the leader of a squad of grunts has just seen the player or a
|
||||||
|
// monster and has made it the squad's enemy. You
|
||||||
|
// can check pev->flags for FL_CLIENT to determine whether this is the player
|
||||||
|
// or a monster. He's going to immediately start
|
||||||
|
// firing, though. If you'd like, we can make an alternate "first sight"
|
||||||
|
// schedule where the leader plays a handsign anim
|
||||||
|
// that gives us enough time to hear a short sentence or spoken command
|
||||||
|
// before he starts pluggin away.
|
||||||
|
if (FOkToSpeak())// && RANDOM_LONG(0,1))
|
||||||
|
{
|
||||||
|
if ((m_hEnemy != 0) && UTIL_IsPlayer( m_hEnemy ))
|
||||||
|
// player
|
||||||
|
SENTENCEG_PlayRndSz(ENT(pev), "ST_ALERT", STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch);
|
||||||
|
|
||||||
|
else if ((m_hEnemy != 0) &&
|
||||||
|
(m_hEnemy->Classify() != CLASS_PLAYER_ALLY) &&
|
||||||
|
(m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE) &&
|
||||||
|
(m_hEnemy->Classify() != CLASS_MACHINE))
|
||||||
|
// monster
|
||||||
|
SENTENCEG_PlayRndSz(ENT(pev), "ST_MONST", STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch);
|
||||||
|
|
||||||
|
JustSpoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasConditions(bits_COND_CAN_RANGE_ATTACK1))
|
||||||
|
{
|
||||||
|
return GetScheduleOfType(SCHED_STROOPER_SUPPRESS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GetScheduleOfType(SCHED_STROOPER_ESTABLISH_LINE_OF_FIRE);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
// no ammo
|
||||||
|
else if (HasConditions(bits_COND_NO_AMMO_LOADED))
|
||||||
|
{
|
||||||
|
//!!!KELLY - this individual just realized he's out of bullet ammo.
|
||||||
|
// He's going to try to find cover to run to and reload, but rarely, if
|
||||||
|
// none is available, he'll drop and reload in the open here.
|
||||||
|
return GetScheduleOfType(SCHED_STROOPER_COVER_AND_RELOAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
// damaged just a little
|
||||||
|
else if (HasConditions(bits_COND_LIGHT_DAMAGE))
|
||||||
|
{
|
||||||
|
// if hurt:
|
||||||
|
// 90% chance of taking cover
|
||||||
|
// 10% chance of flinch.
|
||||||
|
int iPercent = RANDOM_LONG(0, 99);
|
||||||
|
|
||||||
|
if (iPercent <= 90 && m_hEnemy != 0)
|
||||||
|
{
|
||||||
|
// only try to take cover if we actually have an enemy!
|
||||||
|
|
||||||
|
//!!!KELLY - this grunt was hit and is going to run to cover.
|
||||||
|
if (FOkToSpeak()) // && RANDOM_LONG(0,1))
|
||||||
|
{
|
||||||
|
SENTENCEG_PlayRndSz( ENT(pev), "ST_COVER", STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch);
|
||||||
|
m_iSentence = STROOPER_SENT_COVER;
|
||||||
|
JustSpoke();
|
||||||
|
}
|
||||||
|
return GetScheduleOfType(SCHED_TAKE_COVER_FROM_ENEMY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GetScheduleOfType(SCHED_SMALL_FLINCH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// can kick
|
||||||
|
else if (HasConditions(bits_COND_CAN_MELEE_ATTACK1))
|
||||||
|
{
|
||||||
|
return GetScheduleOfType(SCHED_MELEE_ATTACK1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// can shoot
|
||||||
|
if (HasConditions(bits_COND_CAN_RANGE_ATTACK1))
|
||||||
|
{
|
||||||
|
if (HasConditions(bits_COND_CAN_RANGE_ATTACK2))
|
||||||
|
{
|
||||||
|
// throw a grenade if can and no engage slots are available
|
||||||
|
return GetScheduleOfType(SCHED_RANGE_ATTACK2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GetScheduleOfType(SCHED_RANGE_ATTACK1);
|
||||||
|
|
||||||
|
// hide!
|
||||||
|
//return GetScheduleOfType(SCHED_TAKE_COVER_FROM_ENEMY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// can't see enemy
|
||||||
|
else if (HasConditions(bits_COND_ENEMY_OCCLUDED))
|
||||||
|
{
|
||||||
|
if (HasConditions(bits_COND_CAN_RANGE_ATTACK2))
|
||||||
|
{
|
||||||
|
//!!!KELLY - this grunt is about to throw or fire a grenade at the player. Great place for "fire in the hole" "frag out" etc
|
||||||
|
if (FOkToSpeak())
|
||||||
|
{
|
||||||
|
SENTENCEG_PlayRndSz(ENT(pev), "ST_THROW", STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch);
|
||||||
|
JustSpoke();
|
||||||
|
}
|
||||||
|
return GetScheduleOfType(SCHED_RANGE_ATTACK2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GetScheduleOfType(SCHED_STROOPER_ESTABLISH_LINE_OF_FIRE);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//!!!KELLY - grunt is going to stay put for a couple seconds to see if
|
||||||
|
// the enemy wanders back out into the open, or approaches the
|
||||||
|
// grunt's covered position. Good place for a taunt, I guess?
|
||||||
|
if (FOkToSpeak() && RANDOM_LONG(0, 1))
|
||||||
|
{
|
||||||
|
SENTENCEG_PlayRndSz(ENT(pev), "ST_TAUNT", STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch);
|
||||||
|
JustSpoke();
|
||||||
|
}
|
||||||
|
return GetScheduleOfType(SCHED_STANDOFF);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasConditions(bits_COND_SEE_ENEMY) && !HasConditions(bits_COND_CAN_RANGE_ATTACK1))
|
||||||
|
{
|
||||||
|
return GetScheduleOfType(SCHED_STROOPER_ESTABLISH_LINE_OF_FIRE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no special cases here, call the base class
|
||||||
|
return CMBaseMonster::GetSchedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
//=========================================================
|
||||||
|
Schedule_t* CMStrooper::GetScheduleOfType(int Type)
|
||||||
|
{
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case SCHED_TAKE_COVER_FROM_ENEMY:
|
||||||
|
{
|
||||||
|
if (RANDOM_LONG(0, 1))
|
||||||
|
{
|
||||||
|
return &slGruntTakeCover[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return &slGruntGrenadeCover[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return CMHGrunt::GetScheduleOfType(Type);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
291
src/dlls/stukabat.cpp
Normal file
291
src/dlls/stukabat.cpp
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
/***
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
||||||
|
*
|
||||||
|
* This product contains software technology licensed from Id
|
||||||
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This source code contains proprietary and confidential information of
|
||||||
|
* Valve LLC and its suppliers. Access to this code is restricted to
|
||||||
|
* persons who have executed a written SDK license with Valve. Any access,
|
||||||
|
* use or distribution of this code by or to any unlicensed person is illegal.
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
//=========================================================
|
||||||
|
// Stukabat - Xen Birb
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmflyingmonster.h"
|
||||||
|
#include "monsters.h"
|
||||||
|
#include "schedule.h"
|
||||||
|
#include "animation.h"
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Monster's Anim Events Go Here
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
#define STUKABAT_AE_BITE 1
|
||||||
|
#define STUKABAT_AE_FLAP 8
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Classify - indicates this monster's place in the
|
||||||
|
// relationship table.
|
||||||
|
//=========================================================
|
||||||
|
int CMStukabat :: Classify ( void )
|
||||||
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
|
return CLASS_ALIEN_PREDATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// SetYawSpeed - allows each sequence to have a different
|
||||||
|
// turn rate associated with it.
|
||||||
|
//=========================================================
|
||||||
|
void CMStukabat :: SetYawSpeed ( void )
|
||||||
|
{
|
||||||
|
int ys;
|
||||||
|
|
||||||
|
switch ( m_Activity )
|
||||||
|
{
|
||||||
|
case ACT_HOVER:
|
||||||
|
default:
|
||||||
|
ys = 90;
|
||||||
|
}
|
||||||
|
|
||||||
|
pev->yaw_speed = ys;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// HandleAnimEvent - catches the monster-specific messages
|
||||||
|
// that occur when tagged animation frames are played.
|
||||||
|
//=========================================================
|
||||||
|
void CMStukabat :: HandleAnimEvent( MonsterEvent_t *pEvent )
|
||||||
|
{
|
||||||
|
switch( pEvent->event )
|
||||||
|
{
|
||||||
|
case STUKABAT_AE_BITE:
|
||||||
|
{
|
||||||
|
edict_t *pHurt = CheckTraceHullAttack( 70, gSkillData.stukabatDmgBite, DMG_SLASH|DMG_POISON );
|
||||||
|
if ( pHurt )
|
||||||
|
{
|
||||||
|
// Play bite sound
|
||||||
|
EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "headcrab/hc_headbite.wav", 1.0, ATTN_NORM, 0, GetBitePitch() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STUKABAT_AE_FLAP:
|
||||||
|
{
|
||||||
|
m_flightSpeed = gSkillData.stukabatSpeed; // set our own speed
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
CMFlyingMonster::HandleAnimEvent( pEvent );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Spawn
|
||||||
|
//=========================================================
|
||||||
|
void CMStukabat :: Spawn()
|
||||||
|
{
|
||||||
|
Precache( );
|
||||||
|
|
||||||
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/stukabat.mdl"));
|
||||||
|
UTIL_SetSize( pev, Vector( -12, -12, 0 ), Vector( 12, 12, 24 ) );
|
||||||
|
|
||||||
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
pev->movetype = MOVETYPE_FLY;
|
||||||
|
pev->flags |= FL_FLY;
|
||||||
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
|
||||||
|
if (!pev->health) { pev->health = gSkillData.stukabatHealth; }
|
||||||
|
pev->view_ofs = Vector ( 0, 0, 22 );// position of the eyes relative to monster's origin.
|
||||||
|
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
|
|
||||||
|
m_pFlapSound = REPLACER::FindSoundReplacement( "stukabat/stukabat_flap1.wav" );
|
||||||
|
|
||||||
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_stukabat" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Stukabat" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// Precache - precaches all resources this monster needs
|
||||||
|
//=========================================================
|
||||||
|
void CMStukabat :: Precache()
|
||||||
|
{
|
||||||
|
PRECACHE_MODEL("models/stukabat.mdl");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("stukabat/stukabat_flap1.wav" ); // flying sound
|
||||||
|
PRECACHE_SOUND("headcrab/hc_headbite.wav"); // bite sound
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// AI Schedules Specific to this monster
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
// Chase enemy
|
||||||
|
Task_t tlStukabatChaseEnemy[] =
|
||||||
|
{
|
||||||
|
{ TASK_SET_FAIL_SCHEDULE, (float)SCHED_CHASE_ENEMY_FAILED },
|
||||||
|
{ TASK_GET_PATH_TO_ENEMY, (float)0 },
|
||||||
|
{ TASK_WALK_PATH, (float)0 }, // flying monster, use walk
|
||||||
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slStukabatChaseEnemy[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlStukabatChaseEnemy,
|
||||||
|
ARRAYSIZE ( tlStukabatChaseEnemy ),
|
||||||
|
bits_COND_NEW_ENEMY |
|
||||||
|
bits_COND_CAN_RANGE_ATTACK1 |
|
||||||
|
bits_COND_TASK_FAILED,
|
||||||
|
0,
|
||||||
|
"Stukabat Chase Enemy"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Chase failed
|
||||||
|
Task_t tlStukabatChaseEnemyFailed[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, (float)0 },
|
||||||
|
{ TASK_WAIT, (float)0.2 },
|
||||||
|
{ TASK_FIND_COVER_FROM_ENEMY, (float)0 },
|
||||||
|
{ TASK_WALK_PATH, (float)0 },
|
||||||
|
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
|
||||||
|
{ TASK_REMEMBER, (float)bits_MEMORY_INCOVER },
|
||||||
|
// { TASK_TURN_LEFT, (float)179 },
|
||||||
|
{ TASK_FACE_ENEMY, (float)0 },
|
||||||
|
{ TASK_WAIT, (float)1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slStukabatChaseEnemyFailed[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlStukabatChaseEnemyFailed,
|
||||||
|
ARRAYSIZE ( tlStukabatChaseEnemyFailed ),
|
||||||
|
bits_COND_NEW_ENEMY |
|
||||||
|
bits_COND_CAN_RANGE_ATTACK1,
|
||||||
|
0,
|
||||||
|
"Stukabat Chase Failed"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fail
|
||||||
|
Task_t tlStukabatFail[] =
|
||||||
|
{
|
||||||
|
{ TASK_STOP_MOVING, (float)0 },
|
||||||
|
{ TASK_SET_ACTIVITY, (float)ACT_HOVER },
|
||||||
|
{ TASK_WAIT, (float)2 },
|
||||||
|
{ TASK_WAIT_PVS, (float)0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
Schedule_t slStukabatFail[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
tlStukabatFail,
|
||||||
|
ARRAYSIZE ( tlStukabatFail ),
|
||||||
|
bits_COND_CAN_ATTACK,
|
||||||
|
0,
|
||||||
|
"Stukabat Fail"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
DEFINE_CUSTOM_SCHEDULES( CMStukabat )
|
||||||
|
{
|
||||||
|
slStukabatChaseEnemy,
|
||||||
|
slStukabatChaseEnemyFailed,
|
||||||
|
slStukabatFail,
|
||||||
|
};
|
||||||
|
|
||||||
|
IMPLEMENT_CUSTOM_SCHEDULES( CMStukabat, CMFlyingMonster );
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// SetActivity
|
||||||
|
//=========================================================
|
||||||
|
void CMStukabat :: SetActivity ( Activity NewActivity )
|
||||||
|
{
|
||||||
|
int iSequence = ACTIVITY_NOT_AVAILABLE;
|
||||||
|
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||||
|
|
||||||
|
switch ( NewActivity )
|
||||||
|
{
|
||||||
|
case ACT_IDLE:
|
||||||
|
return; // refuse
|
||||||
|
case ACT_HOVER:
|
||||||
|
case ACT_FLY:
|
||||||
|
default:
|
||||||
|
iSequence = LookupActivity ( NewActivity );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present
|
||||||
|
|
||||||
|
// Set to the desired anim, or default anim if the desired is not present
|
||||||
|
if ( iSequence > ACTIVITY_NOT_AVAILABLE )
|
||||||
|
{
|
||||||
|
if ( pev->sequence != iSequence || !m_fSequenceLoops )
|
||||||
|
{
|
||||||
|
pev->frame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pev->sequence = iSequence; // Set to the reset anim (if it's there)
|
||||||
|
ResetSequenceInfo( );
|
||||||
|
SetYawSpeed();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not available try to get default anim
|
||||||
|
ALERT ( at_console, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity );
|
||||||
|
pev->sequence = 0; // Set to the reset anim (if it's there)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// GetScheduleOfType
|
||||||
|
//=========================================================
|
||||||
|
Schedule_t* CMStukabat :: GetScheduleOfType ( int Type )
|
||||||
|
{
|
||||||
|
switch ( Type )
|
||||||
|
{
|
||||||
|
case SCHED_CHASE_ENEMY:
|
||||||
|
return slStukabatChaseEnemy;
|
||||||
|
case SCHED_CHASE_ENEMY_FAILED:
|
||||||
|
return slStukabatChaseEnemyFailed;
|
||||||
|
case SCHED_FAIL:
|
||||||
|
return slStukabatFail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMBaseMonster :: GetScheduleOfType( Type );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// CheckRangeAttack1 - Poisonous Bite
|
||||||
|
//=========================================================
|
||||||
|
BOOL CMStukabat :: CheckRangeAttack1 ( float flDot, float flDist )
|
||||||
|
{
|
||||||
|
if ( flDot > 0.7 && flDist <= 64 )
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
@@ -145,12 +145,25 @@ void FireTargets( const char *targetName, edict_t *pActivator, edict_t *pCaller,
|
|||||||
if (FNullEnt(pentTarget))
|
if (FNullEnt(pentTarget))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// MonsterMod entity
|
||||||
CMBaseEntity *pTarget = CMBaseEntity::Instance( pentTarget );
|
CMBaseEntity *pTarget = CMBaseEntity::Instance( pentTarget );
|
||||||
if ( pTarget && !(pTarget->pev->flags & FL_KILLME) ) // Don't use dying ents
|
if ( pTarget && !(pTarget->pev->flags & FL_KILLME) )
|
||||||
{
|
{
|
||||||
ALERT( at_aiconsole, "Found: %s, firing (%s)\n", STRING(pTarget->pev->classname), targetName );
|
ALERT( at_aiconsole, "Found: %s, firing (%s)\n", STRING(pTarget->pev->classname), targetName );
|
||||||
pTarget->Use( pActivator, pCaller, useType, value );
|
pTarget->Use( pActivator, pCaller, useType, value );
|
||||||
}
|
}
|
||||||
|
// Valid entity but not recognized by monstermod, must be a normal entity
|
||||||
|
else if (!(pentTarget->v.flags & FL_KILLME))
|
||||||
|
{
|
||||||
|
if (CVAR_GET_FLOAT("_glb_use")) // avoid "unknown command" spam
|
||||||
|
{
|
||||||
|
ALERT( at_aiconsole, "Found: %s, firing (%s)\n", STRING(pentTarget->v.classname), targetName );
|
||||||
|
|
||||||
|
char extCmd[64];
|
||||||
|
sprintf( extCmd, "_trigger %i %i %i %i %f\n", ENTINDEX( pentTarget ), ENTINDEX( ENT( pActivator ) ), ENTINDEX( ENT( pCaller ) ), useType, value );
|
||||||
|
SERVER_COMMAND( extCmd );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +226,7 @@ void CMBaseDelay :: SUB_UseTargets( edict_t *pActivator, USE_TYPE useType, float
|
|||||||
pentKillTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_iszKillTarget) );
|
pentKillTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_iszKillTarget) );
|
||||||
while ( !FNullEnt(pentKillTarget) )
|
while ( !FNullEnt(pentKillTarget) )
|
||||||
{
|
{
|
||||||
UTIL_Remove( CMBaseEntity::Instance(pentKillTarget)->edict() );
|
UTIL_Remove( pentKillTarget );
|
||||||
|
|
||||||
ALERT( at_aiconsole, "killing %s\n", STRING( pentKillTarget->v.classname ) );
|
ALERT( at_aiconsole, "killing %s\n", STRING( pentKillTarget->v.classname ) );
|
||||||
pentKillTarget = FIND_ENTITY_BY_TARGETNAME( pentKillTarget, STRING(m_iszKillTarget) );
|
pentKillTarget = FIND_ENTITY_BY_TARGETNAME( pentKillTarget, STRING(m_iszKillTarget) );
|
||||||
|
|||||||
29
src/dlls/turret.cpp
Executable file → Normal file
29
src/dlls/turret.cpp
Executable file → Normal file
@@ -92,6 +92,9 @@ void CMBaseTurret::Spawn()
|
|||||||
m_iAutoStart = TRUE;
|
m_iAutoStart = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_flDistLook)
|
||||||
|
m_flDistLook = TURRET_RANGE;
|
||||||
|
|
||||||
ResetSequenceInfo( );
|
ResetSequenceInfo( );
|
||||||
SetBoneController( 0, 0 );
|
SetBoneController( 0, 0 );
|
||||||
SetBoneController( 1, 0 );
|
SetBoneController( 1, 0 );
|
||||||
@@ -121,8 +124,8 @@ void CMBaseTurret::Precache( )
|
|||||||
void CMTurret::Spawn()
|
void CMTurret::Spawn()
|
||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
SET_MODEL(ENT(pev), "models/turret.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/turret.mdl"));
|
||||||
pev->health = gSkillData.turretHealth;
|
if (!pev->health) { pev->health = gSkillData.turretHealth; }
|
||||||
m_HackedGunPos = Vector( 0, 0, 12.75 );
|
m_HackedGunPos = Vector( 0, 0, 12.75 );
|
||||||
m_flMaxSpin = TURRET_MAXSPIN;
|
m_flMaxSpin = TURRET_MAXSPIN;
|
||||||
pev->view_ofs.z = 12.75;
|
pev->view_ofs.z = 12.75;
|
||||||
@@ -161,8 +164,8 @@ void CMTurret::Precache()
|
|||||||
void CMMiniTurret::Spawn()
|
void CMMiniTurret::Spawn()
|
||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
SET_MODEL(ENT(pev), "models/miniturret.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/miniturret.mdl"));
|
||||||
pev->health = gSkillData.miniturretHealth;
|
if (!pev->health) { pev->health = gSkillData.miniturretHealth; }
|
||||||
m_HackedGunPos = Vector( 0, 0, 12.75 );
|
m_HackedGunPos = Vector( 0, 0, 12.75 );
|
||||||
m_flMaxSpin = 0;
|
m_flMaxSpin = 0;
|
||||||
pev->view_ofs.z = 12.75;
|
pev->view_ofs.z = 12.75;
|
||||||
@@ -348,7 +351,7 @@ void CMBaseTurret::ActiveThink(void)
|
|||||||
Vector vec = UTIL_VecToAngles(vecMidEnemy - vecMid);
|
Vector vec = UTIL_VecToAngles(vecMidEnemy - vecMid);
|
||||||
|
|
||||||
// Current enemy is not visible.
|
// Current enemy is not visible.
|
||||||
if (!fEnemyVisible || (flDistToEnemy > TURRET_RANGE))
|
if (!fEnemyVisible || (flDistToEnemy > m_flDistLook))
|
||||||
{
|
{
|
||||||
if (!m_flLastSight)
|
if (!m_flLastSight)
|
||||||
m_flLastSight = gpGlobals->time + 0.5;
|
m_flLastSight = gpGlobals->time + 0.5;
|
||||||
@@ -459,7 +462,7 @@ void CMBaseTurret::ActiveThink(void)
|
|||||||
|
|
||||||
void CMTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy)
|
void CMTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy)
|
||||||
{
|
{
|
||||||
FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, TURRET_RANGE, BULLET_MONSTER_12MM, 1 );
|
FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, m_flDistLook, BULLET_MONSTER_12MM, 1 );
|
||||||
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "turret/tu_fire1.wav", 1, 0.6);
|
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "turret/tu_fire1.wav", 1, 0.6);
|
||||||
pev->effects = pev->effects | EF_MUZZLEFLASH;
|
pev->effects = pev->effects | EF_MUZZLEFLASH;
|
||||||
}
|
}
|
||||||
@@ -467,7 +470,7 @@ void CMTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy)
|
|||||||
|
|
||||||
void CMMiniTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy)
|
void CMMiniTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy)
|
||||||
{
|
{
|
||||||
FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, TURRET_RANGE, BULLET_MONSTER_9MM, 1 );
|
FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, m_flDistLook, BULLET_MONSTER_9MM, 1 );
|
||||||
|
|
||||||
switch(RANDOM_LONG(0,2))
|
switch(RANDOM_LONG(0,2))
|
||||||
{
|
{
|
||||||
@@ -721,7 +724,7 @@ void CMBaseTurret::SearchThink(void)
|
|||||||
// Acquire Target
|
// Acquire Target
|
||||||
if (m_hEnemy == NULL)
|
if (m_hEnemy == NULL)
|
||||||
{
|
{
|
||||||
Look(TURRET_RANGE);
|
Look(m_flDistLook);
|
||||||
m_hEnemy = BestVisibleEnemy();
|
m_hEnemy = BestVisibleEnemy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,7 +782,7 @@ void CMBaseTurret::AutoSearchThink(void)
|
|||||||
|
|
||||||
if (m_hEnemy == NULL)
|
if (m_hEnemy == NULL)
|
||||||
{
|
{
|
||||||
Look( TURRET_RANGE );
|
Look( m_flDistLook );
|
||||||
m_hEnemy = BestVisibleEnemy();
|
m_hEnemy = BestVisibleEnemy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -801,6 +804,7 @@ void CMBaseTurret :: TurretDeath( void )
|
|||||||
if (pev->deadflag != DEAD_DEAD)
|
if (pev->deadflag != DEAD_DEAD)
|
||||||
{
|
{
|
||||||
pev->deadflag = DEAD_DEAD;
|
pev->deadflag = DEAD_DEAD;
|
||||||
|
FCheckAITrigger(); // trigger death condition
|
||||||
|
|
||||||
float flRndSound = RANDOM_FLOAT ( 0 , 1 );
|
float flRndSound = RANDOM_FLOAT ( 0 , 1 );
|
||||||
|
|
||||||
@@ -1014,8 +1018,8 @@ void CMSentry::Precache()
|
|||||||
void CMSentry::Spawn()
|
void CMSentry::Spawn()
|
||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
SET_MODEL(ENT(pev), "models/sentry.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/sentry.mdl"));
|
||||||
pev->health = gSkillData.sentryHealth;
|
if (!pev->health) { pev->health = gSkillData.sentryHealth; }
|
||||||
m_HackedGunPos = Vector( 0, 0, 48 );
|
m_HackedGunPos = Vector( 0, 0, 48 );
|
||||||
pev->view_ofs.z = 48;
|
pev->view_ofs.z = 48;
|
||||||
m_flMaxWait = 1E6;
|
m_flMaxWait = 1E6;
|
||||||
@@ -1041,7 +1045,7 @@ void CMSentry::Spawn()
|
|||||||
|
|
||||||
void CMSentry::Shoot(Vector &vecSrc, Vector &vecDirToEnemy)
|
void CMSentry::Shoot(Vector &vecSrc, Vector &vecDirToEnemy)
|
||||||
{
|
{
|
||||||
FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, TURRET_RANGE, BULLET_MONSTER_MP5, 1 );
|
FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, m_flDistLook, BULLET_MONSTER_MP5, 1 );
|
||||||
|
|
||||||
switch(RANDOM_LONG(0,2))
|
switch(RANDOM_LONG(0,2))
|
||||||
{
|
{
|
||||||
@@ -1105,6 +1109,7 @@ void CMSentry::SentryDeath( void )
|
|||||||
if (pev->deadflag != DEAD_DEAD)
|
if (pev->deadflag != DEAD_DEAD)
|
||||||
{
|
{
|
||||||
pev->deadflag = DEAD_DEAD;
|
pev->deadflag = DEAD_DEAD;
|
||||||
|
FCheckAITrigger(); // trigger death condition
|
||||||
|
|
||||||
float flRndSound = RANDOM_FLOAT ( 0 , 1 );
|
float flRndSound = RANDOM_FLOAT ( 0 , 1 );
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ typedef struct {
|
|||||||
} gamedll_funcs_t;
|
} gamedll_funcs_t;
|
||||||
|
|
||||||
extern gamedll_funcs_t *gpGamedllFuncs;
|
extern gamedll_funcs_t *gpGamedllFuncs;
|
||||||
|
extern void check_player_dead( edict_t *pPlayer );
|
||||||
|
|
||||||
// Print to console.
|
// Print to console.
|
||||||
void META_CONS(char *fmt, ...) {
|
void META_CONS(char *fmt, ...) {
|
||||||
@@ -226,6 +226,120 @@ UTIL_GroupTrace::~UTIL_GroupTrace( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TYPEDESCRIPTION gEntvarsDescription[] =
|
||||||
|
{
|
||||||
|
DEFINE_ENTITY_FIELD( classname, FIELD_STRING ),
|
||||||
|
DEFINE_ENTITY_GLOBAL_FIELD( globalname, FIELD_STRING ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( origin, FIELD_POSITION_VECTOR ),
|
||||||
|
DEFINE_ENTITY_FIELD( oldorigin, FIELD_POSITION_VECTOR ),
|
||||||
|
DEFINE_ENTITY_FIELD( velocity, FIELD_VECTOR ),
|
||||||
|
DEFINE_ENTITY_FIELD( basevelocity, FIELD_VECTOR ),
|
||||||
|
DEFINE_ENTITY_FIELD( movedir, FIELD_VECTOR ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( angles, FIELD_VECTOR ),
|
||||||
|
DEFINE_ENTITY_FIELD( avelocity, FIELD_VECTOR ),
|
||||||
|
DEFINE_ENTITY_FIELD( punchangle, FIELD_VECTOR ),
|
||||||
|
DEFINE_ENTITY_FIELD( v_angle, FIELD_VECTOR ),
|
||||||
|
DEFINE_ENTITY_FIELD( fixangle, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( idealpitch, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( pitch_speed, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( ideal_yaw, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( yaw_speed, FIELD_FLOAT ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( modelindex, FIELD_INTEGER ),
|
||||||
|
DEFINE_ENTITY_GLOBAL_FIELD( model, FIELD_MODELNAME ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( viewmodel, FIELD_MODELNAME ),
|
||||||
|
DEFINE_ENTITY_FIELD( weaponmodel, FIELD_MODELNAME ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( absmin, FIELD_POSITION_VECTOR ),
|
||||||
|
DEFINE_ENTITY_FIELD( absmax, FIELD_POSITION_VECTOR ),
|
||||||
|
DEFINE_ENTITY_GLOBAL_FIELD( mins, FIELD_VECTOR ),
|
||||||
|
DEFINE_ENTITY_GLOBAL_FIELD( maxs, FIELD_VECTOR ),
|
||||||
|
DEFINE_ENTITY_GLOBAL_FIELD( size, FIELD_VECTOR ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( ltime, FIELD_TIME ),
|
||||||
|
DEFINE_ENTITY_FIELD( nextthink, FIELD_TIME ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( solid, FIELD_INTEGER ),
|
||||||
|
DEFINE_ENTITY_FIELD( movetype, FIELD_INTEGER ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( skin, FIELD_INTEGER ),
|
||||||
|
DEFINE_ENTITY_FIELD( body, FIELD_INTEGER ),
|
||||||
|
DEFINE_ENTITY_FIELD( effects, FIELD_INTEGER ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( gravity, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( friction, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( light_level, FIELD_FLOAT ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( frame, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( scale, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( sequence, FIELD_INTEGER ),
|
||||||
|
DEFINE_ENTITY_FIELD( animtime, FIELD_TIME ),
|
||||||
|
DEFINE_ENTITY_FIELD( framerate, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( controller, FIELD_INTEGER ),
|
||||||
|
DEFINE_ENTITY_FIELD( blending, FIELD_INTEGER ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( rendermode, FIELD_INTEGER ),
|
||||||
|
DEFINE_ENTITY_FIELD( renderamt, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( rendercolor, FIELD_VECTOR ),
|
||||||
|
DEFINE_ENTITY_FIELD( renderfx, FIELD_INTEGER ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( health, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( frags, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( weapons, FIELD_INTEGER ),
|
||||||
|
DEFINE_ENTITY_FIELD( takedamage, FIELD_FLOAT ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( deadflag, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( view_ofs, FIELD_VECTOR ),
|
||||||
|
DEFINE_ENTITY_FIELD( button, FIELD_INTEGER ),
|
||||||
|
DEFINE_ENTITY_FIELD( impulse, FIELD_INTEGER ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( chain, FIELD_EDICT ),
|
||||||
|
DEFINE_ENTITY_FIELD( dmg_inflictor, FIELD_EDICT ),
|
||||||
|
DEFINE_ENTITY_FIELD( enemy, FIELD_EDICT ),
|
||||||
|
DEFINE_ENTITY_FIELD( aiment, FIELD_EDICT ),
|
||||||
|
DEFINE_ENTITY_FIELD( owner, FIELD_EDICT ),
|
||||||
|
DEFINE_ENTITY_FIELD( groundentity, FIELD_EDICT ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( spawnflags, FIELD_INTEGER ),
|
||||||
|
DEFINE_ENTITY_FIELD( flags, FIELD_FLOAT ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( colormap, FIELD_INTEGER ),
|
||||||
|
DEFINE_ENTITY_FIELD( team, FIELD_INTEGER ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( max_health, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( teleport_time, FIELD_TIME ),
|
||||||
|
DEFINE_ENTITY_FIELD( armortype, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( armorvalue, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( waterlevel, FIELD_INTEGER ),
|
||||||
|
DEFINE_ENTITY_FIELD( watertype, FIELD_INTEGER ),
|
||||||
|
|
||||||
|
// Having these fields be local to the individual levels makes it easier to test those levels individually.
|
||||||
|
DEFINE_ENTITY_GLOBAL_FIELD( target, FIELD_STRING ),
|
||||||
|
DEFINE_ENTITY_GLOBAL_FIELD( targetname, FIELD_STRING ),
|
||||||
|
DEFINE_ENTITY_FIELD( netname, FIELD_STRING ),
|
||||||
|
DEFINE_ENTITY_FIELD( message, FIELD_STRING ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( dmg_take, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( dmg_save, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( dmg, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( dmgtime, FIELD_TIME ),
|
||||||
|
|
||||||
|
DEFINE_ENTITY_FIELD( noise, FIELD_SOUNDNAME ),
|
||||||
|
DEFINE_ENTITY_FIELD( noise1, FIELD_SOUNDNAME ),
|
||||||
|
DEFINE_ENTITY_FIELD( noise2, FIELD_SOUNDNAME ),
|
||||||
|
DEFINE_ENTITY_FIELD( noise3, FIELD_SOUNDNAME ),
|
||||||
|
DEFINE_ENTITY_FIELD( speed, FIELD_FLOAT ),
|
||||||
|
DEFINE_ENTITY_FIELD( air_finished, FIELD_TIME ),
|
||||||
|
DEFINE_ENTITY_FIELD( pain_finished, FIELD_TIME ),
|
||||||
|
DEFINE_ENTITY_FIELD( radsuit_finished, FIELD_TIME ),
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ENTVARS_COUNT (sizeof(gEntvarsDescription)/sizeof(gEntvarsDescription[0]))
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
edict_t *DBG_EntOfVars( const entvars_t *pev )
|
edict_t *DBG_EntOfVars( const entvars_t *pev )
|
||||||
{
|
{
|
||||||
@@ -1450,9 +1564,9 @@ void UTIL_Remove( edict_t *pEntity )
|
|||||||
if ( !pEntity )
|
if ( !pEntity )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//jlb pEntity->UpdateOnRemove();
|
//pEntity->UpdateOnRemove();
|
||||||
pEntity->v.flags |= FL_KILLME;
|
|
||||||
pEntity->v.targetname = 0;
|
pEntity->v.targetname = 0;
|
||||||
|
pEntity->v.flags |= FL_KILLME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1512,6 +1626,55 @@ void UTIL_StripToken( const char *pKey, char *pDest )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
TYPEDESCRIPTION *pField;
|
||||||
|
|
||||||
|
for ( i = 0; i < ENTVARS_COUNT; i++ )
|
||||||
|
{
|
||||||
|
pField = &gEntvarsDescription[i];
|
||||||
|
|
||||||
|
if ( !stricmp( pField->fieldName, pkvd->szKeyName ) )
|
||||||
|
{
|
||||||
|
switch( pField->fieldType )
|
||||||
|
{
|
||||||
|
case FIELD_MODELNAME:
|
||||||
|
case FIELD_SOUNDNAME:
|
||||||
|
case FIELD_STRING:
|
||||||
|
(*(int *)((char *)pev + pField->fieldOffset)) = ALLOC_STRING( pkvd->szValue );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FIELD_TIME:
|
||||||
|
case FIELD_FLOAT:
|
||||||
|
(*(float *)((char *)pev + pField->fieldOffset)) = atof( pkvd->szValue );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FIELD_INTEGER:
|
||||||
|
(*(int *)((char *)pev + pField->fieldOffset)) = atoi( pkvd->szValue );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FIELD_POSITION_VECTOR:
|
||||||
|
case FIELD_VECTOR:
|
||||||
|
UTIL_StringToVector( (float *)((char *)pev + pField->fieldOffset), pkvd->szValue );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case FIELD_EVARS:
|
||||||
|
case FIELD_CLASSPTR:
|
||||||
|
case FIELD_EDICT:
|
||||||
|
case FIELD_ENTITY:
|
||||||
|
case FIELD_POINTER:
|
||||||
|
ALERT( at_error, "Bad field in entity!!\n" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Vector VecBModelOrigin( entvars_t* pevBModel )
|
Vector VecBModelOrigin( entvars_t* pevBModel )
|
||||||
{
|
{
|
||||||
return pevBModel->absmin + ( pevBModel->size * 0.5 );
|
return pevBModel->absmin + ( pevBModel->size * 0.5 );
|
||||||
@@ -1520,15 +1683,13 @@ Vector VecBModelOrigin( entvars_t* pevBModel )
|
|||||||
|
|
||||||
bool UTIL_IsAlive(entvars_t *pev)
|
bool UTIL_IsAlive(entvars_t *pev)
|
||||||
{
|
{
|
||||||
return ((pev->deadflag == DEAD_NO) && (pev->health > 0) &&
|
return ((pev->deadflag == DEAD_NO) && (pev->health > 0));
|
||||||
((pev->flags & FL_NOTARGET) == 0) && (pev->takedamage != 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool UTIL_IsAlive(edict_t *pEdict)
|
bool UTIL_IsAlive(edict_t *pEdict)
|
||||||
{
|
{
|
||||||
return ((pEdict->v.deadflag == DEAD_NO) && (pEdict->v.health > 0) &&
|
return ((pEdict->v.deadflag == DEAD_NO) && (pEdict->v.health > 0));
|
||||||
((pEdict->v.flags & FL_NOTARGET) == 0) && (pEdict->v.takedamage != 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1677,8 +1838,8 @@ int UTIL_TakeDamage( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAtt
|
|||||||
flBonus = ARMOR_BONUS;
|
flBonus = ARMOR_BONUS;
|
||||||
flRatio = ARMOR_RATIO;
|
flRatio = ARMOR_RATIO;
|
||||||
|
|
||||||
if (!pEdict->v.takedamage)
|
if (!pEdict->v.takedamage || (pEdict->v.flags & FL_GODMODE))
|
||||||
return 0;
|
return 0; // refuse the damage
|
||||||
|
|
||||||
if ( ( bitsDamageType & DMG_BLAST ) )
|
if ( ( bitsDamageType & DMG_BLAST ) )
|
||||||
{
|
{
|
||||||
@@ -1762,6 +1923,7 @@ int UTIL_TakeDamage( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAtt
|
|||||||
{
|
{
|
||||||
pEdict->v.health = 1; // can't suicide if already dead!
|
pEdict->v.health = 1; // can't suicide if already dead!
|
||||||
gpGamedllFuncs->dllapi_table->pfnClientKill(pEdict);
|
gpGamedllFuncs->dllapi_table->pfnClientKill(pEdict);
|
||||||
|
check_player_dead(pEdict); // will you just fucking work?
|
||||||
|
|
||||||
// Add 1 score to the monster that killed this player
|
// Add 1 score to the monster that killed this player
|
||||||
if ( pevAttacker->flags & FL_MONSTER )
|
if ( pevAttacker->flags & FL_MONSTER )
|
||||||
@@ -1875,7 +2037,11 @@ void UTIL_TraceBleed( edict_t *pEdict, float flDamage, Vector vecDir, TraceResul
|
|||||||
|
|
||||||
if ( Bloodtr.flFraction != 1.0 )
|
if ( Bloodtr.flFraction != 1.0 )
|
||||||
{
|
{
|
||||||
UTIL_BloodDecalTrace( &Bloodtr, BLOOD_COLOR_RED );
|
int bloodColor = pEdict->v.iuser3;
|
||||||
|
if ( !bloodColor )
|
||||||
|
bloodColor = BLOOD_COLOR_RED;
|
||||||
|
|
||||||
|
UTIL_BloodDecalTrace( &Bloodtr, bloodColor );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1886,9 +2052,13 @@ void UTIL_TraceAttack( edict_t *pEdict, entvars_t *pevAttacker, float flDamage,
|
|||||||
|
|
||||||
if ( pEdict->v.takedamage )
|
if ( pEdict->v.takedamage )
|
||||||
{
|
{
|
||||||
|
int bloodColor = pEdict->v.iuser3;
|
||||||
|
if ( !bloodColor )
|
||||||
|
bloodColor = BLOOD_COLOR_RED;
|
||||||
|
|
||||||
AddMultiDamage( pevAttacker, pEdict, flDamage, bitsDamageType );
|
AddMultiDamage( pevAttacker, pEdict, flDamage, bitsDamageType );
|
||||||
|
|
||||||
SpawnBlood(ptr->vecEndPos, BLOOD_COLOR_RED, flDamage);// a little surface blood.
|
SpawnBlood(ptr->vecEndPos, bloodColor, flDamage);// a little surface blood.
|
||||||
|
|
||||||
UTIL_TraceBleed( pEdict, flDamage, vecDir, ptr, bitsDamageType );
|
UTIL_TraceBleed( pEdict, flDamage, vecDir, ptr, bitsDamageType );
|
||||||
}
|
}
|
||||||
@@ -1968,3 +2138,14 @@ bool UTIL_IsBSPModel( edict_t *pent )
|
|||||||
{
|
{
|
||||||
return (pent->v.solid == SOLID_BSP || pent->v.movetype == MOVETYPE_PUSHSTEP);
|
return (pent->v.solid == SOLID_BSP || pent->v.movetype == MOVETYPE_PUSHSTEP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UTIL_TakeDamageExternal( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
||||||
|
{
|
||||||
|
// Tell AMXX to call TakeDamage for us if it can.
|
||||||
|
if (CVAR_GET_FLOAT("_glb_takedamage"))
|
||||||
|
{
|
||||||
|
char extCmd[64];
|
||||||
|
sprintf( extCmd, "_takedamage %i %i %i %f %i\n", ENTINDEX( pEdict ), ENTINDEX( ENT( pevInflictor ) ), ENTINDEX( ENT( pevAttacker ) ), flDamage, bitsDamageType );
|
||||||
|
SERVER_COMMAND( extCmd );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -149,7 +149,12 @@ inline BOOL FStringNull(int iString) { return iString == iStringNull; }
|
|||||||
#define DONT_BLEED -1
|
#define DONT_BLEED -1
|
||||||
#define BLOOD_COLOR_RED (BYTE)247
|
#define BLOOD_COLOR_RED (BYTE)247
|
||||||
#define BLOOD_COLOR_YELLOW (BYTE)195
|
#define BLOOD_COLOR_YELLOW (BYTE)195
|
||||||
#define BLOOD_COLOR_GREEN BLOOD_COLOR_YELLOW
|
#define BLOOD_COLOR_BLUE (BYTE)211 // custom colors
|
||||||
|
#define BLOOD_COLOR_PINK (BYTE)147
|
||||||
|
#define BLOOD_COLOR_WHITE (BYTE)11
|
||||||
|
#define BLOOD_COLOR_ORANGE (BYTE)231
|
||||||
|
#define BLOOD_COLOR_BLACK (BYTE)49 // not 100% accurate but close enough
|
||||||
|
#define BLOOD_COLOR_GREEN (BYTE)181 // ^
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -400,6 +405,9 @@ extern DLL_GLOBAL const Vector g_vecZero;
|
|||||||
#define SVC_ROOMTYPE 37
|
#define SVC_ROOMTYPE 37
|
||||||
#define SVC_HLTV 50
|
#define SVC_HLTV 50
|
||||||
|
|
||||||
|
// Added to stuff text to the clients
|
||||||
|
#define SVC_STUFFTEXT 9 // [string] stuffed into client's console buffer
|
||||||
|
|
||||||
// prxoy director stuff
|
// prxoy director stuff
|
||||||
#define DRC_EVENT 3 // informs the dircetor about ann important game event
|
#define DRC_EVENT 3 // informs the dircetor about ann important game event
|
||||||
|
|
||||||
@@ -433,6 +441,18 @@ extern DLL_GLOBAL const Vector g_vecZero;
|
|||||||
|
|
||||||
#define SF_TRIG_PUSH_ONCE 1
|
#define SF_TRIG_PUSH_ONCE 1
|
||||||
|
|
||||||
|
// Override a few engine callbacks for model replacements
|
||||||
|
#include "globalreplace.h"
|
||||||
|
#define SET_MODEL( entity, model ) \
|
||||||
|
{ SET_MODEL2( entity, REPLACER::FindModelReplacement( entity, model ) ); }
|
||||||
|
#define PRECACHE_MODEL( model ) \
|
||||||
|
{ PRECACHE_MODEL2( (char*)REPLACER::FindModelReplacement( model ) ); }
|
||||||
|
#define PRECACHE_SOUND( sound ) \
|
||||||
|
{ PRECACHE_SOUND2( (char*)REPLACER::FindSoundReplacement( sound ) ); }
|
||||||
|
inline int PRECACHE_MODELINDEX( char* model )
|
||||||
|
{
|
||||||
|
return PRECACHE_MODEL2( (char*)REPLACER::FindModelReplacement( model ) );
|
||||||
|
}
|
||||||
|
|
||||||
// Sound Utilities
|
// Sound Utilities
|
||||||
|
|
||||||
@@ -466,9 +486,7 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int
|
|||||||
// EMIT_SOUND_DYN with pitch != 100 should be used sparingly, as it's not quite as
|
// EMIT_SOUND_DYN with pitch != 100 should be used sparingly, as it's not quite as
|
||||||
// fast as EMIT_SOUND (the pitchshift mixer is not native coded).
|
// fast as EMIT_SOUND (the pitchshift mixer is not native coded).
|
||||||
|
|
||||||
void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation,
|
void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch);
|
||||||
int flags, int pitch);
|
|
||||||
|
|
||||||
|
|
||||||
inline void EMIT_SOUND(edict_t *entity, int channel, const char *sample, float volume, float attenuation)
|
inline void EMIT_SOUND(edict_t *entity, int channel, const char *sample, float volume, float attenuation)
|
||||||
{
|
{
|
||||||
@@ -485,7 +503,7 @@ void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg);
|
|||||||
void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname);
|
void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname);
|
||||||
|
|
||||||
#define PRECACHE_SOUND_ARRAY( a ) \
|
#define PRECACHE_SOUND_ARRAY( a ) \
|
||||||
{ for (int i = 0; i < ARRAYSIZE( a ); i++ ) PRECACHE_SOUND((char *) a [i]); }
|
{ for (int i = 0; i < ARRAYSIZE( a ); i++ ) PRECACHE_SOUND2((char *) REPLACER::FindSoundReplacement(a[i])); }
|
||||||
|
|
||||||
#define EMIT_SOUND_ARRAY_DYN( chan, array ) \
|
#define EMIT_SOUND_ARRAY_DYN( chan, array ) \
|
||||||
EMIT_SOUND_DYN ( ENT(pev), chan , array [ RANDOM_LONG(0,ARRAYSIZE( array )-1) ], 1.0, ATTN_NORM, 0, RANDOM_LONG(95,105) );
|
EMIT_SOUND_DYN ( ENT(pev), chan , array [ RANDOM_LONG(0,ARRAYSIZE( array )-1) ], 1.0, ATTN_NORM, 0, RANDOM_LONG(95,105) );
|
||||||
@@ -538,3 +556,4 @@ Vector UTIL_Center(edict_t *pEdict);
|
|||||||
edict_t *UTIL_GetNextTarget( edict_t *pEntity );
|
edict_t *UTIL_GetNextTarget( edict_t *pEntity );
|
||||||
edict_t *UTIL_FindNearestPlayer(edict_t *pEdict, float m_flFieldOfView);
|
edict_t *UTIL_FindNearestPlayer(edict_t *pEdict, float m_flFieldOfView);
|
||||||
bool UTIL_IsBSPModel( edict_t *pent );
|
bool UTIL_IsBSPModel( edict_t *pent );
|
||||||
|
void UTIL_TakeDamageExternal( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
|
||||||
1336
src/dlls/voltigore.cpp
Normal file
1336
src/dlls/voltigore.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -79,6 +79,8 @@ void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker )
|
|||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(gMultiDamage.pEntity));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(gMultiDamage.pEntity));
|
||||||
pMonster->TakeDamage(pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type );
|
pMonster->TakeDamage(pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
UTIL_TakeDamageExternal(gMultiDamage.pEntity, pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -136,6 +138,19 @@ void DecalGunshot( TraceResult *pTrace, int iBulletType )
|
|||||||
|
|
||||||
switch( iBulletType )
|
switch( iBulletType )
|
||||||
{
|
{
|
||||||
|
case BULLET_PLAYER_CROWBAR:
|
||||||
|
{
|
||||||
|
// wall decal
|
||||||
|
UTIL_DecalTrace( pTrace, DamageDecal( pEntity, DMG_CLUB ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// smoke and decal
|
||||||
|
UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* why the duplicate case?
|
||||||
case BULLET_PLAYER_9MM:
|
case BULLET_PLAYER_9MM:
|
||||||
case BULLET_MONSTER_9MM:
|
case BULLET_MONSTER_9MM:
|
||||||
case BULLET_PLAYER_MP5:
|
case BULLET_PLAYER_MP5:
|
||||||
@@ -154,6 +169,7 @@ void DecalGunshot( TraceResult *pTrace, int iBulletType )
|
|||||||
// wall decal
|
// wall decal
|
||||||
UTIL_DecalTrace( pTrace, DamageDecal( pEntity, DMG_CLUB ) );
|
UTIL_DecalTrace( pTrace, DamageDecal( pEntity, DMG_CLUB ) );
|
||||||
break;
|
break;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,37 @@ public:
|
|||||||
virtual void Killed( entvars_t *pevAttacker, int iGib );
|
virtual void Killed( entvars_t *pevAttacker, int iGib );
|
||||||
|
|
||||||
BOOL m_fRegisteredSound;// whether or not this grenade has issued its DANGER sound to the world sound list yet.
|
BOOL m_fRegisteredSound;// whether or not this grenade has issued its DANGER sound to the world sound list yet.
|
||||||
|
EHANDLE m_hOwner;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Contact/Timed spore grenade
|
||||||
|
class CMSporeGrenade : public CMBaseMonster
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Precache(void);
|
||||||
|
void Spawn(void);
|
||||||
|
|
||||||
|
static CMSporeGrenade *ShootTimed(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, bool ai);
|
||||||
|
static CMSporeGrenade *ShootContact(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity);
|
||||||
|
|
||||||
|
void Explode(TraceResult *pTrace);
|
||||||
|
|
||||||
|
void EXPORT BounceTouch(edict_t *pOther);
|
||||||
|
void EXPORT ExplodeTouch(edict_t *pOther);
|
||||||
|
void EXPORT DangerSoundThink(void);
|
||||||
|
void EXPORT Detonate(void);
|
||||||
|
void EXPORT TumbleThink(void);
|
||||||
|
|
||||||
|
void BounceSound(void);
|
||||||
|
void DangerSound();
|
||||||
|
static void SpawnTrailParticles(const Vector& origin, const Vector& direction, int modelindex, int count, float speed, float noise);
|
||||||
|
static void SpawnExplosionParticles(const Vector& origin, const Vector& direction, int modelindex, int count, float speed, float noise);
|
||||||
|
|
||||||
|
void UpdateOnRemove();
|
||||||
|
|
||||||
|
CMSprite* m_pSporeGlow;
|
||||||
|
EHANDLE m_hOwner;
|
||||||
|
};
|
||||||
|
|
||||||
// constant items
|
// constant items
|
||||||
#define ITEM_HEALTHKIT 1
|
#define ITEM_HEALTHKIT 1
|
||||||
@@ -177,6 +206,8 @@ typedef enum
|
|||||||
BULLET_MONSTER_9MM,
|
BULLET_MONSTER_9MM,
|
||||||
BULLET_MONSTER_MP5,
|
BULLET_MONSTER_MP5,
|
||||||
BULLET_MONSTER_12MM,
|
BULLET_MONSTER_12MM,
|
||||||
|
BULLET_MONSTER_762,
|
||||||
|
BULLET_MONSTER_357,
|
||||||
} Bullet;
|
} Bullet;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
377
src/dlls/xenmaker.cpp
Normal file
377
src/dlls/xenmaker.cpp
Normal file
@@ -0,0 +1,377 @@
|
|||||||
|
//=========================================================
|
||||||
|
// Xen Maker - Sven Co-op's env_xenmaker.
|
||||||
|
// Spawns a monster with visual/auditive teleportation effects.
|
||||||
|
//=========================================================
|
||||||
|
|
||||||
|
#include "extdll.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "cmbase.h"
|
||||||
|
#include "cmbasemonster.h"
|
||||||
|
#include "cmbaseextra.h"
|
||||||
|
#include "monsters.h"
|
||||||
|
|
||||||
|
// Xenmaker spawnflags
|
||||||
|
#define SF_XENMAKER_TRY_ONCE 1 // only one attempt to spawn each time it is fired
|
||||||
|
#define SF_XENMAKER_NO_SPAWN 2 // don't spawn anything, only do effects
|
||||||
|
|
||||||
|
#define SF_XENMAKER_NO_LIGHT 4 // don't do light effect
|
||||||
|
#define SF_XENMAKER_NO_BEAMS 8 // don't do beam effects
|
||||||
|
#define SF_XENMAKER_NO_SPRITE 16 // don't do sprite effects
|
||||||
|
#define SF_XENMAKER_NO_SOUND 32 // don't do sound effect
|
||||||
|
|
||||||
|
extern monster_type_t monster_types[];
|
||||||
|
extern edict_t* spawn_monster(int monster_type, Vector origin, Vector angles, int spawnflags, pKVD *keyvalue);
|
||||||
|
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
void CMXenMaker::KeyValue(KeyValueData *pkvd)
|
||||||
|
{
|
||||||
|
if (FStrEq(pkvd->szKeyName, "monstertype"))
|
||||||
|
{
|
||||||
|
// Process monster_index
|
||||||
|
int mIndex;
|
||||||
|
for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
|
||||||
|
{
|
||||||
|
if (strcmp(pkvd->szValue, monster_types[mIndex].name) == 0)
|
||||||
|
{
|
||||||
|
m_iMonsterIndex = mIndex;
|
||||||
|
break; // grab the first entry we find
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (monster_types[mIndex].name[0] == 0)
|
||||||
|
{
|
||||||
|
ALERT(at_console, "[MONSTER] XenMaker - %s is not a valid monster type!\n", pkvd->szValue);
|
||||||
|
m_iMonsterIndex = -1;
|
||||||
|
}
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "m_flBeamRadius"))
|
||||||
|
{
|
||||||
|
m_flBeamRadius = atof(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "m_iBeamAlpha"))
|
||||||
|
{
|
||||||
|
m_iBeamAlpha = atoi(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "m_iBeamCount"))
|
||||||
|
{
|
||||||
|
m_iBeamCount = atoi(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "m_vBeamColor"))
|
||||||
|
{
|
||||||
|
UTIL_StringToVector(m_vBeamColor, pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "m_flLightRadius"))
|
||||||
|
{
|
||||||
|
m_flLightRadius = atof(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "m_vLightColor"))
|
||||||
|
{
|
||||||
|
UTIL_StringToVector(m_vLightColor, pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "m_flStartSpriteFramerate"))
|
||||||
|
{
|
||||||
|
m_flStartSpriteFramerate = atof(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "m_flStartSpriteScale"))
|
||||||
|
{
|
||||||
|
m_flStartSpriteScale = atof(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "m_iStartSpriteAlpha"))
|
||||||
|
{
|
||||||
|
m_iStartSpriteAlpha = atoi(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "m_vStartSpriteColor"))
|
||||||
|
{
|
||||||
|
UTIL_StringToVector(m_vStartSpriteColor, pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "m_flEndSpriteFramerate"))
|
||||||
|
{
|
||||||
|
m_flEndSpriteFramerate = atof(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "m_flEndSpriteScale"))
|
||||||
|
{
|
||||||
|
m_flEndSpriteScale = atof(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "m_iEndSpriteAlpha"))
|
||||||
|
{
|
||||||
|
m_iEndSpriteAlpha = atoi(pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "m_vEndSpriteColor"))
|
||||||
|
{
|
||||||
|
UTIL_StringToVector(m_vEndSpriteColor, pkvd->szValue);
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CMBaseMonster::KeyValue(pkvd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CMXenMaker::Spawn()
|
||||||
|
{
|
||||||
|
// likely omitted keyvalue, but it could truly be an alien grunt spawn
|
||||||
|
if (m_iMonsterIndex == 0)
|
||||||
|
{
|
||||||
|
if (!monster_types[0].need_to_precache)
|
||||||
|
{
|
||||||
|
// monstertype was not defined, it may be intentional if nothing is to spawn here
|
||||||
|
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_SPAWN))
|
||||||
|
ALERT(at_console, "[MONSTER] Spawned a env_xenmaker entity without a monstertype! targetname: \"%s\"\n", STRING(pev->targetname));
|
||||||
|
m_iMonsterIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix uninitialized keyvalues (default per Sven Co-op's FGD)
|
||||||
|
if (!m_flStartSpriteScale) m_flStartSpriteScale = 1.0;
|
||||||
|
if (!m_flEndSpriteScale) m_flEndSpriteScale = 1.0;
|
||||||
|
if (!m_flStartSpriteFramerate) m_flStartSpriteFramerate = 12;
|
||||||
|
if (!m_flEndSpriteFramerate) m_flEndSpriteFramerate = 12;
|
||||||
|
|
||||||
|
pev->solid = SOLID_NOT;
|
||||||
|
|
||||||
|
Precache();
|
||||||
|
|
||||||
|
SetUse(&CMXenMaker::CyclicUse); // drop one monster each time we fire
|
||||||
|
SetThink(&CMXenMaker::SUB_DoNothing);
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING("env_xenmaker");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMXenMaker::Precache(void)
|
||||||
|
{
|
||||||
|
m_iBeamIndex = PRECACHE_MODELINDEX("sprites/lgtning.spr");
|
||||||
|
PRECACHE_MODEL("sprites/fexplo1.spr");
|
||||||
|
PRECACHE_MODEL("sprites/xflare1.spr");
|
||||||
|
|
||||||
|
PRECACHE_SOUND("debris/beamstart7.wav");
|
||||||
|
PRECACHE_SOUND("debris/beamstart2.wav");
|
||||||
|
|
||||||
|
CMBaseMonster::Precache();
|
||||||
|
// choosen monster is auto-precached
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// StartEffect - spawns the monster and starts the effects
|
||||||
|
//=========================================================
|
||||||
|
void CMXenMaker::StartEffect(void)
|
||||||
|
{
|
||||||
|
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_SPAWN))
|
||||||
|
{
|
||||||
|
// monstermaker incorrectly setup
|
||||||
|
if (m_iMonsterIndex == -1)
|
||||||
|
{
|
||||||
|
ALERT(at_console, "[MONSTER] NULL Ent in XenMaker!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
edict_t *pent;
|
||||||
|
|
||||||
|
Vector mins = pev->origin - Vector(34, 34, 34);
|
||||||
|
Vector maxs = pev->origin + Vector(34, 34, 34);
|
||||||
|
|
||||||
|
edict_t *pList[2];
|
||||||
|
int count = UTIL_EntitiesInBox(pList, 2, mins, maxs, FL_CLIENT | FL_MONSTER);
|
||||||
|
if (!count)
|
||||||
|
{
|
||||||
|
// Attempt to spawn monster
|
||||||
|
pent = spawn_monster(m_iMonsterIndex, pev->origin, pev->angles, 0, NULL);
|
||||||
|
if (pent == NULL)
|
||||||
|
{
|
||||||
|
ALERT(at_console, "[MONSTER] XenMaker - failed to spawn monster! targetname: \"%s\"\n", STRING(pev->targetname));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pent->v.spawnflags |= SF_MONSTER_FADECORPSE;
|
||||||
|
}
|
||||||
|
else if (!FBitSet(pev->spawnflags, SF_XENMAKER_TRY_ONCE))
|
||||||
|
{
|
||||||
|
// wait until spawnpoint is clear
|
||||||
|
pev->nextthink = gpGlobals->time + 1;
|
||||||
|
SetUse(NULL);
|
||||||
|
SetThink(&CMXenMaker::RetryThink);
|
||||||
|
return; // don't do effects
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// no effects here, either
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BEAM EFFECT
|
||||||
|
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_BEAMS))
|
||||||
|
{
|
||||||
|
for (int beam = 0; beam < m_iBeamCount; beam++)
|
||||||
|
{
|
||||||
|
SpawnBeam();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LIGHT EFFECT
|
||||||
|
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_LIGHT))
|
||||||
|
{
|
||||||
|
MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
|
||||||
|
WRITE_BYTE(TE_DLIGHT);
|
||||||
|
WRITE_COORD(pev->origin.x);
|
||||||
|
WRITE_COORD(pev->origin.y);
|
||||||
|
WRITE_COORD(pev->origin.z);
|
||||||
|
WRITE_BYTE((int)(m_flLightRadius / 10));
|
||||||
|
WRITE_BYTE((int)m_vLightColor.x);
|
||||||
|
WRITE_BYTE((int)m_vLightColor.y);
|
||||||
|
WRITE_BYTE((int)m_vLightColor.z);
|
||||||
|
WRITE_BYTE(10); // life
|
||||||
|
WRITE_BYTE(0); // decay rate
|
||||||
|
MESSAGE_END();
|
||||||
|
}
|
||||||
|
|
||||||
|
// SPRITE EFFECT
|
||||||
|
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_SPRITE))
|
||||||
|
{
|
||||||
|
CMSprite *pSprite = CMSprite::SpriteCreate("sprites/fexplo1.spr", pev->origin, FALSE);
|
||||||
|
if (pSprite)
|
||||||
|
{
|
||||||
|
pSprite->SetScale(m_flStartSpriteScale);
|
||||||
|
pSprite->SetTransparency(kRenderGlow, (int)m_vStartSpriteColor.x, (int)m_vStartSpriteColor.y, (int)m_vStartSpriteColor.z, m_iStartSpriteAlpha, kRenderFxNoDissipation);
|
||||||
|
pSprite->AnimateAndDie(m_flStartSpriteFramerate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SOUND EFFECT
|
||||||
|
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_SOUND))
|
||||||
|
EMIT_SOUND_DYN(ENT(pev), CHAN_AUTO, "debris/beamstart7.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
|
||||||
|
|
||||||
|
pev->nextthink = gpGlobals->time + 0.5;
|
||||||
|
SetUse(NULL);
|
||||||
|
SetThink(&CMXenMaker::MiddleEffect);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// MiddleEffect - second set of effects
|
||||||
|
//=========================================================
|
||||||
|
void CMXenMaker::MiddleEffect(void)
|
||||||
|
{
|
||||||
|
// SPRITE EFFECT
|
||||||
|
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_SPRITE))
|
||||||
|
{
|
||||||
|
CMSprite *pSprite = CMSprite::SpriteCreate("sprites/xflare1.spr", pev->origin, FALSE);
|
||||||
|
if (pSprite)
|
||||||
|
{
|
||||||
|
pSprite->SetScale(m_flEndSpriteScale);
|
||||||
|
pSprite->SetTransparency(kRenderGlow, (int)m_vEndSpriteColor.x, (int)m_vEndSpriteColor.y, (int)m_vEndSpriteColor.z, m_iEndSpriteAlpha, kRenderFxNoDissipation);
|
||||||
|
pSprite->AnimateAndDie(m_flEndSpriteFramerate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pev->nextthink = gpGlobals->time + 0.5;
|
||||||
|
SetThink(&CMXenMaker::EndEffect);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// EndEffect - final set of effects
|
||||||
|
//=========================================================
|
||||||
|
void CMXenMaker::EndEffect(void)
|
||||||
|
{
|
||||||
|
// SOUND EFFECT
|
||||||
|
if (!FBitSet(pev->spawnflags, SF_XENMAKER_NO_SOUND))
|
||||||
|
EMIT_SOUND_DYN(ENT(pev), CHAN_AUTO, "debris/beamstart2.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
|
||||||
|
|
||||||
|
SetUse(&CMXenMaker::CyclicUse);
|
||||||
|
SetThink(&CMXenMaker::SUB_DoNothing);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// CyclicUse - drops one monster from the xen maker
|
||||||
|
// each time we call this.
|
||||||
|
//=========================================================
|
||||||
|
void CMXenMaker::CyclicUse(edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value)
|
||||||
|
{
|
||||||
|
StartEffect();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// RetryThink - try spawning again if spawn was obstructed
|
||||||
|
//=========================================================
|
||||||
|
void CMXenMaker::RetryThink(void)
|
||||||
|
{
|
||||||
|
SetUse(&CMXenMaker::CyclicUse);
|
||||||
|
SetThink(&CMXenMaker::SUB_DoNothing);
|
||||||
|
|
||||||
|
StartEffect();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================
|
||||||
|
// SpawnBeam - calculates beam end position and creates it.
|
||||||
|
// starting position is the origin of the xenmaker itself.
|
||||||
|
//=========================================================
|
||||||
|
void CMXenMaker::SpawnBeam(void)
|
||||||
|
{
|
||||||
|
// CLightning::RandomArea
|
||||||
|
for (int iLoops = 0; iLoops < 10; iLoops++)
|
||||||
|
{
|
||||||
|
Vector vecSrc = pev->origin;
|
||||||
|
|
||||||
|
Vector vecDir1 = Vector(RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0));
|
||||||
|
vecDir1 = vecDir1.Normalize();
|
||||||
|
TraceResult tr1;
|
||||||
|
UTIL_TraceLine(vecSrc, vecSrc + vecDir1 * m_flBeamRadius, ignore_monsters, ENT(pev), &tr1);
|
||||||
|
|
||||||
|
if (tr1.flFraction == 1.0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Vector vecDir2;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
vecDir2 = Vector(RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0), RANDOM_FLOAT(-1.0, 1.0));
|
||||||
|
} while (DotProduct(vecDir1, vecDir2) > 0);
|
||||||
|
vecDir2 = vecDir2.Normalize();
|
||||||
|
TraceResult tr2;
|
||||||
|
UTIL_TraceLine(vecSrc, vecSrc + vecDir2 * m_flBeamRadius, ignore_monsters, ENT(pev), &tr2);
|
||||||
|
|
||||||
|
if (tr2.flFraction == 1.0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((tr1.vecEndPos - tr2.vecEndPos).Length() < m_flBeamRadius * 0.1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
UTIL_TraceLine(tr1.vecEndPos, tr2.vecEndPos, ignore_monsters, ENT(pev), &tr2);
|
||||||
|
|
||||||
|
if (tr2.flFraction != 1.0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// CLightning::Zap
|
||||||
|
MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
|
||||||
|
WRITE_BYTE(TE_BEAMPOINTS);
|
||||||
|
WRITE_COORD(tr1.vecEndPos.x);
|
||||||
|
WRITE_COORD(tr1.vecEndPos.y);
|
||||||
|
WRITE_COORD(tr1.vecEndPos.z);
|
||||||
|
WRITE_COORD(tr2.vecEndPos.x);
|
||||||
|
WRITE_COORD(tr2.vecEndPos.y);
|
||||||
|
WRITE_COORD(tr2.vecEndPos.z);
|
||||||
|
WRITE_SHORT(m_iBeamIndex);
|
||||||
|
WRITE_BYTE(0); // starting frame
|
||||||
|
WRITE_BYTE(10); // framerate
|
||||||
|
WRITE_BYTE(10); // life
|
||||||
|
WRITE_BYTE(16); // width
|
||||||
|
WRITE_BYTE(64); // noise
|
||||||
|
WRITE_BYTE((int)m_vBeamColor.x);
|
||||||
|
WRITE_BYTE((int)m_vBeamColor.y);
|
||||||
|
WRITE_BYTE((int)m_vBeamColor.z);
|
||||||
|
WRITE_BYTE(m_iBeamAlpha);
|
||||||
|
WRITE_BYTE(15); // speed
|
||||||
|
MESSAGE_END();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -111,16 +111,6 @@ void CMZombie :: SetYawSpeed ( void )
|
|||||||
|
|
||||||
int CMZombie :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
int CMZombie :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
||||||
{
|
{
|
||||||
// Take 30% damage from bullets
|
|
||||||
if ( bitsDamageType == DMG_BULLET )
|
|
||||||
{
|
|
||||||
Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5;
|
|
||||||
vecDir = vecDir.Normalize();
|
|
||||||
float flForce = DamageForce( flDamage );
|
|
||||||
pev->velocity = pev->velocity + vecDir * flForce;
|
|
||||||
flDamage *= 0.3;
|
|
||||||
}
|
|
||||||
|
|
||||||
// HACK HACK -- until we fix this.
|
// HACK HACK -- until we fix this.
|
||||||
if ( IsAlive() )
|
if ( IsAlive() )
|
||||||
PainSound();
|
PainSound();
|
||||||
@@ -246,13 +236,13 @@ void CMZombie :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/zombie.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/zombie.mdl"));
|
||||||
UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX );
|
UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX );
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
pev->movetype = MOVETYPE_STEP;
|
pev->movetype = MOVETYPE_STEP;
|
||||||
m_bloodColor = BLOOD_COLOR_GREEN;
|
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
|
||||||
pev->health = gSkillData.zombieHealth;
|
if (!pev->health) { pev->health = gSkillData.zombieHealth; }
|
||||||
pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin.
|
pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin.
|
||||||
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
|
||||||
m_MonsterState = MONSTERSTATE_NONE;
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
@@ -273,27 +263,14 @@ void CMZombie :: Spawn()
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
void CMZombie :: Precache()
|
void CMZombie :: Precache()
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
PRECACHE_MODEL("models/zombie.mdl");
|
PRECACHE_MODEL("models/zombie.mdl");
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
|
PRECACHE_SOUND_ARRAY(pAttackHitSounds);
|
||||||
PRECACHE_SOUND((char *)pAttackHitSounds[i]);
|
PRECACHE_SOUND_ARRAY(pAttackMissSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pAttackSounds);
|
||||||
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
|
PRECACHE_SOUND_ARRAY(pIdleSounds);
|
||||||
PRECACHE_SOUND((char *)pAttackMissSounds[i]);
|
PRECACHE_SOUND_ARRAY(pAlertSounds);
|
||||||
|
PRECACHE_SOUND_ARRAY(pPainSounds);
|
||||||
for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pAttackSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pIdleSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pAlertSounds[i]);
|
|
||||||
|
|
||||||
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
|
|
||||||
PRECACHE_SOUND((char *)pPainSounds[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
|
|||||||
@@ -420,11 +420,10 @@ typedef enum _fieldtypes
|
|||||||
FIELD_TYPECOUNT, // MUST BE LAST
|
FIELD_TYPECOUNT, // MUST BE LAST
|
||||||
} FIELDTYPE;
|
} FIELDTYPE;
|
||||||
|
|
||||||
#ifndef linux
|
|
||||||
#ifndef offsetof
|
#if !defined(offsetof) && !defined(GNUC)
|
||||||
#define offsetof(s,m) (size_t)&(((s *)0)->m)
|
#define offsetof(s,m) (size_t)&(((s *)0)->m)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
#define _FIELD(type,name,fieldtype,count,flags) { fieldtype, #name, offsetof(type, name), count, flags }
|
#define _FIELD(type,name,fieldtype,count,flags) { fieldtype, #name, offsetof(type, name), count, flags }
|
||||||
#define DEFINE_FIELD(type,name,fieldtype) _FIELD(type, name, fieldtype, 1, 0)
|
#define DEFINE_FIELD(type,name,fieldtype) _FIELD(type, name, fieldtype, 1, 0)
|
||||||
|
|||||||
@@ -74,15 +74,18 @@
|
|||||||
#endif //defined WIN32
|
#endif //defined WIN32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (_WIN32) && defined (_MSC_VER)
|
// VS2015 and newer already has va_copy defined
|
||||||
|
#if defined (_WIN32) && defined (_MSC_VER) && _MSC_VER < 1900
|
||||||
// On x86 va_list is just a pointer.
|
// On x86 va_list is just a pointer.
|
||||||
#define va_copy(dst,src) ((dst)=(src))
|
#define va_copy(dst,src) ((dst)=(src))
|
||||||
#else
|
#else
|
||||||
|
#if (linux)
|
||||||
// Some systems that do not supply va_copy have __va_copy instead, since
|
// Some systems that do not supply va_copy have __va_copy instead, since
|
||||||
// that was the name used in the draft proposal.
|
// that was the name used in the draft proposal.
|
||||||
#if !defined(__GNUC__) || __GNUC__ < 3
|
#if !defined(__GNUC__) || __GNUC__ < 3
|
||||||
#define va_copy __va_copy
|
#define va_copy __va_copy
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Manual branch optimization for GCC 3.0.0 and newer
|
// Manual branch optimization for GCC 3.0.0 and newer
|
||||||
|
|||||||
@@ -37,7 +37,13 @@
|
|||||||
#ifndef ENGINE_API_H
|
#ifndef ENGINE_API_H
|
||||||
#define ENGINE_API_H
|
#define ENGINE_API_H
|
||||||
|
|
||||||
#include <stdint.h> // why?
|
// No proper C99 support in old MVSC6, use custom stdint.h
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "stdint_c99.h"
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "comp_dep.h"
|
#include "comp_dep.h"
|
||||||
|
|
||||||
// Plugin's GetEngineFunctions, called by metamod.
|
// Plugin's GetEngineFunctions, called by metamod.
|
||||||
|
|||||||
@@ -80,7 +80,9 @@
|
|||||||
// DLL.
|
// DLL.
|
||||||
#undef DLLEXPORT
|
#undef DLLEXPORT
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define DLLEXPORT __declspec(dllexport) __attribute__ ((externally_visible))
|
// __attribute__ ((externally_visible)) is not recognized by VC++6
|
||||||
|
// or, rather, is GCC-only. do we need it for windows builds? -Giegue
|
||||||
|
#define DLLEXPORT __declspec(dllexport)
|
||||||
// WINAPI should be provided in the windows compiler headers.
|
// WINAPI should be provided in the windows compiler headers.
|
||||||
// It's usually defined to something like "__stdcall".
|
// It's usually defined to something like "__stdcall".
|
||||||
#elif defined(linux)
|
#elif defined(linux)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user