Compare commits
97 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
0f2bd95275 | ||
|
|
be8df87e82 | ||
|
|
aa99d801c7 | ||
|
|
aa57599c3c | ||
|
|
b2beda8f68 | ||
|
|
6d4a608793 | ||
|
|
612ce63050 | ||
|
|
1e68434df5 | ||
|
|
4d61695e6b | ||
|
|
4912f6d23d | ||
|
|
50fd9aa13a | ||
|
|
d72aba3b6f | ||
|
|
d39bc85ab6 | ||
|
|
5c275e5b62 | ||
|
|
b4ec347170 | ||
|
|
8f899d2c6d | ||
|
|
d63e0af548 |
82
README.md
82
README.md
@@ -21,27 +21,57 @@ 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 when hurt during death animations.
|
||||||
|
|
||||||
|
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
|
||||||
@@ -53,29 +83,41 @@ Current milestones are separated by "Tiers", which are as follows:
|
|||||||
- Rework config processing to use a "key --> value" format. **[DONE]**
|
- Rework config processing to use a "key --> value" format. **[DONE]**
|
||||||
- Add info_node and info_node_air support for AI navigation. **[DONE]**
|
- Add info_node and info_node_air support for AI navigation. **[DONE]**
|
||||||
- Add node_viewer to debug node graph generation. **[DONE]**
|
- Add node_viewer to debug node graph generation. **[DONE]**
|
||||||
- Implement Gargantua and all Turrets from Half-Life.
|
- Implement Gargantua and all Turrets from Half-Life. **[DONE]**
|
||||||
|
|
||||||
### Tier 2
|
### Tier 2
|
||||||
|
|
||||||
- Add *-at least minimal-* death messages. *-Example: "\<player\> was killed by a \<monster\>".-*
|
- Add *-at least minimal-* death messages. *-Example: "\<player\> was killed by a \<monster\>".-* **[DONE]**
|
||||||
- Implement HUD info about the monsters, along with the "displayname" keyvalue.
|
- Implement HUD info about the monsters, along with the "displayname" keyvalue. **[DONE]**
|
||||||
- Implement custom monster classification, the "classify" keyvalue.
|
- Implement custom monster classification, the "classify" keyvalue. **[DONE]**
|
||||||
|
|
||||||
### 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,20 +2,21 @@
|
|||||||
// 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
|
||||||
|
|
||||||
{
|
{
|
||||||
"origin" "90 -180 150"
|
"origin" "90 -180 150"
|
||||||
"delay" "30"
|
"displayname" "Example Custom Name"
|
||||||
"orientation" "1"
|
"orientation" "1"
|
||||||
"spawnflags" "32"
|
"spawnflags" "32"
|
||||||
"classname" "monster_miniturret"
|
"classname" "monster_miniturret"
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
"origin" "123 456 789"
|
"origin" "123 456 789"
|
||||||
"delay" "5"
|
"classify" "7"
|
||||||
"angles" "0 45 0"
|
"angles" "0 45 0"
|
||||||
"classname" "monster_houndeye"
|
"classname" "monster_houndeye"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,25 @@
|
|||||||
|
// 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.
|
||||||
//
|
//
|
||||||
// (just remove the comment characters at the beginning of the line for the
|
// Install this file to your mod's base directory.
|
||||||
// monsters that you always want to precache.)
|
// Then, remove the comment characters at the beginning of the line for the
|
||||||
|
// monsters that you always want to precache.
|
||||||
|
//
|
||||||
|
// Be wary if you precache too many monsters, it may easily crash your
|
||||||
|
// 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_hassassin
|
//monster_human_assassin
|
||||||
//monster_headcrab
|
//monster_headcrab
|
||||||
//monster_human_grunt
|
//monster_human_grunt
|
||||||
//monster_houndeye
|
//monster_houndeye
|
||||||
//monster_alien_slave
|
//monster_alien_slave
|
||||||
//monster_icthyosaur
|
|
||||||
//monster_alien_controller
|
//monster_alien_controller
|
||||||
//monster_scientist
|
//monster_scientist
|
||||||
//monster_snark
|
//monster_snark
|
||||||
@@ -23,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
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
// MONSTERS health and damage amounts
|
// MONSTERS health and damage amounts
|
||||||
//
|
//
|
||||||
// (Note: Some of these aren't currently used. They're in here for future use.)
|
// 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
|
||||||
@@ -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,20 +31,34 @@ 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 \
|
||||||
|
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 \
|
||||||
zombie.o
|
zombie.o
|
||||||
|
|
||||||
|
|||||||
@@ -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",
|
||||||
@@ -125,10 +132,13 @@ const char *CMAGrunt::pAlertSounds[] =
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMAGrunt::IRelationship ( CMBaseEntity *pTarget )
|
int CMAGrunt::IRelationship ( CMBaseEntity *pTarget )
|
||||||
{
|
{
|
||||||
|
// ditto hgrunt.cpp
|
||||||
|
/*
|
||||||
if ( strcmp(STRING(pTarget->pev->model), "models/hgrunt.mdl") == 0 )
|
if ( strcmp(STRING(pTarget->pev->model), "models/hgrunt.mdl") == 0 )
|
||||||
{
|
{
|
||||||
return R_NM;
|
return R_NM;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
return CMBaseMonster :: IRelationship( pTarget );
|
return CMBaseMonster :: IRelationship( pTarget );
|
||||||
}
|
}
|
||||||
@@ -181,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -313,6 +318,11 @@ void CMAGrunt :: PainSound ( void )
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMAGrunt :: Classify ( void )
|
int CMAGrunt :: Classify ( void )
|
||||||
{
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
return CLASS_ALIEN_MILITARY;
|
return CLASS_ALIEN_MILITARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,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 )
|
||||||
@@ -524,12 +536,12 @@ 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;
|
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 )
|
||||||
@@ -541,6 +553,13 @@ void CMAGrunt :: Spawn()
|
|||||||
m_flNextSpeakTime = m_flNextWordTime = gpGlobals->time + 10 + RANDOM_LONG(0, 10);
|
m_flNextSpeakTime = m_flNextWordTime = gpGlobals->time + 10 + RANDOM_LONG(0, 10);
|
||||||
|
|
||||||
MonsterInit();
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_alien_grunt" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Alien Grunt" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -548,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();
|
||||||
@@ -1015,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,7 +35,7 @@ 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 );
|
||||||
|
|
||||||
@@ -84,6 +84,13 @@ void CMApache :: Spawn( void )
|
|||||||
m_flPrevSeen = 0.0f;
|
m_flPrevSeen = 0.0f;
|
||||||
|
|
||||||
m_iSoundState = 0;
|
m_iSoundState = 0;
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_apache" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Apache" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -98,20 +105,28 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CMApache :: Classify ( void )
|
||||||
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
|
return CLASS_HUMAN_MILITARY;
|
||||||
|
}
|
||||||
|
|
||||||
void CMApache::NullThink( void )
|
void CMApache::NullThink( void )
|
||||||
{
|
{
|
||||||
@@ -142,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;
|
||||||
@@ -163,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 );
|
||||||
@@ -178,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 );
|
||||||
@@ -404,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( );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -915,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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -186,6 +186,11 @@ int CMBarney :: ISoundMask ( void)
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMBarney :: Classify ( void )
|
int CMBarney :: Classify ( void )
|
||||||
{
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
return CLASS_PLAYER_ALLY;
|
return CLASS_PLAYER_ALLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,12 +345,12 @@ 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;
|
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;
|
||||||
@@ -357,6 +362,13 @@ void CMBarney :: Spawn()
|
|||||||
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
|
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
|
||||||
|
|
||||||
MonsterInit();
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_barney" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Barney" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ public:
|
|||||||
|
|
||||||
void CMInfoBM::Spawn( void )
|
void CMInfoBM::Spawn( void )
|
||||||
{
|
{
|
||||||
|
pev->classname = MAKE_STRING( "info_bigmomma" );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMInfoBM::KeyValue( KeyValueData* pkvd )
|
void CMInfoBM::KeyValue( KeyValueData* pkvd )
|
||||||
@@ -298,6 +299,11 @@ void CMBigMomma :: KeyValue( KeyValueData *pkvd )
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMBigMomma :: Classify ( void )
|
int CMBigMomma :: Classify ( void )
|
||||||
{
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
return CLASS_ALIEN_MONSTER;
|
return CLASS_ALIEN_MONSTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -597,19 +603,26 @@ 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;
|
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;
|
||||||
|
|
||||||
MonsterInit();
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_bigmomma" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Big Momma" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -635,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" );
|
||||||
|
|||||||
@@ -166,6 +166,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 );
|
||||||
@@ -357,6 +359,11 @@ BOOL CMBullsquid :: FValidateHintType ( short sHint )
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMBullsquid :: Classify ( void )
|
int CMBullsquid :: Classify ( void )
|
||||||
{
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
return CLASS_ALIEN_MONSTER;
|
return CLASS_ALIEN_MONSTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -603,12 +610,12 @@ 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;
|
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 )
|
||||||
@@ -617,6 +624,13 @@ void CMBullsquid :: Spawn()
|
|||||||
m_flNextSpitTime = gpGlobals->time;
|
m_flNextSpitTime = gpGlobals->time;
|
||||||
|
|
||||||
MonsterInit();
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_bullchicken" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Bullsquid" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -628,7 +642,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 ) {}
|
||||||
|
|
||||||
@@ -540,7 +542,6 @@ public:
|
|||||||
|
|
||||||
class CMBaseMonster;
|
class CMBaseMonster;
|
||||||
|
|
||||||
|
|
||||||
extern int GetMonsterIndex(void);
|
extern int GetMonsterIndex(void);
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -600,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
|
||||||
@@ -608,3 +608,7 @@ template <class T> T * CreateClassPtr( T *a )
|
|||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef GLOBALREPLACE_H
|
||||||
|
#include "globalreplace.h"
|
||||||
|
#endif
|
||||||
|
|||||||
51
src/dlls/cmbaseextra.h
Normal file
51
src/dlls/cmbaseextra.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#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
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BASEEXTRA_H
|
||||||
@@ -102,6 +102,14 @@ public:
|
|||||||
|
|
||||||
Vector m_HackedGunPos; // HACK until we can query end of gun
|
Vector m_HackedGunPos; // HACK until we can query end of gun
|
||||||
|
|
||||||
|
string_t m_szMonsterName; // Monster name to display on HUD
|
||||||
|
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
|
||||||
@@ -131,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 );
|
||||||
@@ -210,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 );
|
||||||
@@ -344,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;
|
||||||
@@ -367,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; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -724,6 +734,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[];
|
||||||
@@ -792,7 +803,7 @@ class CMApache : public CMBaseMonster
|
|||||||
public:
|
public:
|
||||||
void Spawn( void );
|
void Spawn( void );
|
||||||
void Precache( void );
|
void Precache( void );
|
||||||
int Classify( void ) { return CLASS_HUMAN_MILITARY; };
|
int Classify( void );
|
||||||
int BloodColor( void ) { return DONT_BLEED; }
|
int BloodColor( void ) { return DONT_BLEED; }
|
||||||
void Killed( entvars_t *pevAttacker, int iGib );
|
void Killed( entvars_t *pevAttacker, int iGib );
|
||||||
void GibMonster( void );
|
void GibMonster( void );
|
||||||
@@ -1084,6 +1095,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
|
||||||
|
|
||||||
@@ -1234,4 +1246,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,6 +597,10 @@ void CMBaseMonster :: Killed( entvars_t *pevAttacker, int iGib )
|
|||||||
unsigned int cCount = 0;
|
unsigned int cCount = 0;
|
||||||
BOOL fDone = FALSE;
|
BOOL fDone = FALSE;
|
||||||
|
|
||||||
|
// If a player killed this monster, add score
|
||||||
|
if ( UTIL_IsPlayer( ENT( pevAttacker ) ) )
|
||||||
|
pevAttacker->frags += 1.0;
|
||||||
|
|
||||||
if ( HasMemory( bits_MEMORY_KILLED ) )
|
if ( HasMemory( bits_MEMORY_KILLED ) )
|
||||||
{
|
{
|
||||||
if ( ShouldGibMonster( iGib ) )
|
if ( ShouldGibMonster( iGib ) )
|
||||||
@@ -606,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 ) )
|
||||||
{
|
{
|
||||||
@@ -1142,6 +1150,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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1195,6 +1253,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;
|
||||||
@@ -1262,32 +1322,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 );
|
||||||
@@ -1356,6 +1416,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 );
|
||||||
@@ -1382,7 +1444,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:
|
||||||
@@ -1408,6 +1472,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);
|
||||||
@@ -1420,7 +1498,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));
|
||||||
|
|
||||||
@@ -1430,7 +1509,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:
|
||||||
@@ -1456,6 +1537,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);
|
||||||
@@ -1469,6 +1564,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 );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,11 @@ const char *CMController::pDeathSounds[] =
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMController :: Classify ( void )
|
int CMController :: Classify ( void )
|
||||||
{
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
return CLASS_ALIEN_MILITARY;
|
return CLASS_ALIEN_MILITARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,19 +302,26 @@ 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;
|
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;
|
||||||
|
|
||||||
MonsterInit();
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_alien_controller" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Alien Controller" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -1113,6 +1125,8 @@ void CMControllerHeadBall :: Spawn( void )
|
|||||||
|
|
||||||
m_hOwner = pev->owner;
|
m_hOwner = pev->owner;
|
||||||
pev->dmgtime = gpGlobals->time;
|
pev->dmgtime = gpGlobals->time;
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "controller_head_ball" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1171,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) );
|
||||||
}
|
}
|
||||||
@@ -1297,8 +1313,9 @@ void CMControllerZapBall :: Spawn( void )
|
|||||||
m_hOwner = pev->owner;
|
m_hOwner = pev->owner;
|
||||||
pev->dmgtime = gpGlobals->time; // keep track of when ball spawned
|
pev->dmgtime = gpGlobals->time; // keep track of when ball spawned
|
||||||
pev->nextthink = gpGlobals->time + 0.1;
|
pev->nextthink = gpGlobals->time + 0.1;
|
||||||
}
|
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "controller_energy_ball" );
|
||||||
|
}
|
||||||
|
|
||||||
void CMControllerZapBall :: Precache( void )
|
void CMControllerZapBall :: Precache( void )
|
||||||
{
|
{
|
||||||
@@ -1346,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 ) );
|
||||||
|
|||||||
1120
src/dlls/dllapi.cpp
1120
src/dlls/dllapi.cpp
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
68
src/dlls/explode.cpp
Executable file → Normal file
68
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,52 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 +172,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 +298,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 +327,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
|
||||||
|
|||||||
694
src/dlls/gargantua.cpp
Executable file → Normal file
694
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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -624,6 +632,11 @@ void CMGargantua :: PrescheduleThink( void )
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMGargantua :: Classify ( void )
|
int CMGargantua :: Classify ( void )
|
||||||
{
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
return CLASS_ALIEN_MONSTER;
|
return CLASS_ALIEN_MONSTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -665,12 +678,12 @@ 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;
|
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 )
|
||||||
@@ -684,6 +697,13 @@ void CMGargantua :: Spawn()
|
|||||||
EyeOff();
|
EyeOff();
|
||||||
m_seeTime = gpGlobals->time + 5;
|
m_seeTime = gpGlobals->time + 5;
|
||||||
m_flameTime = gpGlobals->time + 2;
|
m_flameTime = gpGlobals->time + 2;
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_gargantua" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Gargantua" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -692,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]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -768,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 );
|
||||||
@@ -776,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 );
|
||||||
@@ -809,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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -973,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;
|
||||||
@@ -1154,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;
|
||||||
@@ -1253,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";
|
||||||
@@ -1272,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;
|
||||||
|
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 );
|
||||||
|
|||||||
164
src/dlls/globalreplace.cpp
Normal file
164
src/dlls/globalreplace.cpp
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
//=========================================================
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -88,6 +88,11 @@ int CMHAssassin :: ISoundMask ( void)
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMHAssassin :: Classify ( void )
|
int CMHAssassin :: Classify ( void )
|
||||||
{
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
return CLASS_HUMAN_MILITARY;
|
return CLASS_HUMAN_MILITARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,12 +215,12 @@ 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;
|
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 )
|
||||||
@@ -230,6 +235,13 @@ void CMHAssassin :: Spawn()
|
|||||||
pev->rendermode = kRenderTransTexture;
|
pev->rendermode = kRenderTransTexture;
|
||||||
|
|
||||||
MonsterInit();
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_human_assassin" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Female Assassin" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -244,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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -119,6 +119,11 @@ const char *CMHeadCrab::pBiteSounds[] =
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMHeadCrab :: Classify ( void )
|
int CMHeadCrab :: Classify ( void )
|
||||||
{
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
return CLASS_ALIEN_PREY;
|
return CLASS_ALIEN_PREY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,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;
|
||||||
@@ -242,12 +247,12 @@ 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;
|
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.
|
||||||
@@ -256,6 +261,13 @@ void CMHeadCrab :: Spawn()
|
|||||||
m_MonsterState = MONSTERSTATE_NONE;
|
m_MonsterState = MONSTERSTATE_NONE;
|
||||||
|
|
||||||
MonsterInit();
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_headcrab" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Head Crab" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -313,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 );
|
||||||
@@ -347,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;
|
||||||
@@ -403,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() );
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -411,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() );
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -419,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() );
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -427,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 )
|
||||||
@@ -449,7 +461,7 @@ 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));
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,12 +174,15 @@ void CMHGrunt :: SpeakSentence( void )
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMHGrunt::IRelationship ( CMBaseEntity *pTarget )
|
int CMHGrunt::IRelationship ( CMBaseEntity *pTarget )
|
||||||
{
|
{
|
||||||
|
// on single player, forcing R_NM makes sense.
|
||||||
|
// on multiplayer, a custom classification will cause misbehaviour.
|
||||||
|
/*
|
||||||
if (( strcmp(STRING(pTarget->pev->model), "models/agrunt.mdl") == 0 ) ||
|
if (( strcmp(STRING(pTarget->pev->model), "models/agrunt.mdl") == 0 ) ||
|
||||||
( strcmp(STRING(pTarget->pev->model), "models/garg.mdl") == 0 ))
|
( strcmp(STRING(pTarget->pev->model), "models/garg.mdl") == 0 ))
|
||||||
{
|
{
|
||||||
return R_NM;
|
return R_NM;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
return CMBaseMonster::IRelationship( pTarget );
|
return CMBaseMonster::IRelationship( pTarget );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -566,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;
|
||||||
@@ -596,6 +600,11 @@ void CMHGrunt :: CheckAmmo ( void )
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMHGrunt :: Classify ( void )
|
int CMHGrunt :: Classify ( void )
|
||||||
{
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
return CLASS_HUMAN_MILITARY;
|
return CLASS_HUMAN_MILITARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -790,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;
|
||||||
@@ -800,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -819,12 +830,12 @@ 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;
|
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 )
|
||||||
@@ -886,6 +897,13 @@ void CMHGrunt :: Spawn()
|
|||||||
CMTalkMonster::g_talkWaitTime = 0;
|
CMTalkMonster::g_talkWaitTime = 0;
|
||||||
|
|
||||||
MonsterInit();
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_human_grunt" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Human Grunt" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -922,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");
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -1658,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 )
|
||||||
{
|
{
|
||||||
@@ -1682,6 +1731,7 @@ DEFINE_CUSTOM_SCHEDULES( CMHGrunt )
|
|||||||
slGruntRepel,
|
slGruntRepel,
|
||||||
slGruntRepelAttack,
|
slGruntRepelAttack,
|
||||||
slGruntRepelLand,
|
slGruntRepelLand,
|
||||||
|
slGruntChaseEnemyFailed,
|
||||||
};
|
};
|
||||||
|
|
||||||
IMPLEMENT_CUSTOM_SCHEDULES( CMHGrunt, CMBaseMonster );
|
IMPLEMENT_CUSTOM_SCHEDULES( CMHGrunt, CMBaseMonster );
|
||||||
@@ -1837,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
|
||||||
@@ -1852,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1873,6 +1925,7 @@ jlb*/
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
// no ammo
|
// no ammo
|
||||||
else if ( HasConditions ( bits_COND_NO_AMMO_LOADED ) )
|
else if ( HasConditions ( bits_COND_NO_AMMO_LOADED ) )
|
||||||
@@ -1898,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 );
|
||||||
}
|
}
|
||||||
@@ -1924,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
|
||||||
@@ -1931,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
|
||||||
@@ -1960,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 ) )
|
||||||
@@ -2094,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 );
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ void CMHornet :: Spawn( void )
|
|||||||
pev->movetype = MOVETYPE_FLY;
|
pev->movetype = MOVETYPE_FLY;
|
||||||
pev->solid = SOLID_BBOX;
|
pev->solid = SOLID_BBOX;
|
||||||
pev->takedamage = DAMAGE_YES;
|
pev->takedamage = DAMAGE_YES;
|
||||||
pev->flags |= FL_MONSTER;
|
pev->flags |= FL_MONSTER; // I have a bad feeling about this
|
||||||
pev->health = 1;// weak!
|
pev->health = 1;// weak!
|
||||||
|
|
||||||
// hornets don't live as long in multiplayer
|
// hornets don't live as long in multiplayer
|
||||||
@@ -83,6 +83,8 @@ void CMHornet :: Spawn( void )
|
|||||||
|
|
||||||
pev->nextthink = gpGlobals->time + 0.1;
|
pev->nextthink = gpGlobals->time + 0.1;
|
||||||
ResetSequenceInfo( );
|
ResetSequenceInfo( );
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "hornet" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -102,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");
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -124,12 +126,13 @@ int CMHornet::IRelationship ( CMBaseEntity *pTarget )
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMHornet::Classify ( void )
|
int CMHornet::Classify ( void )
|
||||||
{
|
{
|
||||||
|
// Ensure classify is consistent with the owner, in the event
|
||||||
if ( pev->owner && pev->owner->v.flags & FL_CLIENT)
|
// it's classification was overriden.
|
||||||
|
if (UTIL_IsValidEntity(pev->owner))
|
||||||
{
|
{
|
||||||
return CLASS_PLAYER_BIOWEAPON;
|
CMBaseMonster *pOwner = GetClassPtr((CMBaseMonster *)VARS(pev->owner));
|
||||||
|
return pOwner->Classify();
|
||||||
}
|
}
|
||||||
|
|
||||||
return CLASS_ALIEN_BIOWEAPON;
|
return CLASS_ALIEN_BIOWEAPON;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,11 +317,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.
|
||||||
|
|
||||||
@@ -361,6 +363,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
|
||||||
|
|||||||
@@ -78,6 +78,11 @@ enum
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMHoundeye :: Classify ( void )
|
int CMHoundeye :: Classify ( void )
|
||||||
{
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
return CLASS_ALIEN_MONSTER;
|
return CLASS_ALIEN_MONSTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,12 +267,12 @@ 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;
|
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?
|
||||||
@@ -277,6 +282,13 @@ void CMHoundeye :: Spawn()
|
|||||||
m_fDontBlink = FALSE;
|
m_fDontBlink = FALSE;
|
||||||
|
|
||||||
MonsterInit();
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_houndeye" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Houndeye" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -314,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" );
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -512,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.
|
||||||
@@ -553,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;
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -67,6 +67,11 @@ const char *CMISlave::pDeathSounds[] =
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMISlave :: Classify ( void )
|
int CMISlave :: Classify ( void )
|
||||||
{
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
return CLASS_ALIEN_MILITARY;
|
return CLASS_ALIEN_MILITARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,12 +416,12 @@ 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;
|
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.
|
||||||
@@ -433,6 +438,12 @@ void CMISlave :: Spawn()
|
|||||||
m_flNextAttack = 0.0f;
|
m_flNextAttack = 0.0f;
|
||||||
|
|
||||||
MonsterInit();
|
MonsterInit();
|
||||||
|
pev->classname = MAKE_STRING( "monster_alien_slave" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Alien Slave" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -440,8 +451,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");
|
||||||
@@ -452,17 +461,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]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -726,6 +728,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;
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,7 +40,8 @@
|
|||||||
#include "sdk_util.h" // UTIL_LogPrintf, etc
|
#include "sdk_util.h" // UTIL_LogPrintf, etc
|
||||||
|
|
||||||
// Must provide at least one of these..
|
// Must provide at least one of these..
|
||||||
static META_FUNCTIONS gMetaFunctionTable = {
|
static META_FUNCTIONS gMetaFunctionTable =
|
||||||
|
{
|
||||||
NULL, // pfnGetEntityAPI HL SDK; called before game DLL
|
NULL, // pfnGetEntityAPI HL SDK; called before game DLL
|
||||||
NULL, // pfnGetEntityAPI_Post META; called after game DLL
|
NULL, // pfnGetEntityAPI_Post META; called after game DLL
|
||||||
GetEntityAPI2, // pfnGetEntityAPI2 HL SDK2; called before game DLL
|
GetEntityAPI2, // pfnGetEntityAPI2 HL SDK2; called before game DLL
|
||||||
@@ -48,15 +49,15 @@ static META_FUNCTIONS gMetaFunctionTable = {
|
|||||||
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
|
||||||
NULL, // pfnGetEngineFunctions META; called before HL engine
|
NULL, // pfnGetEngineFunctions META; called before HL engine
|
||||||
NULL, // pfnGetEngineFunctions_Post META; called after HL engine
|
GetEngineFunctions_Post, // pfnGetEngineFunctions_Post META; called after HL engine
|
||||||
};
|
};
|
||||||
|
|
||||||
// Description of plugin
|
// Description of plugin
|
||||||
plugin_info_t Plugin_info = {
|
plugin_info_t Plugin_info = {
|
||||||
META_INTERFACE_VERSION, // interface version
|
META_INTERFACE_VERSION, // interface version
|
||||||
"MonsterMod", // name
|
"MonsterMod", // name
|
||||||
"1.0", // version
|
"4.0", // version
|
||||||
"17/03/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
|
||||||
@@ -77,10 +78,25 @@ meta_globals_t *gpMetaGlobals; // metamod globals
|
|||||||
gamedll_funcs_t *gpGamedllFuncs; // gameDLL function tables
|
gamedll_funcs_t *gpGamedllFuncs; // gameDLL function tables
|
||||||
mutil_funcs_t *gpMetaUtilFuncs; // metamod utility functions
|
mutil_funcs_t *gpMetaUtilFuncs; // metamod utility functions
|
||||||
|
|
||||||
|
// CVars
|
||||||
cvar_t init_dllapi_log = {"monster_log", "0", FCVAR_EXTDLL, 0, NULL};
|
cvar_t init_dllapi_log = {"monster_log", "0", FCVAR_EXTDLL, 0, NULL};
|
||||||
cvar_t *dllapi_log = NULL;
|
cvar_t *dllapi_log = NULL;
|
||||||
cvar_t init_monster_spawn = {"monster_spawn", "1", FCVAR_EXTDLL, 0, NULL};
|
cvar_t init_monster_spawn = {"monster_spawn", "1", FCVAR_EXTDLL, 0, NULL};
|
||||||
cvar_t *monster_spawn = NULL;
|
cvar_t *monster_spawn = NULL;
|
||||||
|
cvar_t init_monster_show_deaths = {"monster_show_deaths", "1", FCVAR_EXTDLL, 0, NULL};
|
||||||
|
cvar_t *monster_show_deaths = NULL;
|
||||||
|
cvar_t init_monster_show_info = {"monster_show_info", "1", FCVAR_EXTDLL, 0, 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:
|
||||||
@@ -103,16 +119,17 @@ C_DLLEXPORT int Meta_Query(char *ifvers, plugin_info_t **pPlugInfo,
|
|||||||
// pFunctionTable (requested) table of function tables this plugin catches
|
// pFunctionTable (requested) table of function tables this plugin catches
|
||||||
// pMGlobals (given) global vars from metamod
|
// pMGlobals (given) global vars from metamod
|
||||||
// pGamedllFuncs (given) copy of function tables from game dll
|
// pGamedllFuncs (given) copy of function tables from game dll
|
||||||
C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable,
|
C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs)
|
||||||
meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs)
|
|
||||||
{
|
{
|
||||||
if(now); // to satisfy gcc -Wunused
|
if(now); // to satisfy gcc -Wunused
|
||||||
if(!pMGlobals) {
|
if(!pMGlobals)
|
||||||
|
{
|
||||||
LOG_ERROR(PLID, "Meta_Attach called with null pMGlobals");
|
LOG_ERROR(PLID, "Meta_Attach called with null pMGlobals");
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
gpMetaGlobals=pMGlobals;
|
gpMetaGlobals=pMGlobals;
|
||||||
if(!pFunctionTable) {
|
if(!pFunctionTable)
|
||||||
|
{
|
||||||
LOG_ERROR(PLID, "Meta_Attach called with null pFunctionTable");
|
LOG_ERROR(PLID, "Meta_Attach called with null pFunctionTable");
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
@@ -133,6 +150,26 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable,
|
|||||||
CVAR_REGISTER(&init_monster_spawn);
|
CVAR_REGISTER(&init_monster_spawn);
|
||||||
monster_spawn = CVAR_GET_POINTER("monster_spawn");
|
monster_spawn = CVAR_GET_POINTER("monster_spawn");
|
||||||
|
|
||||||
|
CVAR_REGISTER(&init_monster_show_deaths);
|
||||||
|
monster_show_deaths = CVAR_GET_POINTER("monster_show_deaths");
|
||||||
|
|
||||||
|
CVAR_REGISTER(&init_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,84 @@ 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 +178,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 +194,37 @@ 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, "info_node") == 0)
|
else if (strcmp(monster_types[mIndex].name, "info_node") == 0)
|
||||||
{
|
{
|
||||||
// Normal node
|
// Normal node
|
||||||
@@ -142,7 +257,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 +265,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 +307,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 +339,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 entity
|
||||||
|
if (strcmp(data[kvd_index-1].value, "monstermaker") == 0 || strcmp(data[kvd_index-1].value, "squadmaker") == 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);
|
||||||
|
|
||||||
|
// 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
|
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 +441,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 +467,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 +502,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)
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
// 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
|
||||||
227
src/dlls/monster_mm.vcxproj
Normal file
227
src/dlls/monster_mm.vcxproj
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
<?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>
|
||||||
|
</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="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="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>
|
||||||
285
src/dlls/monster_mm.vcxproj.filters
Normal file
285
src/dlls/monster_mm.vcxproj.filters
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
<?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>
|
||||||
|
</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 400
|
||||||
|
|
||||||
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 200
|
||||||
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
|
||||||
|
|||||||
355
src/dlls/monstermaker.cpp
Normal file
355
src/dlls/monstermaker.cpp
Normal file
@@ -0,0 +1,355 @@
|
|||||||
|
/***
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
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]; // sometimes, i don't know what am i doing. -Giegue
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, sizeof(REPLACER::REPLACER));
|
||||||
|
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)
|
||||||
@@ -2504,11 +2613,51 @@ void CMBaseMonster :: KeyValue( KeyValueData *pkvd )
|
|||||||
m_iszTriggerTarget = ALLOC_STRING( pkvd->szValue );
|
m_iszTriggerTarget = ALLOC_STRING( pkvd->szValue );
|
||||||
pkvd->fHandled = TRUE;
|
pkvd->fHandled = TRUE;
|
||||||
}
|
}
|
||||||
else if (FStrEq(pkvd->szKeyName, "TriggerCondition") )
|
else if (FStrEq(pkvd->szKeyName, "TriggerCondition"))
|
||||||
{
|
{
|
||||||
m_iTriggerCondition = atoi( pkvd->szValue );
|
m_iTriggerCondition = atoi( pkvd->szValue );
|
||||||
pkvd->fHandled = TRUE;
|
pkvd->fHandled = TRUE;
|
||||||
}
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "displayname"))
|
||||||
|
{
|
||||||
|
m_szMonsterName = ALLOC_STRING( pkvd->szValue );
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "classify"))
|
||||||
|
{
|
||||||
|
m_iClassifyOverride = atoi( pkvd->szValue );
|
||||||
|
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 );
|
||||||
@@ -2872,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;
|
||||||
@@ -1485,8 +1490,6 @@ void CTestHull :: Spawn( entvars_t *pevMasterNode )
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
void CTestHull::DropDelay ( void )
|
void CTestHull::DropDelay ( void )
|
||||||
{
|
{
|
||||||
// Do NOT uncomment or you'll get a "Tried to create a message with a bogus message type ( 0 )" crash!
|
|
||||||
// Left here only because it's on the original HLSDK, and for comedy purposes. -Giegue
|
|
||||||
//UTIL_CenterPrintAll( "Node Graph out of Date. Rebuilding..." );
|
//UTIL_CenterPrintAll( "Node Graph out of Date. Rebuilding..." );
|
||||||
|
|
||||||
UTIL_SetOrigin ( VARS(pev), WorldGraph.m_pNodes[ 0 ].m_vecOrigin );
|
UTIL_SetOrigin ( VARS(pev), WorldGraph.m_pNodes[ 0 ].m_vecOrigin );
|
||||||
@@ -1891,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;
|
||||||
}
|
}
|
||||||
@@ -3439,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;
|
||||||
|
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;
|
||||||
|
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);
|
||||||
@@ -517,6 +517,11 @@ void CMScientist :: RunTask( Task_t *pTask )
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMScientist :: Classify ( void )
|
int CMScientist :: Classify ( void )
|
||||||
{
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
return CLASS_HUMAN_PASSIVE;
|
return CLASS_HUMAN_PASSIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -591,12 +596,12 @@ 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;
|
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
|
||||||
@@ -616,6 +621,13 @@ void CMScientist :: Spawn( void )
|
|||||||
pev->skin = 1;
|
pev->skin = 1;
|
||||||
|
|
||||||
MonsterInit();
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_scientist" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Scientist" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
|
|||||||
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);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,6 +47,12 @@ float CMSqueakGrenade::m_flNextBounceSoundTime = 0;
|
|||||||
|
|
||||||
int CMSqueakGrenade :: Classify ( void )
|
int CMSqueakGrenade :: Classify ( void )
|
||||||
{
|
{
|
||||||
|
// E
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
return CLASS_ALIEN_MONSTER;
|
return CLASS_ALIEN_MONSTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +90,13 @@ void CMSqueakGrenade :: Spawn( void )
|
|||||||
ResetSequenceInfo( );
|
ResetSequenceInfo( );
|
||||||
|
|
||||||
m_hEnemy = NULL;
|
m_hEnemy = NULL;
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_snark" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// hi :3
|
||||||
|
m_szMonsterName = MAKE_STRING( "Snark" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSqueakGrenade::Precache( void )
|
void CMSqueakGrenade::Precache( void )
|
||||||
@@ -289,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;
|
||||||
|
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;
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
52
src/dlls/turret.cpp
Executable file → Normal file
52
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,7 +124,7 @@ 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;
|
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;
|
||||||
@@ -142,6 +145,13 @@ void CMTurret::Spawn()
|
|||||||
m_eyeBrightness = 0;
|
m_eyeBrightness = 0;
|
||||||
|
|
||||||
pev->nextthink = gpGlobals->time + 0.3;
|
pev->nextthink = gpGlobals->time + 0.3;
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_turret" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Turret" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMTurret::Precache()
|
void CMTurret::Precache()
|
||||||
@@ -154,7 +164,7 @@ 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;
|
pev->health = gSkillData.miniturretHealth;
|
||||||
m_HackedGunPos = Vector( 0, 0, 12.75 );
|
m_HackedGunPos = Vector( 0, 0, 12.75 );
|
||||||
m_flMaxSpin = 0;
|
m_flMaxSpin = 0;
|
||||||
@@ -168,6 +178,13 @@ void CMMiniTurret::Spawn()
|
|||||||
|
|
||||||
SetThink(&CMMiniTurret::Initialize);
|
SetThink(&CMMiniTurret::Initialize);
|
||||||
pev->nextthink = gpGlobals->time + 0.3;
|
pev->nextthink = gpGlobals->time + 0.3;
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_miniturret" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Mini-Turret" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -334,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;
|
||||||
@@ -445,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;
|
||||||
}
|
}
|
||||||
@@ -453,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))
|
||||||
{
|
{
|
||||||
@@ -707,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -765,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -787,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 );
|
||||||
|
|
||||||
@@ -978,7 +996,15 @@ int CMBaseTurret::MoveTurret(void)
|
|||||||
int CMBaseTurret::Classify ( void )
|
int CMBaseTurret::Classify ( void )
|
||||||
{
|
{
|
||||||
if (m_iOn || m_iAutoStart)
|
if (m_iOn || m_iAutoStart)
|
||||||
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
return CLASS_MACHINE;
|
return CLASS_MACHINE;
|
||||||
|
}
|
||||||
|
|
||||||
return CLASS_NONE;
|
return CLASS_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -992,7 +1018,7 @@ 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;
|
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;
|
||||||
@@ -1008,11 +1034,18 @@ void CMSentry::Spawn()
|
|||||||
SetTouch(&CMSentry::SentryTouch);
|
SetTouch(&CMSentry::SentryTouch);
|
||||||
SetThink(&CMSentry::Initialize);
|
SetThink(&CMSentry::Initialize);
|
||||||
pev->nextthink = gpGlobals->time + 0.3;
|
pev->nextthink = gpGlobals->time + 0.3;
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_sentry" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Sentry Turret" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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))
|
||||||
{
|
{
|
||||||
@@ -1076,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 )
|
||||||
{
|
{
|
||||||
@@ -757,7 +871,7 @@ int gmsgSayText = 0;
|
|||||||
|
|
||||||
void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 )
|
void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 )
|
||||||
{
|
{
|
||||||
if (gmsgTextMsg)
|
if (gmsgTextMsg == 0)
|
||||||
gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 );
|
gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 );
|
||||||
|
|
||||||
MESSAGE_BEGIN( MSG_ALL, gmsgTextMsg );
|
MESSAGE_BEGIN( MSG_ALL, gmsgTextMsg );
|
||||||
@@ -778,7 +892,7 @@ void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1
|
|||||||
|
|
||||||
void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 )
|
void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 )
|
||||||
{
|
{
|
||||||
if (gmsgTextMsg)
|
if (gmsgTextMsg == 0)
|
||||||
gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 );
|
gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 );
|
||||||
|
|
||||||
MESSAGE_BEGIN( MSG_ONE, gmsgTextMsg, NULL, client );
|
MESSAGE_BEGIN( MSG_ONE, gmsgTextMsg, NULL, client );
|
||||||
@@ -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 ) )
|
||||||
{
|
{
|
||||||
@@ -1755,10 +1916,18 @@ int UTIL_TakeDamage( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAtt
|
|||||||
// do the damage
|
// do the damage
|
||||||
pEdict->v.health -= flTake;
|
pEdict->v.health -= flTake;
|
||||||
|
|
||||||
|
// store entity that hurt this player
|
||||||
|
pEdict->v.dmg_inflictor = ENT(pevAttacker);
|
||||||
|
|
||||||
if ( pEdict->v.health <= 0 )
|
if ( pEdict->v.health <= 0 )
|
||||||
{
|
{
|
||||||
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
|
||||||
|
if ( pevAttacker->flags & FL_MONSTER )
|
||||||
|
pevAttacker->frags += 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tell director about it
|
// tell director about it
|
||||||
@@ -1868,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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1879,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 );
|
||||||
}
|
}
|
||||||
@@ -1961,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;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,11 @@ const char *CMZombie::pPainSounds[] =
|
|||||||
//=========================================================
|
//=========================================================
|
||||||
int CMZombie :: Classify ( void )
|
int CMZombie :: Classify ( void )
|
||||||
{
|
{
|
||||||
|
if ( m_iClassifyOverride == -1 ) // helper
|
||||||
|
return CLASS_NONE;
|
||||||
|
else if ( m_iClassifyOverride > 0 )
|
||||||
|
return m_iClassifyOverride; // override
|
||||||
|
|
||||||
return CLASS_ALIEN_MONSTER;
|
return CLASS_ALIEN_MONSTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,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();
|
||||||
@@ -241,12 +236,12 @@ 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;
|
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 )
|
||||||
@@ -254,6 +249,13 @@ void CMZombie :: Spawn()
|
|||||||
m_afCapability = bits_CAP_DOORS_GROUP;
|
m_afCapability = bits_CAP_DOORS_GROUP;
|
||||||
|
|
||||||
MonsterInit();
|
MonsterInit();
|
||||||
|
|
||||||
|
pev->classname = MAKE_STRING( "monster_zombie" );
|
||||||
|
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
|
||||||
|
{
|
||||||
|
// default name
|
||||||
|
m_szMonsterName = MAKE_STRING( "Zombie" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -261,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)
|
||||||
|
|||||||
218
src/metamod/stdint_c99.h
Normal file
218
src/metamod/stdint_c99.h
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
/**
|
||||||
|
* This file has no copyright assigned and is placed in the Public Domain.
|
||||||
|
* This file was originally part of the w64 mingw-runtime package.
|
||||||
|
*/
|
||||||
|
/* ISO C9x 7.18 Integer types <stdint.h>
|
||||||
|
* Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794)
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS NOT COPYRIGHTED
|
||||||
|
*
|
||||||
|
* Contributor: Danny Smith <danny_r_smith_2001@yahoo.co.nz>
|
||||||
|
* Modified for libusb/MSVC: Pete Batard <pbatard@gmail.com>
|
||||||
|
*
|
||||||
|
* This source code is offered for use in the public domain. You may
|
||||||
|
* use, modify or distribute it freely.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful but
|
||||||
|
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
|
||||||
|
* DISCLAIMED. This includes but is not limited to warranties of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* Date: 2010-04-02
|
||||||
|
*/
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#error This header should only be used with Microsoft compilers
|
||||||
|
#endif
|
||||||
|
#ifndef _STDINT_H
|
||||||
|
#define _STDINT_H
|
||||||
|
#ifndef _INTPTR_T_DEFINED
|
||||||
|
#define _INTPTR_T_DEFINED
|
||||||
|
#ifndef __intptr_t_defined
|
||||||
|
#define __intptr_t_defined
|
||||||
|
#undef intptr_t
|
||||||
|
#ifdef _WIN64
|
||||||
|
typedef __int64 intptr_t;
|
||||||
|
#else
|
||||||
|
typedef int intptr_t;
|
||||||
|
#endif /* _WIN64 */
|
||||||
|
#endif /* __intptr_t_defined */
|
||||||
|
#endif /* _INTPTR_T_DEFINED */
|
||||||
|
#ifndef _UINTPTR_T_DEFINED
|
||||||
|
#define _UINTPTR_T_DEFINED
|
||||||
|
#ifndef __uintptr_t_defined
|
||||||
|
#define __uintptr_t_defined
|
||||||
|
#undef uintptr_t
|
||||||
|
#ifdef _WIN64
|
||||||
|
typedef unsigned __int64 uintptr_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned int uintptr_t;
|
||||||
|
#endif /* _WIN64 */
|
||||||
|
#endif /* __uintptr_t_defined */
|
||||||
|
#endif /* _UINTPTR_T_DEFINED */
|
||||||
|
#ifndef _PTRDIFF_T_DEFINED
|
||||||
|
#define _PTRDIFF_T_DEFINED
|
||||||
|
#ifndef _PTRDIFF_T_
|
||||||
|
#define _PTRDIFF_T_
|
||||||
|
#undef ptrdiff_t
|
||||||
|
#ifdef _WIN64
|
||||||
|
typedef __int64 ptrdiff_t;
|
||||||
|
#else
|
||||||
|
typedef int ptrdiff_t;
|
||||||
|
#endif /* _WIN64 */
|
||||||
|
#endif /* _PTRDIFF_T_ */
|
||||||
|
#endif /* _PTRDIFF_T_DEFINED */
|
||||||
|
#ifndef _WCHAR_T_DEFINED
|
||||||
|
#define _WCHAR_T_DEFINED
|
||||||
|
#ifndef __cplusplus
|
||||||
|
typedef unsigned short wchar_t;
|
||||||
|
#endif /* C++ */
|
||||||
|
#endif /* _WCHAR_T_DEFINED */
|
||||||
|
#ifndef _WCTYPE_T_DEFINED
|
||||||
|
#define _WCTYPE_T_DEFINED
|
||||||
|
#ifndef _WINT_T
|
||||||
|
#define _WINT_T
|
||||||
|
typedef unsigned short wint_t;
|
||||||
|
typedef unsigned short wctype_t;
|
||||||
|
#endif /* _WINT_T */
|
||||||
|
#endif /* _WCTYPE_T_DEFINED */
|
||||||
|
/* 7.18.1.1 Exact-width integer types */
|
||||||
|
typedef __int8 int8_t;
|
||||||
|
typedef unsigned __int8 uint8_t;
|
||||||
|
typedef __int16 int16_t;
|
||||||
|
typedef unsigned __int16 uint16_t;
|
||||||
|
typedef __int32 int32_t;
|
||||||
|
typedef unsigned __int32 uint32_t;
|
||||||
|
typedef __int64 int64_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
/* 7.18.1.2 Minimum-width integer types */
|
||||||
|
typedef signed char int_least8_t;
|
||||||
|
typedef unsigned char uint_least8_t;
|
||||||
|
typedef short int_least16_t;
|
||||||
|
typedef unsigned short uint_least16_t;
|
||||||
|
typedef int int_least32_t;
|
||||||
|
typedef unsigned uint_least32_t;
|
||||||
|
typedef __int64 int_least64_t;
|
||||||
|
typedef unsigned __int64 uint_least64_t;
|
||||||
|
/* 7.18.1.3 Fastest minimum-width integer types
|
||||||
|
* Not actually guaranteed to be fastest for all purposes
|
||||||
|
* Here we use the exact-width types for 8 and 16-bit ints.
|
||||||
|
*/
|
||||||
|
typedef __int8 int_fast8_t;
|
||||||
|
typedef unsigned __int8 uint_fast8_t;
|
||||||
|
typedef __int16 int_fast16_t;
|
||||||
|
typedef unsigned __int16 uint_fast16_t;
|
||||||
|
typedef __int32 int_fast32_t;
|
||||||
|
typedef unsigned __int32 uint_fast32_t;
|
||||||
|
typedef __int64 int_fast64_t;
|
||||||
|
typedef unsigned __int64 uint_fast64_t;
|
||||||
|
/* 7.18.1.5 Greatest-width integer types */
|
||||||
|
typedef __int64 intmax_t;
|
||||||
|
typedef unsigned __int64 uintmax_t;
|
||||||
|
/* 7.18.2 Limits of specified-width integer types */
|
||||||
|
/* 7.18.2.1 Limits of exact-width integer types */
|
||||||
|
#define INT8_MIN (-128)
|
||||||
|
#define INT16_MIN (-32768)
|
||||||
|
#define INT32_MIN (-2147483647 - 1)
|
||||||
|
#define INT64_MIN (-9223372036854775807LL - 1)
|
||||||
|
#define INT8_MAX 127
|
||||||
|
#define INT16_MAX 32767
|
||||||
|
#define INT32_MAX 2147483647
|
||||||
|
#define INT64_MAX 9223372036854775807LL
|
||||||
|
#define UINT8_MAX 255
|
||||||
|
#define UINT16_MAX 65535
|
||||||
|
#define UINT32_MAX 0xffffffffU /* 4294967295U */
|
||||||
|
#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */
|
||||||
|
/* 7.18.2.2 Limits of minimum-width integer types */
|
||||||
|
#define INT_LEAST8_MIN INT8_MIN
|
||||||
|
#define INT_LEAST16_MIN INT16_MIN
|
||||||
|
#define INT_LEAST32_MIN INT32_MIN
|
||||||
|
#define INT_LEAST64_MIN INT64_MIN
|
||||||
|
#define INT_LEAST8_MAX INT8_MAX
|
||||||
|
#define INT_LEAST16_MAX INT16_MAX
|
||||||
|
#define INT_LEAST32_MAX INT32_MAX
|
||||||
|
#define INT_LEAST64_MAX INT64_MAX
|
||||||
|
#define UINT_LEAST8_MAX UINT8_MAX
|
||||||
|
#define UINT_LEAST16_MAX UINT16_MAX
|
||||||
|
#define UINT_LEAST32_MAX UINT32_MAX
|
||||||
|
#define UINT_LEAST64_MAX UINT64_MAX
|
||||||
|
/* 7.18.2.3 Limits of fastest minimum-width integer types */
|
||||||
|
#define INT_FAST8_MIN INT8_MIN
|
||||||
|
#define INT_FAST16_MIN INT16_MIN
|
||||||
|
#define INT_FAST32_MIN INT32_MIN
|
||||||
|
#define INT_FAST64_MIN INT64_MIN
|
||||||
|
#define INT_FAST8_MAX INT8_MAX
|
||||||
|
#define INT_FAST16_MAX INT16_MAX
|
||||||
|
#define INT_FAST32_MAX INT32_MAX
|
||||||
|
#define INT_FAST64_MAX INT64_MAX
|
||||||
|
#define UINT_FAST8_MAX UINT8_MAX
|
||||||
|
#define UINT_FAST16_MAX UINT16_MAX
|
||||||
|
#define UINT_FAST32_MAX UINT32_MAX
|
||||||
|
#define UINT_FAST64_MAX UINT64_MAX
|
||||||
|
/* 7.18.2.4 Limits of integer types capable of holding
|
||||||
|
object pointers */
|
||||||
|
#ifdef _WIN64
|
||||||
|
#define INTPTR_MIN INT64_MIN
|
||||||
|
#define INTPTR_MAX INT64_MAX
|
||||||
|
#define UINTPTR_MAX UINT64_MAX
|
||||||
|
#else
|
||||||
|
#define INTPTR_MIN INT32_MIN
|
||||||
|
#define INTPTR_MAX INT32_MAX
|
||||||
|
#define UINTPTR_MAX UINT32_MAX
|
||||||
|
#endif
|
||||||
|
/* 7.18.2.5 Limits of greatest-width integer types */
|
||||||
|
#define INTMAX_MIN INT64_MIN
|
||||||
|
#define INTMAX_MAX INT64_MAX
|
||||||
|
#define UINTMAX_MAX UINT64_MAX
|
||||||
|
/* 7.18.3 Limits of other integer types */
|
||||||
|
#ifdef _WIN64
|
||||||
|
#define PTRDIFF_MIN INT64_MIN
|
||||||
|
#define PTRDIFF_MAX INT64_MAX
|
||||||
|
#else
|
||||||
|
#define PTRDIFF_MIN INT32_MIN
|
||||||
|
#define PTRDIFF_MAX INT32_MAX
|
||||||
|
#endif
|
||||||
|
#define SIG_ATOMIC_MIN INT32_MIN
|
||||||
|
#define SIG_ATOMIC_MAX INT32_MAX
|
||||||
|
#ifndef SIZE_MAX
|
||||||
|
#ifdef _WIN64
|
||||||
|
#define SIZE_MAX UINT64_MAX
|
||||||
|
#else
|
||||||
|
#define SIZE_MAX UINT32_MAX
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifndef WCHAR_MIN /* also in wchar.h */
|
||||||
|
#define WCHAR_MIN 0U
|
||||||
|
#define WCHAR_MAX 0xffffU
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* wint_t is unsigned short for compatibility with MS runtime
|
||||||
|
*/
|
||||||
|
#define WINT_MIN 0U
|
||||||
|
#define WINT_MAX 0xffffU
|
||||||
|
/* 7.18.4 Macros for integer constants */
|
||||||
|
/* 7.18.4.1 Macros for minimum-width integer constants
|
||||||
|
Accoding to Douglas Gwyn <gwyn@arl.mil>:
|
||||||
|
"This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC
|
||||||
|
9899:1999 as initially published, the expansion was required
|
||||||
|
to be an integer constant of precisely matching type, which
|
||||||
|
is impossible to accomplish for the shorter types on most
|
||||||
|
platforms, because C99 provides no standard way to designate
|
||||||
|
an integer constant with width less than that of type int.
|
||||||
|
TC1 changed this to require just an integer constant
|
||||||
|
*expression* with *promoted* type."
|
||||||
|
The trick used here is from Clive D W Feather.
|
||||||
|
*/
|
||||||
|
#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val))
|
||||||
|
#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val))
|
||||||
|
#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val))
|
||||||
|
/* The 'trick' doesn't work in C89 for long long because, without
|
||||||
|
suffix, (val) will be evaluated as int, not intmax_t */
|
||||||
|
#define INT64_C(val) val##i64
|
||||||
|
#define UINT8_C(val) (val)
|
||||||
|
#define UINT16_C(val) (val)
|
||||||
|
#define UINT32_C(val) (val##i32)
|
||||||
|
#define UINT64_C(val) val##ui64
|
||||||
|
/* 7.18.4.2 Macros for greatest-width integer constants */
|
||||||
|
#define INTMAX_C(val) val##i64
|
||||||
|
#define UINTMAX_C(val) val##ui64
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user