Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
164
README.md
164
README.md
@@ -21,26 +21,155 @@ A small light is seen at the distance...
|
||||
|
||||
## 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 20 years (and a half) since botman's original plugin was released, the future of the project became nothing but a forgotten, ancient relic of the past.
|
||||
|
||||
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.
|
||||
|
||||
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`
|
||||
|
||||
Additional configuration files are included in the release files, each explaining it's usage and installation instructions.
|
||||
|
||||
## Build Instructions
|
||||
|
||||
*TODO: Add build instructions.*
|
||||
|
||||
## 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.
|
||||
|
||||
## Using MonsterMod on Counter-Strike
|
||||
|
||||
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 Half-Life can only store a maximum of 512 precached resources. Most of these sounds are handled client-side by the models themselves, there is no need for all of them to be kept precached on the server. Only the weapons fire sounds are needed.
|
||||
|
||||
MonsterMod does not have an integrated "Unprecacher" to remove those sounds, but you can remove them manually with AMX Mod X, using Fakemeta. Register forward **FM_PrecacheSound** and return **FMRES_SUPERCEDE** on the following sounds:
|
||||
|
||||
```
|
||||
"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"
|
||||
```
|
||||
|
||||
Doing this will free **85** sounds from the precache list that you can now use for additional monsters.
|
||||
|
||||
## Known Bugs
|
||||
|
||||
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:
|
||||
|
||||
- Human Grunts are unable to reload their weapons. As a workaround, infinite ammo has been given to them.
|
||||
|
||||
- Male Assassins share the same AI as HGrunts, so their ammo problem is still a thing, and the same workaround is used.
|
||||
|
||||
- Shock Troopers seems to be broken despite sharing HGrunts AI code. Despite having infinite ammo, they eventually stop firing. Worse, taking cover is absolutely broken, and they remain completely frozen in place when it happens.
|
||||
|
||||
- If a Heavy Weapons Grunt is to lose their target while his minigun is still spinning, the next time it targets an enemy it will instantly fire instead of spinning up the minigun again.
|
||||
|
||||
## Milestones
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
The original Visual C++ 6.0 DSP file exists in the repository but neither the file nor the code has been updated to newer formats. Don't expect it to compile on modern Visual Studio versions.
|
||||
|
||||
Current milestones are separated by "Tiers", which are as follows:
|
||||
|
||||
@@ -63,19 +192,24 @@ Current milestones are separated by "Tiers", which are as follows:
|
||||
|
||||
### Tier 3
|
||||
|
||||
- Implement *-almost-* all Opposing Force monsters.
|
||||
- Implement *-almost-* all default Sven Co-op monsters.
|
||||
- Add configurations to change AI behaviour.
|
||||
- Update source code so it can compile AND run **ON WINDOWS**. **[DONE]**
|
||||
- Implement *-almost-* all Opposing Force monsters. **[DONE]**
|
||||
- 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
|
||||
|
||||
- Custom model support, along with scaling.
|
||||
- Custom sound support.
|
||||
- Implement extra entities to enhance map gameplay.
|
||||
- Implement reading entities within the BSP itself.
|
||||
- Model scaling. *-If possible.-*
|
||||
- Custom sound support, along with sentences.
|
||||
- Fix all pending bugs.
|
||||
|
||||
### Tier 5
|
||||
|
||||
- Update source code so it can compile AND run **ON WINDOWS**.
|
||||
- Add configurations to change AI behaviour.
|
||||
- Optimize code and enhance the AI.
|
||||
- Create "tool" entities for easier map customization.
|
||||
|
||||
|
||||
What will the future hold after all Tiers has been completed?
|
||||
|
||||
7
aux/README.md
Normal file
7
aux/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## 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.
|
||||
|
||||
Once all milestones are completed, the possibility of removing the need for external plugins will be considered. Until then, this has to stay.
|
||||
19
aux/valve/README.md
Normal file
19
aux/valve/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
## 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.
|
||||
|
||||
#### Half-Life <--> MonsterMod 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.
|
||||
BIN
aux/valve/bin/hl_monsterbridge.amxx
Normal file
BIN
aux/valve/bin/hl_monsterbridge.amxx
Normal file
Binary file not shown.
188
aux/valve/src/hl_monsterbridge.sma
Normal file
188
aux/valve/src/hl_monsterbridge.sma
Normal file
@@ -0,0 +1,188 @@
|
||||
#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;
|
||||
|
||||
public plugin_init()
|
||||
{
|
||||
register_plugin( "HL-MONSTER Bridge", "1.0", "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" );
|
||||
|
||||
set_task( 0.3, "hlScan", 0, "", 0, "b" );
|
||||
register_srvcmd( "monster_hurt_entity", "hlTakeDamage" );
|
||||
}
|
||||
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 hlScan()
|
||||
{
|
||||
new entity, szClassname[ 33 ], szDisplayname[ 129 ], bool:found;
|
||||
for ( entity = 0; entity < get_global_int( GL_maxEntities ); entity++ )
|
||||
{
|
||||
// Nothing deleted me?
|
||||
if ( is_valid_ent( entity ) )
|
||||
{
|
||||
entity_get_string( entity, EV_SZ_classname, szClassname, charsmax( szClassname ) );
|
||||
if ( equal( szClassname, "monster_", 8 ) )
|
||||
{
|
||||
// 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?
|
||||
entity_get_string( entity, EV_SZ_netname, szDisplayname, charsmax( szDisplayname ) );
|
||||
if ( !strlen( szDisplayname ) )
|
||||
{
|
||||
// Find a default name
|
||||
found = TrieGetString( g_HLDefaultNames, szClassname, szDisplayname, charsmax( szDisplayname ) );
|
||||
|
||||
// Use this name
|
||||
entity_set_string( entity, EV_SZ_netname, ( found ? szDisplayname : "Monster" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 hlTakeDamage()
|
||||
{
|
||||
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 );
|
||||
}
|
||||
}
|
||||
@@ -3,15 +3,14 @@
|
||||
// Send this new file to your maps folder.
|
||||
//
|
||||
// To add entries to this file, just pretend it's ripent.
|
||||
//
|
||||
// "delay" means monster respawndelay.
|
||||
//
|
||||
// You may also be interesed in these other 2 keyvalues:
|
||||
// You may also be interesed in these other keyvalues:
|
||||
//
|
||||
// "displayname" to change the monster's name, shown in HUD when you point at it.
|
||||
// "model" to change the monster's default model. If using monstermaker, use "new_model".
|
||||
// "classify" to change the monster's default classification, use one of these values:
|
||||
//
|
||||
// CLASS_NONE 0
|
||||
// CLASS_NONE -1
|
||||
// CLASS_MACHINE 1
|
||||
// CLASS_PLAYER 2
|
||||
// CLASS_HUMAN_PASSIVE 3
|
||||
@@ -25,6 +24,8 @@
|
||||
// CLASS_PLAYER_ALLY 11
|
||||
// CLASS_PLAYER_BIOWEAPON 12
|
||||
// CLASS_ALIEN_BIOWEAPON 13
|
||||
// CLASS_RACEX_PITDRONE 14
|
||||
// CLASS_RACEX_SHOCK 15
|
||||
|
||||
{
|
||||
"origin" "90 -180 150"
|
||||
|
||||
@@ -3,8 +3,11 @@
|
||||
//
|
||||
// Install this file to your mod's base directory.
|
||||
//
|
||||
// (just remove the comment characters at the beginning of the line for the
|
||||
// monsters that you always want to precache.)
|
||||
// Just remove the comment characters at the beginning of the line for the
|
||||
// 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_apache
|
||||
@@ -24,3 +27,14 @@
|
||||
//monster_turret
|
||||
//monster_miniturret
|
||||
//monster_sentry
|
||||
//monster_gonome
|
||||
//monster_male_assassin
|
||||
//monster_otis
|
||||
//monster_pitdrone
|
||||
//monster_shocktrooper
|
||||
//monster_alien_voltigore
|
||||
//monster_alien_babyvoltigore
|
||||
//monster_babygarg
|
||||
//monster_hwgrunt
|
||||
//monster_robogrunt
|
||||
//monster_stukabat
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
//
|
||||
// Install this file to your mod's base directory.
|
||||
|
||||
|
||||
// ORIGINAL HALF-LIFE MONSTERS
|
||||
|
||||
// Alien Grunt
|
||||
sk_agrunt_health 90
|
||||
sk_agrunt_dmg_punch 20
|
||||
@@ -55,10 +58,6 @@ sk_islave_dmg_claw 10
|
||||
sk_islave_dmg_clawrake 25
|
||||
sk_islave_dmg_zap 10
|
||||
|
||||
// Icthyosaur
|
||||
sk_ichthyosaur_health 200
|
||||
sk_ichthyosaur_shake 35
|
||||
|
||||
// Controller
|
||||
sk_controller_health 60
|
||||
sk_controller_dmgzap 25
|
||||
@@ -88,8 +87,75 @@ sk_miniturret_health 40
|
||||
// Sentry Turret
|
||||
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
|
||||
sk_9mm_bullet 5
|
||||
sk_9mmAR_bullet 4
|
||||
sk_9mmAR_grenade 100
|
||||
sk_12mm_bullet 10
|
||||
sk_762_bullet 100
|
||||
sk_357_bullet 40
|
||||
|
||||
1542
src/common/const.h
1542
src/common/const.h
File diff suppressed because it is too large
Load Diff
104
src/common/crc.h
104
src/common/crc.h
@@ -1,52 +1,52 @@
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 2000, 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.
|
||||
*
|
||||
****/
|
||||
/* crc.h */
|
||||
#ifndef CRC_H
|
||||
#define CRC_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// MD5 Hash
|
||||
typedef struct
|
||||
{
|
||||
unsigned int buf[4];
|
||||
unsigned int bits[2];
|
||||
unsigned char in[64];
|
||||
} MD5Context_t;
|
||||
|
||||
|
||||
typedef unsigned long CRC32_t;
|
||||
void CRC32_Init(CRC32_t *pulCRC);
|
||||
CRC32_t CRC32_Final(CRC32_t pulCRC);
|
||||
void CRC32_ProcessBuffer(CRC32_t *pulCRC, void *p, int len);
|
||||
void CRC32_ProcessByte(CRC32_t *pulCRC, unsigned char ch);
|
||||
int CRC_File(CRC32_t *crcvalue, char *pszFileName);
|
||||
|
||||
unsigned char COM_BlockSequenceCRCByte (unsigned char *base, int length, int sequence);
|
||||
|
||||
void MD5Init(MD5Context_t *context);
|
||||
void MD5Update(MD5Context_t *context, unsigned char const *buf,
|
||||
unsigned int len);
|
||||
void MD5Final(unsigned char digest[16], MD5Context_t *context);
|
||||
void Transform(unsigned int buf[4], unsigned int const in[16]);
|
||||
|
||||
int MD5_Hash_File(unsigned char digest[16], char *pszFileName, int bUsefopen, int bSeed, unsigned int seed[4]);
|
||||
char *MD5_Print(unsigned char hash[16]);
|
||||
int MD5_Hash_CachedFile(unsigned char digest[16], unsigned char *pCache, int nFileSize, int bSeed, unsigned int seed[4]);
|
||||
|
||||
int CRC_MapFile(CRC32_t *crcvalue, char *pszFileName);
|
||||
|
||||
#endif
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 2000, 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.
|
||||
*
|
||||
****/
|
||||
/* crc.h */
|
||||
#ifndef CRC_H
|
||||
#define CRC_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// MD5 Hash
|
||||
typedef struct
|
||||
{
|
||||
unsigned int buf[4];
|
||||
unsigned int bits[2];
|
||||
unsigned char in[64];
|
||||
} MD5Context_t;
|
||||
|
||||
|
||||
typedef unsigned long CRC32_t;
|
||||
void CRC32_Init(CRC32_t *pulCRC);
|
||||
CRC32_t CRC32_Final(CRC32_t pulCRC);
|
||||
void CRC32_ProcessBuffer(CRC32_t *pulCRC, void *p, int len);
|
||||
void CRC32_ProcessByte(CRC32_t *pulCRC, unsigned char ch);
|
||||
int CRC_File(CRC32_t *crcvalue, char *pszFileName);
|
||||
|
||||
unsigned char COM_BlockSequenceCRCByte (unsigned char *base, int length, int sequence);
|
||||
|
||||
void MD5Init(MD5Context_t *context);
|
||||
void MD5Update(MD5Context_t *context, unsigned char const *buf,
|
||||
unsigned int len);
|
||||
void MD5Final(unsigned char digest[16], MD5Context_t *context);
|
||||
void Transform(unsigned int buf[4], unsigned int const in[16]);
|
||||
|
||||
int MD5_Hash_File(unsigned char digest[16], char *pszFileName, int bUsefopen, int bSeed, unsigned int seed[4]);
|
||||
char *MD5_Print(unsigned char hash[16]);
|
||||
int MD5_Hash_CachedFile(unsigned char digest[16], unsigned char *pCache, int nFileSize, int bSeed, unsigned int seed[4]);
|
||||
|
||||
int CRC_MapFile(CRC32_t *crcvalue, char *pszFileName);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 2000, 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.
|
||||
*
|
||||
****/
|
||||
#ifndef CVARDEF_H
|
||||
#define CVARDEF_H
|
||||
|
||||
#define FCVAR_ARCHIVE (1<<0) // set to cause it to be saved to vars.rc
|
||||
#define FCVAR_USERINFO (1<<1) // changes the client's info string
|
||||
#define FCVAR_SERVER (1<<2) // notifies players when changed
|
||||
#define FCVAR_EXTDLL (1<<3) // defined by external DLL
|
||||
#define FCVAR_CLIENTDLL (1<<4) // defined by the client dll
|
||||
#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value
|
||||
#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server.
|
||||
#define FCVAR_PRINTABLEONLY (1<<7) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ).
|
||||
#define FCVAR_UNLOGGED (1<<8) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log
|
||||
|
||||
typedef struct cvar_s
|
||||
{
|
||||
char *name;
|
||||
char *string;
|
||||
int flags;
|
||||
float value;
|
||||
struct cvar_s *next;
|
||||
} cvar_t;
|
||||
#endif
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 2000, 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.
|
||||
*
|
||||
****/
|
||||
#ifndef CVARDEF_H
|
||||
#define CVARDEF_H
|
||||
|
||||
#define FCVAR_ARCHIVE (1<<0) // set to cause it to be saved to vars.rc
|
||||
#define FCVAR_USERINFO (1<<1) // changes the client's info string
|
||||
#define FCVAR_SERVER (1<<2) // notifies players when changed
|
||||
#define FCVAR_EXTDLL (1<<3) // defined by external DLL
|
||||
#define FCVAR_CLIENTDLL (1<<4) // defined by the client dll
|
||||
#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value
|
||||
#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server.
|
||||
#define FCVAR_PRINTABLEONLY (1<<7) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ).
|
||||
#define FCVAR_UNLOGGED (1<<8) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log
|
||||
|
||||
typedef struct cvar_s
|
||||
{
|
||||
char *name;
|
||||
char *string;
|
||||
int flags;
|
||||
float value;
|
||||
struct cvar_s *next;
|
||||
} cvar_t;
|
||||
#endif
|
||||
|
||||
@@ -1,193 +1,193 @@
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 2000 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.
|
||||
*
|
||||
****/
|
||||
#if !defined( ENTITY_STATEH )
|
||||
#define ENTITY_STATEH
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// For entityType below
|
||||
#define ENTITY_NORMAL (1<<0)
|
||||
#define ENTITY_BEAM (1<<1)
|
||||
|
||||
// Entity state is used for the baseline and for delta compression of a packet of
|
||||
// entities that is sent to a client.
|
||||
typedef struct entity_state_s entity_state_t;
|
||||
|
||||
struct entity_state_s
|
||||
{
|
||||
// Fields which are filled in by routines outside of delta compression
|
||||
int entityType;
|
||||
// Index into cl_entities array for this entity.
|
||||
int number;
|
||||
float msg_time;
|
||||
|
||||
// Message number last time the player/entity state was updated.
|
||||
int messagenum;
|
||||
|
||||
// Fields which can be transitted and reconstructed over the network stream
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
|
||||
int modelindex;
|
||||
int sequence;
|
||||
float frame;
|
||||
int colormap;
|
||||
short skin;
|
||||
short solid;
|
||||
int effects;
|
||||
float scale;
|
||||
|
||||
byte eflags;
|
||||
|
||||
// Render information
|
||||
int rendermode;
|
||||
int renderamt;
|
||||
color24 rendercolor;
|
||||
int renderfx;
|
||||
|
||||
int movetype;
|
||||
float animtime;
|
||||
float framerate;
|
||||
int body;
|
||||
byte controller[4];
|
||||
byte blending[4];
|
||||
vec3_t velocity;
|
||||
|
||||
// Send bbox down to client for use during prediction.
|
||||
vec3_t mins;
|
||||
vec3_t maxs;
|
||||
|
||||
int aiment;
|
||||
// If owned by a player, the index of that player ( for projectiles ).
|
||||
int owner;
|
||||
|
||||
// Friction, for prediction.
|
||||
float friction;
|
||||
// Gravity multiplier
|
||||
float gravity;
|
||||
|
||||
// PLAYER SPECIFIC
|
||||
int team;
|
||||
int playerclass;
|
||||
int health;
|
||||
qboolean spectator;
|
||||
int weaponmodel;
|
||||
int gaitsequence;
|
||||
// If standing on conveyor, e.g.
|
||||
vec3_t basevelocity;
|
||||
// Use the crouched hull, or the regular player hull.
|
||||
int usehull;
|
||||
// Latched buttons last time state updated.
|
||||
int oldbuttons;
|
||||
// -1 = in air, else pmove entity number
|
||||
int onground;
|
||||
int iStepLeft;
|
||||
// How fast we are falling
|
||||
float flFallVelocity;
|
||||
|
||||
float fov;
|
||||
int weaponanim;
|
||||
|
||||
// Parametric movement overrides
|
||||
vec3_t startpos;
|
||||
vec3_t endpos;
|
||||
float impacttime;
|
||||
float starttime;
|
||||
|
||||
// For mods
|
||||
int iuser1;
|
||||
int iuser2;
|
||||
int iuser3;
|
||||
int iuser4;
|
||||
float fuser1;
|
||||
float fuser2;
|
||||
float fuser3;
|
||||
float fuser4;
|
||||
vec3_t vuser1;
|
||||
vec3_t vuser2;
|
||||
vec3_t vuser3;
|
||||
vec3_t vuser4;
|
||||
};
|
||||
|
||||
#include "pm_info.h"
|
||||
|
||||
typedef struct clientdata_s
|
||||
{
|
||||
vec3_t origin;
|
||||
vec3_t velocity;
|
||||
|
||||
int viewmodel;
|
||||
vec3_t punchangle;
|
||||
int flags;
|
||||
int waterlevel;
|
||||
int watertype;
|
||||
vec3_t view_ofs;
|
||||
float health;
|
||||
|
||||
int bInDuck;
|
||||
|
||||
int weapons; // remove?
|
||||
|
||||
int flTimeStepSound;
|
||||
int flDuckTime;
|
||||
int flSwimTime;
|
||||
int waterjumptime;
|
||||
|
||||
float maxspeed;
|
||||
|
||||
float fov;
|
||||
int weaponanim;
|
||||
|
||||
int m_iId;
|
||||
int ammo_shells;
|
||||
int ammo_nails;
|
||||
int ammo_cells;
|
||||
int ammo_rockets;
|
||||
float m_flNextAttack;
|
||||
|
||||
int tfstate;
|
||||
|
||||
int pushmsec;
|
||||
|
||||
int deadflag;
|
||||
|
||||
char physinfo[ MAX_PHYSINFO_STRING ];
|
||||
|
||||
// For mods
|
||||
int iuser1;
|
||||
int iuser2;
|
||||
int iuser3;
|
||||
int iuser4;
|
||||
float fuser1;
|
||||
float fuser2;
|
||||
float fuser3;
|
||||
float fuser4;
|
||||
vec3_t vuser1;
|
||||
vec3_t vuser2;
|
||||
vec3_t vuser3;
|
||||
vec3_t vuser4;
|
||||
} clientdata_t;
|
||||
|
||||
#include "weaponinfo.h"
|
||||
|
||||
typedef struct local_state_s
|
||||
{
|
||||
entity_state_t playerstate;
|
||||
clientdata_t client;
|
||||
weapon_data_t weapondata[ 32 ];
|
||||
} local_state_t;
|
||||
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 2000 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.
|
||||
*
|
||||
****/
|
||||
#if !defined( ENTITY_STATEH )
|
||||
#define ENTITY_STATEH
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// For entityType below
|
||||
#define ENTITY_NORMAL (1<<0)
|
||||
#define ENTITY_BEAM (1<<1)
|
||||
|
||||
// Entity state is used for the baseline and for delta compression of a packet of
|
||||
// entities that is sent to a client.
|
||||
typedef struct entity_state_s entity_state_t;
|
||||
|
||||
struct entity_state_s
|
||||
{
|
||||
// Fields which are filled in by routines outside of delta compression
|
||||
int entityType;
|
||||
// Index into cl_entities array for this entity.
|
||||
int number;
|
||||
float msg_time;
|
||||
|
||||
// Message number last time the player/entity state was updated.
|
||||
int messagenum;
|
||||
|
||||
// Fields which can be transitted and reconstructed over the network stream
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
|
||||
int modelindex;
|
||||
int sequence;
|
||||
float frame;
|
||||
int colormap;
|
||||
short skin;
|
||||
short solid;
|
||||
int effects;
|
||||
float scale;
|
||||
|
||||
byte eflags;
|
||||
|
||||
// Render information
|
||||
int rendermode;
|
||||
int renderamt;
|
||||
color24 rendercolor;
|
||||
int renderfx;
|
||||
|
||||
int movetype;
|
||||
float animtime;
|
||||
float framerate;
|
||||
int body;
|
||||
byte controller[4];
|
||||
byte blending[4];
|
||||
vec3_t velocity;
|
||||
|
||||
// Send bbox down to client for use during prediction.
|
||||
vec3_t mins;
|
||||
vec3_t maxs;
|
||||
|
||||
int aiment;
|
||||
// If owned by a player, the index of that player ( for projectiles ).
|
||||
int owner;
|
||||
|
||||
// Friction, for prediction.
|
||||
float friction;
|
||||
// Gravity multiplier
|
||||
float gravity;
|
||||
|
||||
// PLAYER SPECIFIC
|
||||
int team;
|
||||
int playerclass;
|
||||
int health;
|
||||
qboolean spectator;
|
||||
int weaponmodel;
|
||||
int gaitsequence;
|
||||
// If standing on conveyor, e.g.
|
||||
vec3_t basevelocity;
|
||||
// Use the crouched hull, or the regular player hull.
|
||||
int usehull;
|
||||
// Latched buttons last time state updated.
|
||||
int oldbuttons;
|
||||
// -1 = in air, else pmove entity number
|
||||
int onground;
|
||||
int iStepLeft;
|
||||
// How fast we are falling
|
||||
float flFallVelocity;
|
||||
|
||||
float fov;
|
||||
int weaponanim;
|
||||
|
||||
// Parametric movement overrides
|
||||
vec3_t startpos;
|
||||
vec3_t endpos;
|
||||
float impacttime;
|
||||
float starttime;
|
||||
|
||||
// For mods
|
||||
int iuser1;
|
||||
int iuser2;
|
||||
int iuser3;
|
||||
int iuser4;
|
||||
float fuser1;
|
||||
float fuser2;
|
||||
float fuser3;
|
||||
float fuser4;
|
||||
vec3_t vuser1;
|
||||
vec3_t vuser2;
|
||||
vec3_t vuser3;
|
||||
vec3_t vuser4;
|
||||
};
|
||||
|
||||
#include "pm_info.h"
|
||||
|
||||
typedef struct clientdata_s
|
||||
{
|
||||
vec3_t origin;
|
||||
vec3_t velocity;
|
||||
|
||||
int viewmodel;
|
||||
vec3_t punchangle;
|
||||
int flags;
|
||||
int waterlevel;
|
||||
int watertype;
|
||||
vec3_t view_ofs;
|
||||
float health;
|
||||
|
||||
int bInDuck;
|
||||
|
||||
int weapons; // remove?
|
||||
|
||||
int flTimeStepSound;
|
||||
int flDuckTime;
|
||||
int flSwimTime;
|
||||
int waterjumptime;
|
||||
|
||||
float maxspeed;
|
||||
|
||||
float fov;
|
||||
int weaponanim;
|
||||
|
||||
int m_iId;
|
||||
int ammo_shells;
|
||||
int ammo_nails;
|
||||
int ammo_cells;
|
||||
int ammo_rockets;
|
||||
float m_flNextAttack;
|
||||
|
||||
int tfstate;
|
||||
|
||||
int pushmsec;
|
||||
|
||||
int deadflag;
|
||||
|
||||
char physinfo[ MAX_PHYSINFO_STRING ];
|
||||
|
||||
// For mods
|
||||
int iuser1;
|
||||
int iuser2;
|
||||
int iuser3;
|
||||
int iuser4;
|
||||
float fuser1;
|
||||
float fuser2;
|
||||
float fuser3;
|
||||
float fuser4;
|
||||
vec3_t vuser1;
|
||||
vec3_t vuser2;
|
||||
vec3_t vuser3;
|
||||
vec3_t vuser4;
|
||||
} clientdata_t;
|
||||
|
||||
#include "weaponinfo.h"
|
||||
|
||||
typedef struct local_state_s
|
||||
{
|
||||
entity_state_t playerstate;
|
||||
clientdata_t client;
|
||||
weapon_data_t weapondata[ 32 ];
|
||||
} local_state_t;
|
||||
|
||||
#endif // !ENTITY_STATEH
|
||||
@@ -1,47 +1,47 @@
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 2000, 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.
|
||||
*
|
||||
****/
|
||||
#if !defined( EVENT_FLAGSH )
|
||||
#define EVENT_FLAGSH
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// Skip local host for event send.
|
||||
#define FEV_NOTHOST (1<<0)
|
||||
|
||||
// Send the event reliably. You must specify the origin and angles and use
|
||||
// PLAYBACK_EVENT_FULL for this to work correctly on the server for anything
|
||||
// that depends on the event origin/angles. I.e., the origin/angles are not
|
||||
// taken from the invoking edict for reliable events.
|
||||
#define FEV_RELIABLE (1<<1)
|
||||
|
||||
// Don't restrict to PAS/PVS, send this event to _everybody_ on the server ( useful for stopping CHAN_STATIC
|
||||
// sounds started by client event when client is not in PVS anymore ( hwguy in TFC e.g. ).
|
||||
#define FEV_GLOBAL (1<<2)
|
||||
|
||||
// If this client already has one of these events in its queue, just update the event instead of sending it as a duplicate
|
||||
//
|
||||
#define FEV_UPDATE (1<<3)
|
||||
|
||||
// Only send to entity specified as the invoker
|
||||
#define FEV_HOSTONLY (1<<4)
|
||||
|
||||
// Only send if the event was created on the server.
|
||||
#define FEV_SERVER (1<<5)
|
||||
|
||||
// Only issue event client side ( from shared code )
|
||||
#define FEV_CLIENT (1<<6)
|
||||
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 2000, 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.
|
||||
*
|
||||
****/
|
||||
#if !defined( EVENT_FLAGSH )
|
||||
#define EVENT_FLAGSH
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// Skip local host for event send.
|
||||
#define FEV_NOTHOST (1<<0)
|
||||
|
||||
// Send the event reliably. You must specify the origin and angles and use
|
||||
// PLAYBACK_EVENT_FULL for this to work correctly on the server for anything
|
||||
// that depends on the event origin/angles. I.e., the origin/angles are not
|
||||
// taken from the invoking edict for reliable events.
|
||||
#define FEV_RELIABLE (1<<1)
|
||||
|
||||
// Don't restrict to PAS/PVS, send this event to _everybody_ on the server ( useful for stopping CHAN_STATIC
|
||||
// sounds started by client event when client is not in PVS anymore ( hwguy in TFC e.g. ).
|
||||
#define FEV_GLOBAL (1<<2)
|
||||
|
||||
// If this client already has one of these events in its queue, just update the event instead of sending it as a duplicate
|
||||
//
|
||||
#define FEV_UPDATE (1<<3)
|
||||
|
||||
// Only send to entity specified as the invoker
|
||||
#define FEV_HOSTONLY (1<<4)
|
||||
|
||||
// Only send if the event was created on the server.
|
||||
#define FEV_SERVER (1<<5)
|
||||
|
||||
// Only issue event client side ( from shared code )
|
||||
#define FEV_CLIENT (1<<6)
|
||||
|
||||
#endif
|
||||
@@ -1,38 +1,38 @@
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 2000, 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.
|
||||
*
|
||||
****/
|
||||
#ifndef IN_BUTTONS_H
|
||||
#define IN_BUTTONS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#define IN_ATTACK (1 << 0)
|
||||
#define IN_JUMP (1 << 1)
|
||||
#define IN_DUCK (1 << 2)
|
||||
#define IN_FORWARD (1 << 3)
|
||||
#define IN_BACK (1 << 4)
|
||||
#define IN_USE (1 << 5)
|
||||
#define IN_CANCEL (1 << 6)
|
||||
#define IN_LEFT (1 << 7)
|
||||
#define IN_RIGHT (1 << 8)
|
||||
#define IN_MOVELEFT (1 << 9)
|
||||
#define IN_MOVERIGHT (1 << 10)
|
||||
#define IN_ATTACK2 (1 << 11)
|
||||
#define IN_RUN (1 << 12)
|
||||
#define IN_RELOAD (1 << 13)
|
||||
#define IN_ALT1 (1 << 14)
|
||||
#define IN_SCORE (1 << 15) // Used by client.dll for when scoreboard is held down
|
||||
|
||||
#endif // IN_BUTTONS_H
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 2000, 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.
|
||||
*
|
||||
****/
|
||||
#ifndef IN_BUTTONS_H
|
||||
#define IN_BUTTONS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#define IN_ATTACK (1 << 0)
|
||||
#define IN_JUMP (1 << 1)
|
||||
#define IN_DUCK (1 << 2)
|
||||
#define IN_FORWARD (1 << 3)
|
||||
#define IN_BACK (1 << 4)
|
||||
#define IN_USE (1 << 5)
|
||||
#define IN_CANCEL (1 << 6)
|
||||
#define IN_LEFT (1 << 7)
|
||||
#define IN_RIGHT (1 << 8)
|
||||
#define IN_MOVELEFT (1 << 9)
|
||||
#define IN_MOVERIGHT (1 << 10)
|
||||
#define IN_ATTACK2 (1 << 11)
|
||||
#define IN_RUN (1 << 12)
|
||||
#define IN_RELOAD (1 << 13)
|
||||
#define IN_ALT1 (1 << 14)
|
||||
#define IN_SCORE (1 << 15) // Used by client.dll for when scoreboard is held down
|
||||
|
||||
#endif // IN_BUTTONS_H
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
//========= Copyright <20> 1996-2001, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#ifndef INC_NOWIN_H
|
||||
#define INC_NOWIN_H
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#endif //!_WIN32
|
||||
//========= Copyright <20> 1996-2001, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#ifndef INC_NOWIN_H
|
||||
#define INC_NOWIN_H
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#endif //!_WIN32
|
||||
#endif //INC_NOWIN_H
|
||||
@@ -1,29 +1,29 @@
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 2000, 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.
|
||||
*
|
||||
****/
|
||||
#if !defined( STUDIO_EVENTH )
|
||||
#define STUDIO_EVENTH
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
typedef struct mstudioevent_s
|
||||
{
|
||||
int frame;
|
||||
int event;
|
||||
int type;
|
||||
char options[64];
|
||||
} mstudioevent_t;
|
||||
|
||||
#endif // STUDIO_EVENTH
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 2000, 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.
|
||||
*
|
||||
****/
|
||||
#if !defined( STUDIO_EVENTH )
|
||||
#define STUDIO_EVENTH
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
typedef struct mstudioevent_s
|
||||
{
|
||||
int frame;
|
||||
int event;
|
||||
int type;
|
||||
char options[64];
|
||||
} mstudioevent_t;
|
||||
|
||||
#endif // STUDIO_EVENTH
|
||||
|
||||
8
src/dlls/.gitignore
vendored
8
src/dlls/.gitignore
vendored
@@ -1,5 +1,5 @@
|
||||
msgs/
|
||||
opt.*/
|
||||
debug.*/
|
||||
*.o
|
||||
msgs/
|
||||
opt.*/
|
||||
debug.*/
|
||||
*.o
|
||||
*.so
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
CPP = g++-7
|
||||
CPP = g++
|
||||
BASEFLAGS = -Dstricmp=strcasecmp -Dstrcmpi=strcasecmp -m32
|
||||
OPTFLAGS = -O2
|
||||
CPPFLAGS = ${BASEFLAGS} ${OPTFLAGS} -w -I. -I../engine -I../common -I../pm_shared -I../metamod
|
||||
@@ -17,31 +17,44 @@ OBJ = \
|
||||
controller.o \
|
||||
defaultai.o \
|
||||
dllapi.o \
|
||||
explode.o \
|
||||
effects.o \
|
||||
explode.o \
|
||||
flyingmonster.o \
|
||||
gargantua.o \
|
||||
ggrenade.o \
|
||||
gonome.o \
|
||||
h_ai.o \
|
||||
h_export.o \
|
||||
hassassin.o \
|
||||
headcrab.o \
|
||||
h_export.o \
|
||||
hgrunt.o \
|
||||
hornet.o \
|
||||
houndeye.o \
|
||||
hwgrunt.o \
|
||||
islave.o \
|
||||
massn.o \
|
||||
monster_api.o \
|
||||
monster_config.o \
|
||||
monsters.o \
|
||||
monsterstate.o \
|
||||
nodes.o \
|
||||
otis.o \
|
||||
pitdrone.o \
|
||||
rgrunt.o \
|
||||
scientist.o \
|
||||
shock.o \
|
||||
shockroach.o \
|
||||
skill.o \
|
||||
sound.o \
|
||||
sporegrenade.o \
|
||||
squeakgrenade.o \
|
||||
strooper.o \
|
||||
stukabat.o \
|
||||
subs.o \
|
||||
talkmonster.o \
|
||||
turret.o \
|
||||
util.o \
|
||||
voltigore.o \
|
||||
weapons.o \
|
||||
zombie.o
|
||||
|
||||
|
||||
@@ -1,109 +1,109 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
|
||||
#ifndef ACTIVITY_H
|
||||
#define ACTIVITY_H
|
||||
|
||||
|
||||
typedef enum {
|
||||
ACT_RESET = 0, // Set m_Activity to this invalid value to force a reset to m_IdealActivity
|
||||
ACT_IDLE = 1,
|
||||
ACT_GUARD,
|
||||
ACT_WALK,
|
||||
ACT_RUN,
|
||||
ACT_FLY, // Fly (and flap if appropriate)
|
||||
ACT_SWIM,
|
||||
ACT_HOP, // vertical jump
|
||||
ACT_LEAP, // long forward jump
|
||||
ACT_FALL,
|
||||
ACT_LAND,
|
||||
ACT_STRAFE_LEFT,
|
||||
ACT_STRAFE_RIGHT,
|
||||
ACT_ROLL_LEFT, // tuck and roll, left
|
||||
ACT_ROLL_RIGHT, // tuck and roll, right
|
||||
ACT_TURN_LEFT, // turn quickly left (stationary)
|
||||
ACT_TURN_RIGHT, // turn quickly right (stationary)
|
||||
ACT_CROUCH, // the act of crouching down from a standing position
|
||||
ACT_CROUCHIDLE, // holding body in crouched position (loops)
|
||||
ACT_STAND, // the act of standing from a crouched position
|
||||
ACT_USE,
|
||||
ACT_SIGNAL1,
|
||||
ACT_SIGNAL2,
|
||||
ACT_SIGNAL3,
|
||||
ACT_TWITCH,
|
||||
ACT_COWER,
|
||||
ACT_SMALL_FLINCH,
|
||||
ACT_BIG_FLINCH,
|
||||
ACT_RANGE_ATTACK1,
|
||||
ACT_RANGE_ATTACK2,
|
||||
ACT_MELEE_ATTACK1,
|
||||
ACT_MELEE_ATTACK2,
|
||||
ACT_RELOAD,
|
||||
ACT_ARM, // pull out gun, for instance
|
||||
ACT_DISARM, // reholster gun
|
||||
ACT_EAT, // monster chowing on a large food item (loop)
|
||||
ACT_DIESIMPLE,
|
||||
ACT_DIEBACKWARD,
|
||||
ACT_DIEFORWARD,
|
||||
ACT_DIEVIOLENT,
|
||||
ACT_BARNACLE_HIT, // barnacle tongue hits a monster
|
||||
ACT_BARNACLE_PULL, // barnacle is lifting the monster ( loop )
|
||||
ACT_BARNACLE_CHOMP, // barnacle latches on to the monster
|
||||
ACT_BARNACLE_CHEW, // barnacle is holding the monster in its mouth ( loop )
|
||||
ACT_SLEEP,
|
||||
ACT_INSPECT_FLOOR, // for active idles, look at something on or near the floor
|
||||
ACT_INSPECT_WALL, // for active idles, look at something directly ahead of you ( doesn't HAVE to be a wall or on a wall )
|
||||
ACT_IDLE_ANGRY, // alternate idle animation in which the monster is clearly agitated. (loop)
|
||||
ACT_WALK_HURT, // limp (loop)
|
||||
ACT_RUN_HURT, // limp (loop)
|
||||
ACT_HOVER, // Idle while in flight
|
||||
ACT_GLIDE, // Fly (don't flap)
|
||||
ACT_FLY_LEFT, // Turn left in flight
|
||||
ACT_FLY_RIGHT, // Turn right in flight
|
||||
ACT_DETECT_SCENT, // this means the monster smells a scent carried by the air
|
||||
ACT_SNIFF, // this is the act of actually sniffing an item in front of the monster
|
||||
ACT_BITE, // some large monsters can eat small things in one bite. This plays one time, EAT loops.
|
||||
ACT_THREAT_DISPLAY, // without attacking, monster demonstrates that it is angry. (Yell, stick out chest, etc )
|
||||
ACT_FEAR_DISPLAY, // monster just saw something that it is afraid of
|
||||
ACT_EXCITED, // for some reason, monster is excited. Sees something he really likes to eat, or whatever.
|
||||
ACT_SPECIAL_ATTACK1, // very monster specific special attacks.
|
||||
ACT_SPECIAL_ATTACK2,
|
||||
ACT_COMBAT_IDLE, // agitated idle.
|
||||
ACT_WALK_SCARED,
|
||||
ACT_RUN_SCARED,
|
||||
ACT_VICTORY_DANCE, // killed a player, do a victory dance.
|
||||
ACT_DIE_HEADSHOT, // die, hit in head.
|
||||
ACT_DIE_CHESTSHOT, // die, hit in chest
|
||||
ACT_DIE_GUTSHOT, // die, hit in gut
|
||||
ACT_DIE_BACKSHOT, // die, hit in back
|
||||
ACT_FLINCH_HEAD,
|
||||
ACT_FLINCH_CHEST,
|
||||
ACT_FLINCH_STOMACH,
|
||||
ACT_FLINCH_LEFTARM,
|
||||
ACT_FLINCH_RIGHTARM,
|
||||
ACT_FLINCH_LEFTLEG,
|
||||
ACT_FLINCH_RIGHTLEG,
|
||||
} Activity;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
char *name;
|
||||
} activity_map_t;
|
||||
|
||||
extern activity_map_t activity_map[];
|
||||
|
||||
|
||||
#endif //ACTIVITY_H
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
|
||||
#ifndef ACTIVITY_H
|
||||
#define ACTIVITY_H
|
||||
|
||||
|
||||
typedef enum {
|
||||
ACT_RESET = 0, // Set m_Activity to this invalid value to force a reset to m_IdealActivity
|
||||
ACT_IDLE = 1,
|
||||
ACT_GUARD,
|
||||
ACT_WALK,
|
||||
ACT_RUN,
|
||||
ACT_FLY, // Fly (and flap if appropriate)
|
||||
ACT_SWIM,
|
||||
ACT_HOP, // vertical jump
|
||||
ACT_LEAP, // long forward jump
|
||||
ACT_FALL,
|
||||
ACT_LAND,
|
||||
ACT_STRAFE_LEFT,
|
||||
ACT_STRAFE_RIGHT,
|
||||
ACT_ROLL_LEFT, // tuck and roll, left
|
||||
ACT_ROLL_RIGHT, // tuck and roll, right
|
||||
ACT_TURN_LEFT, // turn quickly left (stationary)
|
||||
ACT_TURN_RIGHT, // turn quickly right (stationary)
|
||||
ACT_CROUCH, // the act of crouching down from a standing position
|
||||
ACT_CROUCHIDLE, // holding body in crouched position (loops)
|
||||
ACT_STAND, // the act of standing from a crouched position
|
||||
ACT_USE,
|
||||
ACT_SIGNAL1,
|
||||
ACT_SIGNAL2,
|
||||
ACT_SIGNAL3,
|
||||
ACT_TWITCH,
|
||||
ACT_COWER,
|
||||
ACT_SMALL_FLINCH,
|
||||
ACT_BIG_FLINCH,
|
||||
ACT_RANGE_ATTACK1,
|
||||
ACT_RANGE_ATTACK2,
|
||||
ACT_MELEE_ATTACK1,
|
||||
ACT_MELEE_ATTACK2,
|
||||
ACT_RELOAD,
|
||||
ACT_ARM, // pull out gun, for instance
|
||||
ACT_DISARM, // reholster gun
|
||||
ACT_EAT, // monster chowing on a large food item (loop)
|
||||
ACT_DIESIMPLE,
|
||||
ACT_DIEBACKWARD,
|
||||
ACT_DIEFORWARD,
|
||||
ACT_DIEVIOLENT,
|
||||
ACT_BARNACLE_HIT, // barnacle tongue hits a monster
|
||||
ACT_BARNACLE_PULL, // barnacle is lifting the monster ( loop )
|
||||
ACT_BARNACLE_CHOMP, // barnacle latches on to the monster
|
||||
ACT_BARNACLE_CHEW, // barnacle is holding the monster in its mouth ( loop )
|
||||
ACT_SLEEP,
|
||||
ACT_INSPECT_FLOOR, // for active idles, look at something on or near the floor
|
||||
ACT_INSPECT_WALL, // for active idles, look at something directly ahead of you ( doesn't HAVE to be a wall or on a wall )
|
||||
ACT_IDLE_ANGRY, // alternate idle animation in which the monster is clearly agitated. (loop)
|
||||
ACT_WALK_HURT, // limp (loop)
|
||||
ACT_RUN_HURT, // limp (loop)
|
||||
ACT_HOVER, // Idle while in flight
|
||||
ACT_GLIDE, // Fly (don't flap)
|
||||
ACT_FLY_LEFT, // Turn left in flight
|
||||
ACT_FLY_RIGHT, // Turn right in flight
|
||||
ACT_DETECT_SCENT, // this means the monster smells a scent carried by the air
|
||||
ACT_SNIFF, // this is the act of actually sniffing an item in front of the monster
|
||||
ACT_BITE, // some large monsters can eat small things in one bite. This plays one time, EAT loops.
|
||||
ACT_THREAT_DISPLAY, // without attacking, monster demonstrates that it is angry. (Yell, stick out chest, etc )
|
||||
ACT_FEAR_DISPLAY, // monster just saw something that it is afraid of
|
||||
ACT_EXCITED, // for some reason, monster is excited. Sees something he really likes to eat, or whatever.
|
||||
ACT_SPECIAL_ATTACK1, // very monster specific special attacks.
|
||||
ACT_SPECIAL_ATTACK2,
|
||||
ACT_COMBAT_IDLE, // agitated idle.
|
||||
ACT_WALK_SCARED,
|
||||
ACT_RUN_SCARED,
|
||||
ACT_VICTORY_DANCE, // killed a player, do a victory dance.
|
||||
ACT_DIE_HEADSHOT, // die, hit in head.
|
||||
ACT_DIE_CHESTSHOT, // die, hit in chest
|
||||
ACT_DIE_GUTSHOT, // die, hit in gut
|
||||
ACT_DIE_BACKSHOT, // die, hit in back
|
||||
ACT_FLINCH_HEAD,
|
||||
ACT_FLINCH_CHEST,
|
||||
ACT_FLINCH_STOMACH,
|
||||
ACT_FLINCH_LEFTARM,
|
||||
ACT_FLINCH_RIGHTARM,
|
||||
ACT_FLINCH_LEFTLEG,
|
||||
ACT_FLINCH_RIGHTLEG,
|
||||
} Activity;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
char *name;
|
||||
} activity_map_t;
|
||||
|
||||
extern activity_map_t activity_map[];
|
||||
|
||||
|
||||
#endif //ACTIVITY_H
|
||||
|
||||
@@ -1,97 +1,97 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
|
||||
#define _A( a ) { a, #a }
|
||||
|
||||
activity_map_t activity_map[] =
|
||||
{
|
||||
_A( ACT_IDLE ),
|
||||
_A( ACT_GUARD ),
|
||||
_A( ACT_WALK ),
|
||||
_A( ACT_RUN ),
|
||||
_A( ACT_FLY ),
|
||||
_A( ACT_SWIM ),
|
||||
_A( ACT_HOP ),
|
||||
_A( ACT_LEAP ),
|
||||
_A( ACT_FALL ),
|
||||
_A( ACT_LAND ),
|
||||
_A( ACT_STRAFE_LEFT ),
|
||||
_A( ACT_STRAFE_RIGHT ),
|
||||
_A( ACT_ROLL_LEFT ),
|
||||
_A( ACT_ROLL_RIGHT ),
|
||||
_A( ACT_TURN_LEFT ),
|
||||
_A( ACT_TURN_RIGHT ),
|
||||
_A( ACT_CROUCH ),
|
||||
_A( ACT_CROUCHIDLE ),
|
||||
_A( ACT_STAND ),
|
||||
_A( ACT_USE ),
|
||||
_A( ACT_SIGNAL1 ),
|
||||
_A( ACT_SIGNAL2 ),
|
||||
_A( ACT_SIGNAL3 ),
|
||||
_A( ACT_TWITCH ),
|
||||
_A( ACT_COWER ),
|
||||
_A( ACT_SMALL_FLINCH ),
|
||||
_A( ACT_BIG_FLINCH ),
|
||||
_A( ACT_RANGE_ATTACK1 ),
|
||||
_A( ACT_RANGE_ATTACK2 ),
|
||||
_A( ACT_MELEE_ATTACK1 ),
|
||||
_A( ACT_MELEE_ATTACK2 ),
|
||||
_A( ACT_RELOAD ),
|
||||
_A( ACT_ARM ),
|
||||
_A( ACT_DISARM ),
|
||||
_A( ACT_EAT ),
|
||||
_A( ACT_DIESIMPLE ),
|
||||
_A( ACT_DIEBACKWARD ),
|
||||
_A( ACT_DIEFORWARD ),
|
||||
_A( ACT_DIEVIOLENT ),
|
||||
_A( ACT_BARNACLE_HIT ),
|
||||
_A( ACT_BARNACLE_PULL ),
|
||||
_A( ACT_BARNACLE_CHOMP ),
|
||||
_A( ACT_BARNACLE_CHEW ),
|
||||
_A( ACT_SLEEP ),
|
||||
_A( ACT_INSPECT_FLOOR ),
|
||||
_A( ACT_INSPECT_WALL ),
|
||||
_A( ACT_IDLE_ANGRY ),
|
||||
_A( ACT_WALK_HURT ),
|
||||
_A( ACT_RUN_HURT ),
|
||||
_A( ACT_HOVER ),
|
||||
_A( ACT_GLIDE ),
|
||||
_A( ACT_FLY_LEFT ),
|
||||
_A( ACT_FLY_RIGHT ),
|
||||
_A( ACT_DETECT_SCENT ),
|
||||
_A( ACT_SNIFF ),
|
||||
_A( ACT_BITE ),
|
||||
_A( ACT_THREAT_DISPLAY ),
|
||||
_A( ACT_FEAR_DISPLAY ),
|
||||
_A( ACT_EXCITED ),
|
||||
_A( ACT_SPECIAL_ATTACK1 ),
|
||||
_A( ACT_SPECIAL_ATTACK2 ),
|
||||
_A( ACT_COMBAT_IDLE ),
|
||||
_A( ACT_WALK_SCARED ),
|
||||
_A( ACT_RUN_SCARED ),
|
||||
_A( ACT_VICTORY_DANCE ),
|
||||
_A( ACT_DIE_HEADSHOT ),
|
||||
_A( ACT_DIE_CHESTSHOT ),
|
||||
_A( ACT_DIE_GUTSHOT ),
|
||||
_A( ACT_DIE_BACKSHOT ),
|
||||
_A( ACT_FLINCH_HEAD ),
|
||||
_A( ACT_FLINCH_CHEST ),
|
||||
_A( ACT_FLINCH_STOMACH ),
|
||||
_A( ACT_FLINCH_LEFTARM ),
|
||||
_A( ACT_FLINCH_RIGHTARM ),
|
||||
_A( ACT_FLINCH_LEFTLEG ),
|
||||
_A( ACT_FLINCH_RIGHTLEG ),
|
||||
0, NULL
|
||||
};
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
|
||||
#define _A( a ) { a, #a }
|
||||
|
||||
activity_map_t activity_map[] =
|
||||
{
|
||||
_A( ACT_IDLE ),
|
||||
_A( ACT_GUARD ),
|
||||
_A( ACT_WALK ),
|
||||
_A( ACT_RUN ),
|
||||
_A( ACT_FLY ),
|
||||
_A( ACT_SWIM ),
|
||||
_A( ACT_HOP ),
|
||||
_A( ACT_LEAP ),
|
||||
_A( ACT_FALL ),
|
||||
_A( ACT_LAND ),
|
||||
_A( ACT_STRAFE_LEFT ),
|
||||
_A( ACT_STRAFE_RIGHT ),
|
||||
_A( ACT_ROLL_LEFT ),
|
||||
_A( ACT_ROLL_RIGHT ),
|
||||
_A( ACT_TURN_LEFT ),
|
||||
_A( ACT_TURN_RIGHT ),
|
||||
_A( ACT_CROUCH ),
|
||||
_A( ACT_CROUCHIDLE ),
|
||||
_A( ACT_STAND ),
|
||||
_A( ACT_USE ),
|
||||
_A( ACT_SIGNAL1 ),
|
||||
_A( ACT_SIGNAL2 ),
|
||||
_A( ACT_SIGNAL3 ),
|
||||
_A( ACT_TWITCH ),
|
||||
_A( ACT_COWER ),
|
||||
_A( ACT_SMALL_FLINCH ),
|
||||
_A( ACT_BIG_FLINCH ),
|
||||
_A( ACT_RANGE_ATTACK1 ),
|
||||
_A( ACT_RANGE_ATTACK2 ),
|
||||
_A( ACT_MELEE_ATTACK1 ),
|
||||
_A( ACT_MELEE_ATTACK2 ),
|
||||
_A( ACT_RELOAD ),
|
||||
_A( ACT_ARM ),
|
||||
_A( ACT_DISARM ),
|
||||
_A( ACT_EAT ),
|
||||
_A( ACT_DIESIMPLE ),
|
||||
_A( ACT_DIEBACKWARD ),
|
||||
_A( ACT_DIEFORWARD ),
|
||||
_A( ACT_DIEVIOLENT ),
|
||||
_A( ACT_BARNACLE_HIT ),
|
||||
_A( ACT_BARNACLE_PULL ),
|
||||
_A( ACT_BARNACLE_CHOMP ),
|
||||
_A( ACT_BARNACLE_CHEW ),
|
||||
_A( ACT_SLEEP ),
|
||||
_A( ACT_INSPECT_FLOOR ),
|
||||
_A( ACT_INSPECT_WALL ),
|
||||
_A( ACT_IDLE_ANGRY ),
|
||||
_A( ACT_WALK_HURT ),
|
||||
_A( ACT_RUN_HURT ),
|
||||
_A( ACT_HOVER ),
|
||||
_A( ACT_GLIDE ),
|
||||
_A( ACT_FLY_LEFT ),
|
||||
_A( ACT_FLY_RIGHT ),
|
||||
_A( ACT_DETECT_SCENT ),
|
||||
_A( ACT_SNIFF ),
|
||||
_A( ACT_BITE ),
|
||||
_A( ACT_THREAT_DISPLAY ),
|
||||
_A( ACT_FEAR_DISPLAY ),
|
||||
_A( ACT_EXCITED ),
|
||||
_A( ACT_SPECIAL_ATTACK1 ),
|
||||
_A( ACT_SPECIAL_ATTACK2 ),
|
||||
_A( ACT_COMBAT_IDLE ),
|
||||
_A( ACT_WALK_SCARED ),
|
||||
_A( ACT_RUN_SCARED ),
|
||||
_A( ACT_VICTORY_DANCE ),
|
||||
_A( ACT_DIE_HEADSHOT ),
|
||||
_A( ACT_DIE_CHESTSHOT ),
|
||||
_A( ACT_DIE_GUTSHOT ),
|
||||
_A( ACT_DIE_BACKSHOT ),
|
||||
_A( ACT_FLINCH_HEAD ),
|
||||
_A( ACT_FLINCH_CHEST ),
|
||||
_A( ACT_FLINCH_STOMACH ),
|
||||
_A( ACT_FLINCH_LEFTARM ),
|
||||
_A( ACT_FLINCH_RIGHTARM ),
|
||||
_A( ACT_FLINCH_LEFTLEG ),
|
||||
_A( ACT_FLINCH_RIGHTLEG ),
|
||||
0, NULL
|
||||
};
|
||||
|
||||
2230
src/dlls/agrunt.cpp
2230
src/dlls/agrunt.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,306 +1,306 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
/*
|
||||
|
||||
===== monsters.cpp ========================================================
|
||||
|
||||
Monster-related utility code
|
||||
|
||||
*/
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "animation.h"
|
||||
|
||||
|
||||
//=========================================================
|
||||
// StudioFrameAdvance - advance the animation frame up to the current time
|
||||
// if an flInterval is passed in, only advance animation that number of seconds
|
||||
//=========================================================
|
||||
float CMBaseAnimating :: StudioFrameAdvance ( float flInterval )
|
||||
{
|
||||
if (flInterval == 0.0)
|
||||
{
|
||||
flInterval = (gpGlobals->time - pev->animtime);
|
||||
if (flInterval <= 0.001)
|
||||
{
|
||||
pev->animtime = gpGlobals->time;
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
if (! pev->animtime)
|
||||
flInterval = 0.0;
|
||||
|
||||
pev->frame += flInterval * m_flFrameRate * pev->framerate;
|
||||
pev->animtime = gpGlobals->time;
|
||||
|
||||
if (pev->frame < 0.0 || pev->frame >= 256.0)
|
||||
{
|
||||
if (m_fSequenceLoops)
|
||||
pev->frame -= (int)(pev->frame / 256.0) * 256.0;
|
||||
else
|
||||
pev->frame = (pev->frame < 0.0) ? 0 : 255;
|
||||
m_fSequenceFinished = TRUE; // just in case it wasn't caught in GetEvents
|
||||
}
|
||||
|
||||
return flInterval;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// LookupActivity
|
||||
//=========================================================
|
||||
int CMBaseAnimating :: LookupActivity ( int activity )
|
||||
{
|
||||
ASSERT( activity != 0 );
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
return ::LookupActivity( pmodel, pev, activity );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// LookupActivityHeaviest
|
||||
//
|
||||
// Get activity with highest 'weight'
|
||||
//
|
||||
//=========================================================
|
||||
int CMBaseAnimating :: LookupActivityHeaviest ( int activity )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
return ::LookupActivityHeaviest( pmodel, pev, activity );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
int CMBaseAnimating :: LookupSequence ( const char *label )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
return ::LookupSequence( pmodel, label );
|
||||
}
|
||||
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
void CMBaseAnimating :: ResetSequenceInfo ( )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
GetSequenceInfo( pmodel, pev, &m_flFrameRate, &m_flGroundSpeed );
|
||||
m_fSequenceLoops = ((GetSequenceFlags() & STUDIO_LOOPING) != 0);
|
||||
pev->animtime = gpGlobals->time;
|
||||
pev->framerate = 1.0;
|
||||
m_fSequenceFinished = FALSE;
|
||||
m_flLastEventCheck = gpGlobals->time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
BOOL CMBaseAnimating :: GetSequenceFlags( )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
return ::GetSequenceFlags( pmodel, pev );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// DispatchAnimEvents
|
||||
//=========================================================
|
||||
void CMBaseAnimating :: DispatchAnimEvents ( float flInterval )
|
||||
{
|
||||
MonsterEvent_t event;
|
||||
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
if ( !pmodel )
|
||||
{
|
||||
ALERT( at_aiconsole, "Gibbed monster is thinking!\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: I have to do this or some events get missed, and this is probably causing the problem below
|
||||
flInterval = 0.1;
|
||||
|
||||
// FIX: this still sometimes hits events twice
|
||||
float flStart = pev->frame + (m_flLastEventCheck - pev->animtime) * m_flFrameRate * pev->framerate;
|
||||
float flEnd = pev->frame + flInterval * m_flFrameRate * pev->framerate;
|
||||
m_flLastEventCheck = pev->animtime + flInterval;
|
||||
|
||||
m_fSequenceFinished = FALSE;
|
||||
if (flEnd >= 256 || flEnd <= 0.0)
|
||||
m_fSequenceFinished = TRUE;
|
||||
|
||||
int index = 0;
|
||||
|
||||
while ( (index = GetAnimationEvent( pmodel, pev, &event, flStart, flEnd, index ) ) != 0 )
|
||||
{
|
||||
HandleAnimEvent( &event );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
float CMBaseAnimating :: SetBoneController ( int iController, float flValue )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
return SetController( pmodel, pev, iController, flValue );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
void CMBaseAnimating :: InitBoneControllers ( void )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
SetController( pmodel, pev, 0, 0.0 );
|
||||
SetController( pmodel, pev, 1, 0.0 );
|
||||
SetController( pmodel, pev, 2, 0.0 );
|
||||
SetController( pmodel, pev, 3, 0.0 );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
float CMBaseAnimating :: SetBlending ( int iBlender, float flValue )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
return ::SetBlending( pmodel, pev, iBlender, flValue );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
void CMBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles )
|
||||
{
|
||||
GET_BONE_POSITION( ENT(pev), iBone, origin, angles );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
void CMBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles )
|
||||
{
|
||||
GET_ATTACHMENT( ENT(pev), iAttachment, origin, angles );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
int CMBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
if (piDir == NULL)
|
||||
{
|
||||
int iDir;
|
||||
int sequence = ::FindTransition( pmodel, iEndingSequence, iGoalSequence, &iDir );
|
||||
if (iDir != 1)
|
||||
return -1;
|
||||
else
|
||||
return sequence;
|
||||
}
|
||||
|
||||
return ::FindTransition( pmodel, iEndingSequence, iGoalSequence, piDir );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
void CMBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CMBaseAnimating :: SetBodygroup( int iGroup, int iValue )
|
||||
{
|
||||
::SetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup, iValue );
|
||||
}
|
||||
|
||||
int CMBaseAnimating :: GetBodygroup( int iGroup )
|
||||
{
|
||||
return ::GetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup );
|
||||
}
|
||||
|
||||
|
||||
int CMBaseAnimating :: ExtractBbox( int sequence, float *mins, float *maxs )
|
||||
{
|
||||
return ::ExtractBbox( GET_MODEL_PTR( ENT(pev) ), sequence, mins, maxs );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
|
||||
void CMBaseAnimating :: SetSequenceBox( void )
|
||||
{
|
||||
Vector mins, maxs;
|
||||
|
||||
// Get sequence bbox
|
||||
if ( ExtractBbox( pev->sequence, mins, maxs ) )
|
||||
{
|
||||
// expand box for rotation
|
||||
// find min / max for rotations
|
||||
float yaw = pev->angles.y * (M_PI / 180.0);
|
||||
|
||||
Vector xvector, yvector;
|
||||
xvector.x = cos(yaw);
|
||||
xvector.y = sin(yaw);
|
||||
yvector.x = -sin(yaw);
|
||||
yvector.y = cos(yaw);
|
||||
Vector bounds[2];
|
||||
|
||||
bounds[0] = mins;
|
||||
bounds[1] = maxs;
|
||||
|
||||
Vector rmin( 9999, 9999, 9999 );
|
||||
Vector rmax( -9999, -9999, -9999 );
|
||||
Vector base, transformed;
|
||||
|
||||
for (int i = 0; i <= 1; i++ )
|
||||
{
|
||||
base.x = bounds[i].x;
|
||||
for ( int j = 0; j <= 1; j++ )
|
||||
{
|
||||
base.y = bounds[j].y;
|
||||
for ( int k = 0; k <= 1; k++ )
|
||||
{
|
||||
base.z = bounds[k].z;
|
||||
|
||||
// transform the point
|
||||
transformed.x = xvector.x*base.x + yvector.x*base.y;
|
||||
transformed.y = xvector.y*base.x + yvector.y*base.y;
|
||||
transformed.z = base.z;
|
||||
|
||||
if (transformed.x < rmin.x)
|
||||
rmin.x = transformed.x;
|
||||
if (transformed.x > rmax.x)
|
||||
rmax.x = transformed.x;
|
||||
if (transformed.y < rmin.y)
|
||||
rmin.y = transformed.y;
|
||||
if (transformed.y > rmax.y)
|
||||
rmax.y = transformed.y;
|
||||
if (transformed.z < rmin.z)
|
||||
rmin.z = transformed.z;
|
||||
if (transformed.z > rmax.z)
|
||||
rmax.z = transformed.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
rmin.z = 0;
|
||||
rmax.z = rmin.z + 1;
|
||||
UTIL_SetSize( pev, rmin, rmax );
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
/*
|
||||
|
||||
===== monsters.cpp ========================================================
|
||||
|
||||
Monster-related utility code
|
||||
|
||||
*/
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "animation.h"
|
||||
|
||||
|
||||
//=========================================================
|
||||
// StudioFrameAdvance - advance the animation frame up to the current time
|
||||
// if an flInterval is passed in, only advance animation that number of seconds
|
||||
//=========================================================
|
||||
float CMBaseAnimating :: StudioFrameAdvance ( float flInterval )
|
||||
{
|
||||
if (flInterval == 0.0)
|
||||
{
|
||||
flInterval = (gpGlobals->time - pev->animtime);
|
||||
if (flInterval <= 0.001)
|
||||
{
|
||||
pev->animtime = gpGlobals->time;
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
if (! pev->animtime)
|
||||
flInterval = 0.0;
|
||||
|
||||
pev->frame += flInterval * m_flFrameRate * pev->framerate;
|
||||
pev->animtime = gpGlobals->time;
|
||||
|
||||
if (pev->frame < 0.0 || pev->frame >= 256.0)
|
||||
{
|
||||
if (m_fSequenceLoops)
|
||||
pev->frame -= (int)(pev->frame / 256.0) * 256.0;
|
||||
else
|
||||
pev->frame = (pev->frame < 0.0) ? 0 : 255;
|
||||
m_fSequenceFinished = TRUE; // just in case it wasn't caught in GetEvents
|
||||
}
|
||||
|
||||
return flInterval;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// LookupActivity
|
||||
//=========================================================
|
||||
int CMBaseAnimating :: LookupActivity ( int activity )
|
||||
{
|
||||
ASSERT( activity != 0 );
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
return ::LookupActivity( pmodel, pev, activity );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// LookupActivityHeaviest
|
||||
//
|
||||
// Get activity with highest 'weight'
|
||||
//
|
||||
//=========================================================
|
||||
int CMBaseAnimating :: LookupActivityHeaviest ( int activity )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
return ::LookupActivityHeaviest( pmodel, pev, activity );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
int CMBaseAnimating :: LookupSequence ( const char *label )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
return ::LookupSequence( pmodel, label );
|
||||
}
|
||||
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
void CMBaseAnimating :: ResetSequenceInfo ( )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
GetSequenceInfo( pmodel, pev, &m_flFrameRate, &m_flGroundSpeed );
|
||||
m_fSequenceLoops = ((GetSequenceFlags() & STUDIO_LOOPING) != 0);
|
||||
pev->animtime = gpGlobals->time;
|
||||
pev->framerate = 1.0;
|
||||
m_fSequenceFinished = FALSE;
|
||||
m_flLastEventCheck = gpGlobals->time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
BOOL CMBaseAnimating :: GetSequenceFlags( )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
return ::GetSequenceFlags( pmodel, pev );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// DispatchAnimEvents
|
||||
//=========================================================
|
||||
void CMBaseAnimating :: DispatchAnimEvents ( float flInterval )
|
||||
{
|
||||
MonsterEvent_t event;
|
||||
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
if ( !pmodel )
|
||||
{
|
||||
ALERT( at_aiconsole, "Gibbed monster is thinking!\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: I have to do this or some events get missed, and this is probably causing the problem below
|
||||
flInterval = 0.1;
|
||||
|
||||
// FIX: this still sometimes hits events twice
|
||||
float flStart = pev->frame + (m_flLastEventCheck - pev->animtime) * m_flFrameRate * pev->framerate;
|
||||
float flEnd = pev->frame + flInterval * m_flFrameRate * pev->framerate;
|
||||
m_flLastEventCheck = pev->animtime + flInterval;
|
||||
|
||||
m_fSequenceFinished = FALSE;
|
||||
if (flEnd >= 256 || flEnd <= 0.0)
|
||||
m_fSequenceFinished = TRUE;
|
||||
|
||||
int index = 0;
|
||||
|
||||
while ( (index = GetAnimationEvent( pmodel, pev, &event, flStart, flEnd, index ) ) != 0 )
|
||||
{
|
||||
HandleAnimEvent( &event );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
float CMBaseAnimating :: SetBoneController ( int iController, float flValue )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
return SetController( pmodel, pev, iController, flValue );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
void CMBaseAnimating :: InitBoneControllers ( void )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
SetController( pmodel, pev, 0, 0.0 );
|
||||
SetController( pmodel, pev, 1, 0.0 );
|
||||
SetController( pmodel, pev, 2, 0.0 );
|
||||
SetController( pmodel, pev, 3, 0.0 );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
float CMBaseAnimating :: SetBlending ( int iBlender, float flValue )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
return ::SetBlending( pmodel, pev, iBlender, flValue );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
void CMBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles )
|
||||
{
|
||||
GET_BONE_POSITION( ENT(pev), iBone, origin, angles );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
void CMBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles )
|
||||
{
|
||||
GET_ATTACHMENT( ENT(pev), iAttachment, origin, angles );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
int CMBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir )
|
||||
{
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
if (piDir == NULL)
|
||||
{
|
||||
int iDir;
|
||||
int sequence = ::FindTransition( pmodel, iEndingSequence, iGoalSequence, &iDir );
|
||||
if (iDir != 1)
|
||||
return -1;
|
||||
else
|
||||
return sequence;
|
||||
}
|
||||
|
||||
return ::FindTransition( pmodel, iEndingSequence, iGoalSequence, piDir );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
void CMBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CMBaseAnimating :: SetBodygroup( int iGroup, int iValue )
|
||||
{
|
||||
::SetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup, iValue );
|
||||
}
|
||||
|
||||
int CMBaseAnimating :: GetBodygroup( int iGroup )
|
||||
{
|
||||
return ::GetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup );
|
||||
}
|
||||
|
||||
|
||||
int CMBaseAnimating :: ExtractBbox( int sequence, float *mins, float *maxs )
|
||||
{
|
||||
return ::ExtractBbox( GET_MODEL_PTR( ENT(pev) ), sequence, mins, maxs );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
|
||||
void CMBaseAnimating :: SetSequenceBox( void )
|
||||
{
|
||||
Vector mins, maxs;
|
||||
|
||||
// Get sequence bbox
|
||||
if ( ExtractBbox( pev->sequence, mins, maxs ) )
|
||||
{
|
||||
// expand box for rotation
|
||||
// find min / max for rotations
|
||||
float yaw = pev->angles.y * (M_PI / 180.0);
|
||||
|
||||
Vector xvector, yvector;
|
||||
xvector.x = cos(yaw);
|
||||
xvector.y = sin(yaw);
|
||||
yvector.x = -sin(yaw);
|
||||
yvector.y = cos(yaw);
|
||||
Vector bounds[2];
|
||||
|
||||
bounds[0] = mins;
|
||||
bounds[1] = maxs;
|
||||
|
||||
Vector rmin( 9999, 9999, 9999 );
|
||||
Vector rmax( -9999, -9999, -9999 );
|
||||
Vector base, transformed;
|
||||
|
||||
for (int i = 0; i <= 1; i++ )
|
||||
{
|
||||
base.x = bounds[i].x;
|
||||
for ( int j = 0; j <= 1; j++ )
|
||||
{
|
||||
base.y = bounds[j].y;
|
||||
for ( int k = 0; k <= 1; k++ )
|
||||
{
|
||||
base.z = bounds[k].z;
|
||||
|
||||
// transform the point
|
||||
transformed.x = xvector.x*base.x + yvector.x*base.y;
|
||||
transformed.y = xvector.y*base.x + yvector.y*base.y;
|
||||
transformed.z = base.z;
|
||||
|
||||
if (transformed.x < rmin.x)
|
||||
rmin.x = transformed.x;
|
||||
if (transformed.x > rmax.x)
|
||||
rmax.x = transformed.x;
|
||||
if (transformed.y < rmin.y)
|
||||
rmin.y = transformed.y;
|
||||
if (transformed.y > rmax.y)
|
||||
rmax.y = transformed.y;
|
||||
if (transformed.z < rmin.z)
|
||||
rmin.z = transformed.z;
|
||||
if (transformed.z > rmax.z)
|
||||
rmax.z = transformed.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
rmin.z = 0;
|
||||
rmax.z = rmin.z + 1;
|
||||
UTIL_SetSize( pev, rmin, rmax );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,47 +1,47 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef ANIMATION_H
|
||||
#define ANIMATION_H
|
||||
|
||||
#define ACTIVITY_NOT_AVAILABLE -1
|
||||
|
||||
#ifndef MONSTEREVENT_H
|
||||
#include "monsterevent.h"
|
||||
#endif
|
||||
|
||||
extern int IsSoundEvent( int eventNumber );
|
||||
|
||||
int LookupActivity( void *pmodel, entvars_t *pev, int activity );
|
||||
int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity );
|
||||
int LookupSequence( void *pmodel, const char *label );
|
||||
void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed );
|
||||
int GetSequenceFlags( void *pmodel, entvars_t *pev );
|
||||
int LookupAnimationEvents( void *pmodel, entvars_t *pev, float flStart, float flEnd );
|
||||
float SetController( void *pmodel, entvars_t *pev, int iController, float flValue );
|
||||
float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue );
|
||||
void GetEyePosition( void *pmodel, float *vecEyePosition );
|
||||
void SequencePrecache( void *pmodel, const char *pSequenceName );
|
||||
int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir );
|
||||
void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue );
|
||||
int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup );
|
||||
|
||||
int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index );
|
||||
int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs );
|
||||
|
||||
// From /engine/studio.h
|
||||
#define STUDIO_LOOPING 0x0001
|
||||
|
||||
|
||||
#endif //ANIMATION_H
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef ANIMATION_H
|
||||
#define ANIMATION_H
|
||||
|
||||
#define ACTIVITY_NOT_AVAILABLE -1
|
||||
|
||||
#ifndef MONSTEREVENT_H
|
||||
#include "monsterevent.h"
|
||||
#endif
|
||||
|
||||
extern int IsSoundEvent( int eventNumber );
|
||||
|
||||
int LookupActivity( void *pmodel, entvars_t *pev, int activity );
|
||||
int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity );
|
||||
int LookupSequence( void *pmodel, const char *label );
|
||||
void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed );
|
||||
int GetSequenceFlags( void *pmodel, entvars_t *pev );
|
||||
int LookupAnimationEvents( void *pmodel, entvars_t *pev, float flStart, float flEnd );
|
||||
float SetController( void *pmodel, entvars_t *pev, int iController, float flValue );
|
||||
float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue );
|
||||
void GetEyePosition( void *pmodel, float *vecEyePosition );
|
||||
void SequencePrecache( void *pmodel, const char *pSequenceName );
|
||||
int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir );
|
||||
void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue );
|
||||
int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup );
|
||||
|
||||
int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index );
|
||||
int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs );
|
||||
|
||||
// From /engine/studio.h
|
||||
#define STUDIO_LOOPING 0x0001
|
||||
|
||||
|
||||
#endif //ANIMATION_H
|
||||
|
||||
1984
src/dlls/apache.cpp
1984
src/dlls/apache.cpp
File diff suppressed because it is too large
Load Diff
1356
src/dlls/barney.cpp
1356
src/dlls/barney.cpp
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,46 +1,46 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// cdll_dll.h
|
||||
|
||||
// this file is included by both the game-dll and the client-dll,
|
||||
|
||||
#ifndef CDLL_DLL_H
|
||||
#define CDLL_DLL_H
|
||||
|
||||
#define MAX_WEAPONS 32 // ???
|
||||
|
||||
#define MAX_WEAPON_SLOTS 5 // hud item selection slots
|
||||
#define MAX_ITEM_TYPES 6 // hud item selection slots
|
||||
|
||||
#define MAX_ITEMS 5 // hard coded item types
|
||||
|
||||
#define HIDEHUD_WEAPONS ( 1<<0 )
|
||||
#define HIDEHUD_FLASHLIGHT ( 1<<1 )
|
||||
#define HIDEHUD_ALL ( 1<<2 )
|
||||
#define HIDEHUD_HEALTH ( 1<<3 )
|
||||
|
||||
#define MAX_AMMO_TYPES 32 // ???
|
||||
#define MAX_AMMO_SLOTS 32 // not really slots
|
||||
|
||||
#define HUD_PRINTNOTIFY 1
|
||||
#define HUD_PRINTCONSOLE 2
|
||||
#define HUD_PRINTTALK 3
|
||||
#define HUD_PRINTCENTER 4
|
||||
|
||||
|
||||
#define WEAPON_SUIT 31
|
||||
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// cdll_dll.h
|
||||
|
||||
// this file is included by both the game-dll and the client-dll,
|
||||
|
||||
#ifndef CDLL_DLL_H
|
||||
#define CDLL_DLL_H
|
||||
|
||||
#define MAX_WEAPONS 32 // ???
|
||||
|
||||
#define MAX_WEAPON_SLOTS 5 // hud item selection slots
|
||||
#define MAX_ITEM_TYPES 6 // hud item selection slots
|
||||
|
||||
#define MAX_ITEMS 5 // hard coded item types
|
||||
|
||||
#define HIDEHUD_WEAPONS ( 1<<0 )
|
||||
#define HIDEHUD_FLASHLIGHT ( 1<<1 )
|
||||
#define HIDEHUD_ALL ( 1<<2 )
|
||||
#define HIDEHUD_HEALTH ( 1<<3 )
|
||||
|
||||
#define MAX_AMMO_TYPES 32 // ???
|
||||
#define MAX_AMMO_SLOTS 32 // not really slots
|
||||
|
||||
#define HUD_PRINTNOTIFY 1
|
||||
#define HUD_PRINTCONSOLE 2
|
||||
#define HUD_PRINTTALK 3
|
||||
#define HUD_PRINTCENTER 4
|
||||
|
||||
|
||||
#define WEAPON_SUIT 31
|
||||
|
||||
#endif
|
||||
@@ -1,306 +1,306 @@
|
||||
/***
|
||||
*
|
||||
* 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 "decals.h"
|
||||
|
||||
extern Vector VecBModelOrigin( entvars_t* pevBModel );
|
||||
extern DLL_GLOBAL Vector g_vecAttackDir;
|
||||
|
||||
edict_t * EHANDLE::Get( void )
|
||||
{
|
||||
if (m_pent)
|
||||
{
|
||||
if (m_pent->serialnumber == m_serialnumber)
|
||||
return m_pent;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
};
|
||||
|
||||
edict_t * EHANDLE::Set( edict_t *pent )
|
||||
{
|
||||
m_pent = pent;
|
||||
if (pent)
|
||||
m_serialnumber = m_pent->serialnumber;
|
||||
return pent;
|
||||
};
|
||||
|
||||
|
||||
EHANDLE :: operator edict_t *()
|
||||
{
|
||||
return Get( );
|
||||
};
|
||||
|
||||
|
||||
edict_t * EHANDLE :: operator = (edict_t *pEntity)
|
||||
{
|
||||
if (pEntity)
|
||||
{
|
||||
m_pent = pEntity;
|
||||
if (m_pent)
|
||||
m_serialnumber = m_pent->serialnumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pent = NULL;
|
||||
m_serialnumber = 0;
|
||||
}
|
||||
return pEntity;
|
||||
}
|
||||
|
||||
|
||||
edict_t * EHANDLE :: operator -> ()
|
||||
{
|
||||
return Get( );
|
||||
}
|
||||
|
||||
|
||||
void *CMBaseEntity::operator new( size_t stAllocateBlock )
|
||||
{
|
||||
void *mem = ::operator new( stAllocateBlock );
|
||||
memset( mem, 0, stAllocateBlock );
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
||||
edict_t *CMBaseEntity::CreateEntity(char *classname)
|
||||
{
|
||||
int istr = MAKE_STRING(classname);
|
||||
|
||||
edict_t *pent = CREATE_NAMED_ENTITY(istr);
|
||||
|
||||
if ( FNullEnt( pent ) )
|
||||
return NULL;
|
||||
|
||||
pev = VARS(pent);
|
||||
|
||||
pev->movetype = MOVETYPE_NONE;
|
||||
pev->solid = SOLID_NOT;
|
||||
pev->flags = 0;
|
||||
|
||||
m_pfnThink = NULL;
|
||||
m_pfnTouch = NULL;
|
||||
m_pfnUse = NULL;
|
||||
m_pfnBlocked = NULL;
|
||||
|
||||
pev->euser4 = (edict_t *)this;
|
||||
|
||||
return pent;
|
||||
}
|
||||
|
||||
// give health
|
||||
int CMBaseEntity :: TakeHealth( float flHealth, int bitsDamageType )
|
||||
{
|
||||
if (!pev->takedamage)
|
||||
return 0;
|
||||
|
||||
// heal
|
||||
if ( pev->health >= pev->max_health )
|
||||
return 0;
|
||||
|
||||
pev->health += flHealth;
|
||||
|
||||
if (pev->health > pev->max_health)
|
||||
pev->health = pev->max_health;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// inflict damage on this entity. bitsDamageType indicates type of damage inflicted, ie: DMG_CRUSH
|
||||
|
||||
int CMBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType )
|
||||
{
|
||||
Vector vecTemp;
|
||||
|
||||
if (!pev->takedamage)
|
||||
return 0;
|
||||
|
||||
// UNDONE: some entity types may be immune or resistant to some bitsDamageType
|
||||
|
||||
// if Attacker == Inflictor, the attack was a melee or other instant-hit attack.
|
||||
// (that is, no actual entity projectile was involved in the attack so use the shooter's origin).
|
||||
if ( pevAttacker == pevInflictor )
|
||||
{
|
||||
vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) );
|
||||
}
|
||||
else
|
||||
// an actual missile was involved.
|
||||
{
|
||||
vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) );
|
||||
}
|
||||
|
||||
// this global is still used for glass and other non-monster killables, along with decals.
|
||||
g_vecAttackDir = vecTemp.Normalize();
|
||||
|
||||
// save damage based on the target's armor level
|
||||
|
||||
// figure momentum add (don't let hurt brushes or other triggers move player)
|
||||
if ((!FNullEnt(pevInflictor)) && (pev->movetype == MOVETYPE_WALK || pev->movetype == MOVETYPE_STEP) && (pevAttacker->solid != SOLID_TRIGGER) )
|
||||
{
|
||||
Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5;
|
||||
vecDir = vecDir.Normalize();
|
||||
|
||||
float flForce = flDamage * ((32 * 32 * 72.0) / (pev->size.x * pev->size.y * pev->size.z)) * 5;
|
||||
|
||||
if (flForce > 1000.0)
|
||||
flForce = 1000.0;
|
||||
pev->velocity = pev->velocity + vecDir * flForce;
|
||||
}
|
||||
|
||||
// do the damage
|
||||
pev->health -= flDamage;
|
||||
if (pev->health <= 0)
|
||||
{
|
||||
Killed( pevAttacker, GIB_NORMAL );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void CMBaseEntity :: Killed( entvars_t *pevAttacker, int iGib )
|
||||
{
|
||||
pev->takedamage = DAMAGE_NO;
|
||||
pev->deadflag = DEAD_DEAD;
|
||||
UTIL_Remove( this->edict() );
|
||||
}
|
||||
|
||||
|
||||
// Initialize absmin & absmax to the appropriate box
|
||||
void SetObjectCollisionBox( entvars_t *pev )
|
||||
{
|
||||
if ( (pev->solid == SOLID_BSP) &&
|
||||
(pev->angles.x || pev->angles.y|| pev->angles.z) )
|
||||
{ // expand for rotation
|
||||
float max, v;
|
||||
int i;
|
||||
|
||||
max = 0;
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
v = fabs( ((float *)pev->mins)[i]);
|
||||
if (v > max)
|
||||
max = v;
|
||||
v = fabs( ((float *)pev->maxs)[i]);
|
||||
if (v > max)
|
||||
max = v;
|
||||
}
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
((float *)pev->absmin)[i] = ((float *)pev->origin)[i] - max;
|
||||
((float *)pev->absmax)[i] = ((float *)pev->origin)[i] + max;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pev->absmin = pev->origin + pev->mins;
|
||||
pev->absmax = pev->origin + pev->maxs;
|
||||
}
|
||||
|
||||
pev->absmin.x -= 1;
|
||||
pev->absmin.y -= 1;
|
||||
pev->absmin.z -= 1;
|
||||
pev->absmax.x += 1;
|
||||
pev->absmax.y += 1;
|
||||
pev->absmax.z += 1;
|
||||
}
|
||||
|
||||
|
||||
void CMBaseEntity::SetObjectCollisionBox( void )
|
||||
{
|
||||
::SetObjectCollisionBox( pev );
|
||||
}
|
||||
|
||||
|
||||
int CMBaseEntity :: Intersects( CMBaseEntity *pOther )
|
||||
{
|
||||
if ( pOther->pev->absmin.x > pev->absmax.x ||
|
||||
pOther->pev->absmin.y > pev->absmax.y ||
|
||||
pOther->pev->absmin.z > pev->absmax.z ||
|
||||
pOther->pev->absmax.x < pev->absmin.x ||
|
||||
pOther->pev->absmax.y < pev->absmin.y ||
|
||||
pOther->pev->absmax.z < pev->absmin.z )
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CMBaseEntity :: MakeDormant( void )
|
||||
{
|
||||
SetBits( pev->flags, FL_DORMANT );
|
||||
|
||||
// Don't touch
|
||||
pev->solid = SOLID_NOT;
|
||||
// Don't move
|
||||
pev->movetype = MOVETYPE_NONE;
|
||||
// Don't draw
|
||||
SetBits( pev->effects, EF_NODRAW );
|
||||
// Don't think
|
||||
pev->nextthink = 0;
|
||||
// Relink
|
||||
UTIL_SetOrigin( pev, pev->origin );
|
||||
}
|
||||
|
||||
int CMBaseEntity :: IsDormant( void )
|
||||
{
|
||||
return FBitSet( pev->flags, FL_DORMANT );
|
||||
}
|
||||
|
||||
BOOL CMBaseEntity :: IsInWorld( void )
|
||||
{
|
||||
// position
|
||||
if (pev->origin.x >= 4096) return FALSE;
|
||||
if (pev->origin.y >= 4096) return FALSE;
|
||||
if (pev->origin.z >= 4096) return FALSE;
|
||||
if (pev->origin.x <= -4096) return FALSE;
|
||||
if (pev->origin.y <= -4096) return FALSE;
|
||||
if (pev->origin.z <= -4096) return FALSE;
|
||||
// speed
|
||||
if (pev->velocity.x >= 2000) return FALSE;
|
||||
if (pev->velocity.y >= 2000) return FALSE;
|
||||
if (pev->velocity.z >= 2000) return FALSE;
|
||||
if (pev->velocity.x <= -2000) return FALSE;
|
||||
if (pev->velocity.y <= -2000) return FALSE;
|
||||
if (pev->velocity.z <= -2000) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int CMBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState )
|
||||
{
|
||||
if ( useType != USE_TOGGLE && useType != USE_SET )
|
||||
{
|
||||
if ( (currentState && useType == USE_ON) || (!currentState && useType == USE_OFF) )
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int CMBaseEntity :: DamageDecal( int bitsDamageType )
|
||||
{
|
||||
if ( pev->rendermode == kRenderTransAlpha )
|
||||
return -1;
|
||||
|
||||
if ( pev->rendermode != kRenderNormal )
|
||||
return DECAL_BPROOF1;
|
||||
|
||||
return DECAL_GUNSHOT1 + RANDOM_LONG(0,4);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
*
|
||||
* 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 "decals.h"
|
||||
|
||||
extern Vector VecBModelOrigin( entvars_t* pevBModel );
|
||||
extern DLL_GLOBAL Vector g_vecAttackDir;
|
||||
|
||||
edict_t * EHANDLE::Get( void )
|
||||
{
|
||||
if (m_pent)
|
||||
{
|
||||
if (m_pent->serialnumber == m_serialnumber)
|
||||
return m_pent;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
};
|
||||
|
||||
edict_t * EHANDLE::Set( edict_t *pent )
|
||||
{
|
||||
m_pent = pent;
|
||||
if (pent)
|
||||
m_serialnumber = m_pent->serialnumber;
|
||||
return pent;
|
||||
};
|
||||
|
||||
|
||||
EHANDLE :: operator edict_t *()
|
||||
{
|
||||
return Get( );
|
||||
};
|
||||
|
||||
|
||||
edict_t * EHANDLE :: operator = (edict_t *pEntity)
|
||||
{
|
||||
if (pEntity)
|
||||
{
|
||||
m_pent = pEntity;
|
||||
if (m_pent)
|
||||
m_serialnumber = m_pent->serialnumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pent = NULL;
|
||||
m_serialnumber = 0;
|
||||
}
|
||||
return pEntity;
|
||||
}
|
||||
|
||||
|
||||
edict_t * EHANDLE :: operator -> ()
|
||||
{
|
||||
return Get( );
|
||||
}
|
||||
|
||||
|
||||
void *CMBaseEntity::operator new( size_t stAllocateBlock )
|
||||
{
|
||||
void *mem = ::operator new( stAllocateBlock );
|
||||
memset( mem, 0, stAllocateBlock );
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
||||
edict_t *CMBaseEntity::CreateEntity(char *classname)
|
||||
{
|
||||
int istr = MAKE_STRING(classname);
|
||||
|
||||
edict_t *pent = CREATE_NAMED_ENTITY(istr);
|
||||
|
||||
if ( FNullEnt( pent ) )
|
||||
return NULL;
|
||||
|
||||
pev = VARS(pent);
|
||||
|
||||
pev->movetype = MOVETYPE_NONE;
|
||||
pev->solid = SOLID_NOT;
|
||||
pev->flags = 0;
|
||||
|
||||
m_pfnThink = NULL;
|
||||
m_pfnTouch = NULL;
|
||||
m_pfnUse = NULL;
|
||||
m_pfnBlocked = NULL;
|
||||
|
||||
pev->euser4 = (edict_t *)this;
|
||||
|
||||
return pent;
|
||||
}
|
||||
|
||||
// give health
|
||||
int CMBaseEntity :: TakeHealth( float flHealth, int bitsDamageType )
|
||||
{
|
||||
if (!pev->takedamage)
|
||||
return 0;
|
||||
|
||||
// heal
|
||||
if ( pev->health >= pev->max_health )
|
||||
return 0;
|
||||
|
||||
pev->health += flHealth;
|
||||
|
||||
if (pev->health > pev->max_health)
|
||||
pev->health = pev->max_health;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// inflict damage on this entity. bitsDamageType indicates type of damage inflicted, ie: DMG_CRUSH
|
||||
|
||||
int CMBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType )
|
||||
{
|
||||
Vector vecTemp;
|
||||
|
||||
if (!pev->takedamage)
|
||||
return 0;
|
||||
|
||||
// UNDONE: some entity types may be immune or resistant to some bitsDamageType
|
||||
|
||||
// if Attacker == Inflictor, the attack was a melee or other instant-hit attack.
|
||||
// (that is, no actual entity projectile was involved in the attack so use the shooter's origin).
|
||||
if ( pevAttacker == pevInflictor )
|
||||
{
|
||||
vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) );
|
||||
}
|
||||
else
|
||||
// an actual missile was involved.
|
||||
{
|
||||
vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) );
|
||||
}
|
||||
|
||||
// this global is still used for glass and other non-monster killables, along with decals.
|
||||
g_vecAttackDir = vecTemp.Normalize();
|
||||
|
||||
// save damage based on the target's armor level
|
||||
|
||||
// figure momentum add (don't let hurt brushes or other triggers move player)
|
||||
if ((!FNullEnt(pevInflictor)) && (pev->movetype == MOVETYPE_WALK || pev->movetype == MOVETYPE_STEP) && (pevAttacker->solid != SOLID_TRIGGER) )
|
||||
{
|
||||
Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5;
|
||||
vecDir = vecDir.Normalize();
|
||||
|
||||
float flForce = flDamage * ((32 * 32 * 72.0) / (pev->size.x * pev->size.y * pev->size.z)) * 5;
|
||||
|
||||
if (flForce > 1000.0)
|
||||
flForce = 1000.0;
|
||||
pev->velocity = pev->velocity + vecDir * flForce;
|
||||
}
|
||||
|
||||
// do the damage
|
||||
pev->health -= flDamage;
|
||||
if (pev->health <= 0)
|
||||
{
|
||||
Killed( pevAttacker, GIB_NORMAL );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void CMBaseEntity :: Killed( entvars_t *pevAttacker, int iGib )
|
||||
{
|
||||
pev->takedamage = DAMAGE_NO;
|
||||
pev->deadflag = DEAD_DEAD;
|
||||
UTIL_Remove( this->edict() );
|
||||
}
|
||||
|
||||
|
||||
// Initialize absmin & absmax to the appropriate box
|
||||
void SetObjectCollisionBox( entvars_t *pev )
|
||||
{
|
||||
if ( (pev->solid == SOLID_BSP) &&
|
||||
(pev->angles.x || pev->angles.y|| pev->angles.z) )
|
||||
{ // expand for rotation
|
||||
float max, v;
|
||||
int i;
|
||||
|
||||
max = 0;
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
v = fabs( ((float *)pev->mins)[i]);
|
||||
if (v > max)
|
||||
max = v;
|
||||
v = fabs( ((float *)pev->maxs)[i]);
|
||||
if (v > max)
|
||||
max = v;
|
||||
}
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
((float *)pev->absmin)[i] = ((float *)pev->origin)[i] - max;
|
||||
((float *)pev->absmax)[i] = ((float *)pev->origin)[i] + max;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pev->absmin = pev->origin + pev->mins;
|
||||
pev->absmax = pev->origin + pev->maxs;
|
||||
}
|
||||
|
||||
pev->absmin.x -= 1;
|
||||
pev->absmin.y -= 1;
|
||||
pev->absmin.z -= 1;
|
||||
pev->absmax.x += 1;
|
||||
pev->absmax.y += 1;
|
||||
pev->absmax.z += 1;
|
||||
}
|
||||
|
||||
|
||||
void CMBaseEntity::SetObjectCollisionBox( void )
|
||||
{
|
||||
::SetObjectCollisionBox( pev );
|
||||
}
|
||||
|
||||
|
||||
int CMBaseEntity :: Intersects( CMBaseEntity *pOther )
|
||||
{
|
||||
if ( pOther->pev->absmin.x > pev->absmax.x ||
|
||||
pOther->pev->absmin.y > pev->absmax.y ||
|
||||
pOther->pev->absmin.z > pev->absmax.z ||
|
||||
pOther->pev->absmax.x < pev->absmin.x ||
|
||||
pOther->pev->absmax.y < pev->absmin.y ||
|
||||
pOther->pev->absmax.z < pev->absmin.z )
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CMBaseEntity :: MakeDormant( void )
|
||||
{
|
||||
SetBits( pev->flags, FL_DORMANT );
|
||||
|
||||
// Don't touch
|
||||
pev->solid = SOLID_NOT;
|
||||
// Don't move
|
||||
pev->movetype = MOVETYPE_NONE;
|
||||
// Don't draw
|
||||
SetBits( pev->effects, EF_NODRAW );
|
||||
// Don't think
|
||||
pev->nextthink = 0;
|
||||
// Relink
|
||||
UTIL_SetOrigin( pev, pev->origin );
|
||||
}
|
||||
|
||||
int CMBaseEntity :: IsDormant( void )
|
||||
{
|
||||
return FBitSet( pev->flags, FL_DORMANT );
|
||||
}
|
||||
|
||||
BOOL CMBaseEntity :: IsInWorld( void )
|
||||
{
|
||||
// position
|
||||
if (pev->origin.x >= 4096) return FALSE;
|
||||
if (pev->origin.y >= 4096) return FALSE;
|
||||
if (pev->origin.z >= 4096) return FALSE;
|
||||
if (pev->origin.x <= -4096) return FALSE;
|
||||
if (pev->origin.y <= -4096) return FALSE;
|
||||
if (pev->origin.z <= -4096) return FALSE;
|
||||
// speed
|
||||
if (pev->velocity.x >= 2000) return FALSE;
|
||||
if (pev->velocity.y >= 2000) return FALSE;
|
||||
if (pev->velocity.z >= 2000) return FALSE;
|
||||
if (pev->velocity.x <= -2000) return FALSE;
|
||||
if (pev->velocity.y <= -2000) return FALSE;
|
||||
if (pev->velocity.z <= -2000) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int CMBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState )
|
||||
{
|
||||
if ( useType != USE_TOGGLE && useType != USE_SET )
|
||||
{
|
||||
if ( (currentState && useType == USE_ON) || (!currentState && useType == USE_OFF) )
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int CMBaseEntity :: DamageDecal( int bitsDamageType )
|
||||
{
|
||||
if ( pev->rendermode == kRenderTransAlpha )
|
||||
return -1;
|
||||
|
||||
if ( pev->rendermode != kRenderNormal )
|
||||
return DECAL_BPROOF1;
|
||||
|
||||
return DECAL_GUNSHOT1 + RANDOM_LONG(0,4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
1219
src/dlls/cmbase.h
1219
src/dlls/cmbase.h
File diff suppressed because it is too large
Load Diff
36
src/dlls/cmbaseextra.h
Normal file
36
src/dlls/cmbaseextra.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#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_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?
|
||||
};
|
||||
|
||||
#endif // BASEEXTRA_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,53 +1,81 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
// Base class for flying monsters. This overrides the movement test & execution code from CBaseMonster
|
||||
|
||||
#ifndef FLYINGMONSTER_H
|
||||
#define FLYINGMONSTER_H
|
||||
|
||||
class CMFlyingMonster : public CMBaseMonster
|
||||
{
|
||||
public:
|
||||
int CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, edict_t *pTarget, float *pflDist );// check validity of a straight move through space
|
||||
BOOL FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, edict_t *pTargetEnt, Vector *pApex );
|
||||
Activity GetStoppedActivity( void );
|
||||
void Killed( entvars_t *pevAttacker, int iGib );
|
||||
void Stop( void );
|
||||
float ChangeYaw( int speed );
|
||||
void HandleAnimEvent( MonsterEvent_t *pEvent );
|
||||
void MoveExecute( edict_t *pTargetEnt, const Vector &vecDir, float flInterval );
|
||||
void Move( float flInterval = 0.1 );
|
||||
BOOL ShouldAdvanceRoute( float flWaypointDist );
|
||||
|
||||
inline void SetFlyingMomentum( float momentum ) { m_momentum = momentum; }
|
||||
inline void SetFlyingFlapSound( const char *pFlapSound ) { m_pFlapSound = pFlapSound; }
|
||||
inline void SetFlyingSpeed( float speed ) { m_flightSpeed = speed; }
|
||||
float CeilingZ( const Vector &position );
|
||||
float FloorZ( const Vector &position );
|
||||
BOOL ProbeZ( const Vector &position, const Vector &probe, float *pFraction );
|
||||
|
||||
|
||||
// UNDONE: Save/restore this stuff!!!
|
||||
protected:
|
||||
Vector m_vecTravel; // Current direction
|
||||
float m_flightSpeed; // Current flight speed (decays when not flapping or gliding)
|
||||
float m_stopTime; // Last time we stopped (to avoid switching states too soon)
|
||||
float m_momentum; // Weight for desired vs. momentum velocity
|
||||
const char *m_pFlapSound;
|
||||
};
|
||||
|
||||
|
||||
#endif //FLYINGMONSTER_H
|
||||
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
// Base class for flying monsters. This overrides the movement test & execution code from CBaseMonster
|
||||
|
||||
#ifndef FLYINGMONSTER_H
|
||||
#define FLYINGMONSTER_H
|
||||
|
||||
#include "cmbasemonster.h"
|
||||
|
||||
class CMFlyingMonster : public CMBaseMonster
|
||||
{
|
||||
public:
|
||||
int CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, edict_t *pTarget, float *pflDist );// check validity of a straight move through space
|
||||
BOOL FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, edict_t *pTargetEnt, Vector *pApex );
|
||||
Activity GetStoppedActivity( void );
|
||||
void Killed( entvars_t *pevAttacker, int iGib );
|
||||
void Stop( void );
|
||||
float ChangeYaw( int speed );
|
||||
void HandleAnimEvent( MonsterEvent_t *pEvent );
|
||||
void MoveExecute( edict_t *pTargetEnt, const Vector &vecDir, float flInterval );
|
||||
void Move( float flInterval = 0.1 );
|
||||
BOOL ShouldAdvanceRoute( float flWaypointDist );
|
||||
|
||||
inline void SetFlyingMomentum( float momentum ) { m_momentum = momentum; }
|
||||
inline void SetFlyingFlapSound( const char *pFlapSound ) { m_pFlapSound = pFlapSound; }
|
||||
inline void SetFlyingSpeed( float speed ) { m_flightSpeed = speed; }
|
||||
float CeilingZ( const Vector &position );
|
||||
float FloorZ( const Vector &position );
|
||||
BOOL ProbeZ( const Vector &position, const Vector &probe, float *pFraction );
|
||||
|
||||
|
||||
// UNDONE: Save/restore this stuff!!!
|
||||
protected:
|
||||
Vector m_vecTravel; // Current direction
|
||||
float m_flightSpeed; // Current flight speed (decays when not flapping or gliding)
|
||||
float m_stopTime; // Last time we stopped (to avoid switching states too soon)
|
||||
float m_momentum; // Weight for desired vs. momentum velocity
|
||||
const char *m_pFlapSound;
|
||||
};
|
||||
|
||||
|
||||
//=========================================================
|
||||
// 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
|
||||
|
||||
|
||||
@@ -1,178 +1,178 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef TALKMONSTER_H
|
||||
#define TALKMONSTER_H
|
||||
|
||||
#ifndef MONSTERS_H
|
||||
#include "monsters.h"
|
||||
#endif
|
||||
|
||||
//=========================================================
|
||||
// Talking monster base class
|
||||
// Used for scientists and barneys
|
||||
//=========================================================
|
||||
|
||||
#define TALKRANGE_MIN 500.0 // don't talk to anyone farther away than this
|
||||
|
||||
#define TLK_STARE_DIST 128 // anyone closer than this and looking at me is probably staring at me.
|
||||
|
||||
#define bit_saidDamageLight (1<<0) // bits so we don't repeat key sentences
|
||||
#define bit_saidDamageMedium (1<<1)
|
||||
#define bit_saidDamageHeavy (1<<2)
|
||||
#define bit_saidHelloPlayer (1<<3)
|
||||
#define bit_saidWoundLight (1<<4)
|
||||
#define bit_saidWoundHeavy (1<<5)
|
||||
#define bit_saidHeard (1<<6)
|
||||
#define bit_saidSmelled (1<<7)
|
||||
|
||||
#define TLK_CFRIENDS 3
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TLK_ANSWER = 0,
|
||||
TLK_QUESTION,
|
||||
TLK_IDLE,
|
||||
TLK_STARE,
|
||||
TLK_USE,
|
||||
TLK_UNUSE,
|
||||
TLK_STOP,
|
||||
TLK_NOSHOOT,
|
||||
TLK_HELLO,
|
||||
TLK_PHELLO,
|
||||
TLK_PIDLE,
|
||||
TLK_PQUESTION,
|
||||
TLK_PLHURT1,
|
||||
TLK_PLHURT2,
|
||||
TLK_PLHURT3,
|
||||
TLK_SMELL,
|
||||
TLK_WOUND,
|
||||
TLK_MORTAL,
|
||||
|
||||
TLK_CGROUPS, // MUST be last entry
|
||||
} TALKGROUPNAMES;
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
SCHED_CANT_FOLLOW = LAST_COMMON_SCHEDULE + 1,
|
||||
SCHED_MOVE_AWAY, // Try to get out of the player's way
|
||||
SCHED_MOVE_AWAY_FOLLOW, // same, but follow afterward
|
||||
SCHED_MOVE_AWAY_FAIL, // Turn back toward player
|
||||
|
||||
LAST_TALKMONSTER_SCHEDULE, // MUST be last
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TASK_CANT_FOLLOW = LAST_COMMON_TASK + 1,
|
||||
TASK_MOVE_AWAY_PATH,
|
||||
TASK_WALK_PATH_FOR_UNITS,
|
||||
|
||||
TASK_TLK_RESPOND, // say my response
|
||||
TASK_TLK_SPEAK, // question or remark
|
||||
TASK_TLK_HELLO, // Try to say hello to player
|
||||
TASK_TLK_HEADRESET, // reset head position
|
||||
TASK_TLK_STOPSHOOTING, // tell player to stop shooting friend
|
||||
TASK_TLK_STARE, // let the player know I know he's staring at me.
|
||||
TASK_TLK_LOOK_AT_CLIENT,// faces player if not moving and not talking and in idle.
|
||||
TASK_TLK_CLIENT_STARE, // same as look at client, but says something if the player stares.
|
||||
TASK_TLK_EYECONTACT, // maintain eyecontact with person who I'm talking to
|
||||
TASK_TLK_IDEALYAW, // set ideal yaw to face who I'm talking to
|
||||
TASK_FACE_PLAYER, // Face the player
|
||||
|
||||
LAST_TALKMONSTER_TASK, // MUST be last
|
||||
};
|
||||
|
||||
class CMTalkMonster : public CMBaseMonster
|
||||
{
|
||||
public:
|
||||
void TalkInit( void );
|
||||
edict_t *FindNearestFriend(BOOL fPlayer);
|
||||
float TargetDistance( void );
|
||||
void StopTalking( void ) { SentenceStop(); }
|
||||
|
||||
// Base Monster functions
|
||||
void Precache( void );
|
||||
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType);
|
||||
void TalkTouch( edict_t *pOther );
|
||||
void Killed( entvars_t *pevAttacker, int iGib );
|
||||
int IRelationship ( CMBaseEntity *pTarget );
|
||||
virtual int CanPlaySentence( BOOL fDisregardState );
|
||||
virtual void PlaySentence( const char *pszSentence, float duration, float volume, float attenuation );
|
||||
void PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, edict_t *pListener );
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
|
||||
// AI functions
|
||||
void SetActivity ( Activity newActivity );
|
||||
Schedule_t *GetScheduleOfType ( int Type );
|
||||
void StartTask( Task_t *pTask );
|
||||
void RunTask( Task_t *pTask );
|
||||
void HandleAnimEvent( MonsterEvent_t *pEvent );
|
||||
void PrescheduleThink( void );
|
||||
|
||||
|
||||
// Conversations / communication
|
||||
int GetVoicePitch( void );
|
||||
void IdleRespond( void );
|
||||
int FIdleSpeak( void );
|
||||
int FIdleStare( void );
|
||||
int FIdleHello( void );
|
||||
void IdleHeadTurn( Vector &vecFriend );
|
||||
int FOkToSpeak( void );
|
||||
void TrySmellTalk( void );
|
||||
edict_t *EnumFriends( edict_t *pentPrevious, int listNumber, BOOL bTrace );
|
||||
void AlertFriends( void );
|
||||
void ShutUpFriends( void );
|
||||
BOOL IsTalking( void );
|
||||
void Talk( float flDuration );
|
||||
// For following
|
||||
BOOL CanFollow( void );
|
||||
BOOL IsFollowing( void ) { return m_hTargetEnt != NULL && UTIL_IsPlayer(m_hTargetEnt); }
|
||||
void StopFollowing( BOOL clearSchedule );
|
||||
void StartFollowing( edict_t *pLeader );
|
||||
virtual void DeclineFollowing( void ) {}
|
||||
void LimitFollowers( edict_t *pPlayer, int maxFollowers );
|
||||
|
||||
void EXPORT FollowerUse( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
virtual void SetAnswerQuestion( edict_t *pSpeaker );
|
||||
virtual int FriendNumber( int arrayNumber ) { return arrayNumber; }
|
||||
|
||||
static char *m_szFriends[TLK_CFRIENDS]; // array of friend names
|
||||
static float g_talkWaitTime;
|
||||
|
||||
int m_bitsSaid; // set bits for sentences we don't want repeated
|
||||
int m_nSpeak; // number of times initiated talking
|
||||
int m_voicePitch; // pitch of voice for this head
|
||||
const char *m_szGrp[TLK_CGROUPS]; // sentence group names
|
||||
float m_useTime; // Don't allow +USE until this time
|
||||
int m_iszUse; // Custom +USE sentence group (follow)
|
||||
int m_iszUnUse; // Custom +USE sentence group (stop following)
|
||||
|
||||
float m_flLastSaidSmelled;// last time we talked about something that stinks
|
||||
float m_flStopTalkTime;// when in the future that I'll be done saying this sentence.
|
||||
|
||||
EHANDLE m_hTalkTarget; // who to look at while talking
|
||||
CUSTOM_SCHEDULES;
|
||||
};
|
||||
|
||||
|
||||
// Clients can push talkmonsters out of their way
|
||||
#define bits_COND_CLIENT_PUSH ( bits_COND_SPECIAL1 )
|
||||
// Don't see a client right now.
|
||||
#define bits_COND_CLIENT_UNSEEN ( bits_COND_SPECIAL2 )
|
||||
|
||||
|
||||
#endif //TALKMONSTER_H
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef TALKMONSTER_H
|
||||
#define TALKMONSTER_H
|
||||
|
||||
#ifndef MONSTERS_H
|
||||
#include "monsters.h"
|
||||
#endif
|
||||
|
||||
//=========================================================
|
||||
// Talking monster base class
|
||||
// Used for scientists and barneys
|
||||
//=========================================================
|
||||
|
||||
#define TALKRANGE_MIN 500.0 // don't talk to anyone farther away than this
|
||||
|
||||
#define TLK_STARE_DIST 128 // anyone closer than this and looking at me is probably staring at me.
|
||||
|
||||
#define bit_saidDamageLight (1<<0) // bits so we don't repeat key sentences
|
||||
#define bit_saidDamageMedium (1<<1)
|
||||
#define bit_saidDamageHeavy (1<<2)
|
||||
#define bit_saidHelloPlayer (1<<3)
|
||||
#define bit_saidWoundLight (1<<4)
|
||||
#define bit_saidWoundHeavy (1<<5)
|
||||
#define bit_saidHeard (1<<6)
|
||||
#define bit_saidSmelled (1<<7)
|
||||
|
||||
#define TLK_CFRIENDS 3
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TLK_ANSWER = 0,
|
||||
TLK_QUESTION,
|
||||
TLK_IDLE,
|
||||
TLK_STARE,
|
||||
TLK_USE,
|
||||
TLK_UNUSE,
|
||||
TLK_STOP,
|
||||
TLK_NOSHOOT,
|
||||
TLK_HELLO,
|
||||
TLK_PHELLO,
|
||||
TLK_PIDLE,
|
||||
TLK_PQUESTION,
|
||||
TLK_PLHURT1,
|
||||
TLK_PLHURT2,
|
||||
TLK_PLHURT3,
|
||||
TLK_SMELL,
|
||||
TLK_WOUND,
|
||||
TLK_MORTAL,
|
||||
|
||||
TLK_CGROUPS, // MUST be last entry
|
||||
} TALKGROUPNAMES;
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
SCHED_CANT_FOLLOW = LAST_COMMON_SCHEDULE + 1,
|
||||
SCHED_MOVE_AWAY, // Try to get out of the player's way
|
||||
SCHED_MOVE_AWAY_FOLLOW, // same, but follow afterward
|
||||
SCHED_MOVE_AWAY_FAIL, // Turn back toward player
|
||||
|
||||
LAST_TALKMONSTER_SCHEDULE, // MUST be last
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TASK_CANT_FOLLOW = LAST_COMMON_TASK + 1,
|
||||
TASK_MOVE_AWAY_PATH,
|
||||
TASK_WALK_PATH_FOR_UNITS,
|
||||
|
||||
TASK_TLK_RESPOND, // say my response
|
||||
TASK_TLK_SPEAK, // question or remark
|
||||
TASK_TLK_HELLO, // Try to say hello to player
|
||||
TASK_TLK_HEADRESET, // reset head position
|
||||
TASK_TLK_STOPSHOOTING, // tell player to stop shooting friend
|
||||
TASK_TLK_STARE, // let the player know I know he's staring at me.
|
||||
TASK_TLK_LOOK_AT_CLIENT,// faces player if not moving and not talking and in idle.
|
||||
TASK_TLK_CLIENT_STARE, // same as look at client, but says something if the player stares.
|
||||
TASK_TLK_EYECONTACT, // maintain eyecontact with person who I'm talking to
|
||||
TASK_TLK_IDEALYAW, // set ideal yaw to face who I'm talking to
|
||||
TASK_FACE_PLAYER, // Face the player
|
||||
|
||||
LAST_TALKMONSTER_TASK, // MUST be last
|
||||
};
|
||||
|
||||
class CMTalkMonster : public CMBaseMonster
|
||||
{
|
||||
public:
|
||||
void TalkInit( void );
|
||||
edict_t *FindNearestFriend(BOOL fPlayer);
|
||||
float TargetDistance( void );
|
||||
void StopTalking( void ) { SentenceStop(); }
|
||||
|
||||
// Base Monster functions
|
||||
void Precache( void );
|
||||
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType);
|
||||
void TalkTouch( edict_t *pOther );
|
||||
void Killed( entvars_t *pevAttacker, int iGib );
|
||||
int IRelationship ( CMBaseEntity *pTarget );
|
||||
virtual int CanPlaySentence( BOOL fDisregardState );
|
||||
virtual void PlaySentence( const char *pszSentence, float duration, float volume, float attenuation );
|
||||
void PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, edict_t *pListener );
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
|
||||
// AI functions
|
||||
void SetActivity ( Activity newActivity );
|
||||
Schedule_t *GetScheduleOfType ( int Type );
|
||||
void StartTask( Task_t *pTask );
|
||||
void RunTask( Task_t *pTask );
|
||||
void HandleAnimEvent( MonsterEvent_t *pEvent );
|
||||
void PrescheduleThink( void );
|
||||
|
||||
|
||||
// Conversations / communication
|
||||
int GetVoicePitch( void );
|
||||
void IdleRespond( void );
|
||||
int FIdleSpeak( void );
|
||||
int FIdleStare( void );
|
||||
int FIdleHello( void );
|
||||
void IdleHeadTurn( Vector &vecFriend );
|
||||
int FOkToSpeak( void );
|
||||
void TrySmellTalk( void );
|
||||
edict_t *EnumFriends( edict_t *pentPrevious, int listNumber, BOOL bTrace );
|
||||
void AlertFriends( void );
|
||||
void ShutUpFriends( void );
|
||||
BOOL IsTalking( void );
|
||||
void Talk( float flDuration );
|
||||
// For following
|
||||
BOOL CanFollow( void );
|
||||
BOOL IsFollowing( void ) { return m_hTargetEnt != NULL && UTIL_IsPlayer(m_hTargetEnt); }
|
||||
void StopFollowing( BOOL clearSchedule );
|
||||
void StartFollowing( edict_t *pLeader );
|
||||
virtual void DeclineFollowing( void ) {}
|
||||
void LimitFollowers( edict_t *pPlayer, int maxFollowers );
|
||||
|
||||
void EXPORT FollowerUse( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
virtual void SetAnswerQuestion( edict_t *pSpeaker );
|
||||
virtual int FriendNumber( int arrayNumber ) { return arrayNumber; }
|
||||
|
||||
static char *m_szFriends[TLK_CFRIENDS]; // array of friend names
|
||||
static float g_talkWaitTime;
|
||||
|
||||
int m_bitsSaid; // set bits for sentences we don't want repeated
|
||||
int m_nSpeak; // number of times initiated talking
|
||||
int m_voicePitch; // pitch of voice for this head
|
||||
const char *m_szGrp[TLK_CGROUPS]; // sentence group names
|
||||
float m_useTime; // Don't allow +USE until this time
|
||||
int m_iszUse; // Custom +USE sentence group (follow)
|
||||
int m_iszUnUse; // Custom +USE sentence group (stop following)
|
||||
|
||||
float m_flLastSaidSmelled;// last time we talked about something that stinks
|
||||
float m_flStopTalkTime;// when in the future that I'll be done saying this sentence.
|
||||
|
||||
EHANDLE m_hTalkTarget; // who to look at while talking
|
||||
CUSTOM_SCHEDULES;
|
||||
};
|
||||
|
||||
|
||||
// Clients can push talkmonsters out of their way
|
||||
#define bits_COND_CLIENT_PUSH ( bits_COND_SPECIAL1 )
|
||||
// Don't see a client right now.
|
||||
#define bits_COND_CLIENT_UNSEEN ( bits_COND_SPECIAL2 )
|
||||
|
||||
|
||||
#endif //TALKMONSTER_H
|
||||
|
||||
3360
src/dlls/combat.cpp
3360
src/dlls/combat.cpp
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,75 +1,75 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef DECALS_H
|
||||
#define DECALS_H
|
||||
|
||||
//
|
||||
// Dynamic Decals
|
||||
//
|
||||
enum decal_e
|
||||
{
|
||||
DECAL_GUNSHOT1 = 0,
|
||||
DECAL_GUNSHOT2,
|
||||
DECAL_GUNSHOT3,
|
||||
DECAL_GUNSHOT4,
|
||||
DECAL_GUNSHOT5,
|
||||
DECAL_LAMBDA1,
|
||||
DECAL_LAMBDA2,
|
||||
DECAL_LAMBDA3,
|
||||
DECAL_LAMBDA4,
|
||||
DECAL_LAMBDA5,
|
||||
DECAL_LAMBDA6,
|
||||
DECAL_SCORCH1,
|
||||
DECAL_SCORCH2,
|
||||
DECAL_BLOOD1,
|
||||
DECAL_BLOOD2,
|
||||
DECAL_BLOOD3,
|
||||
DECAL_BLOOD4,
|
||||
DECAL_BLOOD5,
|
||||
DECAL_BLOOD6,
|
||||
DECAL_YBLOOD1,
|
||||
DECAL_YBLOOD2,
|
||||
DECAL_YBLOOD3,
|
||||
DECAL_YBLOOD4,
|
||||
DECAL_YBLOOD5,
|
||||
DECAL_YBLOOD6,
|
||||
DECAL_GLASSBREAK1,
|
||||
DECAL_GLASSBREAK2,
|
||||
DECAL_GLASSBREAK3,
|
||||
DECAL_BIGSHOT1,
|
||||
DECAL_BIGSHOT2,
|
||||
DECAL_BIGSHOT3,
|
||||
DECAL_BIGSHOT4,
|
||||
DECAL_BIGSHOT5,
|
||||
DECAL_SPIT1,
|
||||
DECAL_SPIT2,
|
||||
DECAL_BPROOF1, // Bulletproof glass decal
|
||||
DECAL_GARGSTOMP1, // Gargantua stomp crack
|
||||
DECAL_SMALLSCORCH1, // Small scorch mark
|
||||
DECAL_SMALLSCORCH2, // Small scorch mark
|
||||
DECAL_SMALLSCORCH3, // Small scorch mark
|
||||
DECAL_MOMMABIRTH, // Big momma birth splatter
|
||||
DECAL_MOMMASPLAT,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
int index;
|
||||
} DLL_DECALLIST;
|
||||
|
||||
extern DLL_DECALLIST gDecals[];
|
||||
|
||||
#endif // DECALS_H
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef DECALS_H
|
||||
#define DECALS_H
|
||||
|
||||
//
|
||||
// Dynamic Decals
|
||||
//
|
||||
enum decal_e
|
||||
{
|
||||
DECAL_GUNSHOT1 = 0,
|
||||
DECAL_GUNSHOT2,
|
||||
DECAL_GUNSHOT3,
|
||||
DECAL_GUNSHOT4,
|
||||
DECAL_GUNSHOT5,
|
||||
DECAL_LAMBDA1,
|
||||
DECAL_LAMBDA2,
|
||||
DECAL_LAMBDA3,
|
||||
DECAL_LAMBDA4,
|
||||
DECAL_LAMBDA5,
|
||||
DECAL_LAMBDA6,
|
||||
DECAL_SCORCH1,
|
||||
DECAL_SCORCH2,
|
||||
DECAL_BLOOD1,
|
||||
DECAL_BLOOD2,
|
||||
DECAL_BLOOD3,
|
||||
DECAL_BLOOD4,
|
||||
DECAL_BLOOD5,
|
||||
DECAL_BLOOD6,
|
||||
DECAL_YBLOOD1,
|
||||
DECAL_YBLOOD2,
|
||||
DECAL_YBLOOD3,
|
||||
DECAL_YBLOOD4,
|
||||
DECAL_YBLOOD5,
|
||||
DECAL_YBLOOD6,
|
||||
DECAL_GLASSBREAK1,
|
||||
DECAL_GLASSBREAK2,
|
||||
DECAL_GLASSBREAK3,
|
||||
DECAL_BIGSHOT1,
|
||||
DECAL_BIGSHOT2,
|
||||
DECAL_BIGSHOT3,
|
||||
DECAL_BIGSHOT4,
|
||||
DECAL_BIGSHOT5,
|
||||
DECAL_SPIT1,
|
||||
DECAL_SPIT2,
|
||||
DECAL_BPROOF1, // Bulletproof glass decal
|
||||
DECAL_GARGSTOMP1, // Gargantua stomp crack
|
||||
DECAL_SMALLSCORCH1, // Small scorch mark
|
||||
DECAL_SMALLSCORCH2, // Small scorch mark
|
||||
DECAL_SMALLSCORCH3, // Small scorch mark
|
||||
DECAL_MOMMABIRTH, // Big momma birth splatter
|
||||
DECAL_MOMMASPLAT,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
int index;
|
||||
} DLL_DECALLIST;
|
||||
|
||||
extern DLL_DECALLIST gDecals[];
|
||||
|
||||
#endif // DECALS_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,98 +1,98 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef DEFAULTAI_H
|
||||
#define DEFAULTAI_H
|
||||
|
||||
//=========================================================
|
||||
// Failed
|
||||
//=========================================================
|
||||
extern Schedule_t slFail[];
|
||||
|
||||
//=========================================================
|
||||
// Idle Schedules
|
||||
//=========================================================
|
||||
extern Schedule_t slIdleStand[];
|
||||
extern Schedule_t slIdleTrigger[];
|
||||
extern Schedule_t slIdleWalk[];
|
||||
|
||||
//=========================================================
|
||||
// Wake Schedules
|
||||
//=========================================================
|
||||
extern Schedule_t slWakeAngry[];
|
||||
|
||||
//=========================================================
|
||||
// AlertTurn Schedules
|
||||
//=========================================================
|
||||
extern Schedule_t slAlertFace[];
|
||||
|
||||
//=========================================================
|
||||
// AlertIdle Schedules
|
||||
//=========================================================
|
||||
extern Schedule_t slAlertStand[];
|
||||
|
||||
//=========================================================
|
||||
// CombatIdle Schedule
|
||||
//=========================================================
|
||||
extern Schedule_t slCombatStand[];
|
||||
|
||||
//=========================================================
|
||||
// CombatFace Schedule
|
||||
//=========================================================
|
||||
extern Schedule_t slCombatFace[];
|
||||
|
||||
//=========================================================
|
||||
// reload schedule
|
||||
//=========================================================
|
||||
extern Schedule_t slReload[];
|
||||
|
||||
//=========================================================
|
||||
// Attack Schedules
|
||||
//=========================================================
|
||||
|
||||
extern Schedule_t slRangeAttack1[];
|
||||
extern Schedule_t slRangeAttack2[];
|
||||
|
||||
extern Schedule_t slTakeCoverFromBestSound[];
|
||||
|
||||
// primary melee attack
|
||||
extern Schedule_t slMeleeAttack[];
|
||||
|
||||
// Chase enemy schedule
|
||||
extern Schedule_t slChaseEnemy[];
|
||||
|
||||
//=========================================================
|
||||
// small flinch, used when a relatively minor bit of damage
|
||||
// is inflicted.
|
||||
//=========================================================
|
||||
extern Schedule_t slSmallFlinch[];
|
||||
|
||||
//=========================================================
|
||||
// Die!
|
||||
//=========================================================
|
||||
extern Schedule_t slDie[];
|
||||
|
||||
//=========================================================
|
||||
// Universal Error Schedule
|
||||
//=========================================================
|
||||
extern Schedule_t slError[];
|
||||
|
||||
//=========================================================
|
||||
// Scripted sequences
|
||||
//=========================================================
|
||||
extern Schedule_t slWalkToScript[];
|
||||
extern Schedule_t slRunToScript[];
|
||||
extern Schedule_t slWaitScript[];
|
||||
|
||||
#endif // DEFAULTAI_H
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef DEFAULTAI_H
|
||||
#define DEFAULTAI_H
|
||||
|
||||
//=========================================================
|
||||
// Failed
|
||||
//=========================================================
|
||||
extern Schedule_t slFail[];
|
||||
|
||||
//=========================================================
|
||||
// Idle Schedules
|
||||
//=========================================================
|
||||
extern Schedule_t slIdleStand[];
|
||||
extern Schedule_t slIdleTrigger[];
|
||||
extern Schedule_t slIdleWalk[];
|
||||
|
||||
//=========================================================
|
||||
// Wake Schedules
|
||||
//=========================================================
|
||||
extern Schedule_t slWakeAngry[];
|
||||
|
||||
//=========================================================
|
||||
// AlertTurn Schedules
|
||||
//=========================================================
|
||||
extern Schedule_t slAlertFace[];
|
||||
|
||||
//=========================================================
|
||||
// AlertIdle Schedules
|
||||
//=========================================================
|
||||
extern Schedule_t slAlertStand[];
|
||||
|
||||
//=========================================================
|
||||
// CombatIdle Schedule
|
||||
//=========================================================
|
||||
extern Schedule_t slCombatStand[];
|
||||
|
||||
//=========================================================
|
||||
// CombatFace Schedule
|
||||
//=========================================================
|
||||
extern Schedule_t slCombatFace[];
|
||||
|
||||
//=========================================================
|
||||
// reload schedule
|
||||
//=========================================================
|
||||
extern Schedule_t slReload[];
|
||||
|
||||
//=========================================================
|
||||
// Attack Schedules
|
||||
//=========================================================
|
||||
|
||||
extern Schedule_t slRangeAttack1[];
|
||||
extern Schedule_t slRangeAttack2[];
|
||||
|
||||
extern Schedule_t slTakeCoverFromBestSound[];
|
||||
|
||||
// primary melee attack
|
||||
extern Schedule_t slMeleeAttack[];
|
||||
|
||||
// Chase enemy schedule
|
||||
extern Schedule_t slChaseEnemy[];
|
||||
|
||||
//=========================================================
|
||||
// small flinch, used when a relatively minor bit of damage
|
||||
// is inflicted.
|
||||
//=========================================================
|
||||
extern Schedule_t slSmallFlinch[];
|
||||
|
||||
//=========================================================
|
||||
// Die!
|
||||
//=========================================================
|
||||
extern Schedule_t slDie[];
|
||||
|
||||
//=========================================================
|
||||
// Universal Error Schedule
|
||||
//=========================================================
|
||||
extern Schedule_t slError[];
|
||||
|
||||
//=========================================================
|
||||
// Scripted sequences
|
||||
//=========================================================
|
||||
extern Schedule_t slWalkToScript[];
|
||||
extern Schedule_t slRunToScript[];
|
||||
extern Schedule_t slWaitScript[];
|
||||
|
||||
#endif // DEFAULTAI_H
|
||||
|
||||
4334
src/dlls/dllapi.cpp
4334
src/dlls/dllapi.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,33 +1,33 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef DOORS_H
|
||||
#define DOORS_H
|
||||
|
||||
// doors
|
||||
#define SF_DOOR_ROTATE_Y 0
|
||||
#define SF_DOOR_START_OPEN 1
|
||||
#define SF_DOOR_ROTATE_BACKWARDS 2
|
||||
#define SF_DOOR_PASSABLE 8
|
||||
#define SF_DOOR_ONEWAY 16
|
||||
#define SF_DOOR_NO_AUTO_RETURN 32
|
||||
#define SF_DOOR_ROTATE_Z 64
|
||||
#define SF_DOOR_ROTATE_X 128
|
||||
#define SF_DOOR_USE_ONLY 256 // door must be opened by player's use button.
|
||||
#define SF_DOOR_NOMONSTERS 512 // Monster can't open
|
||||
#define SF_DOOR_SILENT 0x80000000
|
||||
|
||||
|
||||
|
||||
#endif //DOORS_H
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef DOORS_H
|
||||
#define DOORS_H
|
||||
|
||||
// doors
|
||||
#define SF_DOOR_ROTATE_Y 0
|
||||
#define SF_DOOR_START_OPEN 1
|
||||
#define SF_DOOR_ROTATE_BACKWARDS 2
|
||||
#define SF_DOOR_PASSABLE 8
|
||||
#define SF_DOOR_ONEWAY 16
|
||||
#define SF_DOOR_NO_AUTO_RETURN 32
|
||||
#define SF_DOOR_ROTATE_Z 64
|
||||
#define SF_DOOR_ROTATE_X 128
|
||||
#define SF_DOOR_USE_ONLY 256 // door must be opened by player's use button.
|
||||
#define SF_DOOR_NOMONSTERS 512 // Monster can't open
|
||||
#define SF_DOOR_SILENT 0x80000000
|
||||
|
||||
|
||||
|
||||
#endif //DOORS_H
|
||||
|
||||
@@ -1,446 +1,446 @@
|
||||
/***
|
||||
*
|
||||
* 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 "customentity.h"
|
||||
#include "effects.h"
|
||||
#include "weapons.h"
|
||||
#include "decals.h"
|
||||
#include "func_break.h"
|
||||
#include "shake.h"
|
||||
|
||||
#define SF_GIBSHOOTER_REPEATABLE 1 // allows a gibshooter to be refired
|
||||
|
||||
#define SF_FUNNEL_REVERSE 1 // funnel effect repels particles instead of attracting them.
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
//
|
||||
// Beams
|
||||
//
|
||||
// --------------------------------------------------
|
||||
|
||||
void CMBeam::Spawn( void )
|
||||
{
|
||||
pev->solid = SOLID_NOT; // Remove model & collisions
|
||||
Precache( );
|
||||
}
|
||||
|
||||
void CMBeam::Precache( void )
|
||||
{
|
||||
if ( pev->owner )
|
||||
SetStartEntity( ENTINDEX( pev->owner ) );
|
||||
if ( pev->aiment )
|
||||
SetEndEntity( ENTINDEX( pev->aiment ) );
|
||||
}
|
||||
|
||||
void CMBeam::SetStartEntity( int entityIndex )
|
||||
{
|
||||
pev->sequence = (entityIndex & 0x0FFF) | ((pev->sequence&0xF000)<<12);
|
||||
pev->owner = g_engfuncs.pfnPEntityOfEntIndex( entityIndex );
|
||||
}
|
||||
|
||||
void CMBeam::SetEndEntity( int entityIndex )
|
||||
{
|
||||
pev->skin = (entityIndex & 0x0FFF) | ((pev->skin&0xF000)<<12);
|
||||
pev->aiment = g_engfuncs.pfnPEntityOfEntIndex( entityIndex );
|
||||
}
|
||||
|
||||
|
||||
// These don't take attachments into account
|
||||
const Vector &CMBeam::GetStartPos( void )
|
||||
{
|
||||
if ( GetType() == BEAM_ENTS )
|
||||
{
|
||||
edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetStartEntity() );
|
||||
return pent->v.origin;
|
||||
}
|
||||
return pev->origin;
|
||||
}
|
||||
|
||||
|
||||
const Vector &CMBeam::GetEndPos( void )
|
||||
{
|
||||
int type = GetType();
|
||||
if ( type == BEAM_POINTS || type == BEAM_HOSE )
|
||||
{
|
||||
return pev->angles;
|
||||
}
|
||||
|
||||
edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetEndEntity() );
|
||||
if ( pent )
|
||||
return pent->v.origin;
|
||||
return pev->angles;
|
||||
}
|
||||
|
||||
|
||||
CMBeam *CMBeam::BeamCreate( const char *pSpriteName, int width )
|
||||
{
|
||||
// Create a new entity with CMBeam private data
|
||||
CMBeam *pBeam = CreateClassPtr( (CMBeam *)NULL );
|
||||
|
||||
if (pBeam == NULL)
|
||||
return NULL;
|
||||
|
||||
pBeam->pev->classname = MAKE_STRING("beam");
|
||||
|
||||
pBeam->BeamInit( pSpriteName, width );
|
||||
|
||||
return pBeam;
|
||||
}
|
||||
|
||||
|
||||
void CMBeam::BeamInit( const char *pSpriteName, int width )
|
||||
{
|
||||
pev->flags |= FL_CUSTOMENTITY;
|
||||
SetColor( 255, 255, 255 );
|
||||
SetBrightness( 255 );
|
||||
SetNoise( 0 );
|
||||
SetFrame( 0 );
|
||||
SetScrollRate( 0 );
|
||||
pev->model = MAKE_STRING( pSpriteName );
|
||||
SetTexture( PRECACHE_MODEL( (char *)pSpriteName ) );
|
||||
SetWidth( width );
|
||||
pev->skin = 0;
|
||||
pev->sequence = 0;
|
||||
pev->rendermode = 0;
|
||||
}
|
||||
|
||||
|
||||
void CMBeam::PointsInit( const Vector &start, const Vector &end )
|
||||
{
|
||||
SetType( BEAM_POINTS );
|
||||
SetStartPos( start );
|
||||
SetEndPos( end );
|
||||
SetStartAttachment( 0 );
|
||||
SetEndAttachment( 0 );
|
||||
RelinkBeam();
|
||||
}
|
||||
|
||||
|
||||
void CMBeam::HoseInit( const Vector &start, const Vector &direction )
|
||||
{
|
||||
SetType( BEAM_HOSE );
|
||||
SetStartPos( start );
|
||||
SetEndPos( direction );
|
||||
SetStartAttachment( 0 );
|
||||
SetEndAttachment( 0 );
|
||||
RelinkBeam();
|
||||
}
|
||||
|
||||
|
||||
void CMBeam::PointEntInit( const Vector &start, int endIndex )
|
||||
{
|
||||
SetType( BEAM_ENTPOINT );
|
||||
SetStartPos( start );
|
||||
SetEndEntity( endIndex );
|
||||
SetStartAttachment( 0 );
|
||||
SetEndAttachment( 0 );
|
||||
RelinkBeam();
|
||||
}
|
||||
|
||||
void CMBeam::EntsInit( int startIndex, int endIndex )
|
||||
{
|
||||
SetType( BEAM_ENTS );
|
||||
SetStartEntity( startIndex );
|
||||
SetEndEntity( endIndex );
|
||||
SetStartAttachment( 0 );
|
||||
SetEndAttachment( 0 );
|
||||
RelinkBeam();
|
||||
}
|
||||
|
||||
|
||||
void CMBeam::RelinkBeam( void )
|
||||
{
|
||||
const Vector &startPos = GetStartPos(), &endPos = GetEndPos();
|
||||
|
||||
pev->mins.x = min( startPos.x, endPos.x );
|
||||
pev->mins.y = min( startPos.y, endPos.y );
|
||||
pev->mins.z = min( startPos.z, endPos.z );
|
||||
pev->maxs.x = max( startPos.x, endPos.x );
|
||||
pev->maxs.y = max( startPos.y, endPos.y );
|
||||
pev->maxs.z = max( startPos.z, endPos.z );
|
||||
pev->mins = pev->mins - pev->origin;
|
||||
pev->maxs = pev->maxs - pev->origin;
|
||||
|
||||
UTIL_SetSize( pev, pev->mins, pev->maxs );
|
||||
UTIL_SetOrigin( pev, pev->origin );
|
||||
}
|
||||
|
||||
#if 0
|
||||
void CMBeam::SetObjectCollisionBox( void )
|
||||
{
|
||||
const Vector &startPos = GetStartPos(), &endPos = GetEndPos();
|
||||
|
||||
pev->absmin.x = min( startPos.x, endPos.x );
|
||||
pev->absmin.y = min( startPos.y, endPos.y );
|
||||
pev->absmin.z = min( startPos.z, endPos.z );
|
||||
pev->absmax.x = max( startPos.x, endPos.x );
|
||||
pev->absmax.y = max( startPos.y, endPos.y );
|
||||
pev->absmax.z = max( startPos.z, endPos.z );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void CMBeam::TriggerTouch( edict_t *pOther )
|
||||
{
|
||||
if ( pOther->v.flags & (FL_CLIENT | FL_MONSTER) )
|
||||
{
|
||||
if ( pev->owner )
|
||||
{
|
||||
if (pev->owner->v.euser4 != NULL)
|
||||
{
|
||||
CMBaseEntity *pOwner = GetClassPtr((CMBaseEntity *)VARS(pev->owner));
|
||||
pOwner->Use( pOther, this->edict(), USE_TOGGLE, 0 );
|
||||
}
|
||||
}
|
||||
ALERT( at_console, "Firing targets!!!\n" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
edict_t *CMBeam::RandomTargetname( const char *szName )
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
edict_t *pEntity = NULL;
|
||||
edict_t *pNewEntity = NULL;
|
||||
while ((pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName )) != NULL)
|
||||
{
|
||||
total++;
|
||||
if (RANDOM_LONG(0,total-1) < 1)
|
||||
pEntity = pNewEntity;
|
||||
}
|
||||
return pEntity;
|
||||
}
|
||||
|
||||
|
||||
void CMBeam::DoSparks( const Vector &start, const Vector &end )
|
||||
{
|
||||
if ( pev->spawnflags & (SF_BEAM_SPARKSTART|SF_BEAM_SPARKEND) )
|
||||
{
|
||||
if ( pev->spawnflags & SF_BEAM_SPARKSTART )
|
||||
{
|
||||
UTIL_Sparks( start );
|
||||
}
|
||||
if ( pev->spawnflags & SF_BEAM_SPARKEND )
|
||||
{
|
||||
UTIL_Sparks( end );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CMBeam::BeamDamage( TraceResult *ptr )
|
||||
{
|
||||
RelinkBeam();
|
||||
if ( ptr->flFraction != 1.0 && ptr->pHit != NULL )
|
||||
{
|
||||
if (UTIL_IsPlayer(ptr->pHit))
|
||||
{
|
||||
ClearMultiDamage();
|
||||
UTIL_TraceAttack(ptr->pHit, pev, pev->dmg * (gpGlobals->time - pev->dmgtime), (ptr->vecEndPos - pev->origin).Normalize(), ptr, DMG_ENERGYBEAM );
|
||||
ApplyMultiDamage( pev, pev );
|
||||
|
||||
if ( pev->spawnflags & SF_BEAM_DECALS )
|
||||
{
|
||||
if ( UTIL_IsBSPModel(ptr->pHit) )
|
||||
UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) );
|
||||
}
|
||||
|
||||
}
|
||||
else if (ptr->pHit->v.euser4 != NULL)
|
||||
{
|
||||
ClearMultiDamage();
|
||||
CMBaseEntity *pMonster = GetClassPtr((CMBaseEntity *)VARS(ptr->pHit));
|
||||
pMonster->TraceAttack( pev, pev->dmg * (gpGlobals->time - pev->dmgtime), (ptr->vecEndPos - pev->origin).Normalize(), ptr, DMG_ENERGYBEAM );
|
||||
ApplyMultiDamage( pev, pev );
|
||||
|
||||
if ( pev->spawnflags & SF_BEAM_DECALS )
|
||||
{
|
||||
if ( pMonster->IsBSPModel() )
|
||||
UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) );
|
||||
}
|
||||
}
|
||||
}
|
||||
pev->dmgtime = gpGlobals->time;
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::Spawn( void )
|
||||
{
|
||||
pev->solid = SOLID_NOT;
|
||||
pev->movetype = MOVETYPE_NONE;
|
||||
pev->effects = 0;
|
||||
pev->frame = 0;
|
||||
|
||||
Precache();
|
||||
SET_MODEL( ENT(pev), STRING(pev->model) );
|
||||
|
||||
m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1;
|
||||
if ( pev->targetname && !(pev->spawnflags & SF_SPRITE_STARTON) )
|
||||
TurnOff();
|
||||
else
|
||||
TurnOn();
|
||||
|
||||
// Worldcraft only sets y rotation, copy to Z
|
||||
if ( pev->angles.y != 0 && pev->angles.z == 0 )
|
||||
{
|
||||
pev->angles.z = pev->angles.y;
|
||||
pev->angles.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::Precache( void )
|
||||
{
|
||||
PRECACHE_MODEL( (char *)STRING(pev->model) );
|
||||
|
||||
// Reset attachment after save/restore
|
||||
if ( pev->aiment )
|
||||
SetAttachment( pev->aiment, pev->body );
|
||||
else
|
||||
{
|
||||
// Clear attachment
|
||||
pev->skin = 0;
|
||||
pev->body = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::SpriteInit( const char *pSpriteName, const Vector &origin )
|
||||
{
|
||||
pev->model = MAKE_STRING(pSpriteName);
|
||||
pev->origin = origin;
|
||||
Spawn();
|
||||
}
|
||||
|
||||
CMSprite *CMSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate )
|
||||
{
|
||||
CMSprite *pSprite = CreateClassPtr( (CMSprite *)NULL );
|
||||
pSprite->SpriteInit( pSpriteName, origin );
|
||||
pSprite->pev->classname = MAKE_STRING("env_sprite");
|
||||
pSprite->pev->solid = SOLID_NOT;
|
||||
pSprite->pev->movetype = MOVETYPE_NOCLIP;
|
||||
if ( animate )
|
||||
pSprite->TurnOn();
|
||||
|
||||
return pSprite;
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::AnimateThink( void )
|
||||
{
|
||||
Animate( pev->framerate * (gpGlobals->time - m_lastTime) );
|
||||
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
m_lastTime = gpGlobals->time;
|
||||
}
|
||||
|
||||
void CMSprite::AnimateUntilDead( void )
|
||||
{
|
||||
if ( gpGlobals->time > pev->dmgtime )
|
||||
UTIL_Remove(this->edict());
|
||||
else
|
||||
{
|
||||
AnimateThink();
|
||||
pev->nextthink = gpGlobals->time;
|
||||
}
|
||||
}
|
||||
|
||||
void CMSprite::Expand( float scaleSpeed, float fadeSpeed )
|
||||
{
|
||||
pev->speed = scaleSpeed;
|
||||
pev->health = fadeSpeed;
|
||||
SetThink( &CMSprite::ExpandThink );
|
||||
|
||||
pev->nextthink = gpGlobals->time;
|
||||
m_lastTime = gpGlobals->time;
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::ExpandThink( void )
|
||||
{
|
||||
float frametime = gpGlobals->time - m_lastTime;
|
||||
pev->scale += pev->speed * frametime;
|
||||
pev->renderamt -= pev->health * frametime;
|
||||
if ( pev->renderamt <= 0 )
|
||||
{
|
||||
pev->renderamt = 0;
|
||||
UTIL_Remove( this->edict() );
|
||||
}
|
||||
else
|
||||
{
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
m_lastTime = gpGlobals->time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::Animate( float frames )
|
||||
{
|
||||
pev->frame += frames;
|
||||
if ( pev->frame > m_maxFrame )
|
||||
{
|
||||
if ( pev->spawnflags & SF_SPRITE_ONCE )
|
||||
{
|
||||
TurnOff();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_maxFrame > 0 )
|
||||
pev->frame = fmod( pev->frame, m_maxFrame );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::TurnOff( void )
|
||||
{
|
||||
pev->effects = EF_NODRAW;
|
||||
pev->nextthink = 0;
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::TurnOn( void )
|
||||
{
|
||||
pev->effects = 0;
|
||||
if ( (pev->framerate && m_maxFrame > 1.0) || (pev->spawnflags & SF_SPRITE_ONCE) )
|
||||
{
|
||||
SetThink( &CMSprite::AnimateThink );
|
||||
pev->nextthink = gpGlobals->time;
|
||||
m_lastTime = gpGlobals->time;
|
||||
}
|
||||
pev->frame = 0;
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::Use( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
int on = pev->effects != EF_NODRAW;
|
||||
if ( ShouldToggle( useType, on ) )
|
||||
{
|
||||
if ( on )
|
||||
{
|
||||
TurnOff();
|
||||
}
|
||||
else
|
||||
{
|
||||
TurnOn();
|
||||
}
|
||||
}
|
||||
}
|
||||
/***
|
||||
*
|
||||
* 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 "customentity.h"
|
||||
#include "effects.h"
|
||||
#include "weapons.h"
|
||||
#include "decals.h"
|
||||
#include "func_break.h"
|
||||
#include "shake.h"
|
||||
|
||||
#define SF_GIBSHOOTER_REPEATABLE 1 // allows a gibshooter to be refired
|
||||
|
||||
#define SF_FUNNEL_REVERSE 1 // funnel effect repels particles instead of attracting them.
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
//
|
||||
// Beams
|
||||
//
|
||||
// --------------------------------------------------
|
||||
|
||||
void CMBeam::Spawn( void )
|
||||
{
|
||||
pev->solid = SOLID_NOT; // Remove model & collisions
|
||||
Precache( );
|
||||
}
|
||||
|
||||
void CMBeam::Precache( void )
|
||||
{
|
||||
if ( pev->owner )
|
||||
SetStartEntity( ENTINDEX( pev->owner ) );
|
||||
if ( pev->aiment )
|
||||
SetEndEntity( ENTINDEX( pev->aiment ) );
|
||||
}
|
||||
|
||||
void CMBeam::SetStartEntity( int entityIndex )
|
||||
{
|
||||
pev->sequence = (entityIndex & 0x0FFF) | ((pev->sequence&0xF000)<<12);
|
||||
pev->owner = g_engfuncs.pfnPEntityOfEntIndex( entityIndex );
|
||||
}
|
||||
|
||||
void CMBeam::SetEndEntity( int entityIndex )
|
||||
{
|
||||
pev->skin = (entityIndex & 0x0FFF) | ((pev->skin&0xF000)<<12);
|
||||
pev->aiment = g_engfuncs.pfnPEntityOfEntIndex( entityIndex );
|
||||
}
|
||||
|
||||
|
||||
// These don't take attachments into account
|
||||
const Vector &CMBeam::GetStartPos( void )
|
||||
{
|
||||
if ( GetType() == BEAM_ENTS )
|
||||
{
|
||||
edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetStartEntity() );
|
||||
return pent->v.origin;
|
||||
}
|
||||
return pev->origin;
|
||||
}
|
||||
|
||||
|
||||
const Vector &CMBeam::GetEndPos( void )
|
||||
{
|
||||
int type = GetType();
|
||||
if ( type == BEAM_POINTS || type == BEAM_HOSE )
|
||||
{
|
||||
return pev->angles;
|
||||
}
|
||||
|
||||
edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetEndEntity() );
|
||||
if ( pent )
|
||||
return pent->v.origin;
|
||||
return pev->angles;
|
||||
}
|
||||
|
||||
|
||||
CMBeam *CMBeam::BeamCreate( const char *pSpriteName, int width )
|
||||
{
|
||||
// Create a new entity with CMBeam private data
|
||||
CMBeam *pBeam = CreateClassPtr( (CMBeam *)NULL );
|
||||
|
||||
if (pBeam == NULL)
|
||||
return NULL;
|
||||
|
||||
pBeam->pev->classname = MAKE_STRING("beam");
|
||||
|
||||
pBeam->BeamInit( pSpriteName, width );
|
||||
|
||||
return pBeam;
|
||||
}
|
||||
|
||||
|
||||
void CMBeam::BeamInit( const char *pSpriteName, int width )
|
||||
{
|
||||
pev->flags |= FL_CUSTOMENTITY;
|
||||
SetColor( 255, 255, 255 );
|
||||
SetBrightness( 255 );
|
||||
SetNoise( 0 );
|
||||
SetFrame( 0 );
|
||||
SetScrollRate( 0 );
|
||||
pev->model = MAKE_STRING( pSpriteName );
|
||||
SetTexture( PRECACHE_MODEL( (char *)pSpriteName ) );
|
||||
SetWidth( width );
|
||||
pev->skin = 0;
|
||||
pev->sequence = 0;
|
||||
pev->rendermode = 0;
|
||||
}
|
||||
|
||||
|
||||
void CMBeam::PointsInit( const Vector &start, const Vector &end )
|
||||
{
|
||||
SetType( BEAM_POINTS );
|
||||
SetStartPos( start );
|
||||
SetEndPos( end );
|
||||
SetStartAttachment( 0 );
|
||||
SetEndAttachment( 0 );
|
||||
RelinkBeam();
|
||||
}
|
||||
|
||||
|
||||
void CMBeam::HoseInit( const Vector &start, const Vector &direction )
|
||||
{
|
||||
SetType( BEAM_HOSE );
|
||||
SetStartPos( start );
|
||||
SetEndPos( direction );
|
||||
SetStartAttachment( 0 );
|
||||
SetEndAttachment( 0 );
|
||||
RelinkBeam();
|
||||
}
|
||||
|
||||
|
||||
void CMBeam::PointEntInit( const Vector &start, int endIndex )
|
||||
{
|
||||
SetType( BEAM_ENTPOINT );
|
||||
SetStartPos( start );
|
||||
SetEndEntity( endIndex );
|
||||
SetStartAttachment( 0 );
|
||||
SetEndAttachment( 0 );
|
||||
RelinkBeam();
|
||||
}
|
||||
|
||||
void CMBeam::EntsInit( int startIndex, int endIndex )
|
||||
{
|
||||
SetType( BEAM_ENTS );
|
||||
SetStartEntity( startIndex );
|
||||
SetEndEntity( endIndex );
|
||||
SetStartAttachment( 0 );
|
||||
SetEndAttachment( 0 );
|
||||
RelinkBeam();
|
||||
}
|
||||
|
||||
|
||||
void CMBeam::RelinkBeam( void )
|
||||
{
|
||||
const Vector &startPos = GetStartPos(), &endPos = GetEndPos();
|
||||
|
||||
pev->mins.x = min( startPos.x, endPos.x );
|
||||
pev->mins.y = min( startPos.y, endPos.y );
|
||||
pev->mins.z = min( startPos.z, endPos.z );
|
||||
pev->maxs.x = max( startPos.x, endPos.x );
|
||||
pev->maxs.y = max( startPos.y, endPos.y );
|
||||
pev->maxs.z = max( startPos.z, endPos.z );
|
||||
pev->mins = pev->mins - pev->origin;
|
||||
pev->maxs = pev->maxs - pev->origin;
|
||||
|
||||
UTIL_SetSize( pev, pev->mins, pev->maxs );
|
||||
UTIL_SetOrigin( pev, pev->origin );
|
||||
}
|
||||
|
||||
#if 0
|
||||
void CMBeam::SetObjectCollisionBox( void )
|
||||
{
|
||||
const Vector &startPos = GetStartPos(), &endPos = GetEndPos();
|
||||
|
||||
pev->absmin.x = min( startPos.x, endPos.x );
|
||||
pev->absmin.y = min( startPos.y, endPos.y );
|
||||
pev->absmin.z = min( startPos.z, endPos.z );
|
||||
pev->absmax.x = max( startPos.x, endPos.x );
|
||||
pev->absmax.y = max( startPos.y, endPos.y );
|
||||
pev->absmax.z = max( startPos.z, endPos.z );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void CMBeam::TriggerTouch( edict_t *pOther )
|
||||
{
|
||||
if ( pOther->v.flags & (FL_CLIENT | FL_MONSTER) )
|
||||
{
|
||||
if ( pev->owner )
|
||||
{
|
||||
if (pev->owner->v.euser4 != NULL)
|
||||
{
|
||||
CMBaseEntity *pOwner = GetClassPtr((CMBaseEntity *)VARS(pev->owner));
|
||||
pOwner->Use( pOther, this->edict(), USE_TOGGLE, 0 );
|
||||
}
|
||||
}
|
||||
ALERT( at_console, "Firing targets!!!\n" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
edict_t *CMBeam::RandomTargetname( const char *szName )
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
edict_t *pEntity = NULL;
|
||||
edict_t *pNewEntity = NULL;
|
||||
while ((pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName )) != NULL)
|
||||
{
|
||||
total++;
|
||||
if (RANDOM_LONG(0,total-1) < 1)
|
||||
pEntity = pNewEntity;
|
||||
}
|
||||
return pEntity;
|
||||
}
|
||||
|
||||
|
||||
void CMBeam::DoSparks( const Vector &start, const Vector &end )
|
||||
{
|
||||
if ( pev->spawnflags & (SF_BEAM_SPARKSTART|SF_BEAM_SPARKEND) )
|
||||
{
|
||||
if ( pev->spawnflags & SF_BEAM_SPARKSTART )
|
||||
{
|
||||
UTIL_Sparks( start );
|
||||
}
|
||||
if ( pev->spawnflags & SF_BEAM_SPARKEND )
|
||||
{
|
||||
UTIL_Sparks( end );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CMBeam::BeamDamage( TraceResult *ptr )
|
||||
{
|
||||
RelinkBeam();
|
||||
if ( ptr->flFraction != 1.0 && ptr->pHit != NULL )
|
||||
{
|
||||
if (UTIL_IsPlayer(ptr->pHit))
|
||||
{
|
||||
ClearMultiDamage();
|
||||
UTIL_TraceAttack(ptr->pHit, pev, pev->dmg * (gpGlobals->time - pev->dmgtime), (ptr->vecEndPos - pev->origin).Normalize(), ptr, DMG_ENERGYBEAM );
|
||||
ApplyMultiDamage( pev, pev );
|
||||
|
||||
if ( pev->spawnflags & SF_BEAM_DECALS )
|
||||
{
|
||||
if ( UTIL_IsBSPModel(ptr->pHit) )
|
||||
UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) );
|
||||
}
|
||||
|
||||
}
|
||||
else if (ptr->pHit->v.euser4 != NULL)
|
||||
{
|
||||
ClearMultiDamage();
|
||||
CMBaseEntity *pMonster = GetClassPtr((CMBaseEntity *)VARS(ptr->pHit));
|
||||
pMonster->TraceAttack( pev, pev->dmg * (gpGlobals->time - pev->dmgtime), (ptr->vecEndPos - pev->origin).Normalize(), ptr, DMG_ENERGYBEAM );
|
||||
ApplyMultiDamage( pev, pev );
|
||||
|
||||
if ( pev->spawnflags & SF_BEAM_DECALS )
|
||||
{
|
||||
if ( pMonster->IsBSPModel() )
|
||||
UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) );
|
||||
}
|
||||
}
|
||||
}
|
||||
pev->dmgtime = gpGlobals->time;
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::Spawn( void )
|
||||
{
|
||||
pev->solid = SOLID_NOT;
|
||||
pev->movetype = MOVETYPE_NONE;
|
||||
pev->effects = 0;
|
||||
pev->frame = 0;
|
||||
|
||||
Precache();
|
||||
SET_MODEL( ENT(pev), STRING(pev->model) );
|
||||
|
||||
m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1;
|
||||
if ( pev->targetname && !(pev->spawnflags & SF_SPRITE_STARTON) )
|
||||
TurnOff();
|
||||
else
|
||||
TurnOn();
|
||||
|
||||
// Worldcraft only sets y rotation, copy to Z
|
||||
if ( pev->angles.y != 0 && pev->angles.z == 0 )
|
||||
{
|
||||
pev->angles.z = pev->angles.y;
|
||||
pev->angles.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::Precache( void )
|
||||
{
|
||||
PRECACHE_MODEL( (char *)STRING(pev->model) );
|
||||
|
||||
// Reset attachment after save/restore
|
||||
if ( pev->aiment )
|
||||
SetAttachment( pev->aiment, pev->body );
|
||||
else
|
||||
{
|
||||
// Clear attachment
|
||||
pev->skin = 0;
|
||||
pev->body = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::SpriteInit( const char *pSpriteName, const Vector &origin )
|
||||
{
|
||||
pev->model = MAKE_STRING(pSpriteName);
|
||||
pev->origin = origin;
|
||||
Spawn();
|
||||
}
|
||||
|
||||
CMSprite *CMSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate )
|
||||
{
|
||||
CMSprite *pSprite = CreateClassPtr( (CMSprite *)NULL );
|
||||
pSprite->SpriteInit( pSpriteName, origin );
|
||||
pSprite->pev->classname = MAKE_STRING("env_sprite");
|
||||
pSprite->pev->solid = SOLID_NOT;
|
||||
pSprite->pev->movetype = MOVETYPE_NOCLIP;
|
||||
if ( animate )
|
||||
pSprite->TurnOn();
|
||||
|
||||
return pSprite;
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::AnimateThink( void )
|
||||
{
|
||||
Animate( pev->framerate * (gpGlobals->time - m_lastTime) );
|
||||
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
m_lastTime = gpGlobals->time;
|
||||
}
|
||||
|
||||
void CMSprite::AnimateUntilDead( void )
|
||||
{
|
||||
if ( gpGlobals->time > pev->dmgtime )
|
||||
UTIL_Remove(this->edict());
|
||||
else
|
||||
{
|
||||
AnimateThink();
|
||||
pev->nextthink = gpGlobals->time;
|
||||
}
|
||||
}
|
||||
|
||||
void CMSprite::Expand( float scaleSpeed, float fadeSpeed )
|
||||
{
|
||||
pev->speed = scaleSpeed;
|
||||
pev->health = fadeSpeed;
|
||||
SetThink( &CMSprite::ExpandThink );
|
||||
|
||||
pev->nextthink = gpGlobals->time;
|
||||
m_lastTime = gpGlobals->time;
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::ExpandThink( void )
|
||||
{
|
||||
float frametime = gpGlobals->time - m_lastTime;
|
||||
pev->scale += pev->speed * frametime;
|
||||
pev->renderamt -= pev->health * frametime;
|
||||
if ( pev->renderamt <= 0 )
|
||||
{
|
||||
pev->renderamt = 0;
|
||||
UTIL_Remove( this->edict() );
|
||||
}
|
||||
else
|
||||
{
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
m_lastTime = gpGlobals->time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::Animate( float frames )
|
||||
{
|
||||
pev->frame += frames;
|
||||
if ( pev->frame > m_maxFrame )
|
||||
{
|
||||
if ( pev->spawnflags & SF_SPRITE_ONCE )
|
||||
{
|
||||
TurnOff();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_maxFrame > 0 )
|
||||
pev->frame = fmod( pev->frame, m_maxFrame );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::TurnOff( void )
|
||||
{
|
||||
pev->effects = EF_NODRAW;
|
||||
pev->nextthink = 0;
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::TurnOn( void )
|
||||
{
|
||||
pev->effects = 0;
|
||||
if ( (pev->framerate && m_maxFrame > 1.0) || (pev->spawnflags & SF_SPRITE_ONCE) )
|
||||
{
|
||||
SetThink( &CMSprite::AnimateThink );
|
||||
pev->nextthink = gpGlobals->time;
|
||||
m_lastTime = gpGlobals->time;
|
||||
}
|
||||
pev->frame = 0;
|
||||
}
|
||||
|
||||
|
||||
void CMSprite::Use( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
int on = pev->effects != EF_NODRAW;
|
||||
if ( ShouldToggle( useType, on ) )
|
||||
{
|
||||
if ( on )
|
||||
{
|
||||
TurnOff();
|
||||
}
|
||||
else
|
||||
{
|
||||
TurnOn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,203 +1,203 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef EFFECTS_H
|
||||
#define EFFECTS_H
|
||||
|
||||
#define SF_BEAM_STARTON 0x0001
|
||||
#define SF_BEAM_TOGGLE 0x0002
|
||||
#define SF_BEAM_RANDOM 0x0004
|
||||
#define SF_BEAM_RING 0x0008
|
||||
#define SF_BEAM_SPARKSTART 0x0010
|
||||
#define SF_BEAM_SPARKEND 0x0020
|
||||
#define SF_BEAM_DECALS 0x0040
|
||||
#define SF_BEAM_SHADEIN 0x0080
|
||||
#define SF_BEAM_SHADEOUT 0x0100
|
||||
#define SF_BEAM_TEMPORARY 0x8000
|
||||
|
||||
#define SF_SPRITE_STARTON 0x0001
|
||||
#define SF_SPRITE_ONCE 0x0002
|
||||
#define SF_SPRITE_TEMPORARY 0x8000
|
||||
|
||||
class CMSprite : public CMPointEntity
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
|
||||
int ObjectCaps( void )
|
||||
{
|
||||
int flags = 0;
|
||||
if ( pev->spawnflags & SF_SPRITE_TEMPORARY )
|
||||
flags = FCAP_DONT_SAVE;
|
||||
return (CMBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags;
|
||||
}
|
||||
void EXPORT AnimateThink( void );
|
||||
void EXPORT ExpandThink( void );
|
||||
void Use( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value );
|
||||
void Animate( float frames );
|
||||
void Expand( float scaleSpeed, float fadeSpeed );
|
||||
void SpriteInit( const char *pSpriteName, const Vector &origin );
|
||||
|
||||
inline void SetAttachment( edict_t *pEntity, int attachment )
|
||||
{
|
||||
if ( pEntity )
|
||||
{
|
||||
pev->skin = ENTINDEX(pEntity);
|
||||
pev->body = attachment;
|
||||
pev->aiment = pEntity;
|
||||
pev->movetype = MOVETYPE_FOLLOW;
|
||||
}
|
||||
}
|
||||
void TurnOff( void );
|
||||
void TurnOn( void );
|
||||
inline float Frames( void ) { return m_maxFrame; }
|
||||
inline void SetTransparency( int rendermode, int r, int g, int b, int a, int fx )
|
||||
{
|
||||
pev->rendermode = rendermode;
|
||||
pev->rendercolor.x = r;
|
||||
pev->rendercolor.y = g;
|
||||
pev->rendercolor.z = b;
|
||||
pev->renderamt = a;
|
||||
pev->renderfx = fx;
|
||||
}
|
||||
inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; }
|
||||
inline void SetScale( float scale ) { pev->scale = scale; }
|
||||
inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; }
|
||||
inline void SetBrightness( int brightness ) { pev->renderamt = brightness; }
|
||||
|
||||
inline void AnimateAndDie( float framerate )
|
||||
{
|
||||
SetThink(&CMSprite::AnimateUntilDead);
|
||||
pev->framerate = framerate;
|
||||
pev->dmgtime = gpGlobals->time + (m_maxFrame / framerate);
|
||||
pev->nextthink = gpGlobals->time;
|
||||
}
|
||||
|
||||
void EXPORT AnimateUntilDead( void );
|
||||
|
||||
static CMSprite *SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate );
|
||||
|
||||
private:
|
||||
|
||||
float m_lastTime;
|
||||
float m_maxFrame;
|
||||
};
|
||||
|
||||
|
||||
class CMBeam : public CMBaseEntity
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
int ObjectCaps( void )
|
||||
{
|
||||
int flags = 0;
|
||||
if ( pev->spawnflags & SF_BEAM_TEMPORARY )
|
||||
flags = FCAP_DONT_SAVE;
|
||||
return (CMBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags;
|
||||
}
|
||||
|
||||
void EXPORT TriggerTouch( edict_t *pOther );
|
||||
|
||||
// These functions are here to show the way beams are encoded as entities.
|
||||
// Encoding beams as entities simplifies their management in the client/server architecture
|
||||
inline void SetType( int type ) { pev->rendermode = (pev->rendermode & 0xF0) | (type&0x0F); }
|
||||
inline void SetFlags( int flags ) { pev->rendermode = (pev->rendermode & 0x0F) | (flags&0xF0); }
|
||||
inline void SetStartPos( const Vector& pos ) { pev->origin = pos; }
|
||||
inline void SetEndPos( const Vector& pos ) { pev->angles = pos; }
|
||||
void SetStartEntity( int entityIndex );
|
||||
void SetEndEntity( int entityIndex );
|
||||
|
||||
inline void SetStartAttachment( int attachment ) { pev->sequence = (pev->sequence & 0x0FFF) | ((attachment&0xF)<<12); }
|
||||
inline void SetEndAttachment( int attachment ) { pev->skin = (pev->skin & 0x0FFF) | ((attachment&0xF)<<12); }
|
||||
|
||||
inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; }
|
||||
inline void SetWidth( int width ) { pev->scale = width; }
|
||||
inline void SetNoise( int amplitude ) { pev->body = amplitude; }
|
||||
inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; }
|
||||
inline void SetBrightness( int brightness ) { pev->renderamt = brightness; }
|
||||
inline void SetFrame( float frame ) { pev->frame = frame; }
|
||||
inline void SetScrollRate( int speed ) { pev->animtime = speed; }
|
||||
|
||||
inline int GetType( void ) { return pev->rendermode & 0x0F; }
|
||||
inline int GetFlags( void ) { return pev->rendermode & 0xF0; }
|
||||
inline int GetStartEntity( void ) { return pev->sequence & 0xFFF; }
|
||||
inline int GetEndEntity( void ) { return pev->skin & 0xFFF; }
|
||||
|
||||
const Vector &GetStartPos( void );
|
||||
const Vector &GetEndPos( void );
|
||||
|
||||
Vector Center( void ) { return (GetStartPos() + GetEndPos()) * 0.5; }; // center point of beam
|
||||
|
||||
inline int GetTexture( void ) { return pev->modelindex; }
|
||||
inline int GetWidth( void ) { return pev->scale; }
|
||||
inline int GetNoise( void ) { return pev->body; }
|
||||
// inline void GetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; }
|
||||
inline int GetBrightness( void ) { return pev->renderamt; }
|
||||
inline int GetFrame( void ) { return pev->frame; }
|
||||
inline int GetScrollRate( void ) { return pev->animtime; }
|
||||
|
||||
// Call after you change start/end positions
|
||||
void RelinkBeam( void );
|
||||
// void SetObjectCollisionBox( void );
|
||||
|
||||
void DoSparks( const Vector &start, const Vector &end );
|
||||
edict_t *RandomTargetname( const char *szName );
|
||||
void BeamDamage( TraceResult *ptr );
|
||||
// Init after BeamCreate()
|
||||
void BeamInit( const char *pSpriteName, int width );
|
||||
void PointsInit( const Vector &start, const Vector &end );
|
||||
void PointEntInit( const Vector &start, int endIndex );
|
||||
void EntsInit( int startIndex, int endIndex );
|
||||
void HoseInit( const Vector &start, const Vector &direction );
|
||||
|
||||
static CMBeam *BeamCreate( const char *pSpriteName, int width );
|
||||
|
||||
inline void LiveForTime( float time ) { SetThink(&CMBeam::SUB_Remove); pev->nextthink = gpGlobals->time + time; }
|
||||
inline void BeamDamageInstant( TraceResult *ptr, float damage )
|
||||
{
|
||||
pev->dmg = damage;
|
||||
pev->dmgtime = gpGlobals->time - 1;
|
||||
BeamDamage(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#define SF_MESSAGE_ONCE 0x0001 // Fade in, not out
|
||||
#define SF_MESSAGE_ALL 0x0002 // Send to all clients
|
||||
|
||||
|
||||
class CMLaser : public CMBeam
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
|
||||
void TurnOn( void );
|
||||
void TurnOff( void );
|
||||
int IsOn( void );
|
||||
|
||||
void FireAtPoint( TraceResult &point );
|
||||
|
||||
void EXPORT StrikeThink( void );
|
||||
void Use( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
CMSprite *m_pSprite;
|
||||
int m_iszSpriteName;
|
||||
Vector m_firePosition;
|
||||
};
|
||||
|
||||
#endif //EFFECTS_H
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef EFFECTS_H
|
||||
#define EFFECTS_H
|
||||
|
||||
#define SF_BEAM_STARTON 0x0001
|
||||
#define SF_BEAM_TOGGLE 0x0002
|
||||
#define SF_BEAM_RANDOM 0x0004
|
||||
#define SF_BEAM_RING 0x0008
|
||||
#define SF_BEAM_SPARKSTART 0x0010
|
||||
#define SF_BEAM_SPARKEND 0x0020
|
||||
#define SF_BEAM_DECALS 0x0040
|
||||
#define SF_BEAM_SHADEIN 0x0080
|
||||
#define SF_BEAM_SHADEOUT 0x0100
|
||||
#define SF_BEAM_TEMPORARY 0x8000
|
||||
|
||||
#define SF_SPRITE_STARTON 0x0001
|
||||
#define SF_SPRITE_ONCE 0x0002
|
||||
#define SF_SPRITE_TEMPORARY 0x8000
|
||||
|
||||
class CMSprite : public CMPointEntity
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
|
||||
int ObjectCaps( void )
|
||||
{
|
||||
int flags = 0;
|
||||
if ( pev->spawnflags & SF_SPRITE_TEMPORARY )
|
||||
flags = FCAP_DONT_SAVE;
|
||||
return (CMBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags;
|
||||
}
|
||||
void EXPORT AnimateThink( void );
|
||||
void EXPORT ExpandThink( void );
|
||||
void Use( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value );
|
||||
void Animate( float frames );
|
||||
void Expand( float scaleSpeed, float fadeSpeed );
|
||||
void SpriteInit( const char *pSpriteName, const Vector &origin );
|
||||
|
||||
inline void SetAttachment( edict_t *pEntity, int attachment )
|
||||
{
|
||||
if ( pEntity )
|
||||
{
|
||||
pev->skin = ENTINDEX(pEntity);
|
||||
pev->body = attachment;
|
||||
pev->aiment = pEntity;
|
||||
pev->movetype = MOVETYPE_FOLLOW;
|
||||
}
|
||||
}
|
||||
void TurnOff( void );
|
||||
void TurnOn( void );
|
||||
inline float Frames( void ) { return m_maxFrame; }
|
||||
inline void SetTransparency( int rendermode, int r, int g, int b, int a, int fx )
|
||||
{
|
||||
pev->rendermode = rendermode;
|
||||
pev->rendercolor.x = r;
|
||||
pev->rendercolor.y = g;
|
||||
pev->rendercolor.z = b;
|
||||
pev->renderamt = a;
|
||||
pev->renderfx = fx;
|
||||
}
|
||||
inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; }
|
||||
inline void SetScale( float scale ) { pev->scale = scale; }
|
||||
inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; }
|
||||
inline void SetBrightness( int brightness ) { pev->renderamt = brightness; }
|
||||
|
||||
inline void AnimateAndDie( float framerate )
|
||||
{
|
||||
SetThink(&CMSprite::AnimateUntilDead);
|
||||
pev->framerate = framerate;
|
||||
pev->dmgtime = gpGlobals->time + (m_maxFrame / framerate);
|
||||
pev->nextthink = gpGlobals->time;
|
||||
}
|
||||
|
||||
void EXPORT AnimateUntilDead( void );
|
||||
|
||||
static CMSprite *SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate );
|
||||
|
||||
private:
|
||||
|
||||
float m_lastTime;
|
||||
float m_maxFrame;
|
||||
};
|
||||
|
||||
|
||||
class CMBeam : public CMBaseEntity
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
int ObjectCaps( void )
|
||||
{
|
||||
int flags = 0;
|
||||
if ( pev->spawnflags & SF_BEAM_TEMPORARY )
|
||||
flags = FCAP_DONT_SAVE;
|
||||
return (CMBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags;
|
||||
}
|
||||
|
||||
void EXPORT TriggerTouch( edict_t *pOther );
|
||||
|
||||
// These functions are here to show the way beams are encoded as entities.
|
||||
// Encoding beams as entities simplifies their management in the client/server architecture
|
||||
inline void SetType( int type ) { pev->rendermode = (pev->rendermode & 0xF0) | (type&0x0F); }
|
||||
inline void SetFlags( int flags ) { pev->rendermode = (pev->rendermode & 0x0F) | (flags&0xF0); }
|
||||
inline void SetStartPos( const Vector& pos ) { pev->origin = pos; }
|
||||
inline void SetEndPos( const Vector& pos ) { pev->angles = pos; }
|
||||
void SetStartEntity( int entityIndex );
|
||||
void SetEndEntity( int entityIndex );
|
||||
|
||||
inline void SetStartAttachment( int attachment ) { pev->sequence = (pev->sequence & 0x0FFF) | ((attachment&0xF)<<12); }
|
||||
inline void SetEndAttachment( int attachment ) { pev->skin = (pev->skin & 0x0FFF) | ((attachment&0xF)<<12); }
|
||||
|
||||
inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; }
|
||||
inline void SetWidth( int width ) { pev->scale = width; }
|
||||
inline void SetNoise( int amplitude ) { pev->body = amplitude; }
|
||||
inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; }
|
||||
inline void SetBrightness( int brightness ) { pev->renderamt = brightness; }
|
||||
inline void SetFrame( float frame ) { pev->frame = frame; }
|
||||
inline void SetScrollRate( int speed ) { pev->animtime = speed; }
|
||||
|
||||
inline int GetType( void ) { return pev->rendermode & 0x0F; }
|
||||
inline int GetFlags( void ) { return pev->rendermode & 0xF0; }
|
||||
inline int GetStartEntity( void ) { return pev->sequence & 0xFFF; }
|
||||
inline int GetEndEntity( void ) { return pev->skin & 0xFFF; }
|
||||
|
||||
const Vector &GetStartPos( void );
|
||||
const Vector &GetEndPos( void );
|
||||
|
||||
Vector Center( void ) { return (GetStartPos() + GetEndPos()) * 0.5; }; // center point of beam
|
||||
|
||||
inline int GetTexture( void ) { return pev->modelindex; }
|
||||
inline int GetWidth( void ) { return pev->scale; }
|
||||
inline int GetNoise( void ) { return pev->body; }
|
||||
// inline void GetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; }
|
||||
inline int GetBrightness( void ) { return pev->renderamt; }
|
||||
inline int GetFrame( void ) { return pev->frame; }
|
||||
inline int GetScrollRate( void ) { return pev->animtime; }
|
||||
|
||||
// Call after you change start/end positions
|
||||
void RelinkBeam( void );
|
||||
// void SetObjectCollisionBox( void );
|
||||
|
||||
void DoSparks( const Vector &start, const Vector &end );
|
||||
edict_t *RandomTargetname( const char *szName );
|
||||
void BeamDamage( TraceResult *ptr );
|
||||
// Init after BeamCreate()
|
||||
void BeamInit( const char *pSpriteName, int width );
|
||||
void PointsInit( const Vector &start, const Vector &end );
|
||||
void PointEntInit( const Vector &start, int endIndex );
|
||||
void EntsInit( int startIndex, int endIndex );
|
||||
void HoseInit( const Vector &start, const Vector &direction );
|
||||
|
||||
static CMBeam *BeamCreate( const char *pSpriteName, int width );
|
||||
|
||||
inline void LiveForTime( float time ) { SetThink(&CMBeam::SUB_Remove); pev->nextthink = gpGlobals->time + time; }
|
||||
inline void BeamDamageInstant( TraceResult *ptr, float damage )
|
||||
{
|
||||
pev->dmg = damage;
|
||||
pev->dmgtime = gpGlobals->time - 1;
|
||||
BeamDamage(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#define SF_MESSAGE_ONCE 0x0001 // Fade in, not out
|
||||
#define SF_MESSAGE_ALL 0x0002 // Send to all clients
|
||||
|
||||
|
||||
class CMLaser : public CMBeam
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
|
||||
void TurnOn( void );
|
||||
void TurnOff( void );
|
||||
int IsOn( void );
|
||||
|
||||
void FireAtPoint( TraceResult &point );
|
||||
|
||||
void EXPORT StrikeThink( void );
|
||||
void Use( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
CMSprite *m_pSprite;
|
||||
int m_iszSpriteName;
|
||||
Vector m_firePosition;
|
||||
};
|
||||
|
||||
#endif //EFFECTS_H
|
||||
|
||||
@@ -1,158 +1,158 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef ENGINECALLBACK_H
|
||||
#define ENGINECALLBACK_H
|
||||
#pragma once
|
||||
|
||||
#include "event_flags.h"
|
||||
|
||||
// Must be provided by user of this code
|
||||
extern enginefuncs_t g_engfuncs;
|
||||
|
||||
// The actual engine callbacks
|
||||
#define GETPLAYERUSERID (*g_engfuncs.pfnGetPlayerUserId)
|
||||
#define PRECACHE_MODEL (*g_engfuncs.pfnPrecacheModel)
|
||||
#define PRECACHE_SOUND (*g_engfuncs.pfnPrecacheSound)
|
||||
#define PRECACHE_GENERIC (*g_engfuncs.pfnPrecacheGeneric)
|
||||
#define SET_MODEL (*g_engfuncs.pfnSetModel)
|
||||
#define MODEL_INDEX (*g_engfuncs.pfnModelIndex)
|
||||
#define MODEL_FRAMES (*g_engfuncs.pfnModelFrames)
|
||||
#define SET_SIZE (*g_engfuncs.pfnSetSize)
|
||||
#define CHANGE_LEVEL (*g_engfuncs.pfnChangeLevel)
|
||||
#define GET_SPAWN_PARMS (*g_engfuncs.pfnGetSpawnParms)
|
||||
#define SAVE_SPAWN_PARMS (*g_engfuncs.pfnSaveSpawnParms)
|
||||
#define VEC_TO_YAW (*g_engfuncs.pfnVecToYaw)
|
||||
#define VEC_TO_ANGLES (*g_engfuncs.pfnVecToAngles)
|
||||
#define MOVE_TO_ORIGIN (*g_engfuncs.pfnMoveToOrigin)
|
||||
#define oldCHANGE_YAW (*g_engfuncs.pfnChangeYaw)
|
||||
#define CHANGE_PITCH (*g_engfuncs.pfnChangePitch)
|
||||
#define MAKE_VECTORS (*g_engfuncs.pfnMakeVectors)
|
||||
#define CREATE_ENTITY (*g_engfuncs.pfnCreateEntity)
|
||||
#define REMOVE_ENTITY (*g_engfuncs.pfnRemoveEntity)
|
||||
#define CREATE_NAMED_ENTITY (*g_engfuncs.pfnCreateNamedEntity)
|
||||
#define MAKE_STATIC (*g_engfuncs.pfnMakeStatic)
|
||||
#define ENT_IS_ON_FLOOR (*g_engfuncs.pfnEntIsOnFloor)
|
||||
#define DROP_TO_FLOOR (*g_engfuncs.pfnDropToFloor)
|
||||
#define WALK_MOVE (*g_engfuncs.pfnWalkMove)
|
||||
#define SET_ORIGIN (*g_engfuncs.pfnSetOrigin)
|
||||
#define EMIT_SOUND_DYN2 (*g_engfuncs.pfnEmitSound)
|
||||
#define BUILD_SOUND_MSG (*g_engfuncs.pfnBuildSoundMsg)
|
||||
#define TRACE_LINE (*g_engfuncs.pfnTraceLine)
|
||||
#define TRACE_TOSS (*g_engfuncs.pfnTraceToss)
|
||||
#define TRACE_MONSTER_HULL (*g_engfuncs.pfnTraceMonsterHull)
|
||||
#define TRACE_HULL (*g_engfuncs.pfnTraceHull)
|
||||
#define GET_AIM_VECTOR (*g_engfuncs.pfnGetAimVector)
|
||||
#define SERVER_COMMAND (*g_engfuncs.pfnServerCommand)
|
||||
#define SERVER_EXECUTE (*g_engfuncs.pfnServerExecute)
|
||||
#define CLIENT_COMMAND (*g_engfuncs.pfnClientCommand)
|
||||
#define PARTICLE_EFFECT (*g_engfuncs.pfnParticleEffect)
|
||||
#define LIGHT_STYLE (*g_engfuncs.pfnLightStyle)
|
||||
#define DECAL_INDEX (*g_engfuncs.pfnDecalIndex)
|
||||
#define POINT_CONTENTS (*g_engfuncs.pfnPointContents)
|
||||
#define CRC32_INIT (*g_engfuncs.pfnCRC32_Init)
|
||||
#define CRC32_PROCESS_BUFFER (*g_engfuncs.pfnCRC32_ProcessBuffer)
|
||||
#define CRC32_PROCESS_BYTE (*g_engfuncs.pfnCRC32_ProcessByte)
|
||||
#define CRC32_FINAL (*g_engfuncs.pfnCRC32_Final)
|
||||
#define RANDOM_LONG (*g_engfuncs.pfnRandomLong)
|
||||
#define RANDOM_FLOAT (*g_engfuncs.pfnRandomFloat)
|
||||
#define GETPLAYERWONID (*g_engfuncs.pfnGetPlayerWONId)
|
||||
|
||||
inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin = NULL, edict_t *ed = NULL ) {
|
||||
(*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ed);
|
||||
}
|
||||
#define MESSAGE_END (*g_engfuncs.pfnMessageEnd)
|
||||
#define WRITE_BYTE (*g_engfuncs.pfnWriteByte)
|
||||
#define WRITE_CHAR (*g_engfuncs.pfnWriteChar)
|
||||
#define WRITE_SHORT (*g_engfuncs.pfnWriteShort)
|
||||
#define WRITE_LONG (*g_engfuncs.pfnWriteLong)
|
||||
#define WRITE_ANGLE (*g_engfuncs.pfnWriteAngle)
|
||||
#define WRITE_COORD (*g_engfuncs.pfnWriteCoord)
|
||||
#define WRITE_STRING (*g_engfuncs.pfnWriteString)
|
||||
#define WRITE_ENTITY (*g_engfuncs.pfnWriteEntity)
|
||||
#define CVAR_REGISTER (*g_engfuncs.pfnCVarRegister)
|
||||
#define CVAR_GET_FLOAT (*g_engfuncs.pfnCVarGetFloat)
|
||||
#define CVAR_GET_STRING (*g_engfuncs.pfnCVarGetString)
|
||||
#define CVAR_SET_FLOAT (*g_engfuncs.pfnCVarSetFloat)
|
||||
#define CVAR_SET_STRING (*g_engfuncs.pfnCVarSetString)
|
||||
#define CVAR_GET_POINTER (*g_engfuncs.pfnCVarGetPointer)
|
||||
#define ALERT (*g_engfuncs.pfnAlertMessage)
|
||||
#define ENGINE_FPRINTF (*g_engfuncs.pfnEngineFprintf)
|
||||
#define ALLOC_PRIVATE (*g_engfuncs.pfnPvAllocEntPrivateData)
|
||||
inline void *GET_PRIVATE( edict_t *pent )
|
||||
{
|
||||
if ( pent )
|
||||
return pent->pvPrivateData;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define FREE_PRIVATE (*g_engfuncs.pfnFreeEntPrivateData)
|
||||
//#define STRING (*g_engfuncs.pfnSzFromIndex)
|
||||
#define ALLOC_STRING (*g_engfuncs.pfnAllocString)
|
||||
#define FIND_ENTITY_BY_STRING (*g_engfuncs.pfnFindEntityByString)
|
||||
#define GETENTITYILLUM (*g_engfuncs.pfnGetEntityIllum)
|
||||
#define FIND_ENTITY_IN_SPHERE (*g_engfuncs.pfnFindEntityInSphere)
|
||||
#define FIND_CLIENT_IN_PVS (*g_engfuncs.pfnFindClientInPVS)
|
||||
#define EMIT_AMBIENT_SOUND (*g_engfuncs.pfnEmitAmbientSound)
|
||||
#define GET_MODEL_PTR (*g_engfuncs.pfnGetModelPtr)
|
||||
#define REG_USER_MSG (*g_engfuncs.pfnRegUserMsg)
|
||||
#define GET_BONE_POSITION (*g_engfuncs.pfnGetBonePosition)
|
||||
#define FUNCTION_FROM_NAME (*g_engfuncs.pfnFunctionFromName)
|
||||
#define NAME_FOR_FUNCTION (*g_engfuncs.pfnNameForFunction)
|
||||
#define TRACE_TEXTURE (*g_engfuncs.pfnTraceTexture)
|
||||
#define CLIENT_PRINTF (*g_engfuncs.pfnClientPrintf)
|
||||
#define CMD_ARGS (*g_engfuncs.pfnCmd_Args)
|
||||
#define CMD_ARGC (*g_engfuncs.pfnCmd_Argc)
|
||||
#define CMD_ARGV (*g_engfuncs.pfnCmd_Argv)
|
||||
#define GET_ATTACHMENT (*g_engfuncs.pfnGetAttachment)
|
||||
#define SET_VIEW (*g_engfuncs.pfnSetView)
|
||||
#define SET_CROSSHAIRANGLE (*g_engfuncs.pfnCrosshairAngle)
|
||||
#define LOAD_FILE_FOR_ME (*g_engfuncs.pfnLoadFileForMe)
|
||||
#define FREE_FILE (*g_engfuncs.pfnFreeFile)
|
||||
#define COMPARE_FILE_TIME (*g_engfuncs.pfnCompareFileTime)
|
||||
#define GET_GAME_DIR (*g_engfuncs.pfnGetGameDir)
|
||||
#define IS_MAP_VALID (*g_engfuncs.pfnIsMapValid)
|
||||
#define NUMBER_OF_ENTITIES (*g_engfuncs.pfnNumberOfEntities)
|
||||
#define IS_DEDICATED_SERVER (*g_engfuncs.pfnIsDedicatedServer)
|
||||
|
||||
#define PRECACHE_EVENT (*g_engfuncs.pfnPrecacheEvent)
|
||||
#define PLAYBACK_EVENT_FULL (*g_engfuncs.pfnPlaybackEvent)
|
||||
|
||||
#define ENGINE_SET_PVS (*g_engfuncs.pfnSetFatPVS)
|
||||
#define ENGINE_SET_PAS (*g_engfuncs.pfnSetFatPAS)
|
||||
|
||||
#define ENGINE_CHECK_VISIBILITY (*g_engfuncs.pfnCheckVisibility)
|
||||
|
||||
#define DELTA_SET ( *g_engfuncs.pfnDeltaSetField )
|
||||
#define DELTA_UNSET ( *g_engfuncs.pfnDeltaUnsetField )
|
||||
#define DELTA_ADDENCODER ( *g_engfuncs.pfnDeltaAddEncoder )
|
||||
#define ENGINE_CURRENT_PLAYER ( *g_engfuncs.pfnGetCurrentPlayer )
|
||||
|
||||
#define ENGINE_CANSKIP ( *g_engfuncs.pfnCanSkipPlayer )
|
||||
|
||||
#define DELTA_FINDFIELD ( *g_engfuncs.pfnDeltaFindField )
|
||||
#define DELTA_SETBYINDEX ( *g_engfuncs.pfnDeltaSetFieldByIndex )
|
||||
#define DELTA_UNSETBYINDEX ( *g_engfuncs.pfnDeltaUnsetFieldByIndex )
|
||||
|
||||
#define ENGINE_GETPHYSINFO ( *g_engfuncs.pfnGetPhysicsInfoString )
|
||||
|
||||
#define ENGINE_SETGROUPMASK ( *g_engfuncs.pfnSetGroupMask )
|
||||
|
||||
#define ENGINE_INSTANCE_BASELINE ( *g_engfuncs.pfnCreateInstancedBaseline )
|
||||
|
||||
#define ENGINE_FORCE_UNMODIFIED ( *g_engfuncs.pfnForceUnmodified )
|
||||
|
||||
#define PLAYER_CNX_STATS ( *g_engfuncs.pfnGetPlayerStats )
|
||||
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef ENGINECALLBACK_H
|
||||
#define ENGINECALLBACK_H
|
||||
#pragma once
|
||||
|
||||
#include "event_flags.h"
|
||||
|
||||
// Must be provided by user of this code
|
||||
extern enginefuncs_t g_engfuncs;
|
||||
|
||||
// The actual engine callbacks
|
||||
#define GETPLAYERUSERID (*g_engfuncs.pfnGetPlayerUserId)
|
||||
#define PRECACHE_MODEL (*g_engfuncs.pfnPrecacheModel)
|
||||
#define PRECACHE_SOUND (*g_engfuncs.pfnPrecacheSound)
|
||||
#define PRECACHE_GENERIC (*g_engfuncs.pfnPrecacheGeneric)
|
||||
#define SET_MODEL (*g_engfuncs.pfnSetModel)
|
||||
#define MODEL_INDEX (*g_engfuncs.pfnModelIndex)
|
||||
#define MODEL_FRAMES (*g_engfuncs.pfnModelFrames)
|
||||
#define SET_SIZE (*g_engfuncs.pfnSetSize)
|
||||
#define CHANGE_LEVEL (*g_engfuncs.pfnChangeLevel)
|
||||
#define GET_SPAWN_PARMS (*g_engfuncs.pfnGetSpawnParms)
|
||||
#define SAVE_SPAWN_PARMS (*g_engfuncs.pfnSaveSpawnParms)
|
||||
#define VEC_TO_YAW (*g_engfuncs.pfnVecToYaw)
|
||||
#define VEC_TO_ANGLES (*g_engfuncs.pfnVecToAngles)
|
||||
#define MOVE_TO_ORIGIN (*g_engfuncs.pfnMoveToOrigin)
|
||||
#define oldCHANGE_YAW (*g_engfuncs.pfnChangeYaw)
|
||||
#define CHANGE_PITCH (*g_engfuncs.pfnChangePitch)
|
||||
#define MAKE_VECTORS (*g_engfuncs.pfnMakeVectors)
|
||||
#define CREATE_ENTITY (*g_engfuncs.pfnCreateEntity)
|
||||
#define REMOVE_ENTITY (*g_engfuncs.pfnRemoveEntity)
|
||||
#define CREATE_NAMED_ENTITY (*g_engfuncs.pfnCreateNamedEntity)
|
||||
#define MAKE_STATIC (*g_engfuncs.pfnMakeStatic)
|
||||
#define ENT_IS_ON_FLOOR (*g_engfuncs.pfnEntIsOnFloor)
|
||||
#define DROP_TO_FLOOR (*g_engfuncs.pfnDropToFloor)
|
||||
#define WALK_MOVE (*g_engfuncs.pfnWalkMove)
|
||||
#define SET_ORIGIN (*g_engfuncs.pfnSetOrigin)
|
||||
#define EMIT_SOUND_DYN2 (*g_engfuncs.pfnEmitSound)
|
||||
#define BUILD_SOUND_MSG (*g_engfuncs.pfnBuildSoundMsg)
|
||||
#define TRACE_LINE (*g_engfuncs.pfnTraceLine)
|
||||
#define TRACE_TOSS (*g_engfuncs.pfnTraceToss)
|
||||
#define TRACE_MONSTER_HULL (*g_engfuncs.pfnTraceMonsterHull)
|
||||
#define TRACE_HULL (*g_engfuncs.pfnTraceHull)
|
||||
#define GET_AIM_VECTOR (*g_engfuncs.pfnGetAimVector)
|
||||
#define SERVER_COMMAND (*g_engfuncs.pfnServerCommand)
|
||||
#define SERVER_EXECUTE (*g_engfuncs.pfnServerExecute)
|
||||
#define CLIENT_COMMAND (*g_engfuncs.pfnClientCommand)
|
||||
#define PARTICLE_EFFECT (*g_engfuncs.pfnParticleEffect)
|
||||
#define LIGHT_STYLE (*g_engfuncs.pfnLightStyle)
|
||||
#define DECAL_INDEX (*g_engfuncs.pfnDecalIndex)
|
||||
#define POINT_CONTENTS (*g_engfuncs.pfnPointContents)
|
||||
#define CRC32_INIT (*g_engfuncs.pfnCRC32_Init)
|
||||
#define CRC32_PROCESS_BUFFER (*g_engfuncs.pfnCRC32_ProcessBuffer)
|
||||
#define CRC32_PROCESS_BYTE (*g_engfuncs.pfnCRC32_ProcessByte)
|
||||
#define CRC32_FINAL (*g_engfuncs.pfnCRC32_Final)
|
||||
#define RANDOM_LONG (*g_engfuncs.pfnRandomLong)
|
||||
#define RANDOM_FLOAT (*g_engfuncs.pfnRandomFloat)
|
||||
#define GETPLAYERWONID (*g_engfuncs.pfnGetPlayerWONId)
|
||||
|
||||
inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin = NULL, edict_t *ed = NULL ) {
|
||||
(*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ed);
|
||||
}
|
||||
#define MESSAGE_END (*g_engfuncs.pfnMessageEnd)
|
||||
#define WRITE_BYTE (*g_engfuncs.pfnWriteByte)
|
||||
#define WRITE_CHAR (*g_engfuncs.pfnWriteChar)
|
||||
#define WRITE_SHORT (*g_engfuncs.pfnWriteShort)
|
||||
#define WRITE_LONG (*g_engfuncs.pfnWriteLong)
|
||||
#define WRITE_ANGLE (*g_engfuncs.pfnWriteAngle)
|
||||
#define WRITE_COORD (*g_engfuncs.pfnWriteCoord)
|
||||
#define WRITE_STRING (*g_engfuncs.pfnWriteString)
|
||||
#define WRITE_ENTITY (*g_engfuncs.pfnWriteEntity)
|
||||
#define CVAR_REGISTER (*g_engfuncs.pfnCVarRegister)
|
||||
#define CVAR_GET_FLOAT (*g_engfuncs.pfnCVarGetFloat)
|
||||
#define CVAR_GET_STRING (*g_engfuncs.pfnCVarGetString)
|
||||
#define CVAR_SET_FLOAT (*g_engfuncs.pfnCVarSetFloat)
|
||||
#define CVAR_SET_STRING (*g_engfuncs.pfnCVarSetString)
|
||||
#define CVAR_GET_POINTER (*g_engfuncs.pfnCVarGetPointer)
|
||||
#define ALERT (*g_engfuncs.pfnAlertMessage)
|
||||
#define ENGINE_FPRINTF (*g_engfuncs.pfnEngineFprintf)
|
||||
#define ALLOC_PRIVATE (*g_engfuncs.pfnPvAllocEntPrivateData)
|
||||
inline void *GET_PRIVATE( edict_t *pent )
|
||||
{
|
||||
if ( pent )
|
||||
return pent->pvPrivateData;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define FREE_PRIVATE (*g_engfuncs.pfnFreeEntPrivateData)
|
||||
//#define STRING (*g_engfuncs.pfnSzFromIndex)
|
||||
#define ALLOC_STRING (*g_engfuncs.pfnAllocString)
|
||||
#define FIND_ENTITY_BY_STRING (*g_engfuncs.pfnFindEntityByString)
|
||||
#define GETENTITYILLUM (*g_engfuncs.pfnGetEntityIllum)
|
||||
#define FIND_ENTITY_IN_SPHERE (*g_engfuncs.pfnFindEntityInSphere)
|
||||
#define FIND_CLIENT_IN_PVS (*g_engfuncs.pfnFindClientInPVS)
|
||||
#define EMIT_AMBIENT_SOUND (*g_engfuncs.pfnEmitAmbientSound)
|
||||
#define GET_MODEL_PTR (*g_engfuncs.pfnGetModelPtr)
|
||||
#define REG_USER_MSG (*g_engfuncs.pfnRegUserMsg)
|
||||
#define GET_BONE_POSITION (*g_engfuncs.pfnGetBonePosition)
|
||||
#define FUNCTION_FROM_NAME (*g_engfuncs.pfnFunctionFromName)
|
||||
#define NAME_FOR_FUNCTION (*g_engfuncs.pfnNameForFunction)
|
||||
#define TRACE_TEXTURE (*g_engfuncs.pfnTraceTexture)
|
||||
#define CLIENT_PRINTF (*g_engfuncs.pfnClientPrintf)
|
||||
#define CMD_ARGS (*g_engfuncs.pfnCmd_Args)
|
||||
#define CMD_ARGC (*g_engfuncs.pfnCmd_Argc)
|
||||
#define CMD_ARGV (*g_engfuncs.pfnCmd_Argv)
|
||||
#define GET_ATTACHMENT (*g_engfuncs.pfnGetAttachment)
|
||||
#define SET_VIEW (*g_engfuncs.pfnSetView)
|
||||
#define SET_CROSSHAIRANGLE (*g_engfuncs.pfnCrosshairAngle)
|
||||
#define LOAD_FILE_FOR_ME (*g_engfuncs.pfnLoadFileForMe)
|
||||
#define FREE_FILE (*g_engfuncs.pfnFreeFile)
|
||||
#define COMPARE_FILE_TIME (*g_engfuncs.pfnCompareFileTime)
|
||||
#define GET_GAME_DIR (*g_engfuncs.pfnGetGameDir)
|
||||
#define IS_MAP_VALID (*g_engfuncs.pfnIsMapValid)
|
||||
#define NUMBER_OF_ENTITIES (*g_engfuncs.pfnNumberOfEntities)
|
||||
#define IS_DEDICATED_SERVER (*g_engfuncs.pfnIsDedicatedServer)
|
||||
|
||||
#define PRECACHE_EVENT (*g_engfuncs.pfnPrecacheEvent)
|
||||
#define PLAYBACK_EVENT_FULL (*g_engfuncs.pfnPlaybackEvent)
|
||||
|
||||
#define ENGINE_SET_PVS (*g_engfuncs.pfnSetFatPVS)
|
||||
#define ENGINE_SET_PAS (*g_engfuncs.pfnSetFatPAS)
|
||||
|
||||
#define ENGINE_CHECK_VISIBILITY (*g_engfuncs.pfnCheckVisibility)
|
||||
|
||||
#define DELTA_SET ( *g_engfuncs.pfnDeltaSetField )
|
||||
#define DELTA_UNSET ( *g_engfuncs.pfnDeltaUnsetField )
|
||||
#define DELTA_ADDENCODER ( *g_engfuncs.pfnDeltaAddEncoder )
|
||||
#define ENGINE_CURRENT_PLAYER ( *g_engfuncs.pfnGetCurrentPlayer )
|
||||
|
||||
#define ENGINE_CANSKIP ( *g_engfuncs.pfnCanSkipPlayer )
|
||||
|
||||
#define DELTA_FINDFIELD ( *g_engfuncs.pfnDeltaFindField )
|
||||
#define DELTA_SETBYINDEX ( *g_engfuncs.pfnDeltaSetFieldByIndex )
|
||||
#define DELTA_UNSETBYINDEX ( *g_engfuncs.pfnDeltaUnsetFieldByIndex )
|
||||
|
||||
#define ENGINE_GETPHYSINFO ( *g_engfuncs.pfnGetPhysicsInfoString )
|
||||
|
||||
#define ENGINE_SETGROUPMASK ( *g_engfuncs.pfnSetGroupMask )
|
||||
|
||||
#define ENGINE_INSTANCE_BASELINE ( *g_engfuncs.pfnCreateInstancedBaseline )
|
||||
|
||||
#define ENGINE_FORCE_UNMODIFIED ( *g_engfuncs.pfnForceUnmodified )
|
||||
|
||||
#define PLAYER_CNX_STATS ( *g_engfuncs.pfnGetPlayerStats )
|
||||
|
||||
#endif //ENGINECALLBACK_H
|
||||
646
src/dlls/explode.cpp
Executable file → Normal file
646
src/dlls/explode.cpp
Executable file → Normal file
@@ -1,301 +1,345 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
/*
|
||||
|
||||
===== explode.cpp ========================================================
|
||||
|
||||
Explosion-related code
|
||||
|
||||
*/
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "decals.h"
|
||||
#include "explode.h"
|
||||
|
||||
// Spark Shower
|
||||
class CMShower : public CMBaseEntity
|
||||
{
|
||||
void Spawn( void );
|
||||
void Think( void );
|
||||
void Touch( CMBaseEntity *pOther );
|
||||
int ObjectCaps( void ) { return FCAP_DONT_SAVE; }
|
||||
};
|
||||
|
||||
void CMShower::Spawn( void )
|
||||
{
|
||||
pev->velocity = RANDOM_FLOAT( 200, 300 ) * pev->angles;
|
||||
pev->velocity.x += RANDOM_FLOAT(-100.f,100.f);
|
||||
pev->velocity.y += RANDOM_FLOAT(-100.f,100.f);
|
||||
if ( pev->velocity.z >= 0 )
|
||||
pev->velocity.z += 200;
|
||||
else
|
||||
pev->velocity.z -= 200;
|
||||
pev->movetype = MOVETYPE_BOUNCE;
|
||||
pev->gravity = 0.5;
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
pev->solid = SOLID_NOT;
|
||||
SET_MODEL( edict(), "models/grenade.mdl"); // Need a model, just use the grenade, we don't draw it anyway
|
||||
UTIL_SetSize(pev, g_vecZero, g_vecZero );
|
||||
pev->effects |= EF_NODRAW;
|
||||
pev->speed = RANDOM_FLOAT( 0.5, 1.5 );
|
||||
|
||||
pev->angles = g_vecZero;
|
||||
pev->classname = MAKE_STRING( "_spark_shower" );
|
||||
}
|
||||
|
||||
|
||||
void CMShower::Think( void )
|
||||
{
|
||||
UTIL_Sparks( pev->origin );
|
||||
|
||||
pev->speed -= 0.1;
|
||||
if ( pev->speed > 0 )
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
else
|
||||
UTIL_Remove( this->edict() );
|
||||
pev->flags &= ~FL_ONGROUND;
|
||||
}
|
||||
|
||||
void CMShower::Touch( CMBaseEntity *pOther )
|
||||
{
|
||||
if ( pev->flags & FL_ONGROUND )
|
||||
pev->velocity = pev->velocity * 0.1;
|
||||
else
|
||||
pev->velocity = pev->velocity * 0.6;
|
||||
|
||||
if ( (pev->velocity.x*pev->velocity.x+pev->velocity.y*pev->velocity.y) < 10.0 )
|
||||
pev->speed = 0;
|
||||
}
|
||||
|
||||
class CMEnvExplosion : public CMBaseMonster
|
||||
{
|
||||
public:
|
||||
void Spawn( );
|
||||
void EXPORT Smoke ( void );
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
void DelayUse( void );
|
||||
void Use( CMBaseEntity *pActivator, CMBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
int m_iMagnitude;// how large is the fireball? how much damage?
|
||||
int m_spriteScale; // what's the exact fireball sprite scale?
|
||||
};
|
||||
|
||||
void CMEnvExplosion::KeyValue( KeyValueData *pkvd )
|
||||
{
|
||||
if (FStrEq(pkvd->szKeyName, "iMagnitude"))
|
||||
{
|
||||
m_iMagnitude = atoi(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else
|
||||
CMBaseEntity::KeyValue( pkvd );
|
||||
}
|
||||
|
||||
void CMEnvExplosion::Spawn( void )
|
||||
{
|
||||
pev->solid = SOLID_NOT;
|
||||
pev->effects = EF_NODRAW;
|
||||
|
||||
pev->movetype = MOVETYPE_NONE;
|
||||
/*
|
||||
if ( m_iMagnitude > 250 )
|
||||
{
|
||||
m_iMagnitude = 250;
|
||||
}
|
||||
*/
|
||||
|
||||
float flSpriteScale;
|
||||
flSpriteScale = ( m_iMagnitude - 50) * 0.6;
|
||||
|
||||
/*
|
||||
if ( flSpriteScale > 50 )
|
||||
{
|
||||
flSpriteScale = 50;
|
||||
}
|
||||
*/
|
||||
if ( flSpriteScale < 10 )
|
||||
{
|
||||
flSpriteScale = 10;
|
||||
}
|
||||
|
||||
m_spriteScale = (int)flSpriteScale;
|
||||
pev->classname = MAKE_STRING( "_env_explosion" );
|
||||
}
|
||||
|
||||
void CMEnvExplosion::DelayUse( void )
|
||||
{
|
||||
Use( NULL, NULL, USE_TOGGLE, 0 );
|
||||
}
|
||||
|
||||
void CMEnvExplosion::Use( CMBaseEntity *pActivator, CMBaseEntity *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
TraceResult tr;
|
||||
|
||||
pev->model = iStringNull;//invisible
|
||||
pev->solid = SOLID_NOT;// intangible
|
||||
|
||||
Vector vecSpot;// trace starts here!
|
||||
|
||||
vecSpot = pev->origin + Vector ( 0 , 0 , 8 );
|
||||
|
||||
UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -40 ), ignore_monsters, ENT(pev), & tr);
|
||||
|
||||
// Pull out of the wall a bit
|
||||
if ( tr.flFraction != 1.0 )
|
||||
{
|
||||
pev->origin = tr.vecEndPos + (tr.vecPlaneNormal * (m_iMagnitude - 24) * 0.6);
|
||||
}
|
||||
else
|
||||
{
|
||||
pev->origin = pev->origin;
|
||||
}
|
||||
|
||||
// draw decal
|
||||
if (! ( pev->spawnflags & SF_ENVEXPLOSION_NODECAL))
|
||||
{
|
||||
if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 )
|
||||
{
|
||||
UTIL_DecalTrace( &tr, DECAL_SCORCH1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_DecalTrace( &tr, DECAL_SCORCH2 );
|
||||
}
|
||||
}
|
||||
|
||||
// draw fireball
|
||||
if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOFIREBALL ) )
|
||||
{
|
||||
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
|
||||
WRITE_BYTE( TE_EXPLOSION);
|
||||
WRITE_COORD( pev->origin.x );
|
||||
WRITE_COORD( pev->origin.y );
|
||||
WRITE_COORD( pev->origin.z );
|
||||
WRITE_SHORT( g_sModelIndexFireball );
|
||||
WRITE_BYTE( (BYTE)m_spriteScale ); // scale * 10
|
||||
WRITE_BYTE( 15 ); // framerate
|
||||
WRITE_BYTE( TE_EXPLFLAG_NONE );
|
||||
MESSAGE_END();
|
||||
}
|
||||
else
|
||||
{
|
||||
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
|
||||
WRITE_BYTE( TE_EXPLOSION);
|
||||
WRITE_COORD( pev->origin.x );
|
||||
WRITE_COORD( pev->origin.y );
|
||||
WRITE_COORD( pev->origin.z );
|
||||
WRITE_SHORT( g_sModelIndexFireball );
|
||||
WRITE_BYTE( 0 ); // no sprite
|
||||
WRITE_BYTE( 15 ); // framerate
|
||||
WRITE_BYTE( TE_EXPLFLAG_NONE );
|
||||
MESSAGE_END();
|
||||
}
|
||||
|
||||
// do damage
|
||||
if ( !( pev->spawnflags & SF_ENVEXPLOSION_NODAMAGE ) )
|
||||
{
|
||||
RadiusDamage ( pev, pev->owner == NULL ? pev : VARS( pev->owner ), m_iMagnitude, CLASS_NONE, DMG_BLAST );
|
||||
}
|
||||
|
||||
SetThink( &CMEnvExplosion::Smoke );
|
||||
pev->nextthink = gpGlobals->time + 0.3;
|
||||
|
||||
// draw sparks
|
||||
if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOSPARKS ) )
|
||||
{
|
||||
int sparkCount = RANDOM_LONG(0,3);
|
||||
|
||||
for ( int i = 0; i < sparkCount; i++ )
|
||||
{
|
||||
CMBaseEntity *pSpark = CreateClassPtr((CMShower *)NULL);
|
||||
if ( pSpark == NULL )
|
||||
{
|
||||
ALERT( at_console, "Failed to spawn spark_shower!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_SetOrigin( pSpark->pev, pev->origin );
|
||||
pSpark->pev->angles = tr.vecPlaneNormal;
|
||||
pSpark->Spawn();
|
||||
}
|
||||
// Create( "spark_shower", pev->origin, tr.vecPlaneNormal, NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CMEnvExplosion::Smoke( void )
|
||||
{
|
||||
if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOSMOKE ) )
|
||||
{
|
||||
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
|
||||
WRITE_BYTE( TE_SMOKE );
|
||||
WRITE_COORD( pev->origin.x );
|
||||
WRITE_COORD( pev->origin.y );
|
||||
WRITE_COORD( pev->origin.z );
|
||||
WRITE_SHORT( g_sModelIndexSmoke );
|
||||
WRITE_BYTE( (BYTE)m_spriteScale ); // scale * 10
|
||||
WRITE_BYTE( 12 ); // framerate
|
||||
MESSAGE_END();
|
||||
}
|
||||
|
||||
if ( !(pev->spawnflags & SF_ENVEXPLOSION_REPEATABLE) )
|
||||
{
|
||||
UTIL_Remove( this->edict() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Stock to quickly create a one-time explosion
|
||||
void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, int flags, float delay )
|
||||
{
|
||||
KeyValueData kvd;
|
||||
char buf[128];
|
||||
|
||||
//CMBaseEntity *pExplosion = CMBaseEntity::Create( "env_explosion", center, angles, pOwner );
|
||||
CMBaseEntity *pExplosion = CreateClassPtr((CMEnvExplosion *)NULL);
|
||||
if ( pExplosion == NULL )
|
||||
{
|
||||
ALERT( at_console, "Failed to create env_explosion!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf( buf, "%3d", magnitude );
|
||||
kvd.szKeyName = "iMagnitude";
|
||||
kvd.szValue = buf;
|
||||
pExplosion->KeyValue( &kvd );
|
||||
pExplosion->pev->owner = pOwner;
|
||||
pExplosion->pev->spawnflags |= flags;
|
||||
|
||||
UTIL_SetOrigin( pExplosion->pev, center );
|
||||
pExplosion->pev->angles = angles;
|
||||
|
||||
// This is a temporary entity, filter out the flag
|
||||
pExplosion->pev->spawnflags &= ~SF_ENVEXPLOSION_REPEATABLE;
|
||||
|
||||
pExplosion->Spawn();
|
||||
if ( delay > 0.0f )
|
||||
{
|
||||
//pExplosion->SetThink( &CMBaseEntity::SUB_CallUseToggle ); // i don't trust you
|
||||
pExplosion->SetThink( &CMEnvExplosion::DelayUse );
|
||||
pExplosion->pev->nextthink = gpGlobals->time + delay;
|
||||
}
|
||||
else
|
||||
{
|
||||
pExplosion->Use( NULL, NULL, USE_TOGGLE, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
/*
|
||||
|
||||
===== explode.cpp ========================================================
|
||||
|
||||
Explosion-related code
|
||||
|
||||
*/
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "decals.h"
|
||||
#include "explode.h"
|
||||
|
||||
// Spark Shower
|
||||
class CMShower : public CMBaseEntity
|
||||
{
|
||||
void Spawn( void );
|
||||
void Think( void );
|
||||
void Touch( CMBaseEntity *pOther );
|
||||
int ObjectCaps( void ) { return FCAP_DONT_SAVE; }
|
||||
};
|
||||
|
||||
void CMShower::Spawn( void )
|
||||
{
|
||||
pev->velocity = RANDOM_FLOAT( 200, 300 ) * pev->angles;
|
||||
pev->velocity.x += RANDOM_FLOAT(-100.f,100.f);
|
||||
pev->velocity.y += RANDOM_FLOAT(-100.f,100.f);
|
||||
if ( pev->velocity.z >= 0 )
|
||||
pev->velocity.z += 200;
|
||||
else
|
||||
pev->velocity.z -= 200;
|
||||
pev->movetype = MOVETYPE_BOUNCE;
|
||||
pev->gravity = 0.5;
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
pev->solid = SOLID_NOT;
|
||||
SET_MODEL( edict(), "models/grenade.mdl"); // Need a model, just use the grenade, we don't draw it anyway
|
||||
UTIL_SetSize(pev, g_vecZero, g_vecZero );
|
||||
pev->effects |= EF_NODRAW;
|
||||
pev->speed = RANDOM_FLOAT( 0.5, 1.5 );
|
||||
|
||||
pev->angles = g_vecZero;
|
||||
pev->classname = MAKE_STRING( "_spark_shower" );
|
||||
}
|
||||
|
||||
|
||||
void CMShower::Think( void )
|
||||
{
|
||||
UTIL_Sparks( pev->origin );
|
||||
|
||||
pev->speed -= 0.1;
|
||||
if ( pev->speed > 0 )
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
else
|
||||
UTIL_Remove( this->edict() );
|
||||
pev->flags &= ~FL_ONGROUND;
|
||||
}
|
||||
|
||||
void CMShower::Touch( CMBaseEntity *pOther )
|
||||
{
|
||||
if ( pev->flags & FL_ONGROUND )
|
||||
pev->velocity = pev->velocity * 0.1;
|
||||
else
|
||||
pev->velocity = pev->velocity * 0.6;
|
||||
|
||||
if ( (pev->velocity.x*pev->velocity.x+pev->velocity.y*pev->velocity.y) < 10.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
|
||||
{
|
||||
public:
|
||||
void Spawn( );
|
||||
void EXPORT Smoke ( void );
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
void EXPORT DelayUse( void );
|
||||
void Use( CMBaseEntity *pActivator, CMBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
int m_iMagnitude;// how large is the fireball? how much damage?
|
||||
int m_spriteScale; // what's the exact fireball sprite scale?
|
||||
};
|
||||
|
||||
void CMEnvExplosion::KeyValue( KeyValueData *pkvd )
|
||||
{
|
||||
if (FStrEq(pkvd->szKeyName, "iMagnitude"))
|
||||
{
|
||||
m_iMagnitude = atoi(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else
|
||||
CMBaseEntity::KeyValue( pkvd );
|
||||
}
|
||||
|
||||
void CMEnvExplosion::Spawn( void )
|
||||
{
|
||||
pev->solid = SOLID_NOT;
|
||||
pev->effects = EF_NODRAW;
|
||||
|
||||
pev->movetype = MOVETYPE_NONE;
|
||||
/*
|
||||
if ( m_iMagnitude > 250 )
|
||||
{
|
||||
m_iMagnitude = 250;
|
||||
}
|
||||
*/
|
||||
|
||||
float flSpriteScale;
|
||||
flSpriteScale = ( m_iMagnitude - 50) * 0.6;
|
||||
|
||||
/*
|
||||
if ( flSpriteScale > 50 )
|
||||
{
|
||||
flSpriteScale = 50;
|
||||
}
|
||||
*/
|
||||
if ( flSpriteScale < 10 )
|
||||
{
|
||||
flSpriteScale = 10;
|
||||
}
|
||||
|
||||
m_spriteScale = (int)flSpriteScale;
|
||||
pev->classname = MAKE_STRING( "_env_explosion" );
|
||||
}
|
||||
|
||||
void CMEnvExplosion::DelayUse( void )
|
||||
{
|
||||
Use( NULL, NULL, USE_TOGGLE, 0 );
|
||||
}
|
||||
|
||||
void CMEnvExplosion::Use( CMBaseEntity *pActivator, CMBaseEntity *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
TraceResult tr;
|
||||
|
||||
pev->model = iStringNull;//invisible
|
||||
pev->solid = SOLID_NOT;// intangible
|
||||
|
||||
Vector vecSpot;// trace starts here!
|
||||
|
||||
vecSpot = pev->origin + Vector ( 0 , 0 , 8 );
|
||||
|
||||
UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -40 ), ignore_monsters, ENT(pev), & tr);
|
||||
|
||||
// Pull out of the wall a bit
|
||||
if ( tr.flFraction != 1.0 )
|
||||
{
|
||||
pev->origin = tr.vecEndPos + (tr.vecPlaneNormal * (m_iMagnitude - 24) * 0.6);
|
||||
}
|
||||
else
|
||||
{
|
||||
pev->origin = pev->origin;
|
||||
}
|
||||
|
||||
// draw decal
|
||||
if (! ( pev->spawnflags & SF_ENVEXPLOSION_NODECAL))
|
||||
{
|
||||
if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 )
|
||||
{
|
||||
UTIL_DecalTrace( &tr, DECAL_SCORCH1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_DecalTrace( &tr, DECAL_SCORCH2 );
|
||||
}
|
||||
}
|
||||
|
||||
// draw fireball
|
||||
if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOFIREBALL ) )
|
||||
{
|
||||
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
|
||||
WRITE_BYTE( TE_EXPLOSION);
|
||||
WRITE_COORD( pev->origin.x );
|
||||
WRITE_COORD( pev->origin.y );
|
||||
WRITE_COORD( pev->origin.z );
|
||||
WRITE_SHORT( g_sModelIndexFireball );
|
||||
WRITE_BYTE( (BYTE)m_spriteScale ); // scale * 10
|
||||
WRITE_BYTE( 15 ); // framerate
|
||||
WRITE_BYTE( TE_EXPLFLAG_NONE );
|
||||
MESSAGE_END();
|
||||
}
|
||||
else
|
||||
{
|
||||
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
|
||||
WRITE_BYTE( TE_EXPLOSION);
|
||||
WRITE_COORD( pev->origin.x );
|
||||
WRITE_COORD( pev->origin.y );
|
||||
WRITE_COORD( pev->origin.z );
|
||||
WRITE_SHORT( g_sModelIndexFireball );
|
||||
WRITE_BYTE( 0 ); // no sprite
|
||||
WRITE_BYTE( 15 ); // framerate
|
||||
WRITE_BYTE( TE_EXPLFLAG_NONE );
|
||||
MESSAGE_END();
|
||||
}
|
||||
|
||||
// do damage
|
||||
if ( !( pev->spawnflags & SF_ENVEXPLOSION_NODAMAGE ) )
|
||||
{
|
||||
RadiusDamage ( pev, pev->owner == NULL ? pev : VARS( pev->owner ), m_iMagnitude, CLASS_NONE, DMG_BLAST );
|
||||
}
|
||||
|
||||
SetThink( &CMEnvExplosion::Smoke );
|
||||
pev->nextthink = gpGlobals->time + 0.3;
|
||||
|
||||
// draw sparks
|
||||
if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOSPARKS ) )
|
||||
{
|
||||
int sparkCount = RANDOM_LONG(0,3);
|
||||
|
||||
for ( int i = 0; i < sparkCount; i++ )
|
||||
{
|
||||
CMBaseEntity *pSpark = CreateClassPtr((CMShower *)NULL);
|
||||
if ( pSpark == NULL )
|
||||
{
|
||||
ALERT( at_console, "Failed to spawn spark_shower!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_SetOrigin( pSpark->pev, pev->origin );
|
||||
pSpark->pev->angles = tr.vecPlaneNormal;
|
||||
pSpark->Spawn();
|
||||
}
|
||||
// Create( "spark_shower", pev->origin, tr.vecPlaneNormal, NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CMEnvExplosion::Smoke( void )
|
||||
{
|
||||
if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOSMOKE ) )
|
||||
{
|
||||
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
|
||||
WRITE_BYTE( TE_SMOKE );
|
||||
WRITE_COORD( pev->origin.x );
|
||||
WRITE_COORD( pev->origin.y );
|
||||
WRITE_COORD( pev->origin.z );
|
||||
WRITE_SHORT( g_sModelIndexSmoke );
|
||||
WRITE_BYTE( (BYTE)m_spriteScale ); // scale * 10
|
||||
WRITE_BYTE( 12 ); // framerate
|
||||
MESSAGE_END();
|
||||
}
|
||||
|
||||
if ( !(pev->spawnflags & SF_ENVEXPLOSION_REPEATABLE) )
|
||||
{
|
||||
UTIL_Remove( this->edict() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Stocks:
|
||||
// Create a one-time explosion
|
||||
void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, int flags, float delay )
|
||||
{
|
||||
KeyValueData kvd;
|
||||
char buf[128];
|
||||
|
||||
//CMBaseEntity *pExplosion = CMBaseEntity::Create( "env_explosion", center, angles, pOwner );
|
||||
CMBaseEntity *pExplosion = CreateClassPtr((CMEnvExplosion *)NULL);
|
||||
if ( pExplosion == NULL )
|
||||
{
|
||||
ALERT( at_console, "Failed to create env_explosion!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf( buf, "%3d", magnitude );
|
||||
kvd.szKeyName = "iMagnitude";
|
||||
kvd.szValue = buf;
|
||||
pExplosion->KeyValue( &kvd );
|
||||
pExplosion->pev->owner = pOwner;
|
||||
pExplosion->pev->spawnflags |= flags;
|
||||
|
||||
UTIL_SetOrigin( pExplosion->pev, center );
|
||||
pExplosion->pev->angles = angles;
|
||||
|
||||
// This is a temporary entity, filter out the flag
|
||||
pExplosion->pev->spawnflags &= ~SF_ENVEXPLOSION_REPEATABLE;
|
||||
|
||||
pExplosion->Spawn();
|
||||
pExplosion->SetThink( &CMEnvExplosion::DelayUse );
|
||||
pExplosion->pev->nextthink = gpGlobals->time + delay;
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
@@ -1,32 +1,33 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef EXPLODE_H
|
||||
#define EXPLODE_H
|
||||
|
||||
|
||||
#define SF_ENVEXPLOSION_NODAMAGE ( 1 << 0 ) // when set, ENV_EXPLOSION will not actually inflict damage
|
||||
#define SF_ENVEXPLOSION_REPEATABLE ( 1 << 1 ) // can this entity be refired?
|
||||
#define SF_ENVEXPLOSION_NOFIREBALL ( 1 << 2 ) // don't draw the fireball
|
||||
#define SF_ENVEXPLOSION_NOSMOKE ( 1 << 3 ) // don't draw the smoke
|
||||
#define SF_ENVEXPLOSION_NODECAL ( 1 << 4 ) // don't make a scorch mark
|
||||
#define SF_ENVEXPLOSION_NOSPARKS ( 1 << 5 ) // don't make a scorch mark
|
||||
|
||||
extern DLL_GLOBAL short g_sModelIndexFireball;
|
||||
extern DLL_GLOBAL short g_sModelIndexSmoke;
|
||||
|
||||
|
||||
extern void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, int flags, float delay );
|
||||
|
||||
#endif //EXPLODE_H
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef EXPLODE_H
|
||||
#define EXPLODE_H
|
||||
|
||||
|
||||
#define SF_ENVEXPLOSION_NODAMAGE ( 1 << 0 ) // when set, ENV_EXPLOSION will not actually inflict damage
|
||||
#define SF_ENVEXPLOSION_REPEATABLE ( 1 << 1 ) // can this entity be refired?
|
||||
#define SF_ENVEXPLOSION_NOFIREBALL ( 1 << 2 ) // don't draw the fireball
|
||||
#define SF_ENVEXPLOSION_NOSMOKE ( 1 << 3 ) // don't draw the smoke
|
||||
#define SF_ENVEXPLOSION_NODECAL ( 1 << 4 ) // don't make a scorch mark
|
||||
#define SF_ENVEXPLOSION_NOSPARKS ( 1 << 5 ) // don't make a scorch mark
|
||||
|
||||
extern DLL_GLOBAL short g_sModelIndexFireball;
|
||||
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 SmokeCreate( const Vector &origin, int amount, int size, int radius, float delay );
|
||||
|
||||
#endif //EXPLODE_H
|
||||
|
||||
@@ -1,87 +1,88 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef EXTDLL_H
|
||||
#define EXTDLL_H
|
||||
|
||||
|
||||
//
|
||||
// Global header file for extension DLLs
|
||||
//
|
||||
|
||||
// Allow "DEBUG" in addition to default "_DEBUG"
|
||||
#ifdef _DEBUG
|
||||
#define DEBUG 1
|
||||
#endif
|
||||
|
||||
// Silence certain warnings
|
||||
#pragma warning(disable : 4244) // int or float down-conversion
|
||||
#pragma warning(disable : 4305) // int or float data truncation
|
||||
#pragma warning(disable : 4201) // nameless struct/union
|
||||
#pragma warning(disable : 4514) // unreferenced inline function removed
|
||||
#pragma warning(disable : 4100) // unreferenced formal parameter
|
||||
|
||||
// Prevent tons of unused windows definitions
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOWINRES
|
||||
#define NOSERVICE
|
||||
#define NOMCX
|
||||
#define NOIME
|
||||
#include "windows.h"
|
||||
#else // _WIN32
|
||||
#define FALSE 0
|
||||
#define TRUE (!FALSE)
|
||||
typedef unsigned long ULONG;
|
||||
typedef unsigned char BYTE;
|
||||
typedef int BOOL;
|
||||
#define MAX_PATH PATH_MAX
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d)
|
||||
#endif //_WIN32
|
||||
|
||||
// Misc C-runtime library headers
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
#include "math.h"
|
||||
|
||||
// min/max is not on math.h library
|
||||
// move outside win32 scope so it can compile on both platforms
|
||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
// Header file containing definition of globalvars_t and entvars_t
|
||||
typedef int func_t; //
|
||||
typedef int string_t; // from engine's pr_comp.h;
|
||||
typedef float vec_t; // needed before including progdefs.h
|
||||
|
||||
// Vector class
|
||||
#include "vector.h"
|
||||
|
||||
// Defining it as a (bogus) struct helps enforce type-checking
|
||||
#define vec3_t Vector
|
||||
|
||||
// Shared engine/DLL constants
|
||||
#include "const.h"
|
||||
#include "progdefs.h"
|
||||
#include "edict.h"
|
||||
|
||||
// Shared header describing protocol between engine and DLLs
|
||||
#include "eiface.h"
|
||||
|
||||
// Shared header between the client DLL and the game DLLs
|
||||
#include "cdll_dll.h"
|
||||
|
||||
#endif //EXTDLL_H
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef EXTDLL_H
|
||||
#define EXTDLL_H
|
||||
|
||||
|
||||
//
|
||||
// Global header file for extension DLLs
|
||||
//
|
||||
|
||||
// Allow "DEBUG" in addition to default "_DEBUG"
|
||||
#ifdef _DEBUG
|
||||
#define DEBUG 1
|
||||
#endif
|
||||
|
||||
// Silence certain warnings
|
||||
#pragma warning(disable : 4244) // int or float down-conversion
|
||||
#pragma warning(disable : 4305) // int or float data truncation
|
||||
#pragma warning(disable : 4201) // nameless struct/union
|
||||
#pragma warning(disable : 4514) // unreferenced inline function removed
|
||||
#pragma warning(disable : 4100) // unreferenced formal parameter
|
||||
#pragma warning(disable : 4390) // empty controlled statement (seems to work fine? monster_api.cpp[101/115])
|
||||
|
||||
// Prevent tons of unused windows definitions
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOWINRES
|
||||
#define NOSERVICE
|
||||
#define NOMCX
|
||||
#define NOIME
|
||||
#include "windows.h"
|
||||
#else // _WIN32
|
||||
#define FALSE 0
|
||||
#define TRUE (!FALSE)
|
||||
typedef unsigned long ULONG;
|
||||
typedef unsigned char BYTE;
|
||||
typedef int BOOL;
|
||||
#define MAX_PATH PATH_MAX
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d)
|
||||
#endif //_WIN32
|
||||
|
||||
// Misc C-runtime library headers
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
#include "math.h"
|
||||
|
||||
// min/max is not on math.h library
|
||||
// move outside win32 scope so it can compile on both platforms
|
||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
// Header file containing definition of globalvars_t and entvars_t
|
||||
typedef int func_t; //
|
||||
typedef int string_t; // from engine's pr_comp.h;
|
||||
typedef float vec_t; // needed before including progdefs.h
|
||||
|
||||
// Vector class
|
||||
#include "vector.h"
|
||||
|
||||
// Defining it as a (bogus) struct helps enforce type-checking
|
||||
#define vec3_t Vector
|
||||
|
||||
// Shared engine/DLL constants
|
||||
#include "const.h"
|
||||
#include "progdefs.h"
|
||||
#include "edict.h"
|
||||
|
||||
// Shared header describing protocol between engine and DLLs
|
||||
#include "eiface.h"
|
||||
|
||||
// Shared header between the client DLL and the game DLLs
|
||||
#include "cdll_dll.h"
|
||||
|
||||
#endif //EXTDLL_H
|
||||
|
||||
@@ -1,281 +1,280 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "monsters.h"
|
||||
#include "schedule.h"
|
||||
|
||||
#define FLYING_AE_FLAP (8)
|
||||
#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 )
|
||||
{
|
||||
// UNDONE: need to check more than the endpoint
|
||||
if (FBitSet(pev->flags, FL_SWIM) && (UTIL_PointContents(vecEnd) != CONTENTS_WATER))
|
||||
{
|
||||
// ALERT(at_aiconsole, "can't swim out of water\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TraceResult tr;
|
||||
|
||||
UTIL_TraceHull( vecStart + Vector( 0, 0, 32 ), vecEnd + Vector( 0, 0, 32 ), dont_ignore_monsters, large_hull, edict(), &tr );
|
||||
|
||||
// ALERT( at_console, "%.0f %.0f %.0f : ", vecStart.x, vecStart.y, vecStart.z );
|
||||
// ALERT( at_console, "%.0f %.0f %.0f\n", vecEnd.x, vecEnd.y, vecEnd.z );
|
||||
|
||||
if (pflDist)
|
||||
{
|
||||
*pflDist = ( (tr.vecEndPos - Vector( 0, 0, 32 )) - vecStart ).Length();// get the distance.
|
||||
}
|
||||
|
||||
// ALERT( at_console, "check %d %d %f\n", tr.fStartSolid, tr.fAllSolid, tr.flFraction );
|
||||
if (tr.fStartSolid || tr.flFraction < 1.0)
|
||||
{
|
||||
if ( pTarget && (pTarget == gpGlobals->trace_ent) )
|
||||
return LOCALMOVE_VALID;
|
||||
return LOCALMOVE_INVALID;
|
||||
}
|
||||
|
||||
return LOCALMOVE_VALID;
|
||||
}
|
||||
|
||||
|
||||
BOOL CMFlyingMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, edict_t *pTargetEnt, Vector *pApex )
|
||||
{
|
||||
return CMBaseMonster::FTriangulate( vecStart, vecEnd, flDist, pTargetEnt, pApex );
|
||||
}
|
||||
|
||||
|
||||
Activity CMFlyingMonster :: GetStoppedActivity( void )
|
||||
{
|
||||
if ( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else
|
||||
return ACT_IDLE;
|
||||
|
||||
return ACT_HOVER;
|
||||
}
|
||||
|
||||
|
||||
void CMFlyingMonster :: Stop( void )
|
||||
{
|
||||
Activity stopped = GetStoppedActivity();
|
||||
if ( m_IdealActivity != stopped )
|
||||
{
|
||||
m_flightSpeed = 0;
|
||||
m_IdealActivity = stopped;
|
||||
}
|
||||
pev->angles.z = 0;
|
||||
pev->angles.x = 0;
|
||||
m_vecTravel = g_vecZero;
|
||||
}
|
||||
|
||||
|
||||
float CMFlyingMonster :: ChangeYaw( int speed )
|
||||
{
|
||||
if ( pev->movetype == MOVETYPE_FLY )
|
||||
{
|
||||
float diff = FlYawDiff();
|
||||
float target = 0;
|
||||
|
||||
if ( m_IdealActivity != GetStoppedActivity() )
|
||||
{
|
||||
if ( diff < -20 )
|
||||
target = 90;
|
||||
else if ( diff > 20 )
|
||||
target = -90;
|
||||
}
|
||||
pev->angles.z = UTIL_Approach( target, pev->angles.z, 220.0 * gpGlobals->frametime );
|
||||
}
|
||||
return CMBaseMonster::ChangeYaw( speed );
|
||||
}
|
||||
|
||||
|
||||
void CMFlyingMonster :: Killed( entvars_t *pevAttacker, int iGib )
|
||||
{
|
||||
pev->movetype = MOVETYPE_STEP;
|
||||
ClearBits( pev->flags, FL_ONGROUND );
|
||||
pev->angles.z = 0;
|
||||
pev->angles.x = 0;
|
||||
CMBaseMonster::Killed( pevAttacker, iGib );
|
||||
}
|
||||
|
||||
|
||||
void CMFlyingMonster :: HandleAnimEvent( MonsterEvent_t *pEvent )
|
||||
{
|
||||
switch( pEvent->event )
|
||||
{
|
||||
case FLYING_AE_FLAP:
|
||||
m_flightSpeed = 400;
|
||||
break;
|
||||
|
||||
case FLYING_AE_FLAPSOUND:
|
||||
if ( m_pFlapSound )
|
||||
EMIT_SOUND( edict(), CHAN_BODY, m_pFlapSound, 1, ATTN_NORM );
|
||||
break;
|
||||
|
||||
default:
|
||||
CMBaseMonster::HandleAnimEvent( pEvent );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMFlyingMonster :: Move( float flInterval )
|
||||
{
|
||||
if ( pev->movetype == MOVETYPE_FLY )
|
||||
m_flGroundSpeed = m_flightSpeed;
|
||||
CMBaseMonster::Move( flInterval );
|
||||
}
|
||||
|
||||
|
||||
BOOL CMFlyingMonster:: ShouldAdvanceRoute( float flWaypointDist )
|
||||
{
|
||||
// Get true 3D distance to the goal so we actually reach the correct height
|
||||
if ( m_Route[ m_iRouteIndex ].iType & bits_MF_IS_GOAL )
|
||||
flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length();
|
||||
|
||||
if ( flWaypointDist <= 64 + (m_flGroundSpeed * gpGlobals->frametime) )
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void CMFlyingMonster::MoveExecute( edict_t *pTargetEnt, const Vector &vecDir, float flInterval )
|
||||
{
|
||||
if ( pev->movetype == MOVETYPE_FLY )
|
||||
{
|
||||
if ( gpGlobals->time - m_stopTime > 1.0 )
|
||||
{
|
||||
if ( m_IdealActivity != m_movementActivity )
|
||||
{
|
||||
m_IdealActivity = m_movementActivity;
|
||||
m_flGroundSpeed = m_flightSpeed = 200;
|
||||
}
|
||||
}
|
||||
Vector vecMove = pev->origin + (( vecDir + (m_vecTravel * m_momentum) ).Normalize() * (m_flGroundSpeed * flInterval));
|
||||
|
||||
if ( m_IdealActivity != m_movementActivity )
|
||||
{
|
||||
m_flightSpeed = UTIL_Approach( 100, m_flightSpeed, 75 * gpGlobals->frametime );
|
||||
if ( m_flightSpeed < 100 )
|
||||
m_stopTime = gpGlobals->time;
|
||||
}
|
||||
else
|
||||
m_flightSpeed = UTIL_Approach( 20, m_flightSpeed, 300 * gpGlobals->frametime );
|
||||
|
||||
if ( CheckLocalMove ( pev->origin, vecMove, pTargetEnt, NULL ) )
|
||||
{
|
||||
m_vecTravel = (vecMove - pev->origin);
|
||||
m_vecTravel = m_vecTravel.Normalize();
|
||||
UTIL_MoveToOrigin(ENT(pev), vecMove, (m_flGroundSpeed * flInterval), MOVE_STRAFE);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_IdealActivity = GetStoppedActivity();
|
||||
m_stopTime = gpGlobals->time;
|
||||
m_vecTravel = g_vecZero;
|
||||
}
|
||||
}
|
||||
else
|
||||
CMBaseMonster::MoveExecute( pTargetEnt, vecDir, flInterval );
|
||||
}
|
||||
|
||||
|
||||
float CMFlyingMonster::CeilingZ( const Vector &position )
|
||||
{
|
||||
TraceResult tr;
|
||||
|
||||
Vector minUp = position;
|
||||
Vector maxUp = position;
|
||||
maxUp.z += 4096.0;
|
||||
|
||||
UTIL_TraceLine(position, maxUp, ignore_monsters, NULL, &tr);
|
||||
if (tr.flFraction != 1.0)
|
||||
maxUp.z = tr.vecEndPos.z;
|
||||
|
||||
if ((pev->flags) & FL_SWIM)
|
||||
{
|
||||
return UTIL_WaterLevel( position, minUp.z, maxUp.z );
|
||||
}
|
||||
return maxUp.z;
|
||||
}
|
||||
|
||||
BOOL CMFlyingMonster::ProbeZ( const Vector &position, const Vector &probe, float *pFraction)
|
||||
{
|
||||
int conPosition = UTIL_PointContents(position);
|
||||
if ( (((pev->flags) & FL_SWIM) == FL_SWIM) ^ (conPosition == CONTENTS_WATER))
|
||||
{
|
||||
// SWIMING & !WATER
|
||||
// or FLYING & WATER
|
||||
//
|
||||
*pFraction = 0.0;
|
||||
return TRUE; // We hit a water boundary because we are where we don't belong.
|
||||
}
|
||||
int conProbe = UTIL_PointContents(probe);
|
||||
if (conProbe == conPosition)
|
||||
{
|
||||
// The probe is either entirely inside the water (for fish) or entirely
|
||||
// outside the water (for birds).
|
||||
//
|
||||
*pFraction = 1.0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Vector ProbeUnit = (probe-position).Normalize();
|
||||
float ProbeLength = (probe-position).Length();
|
||||
float maxProbeLength = ProbeLength;
|
||||
float minProbeLength = 0;
|
||||
|
||||
float diff = maxProbeLength - minProbeLength;
|
||||
while (diff > 1.0)
|
||||
{
|
||||
float midProbeLength = minProbeLength + diff/2.0;
|
||||
Vector midProbeVec = midProbeLength * ProbeUnit;
|
||||
if (UTIL_PointContents(position+midProbeVec) == conPosition)
|
||||
{
|
||||
minProbeLength = midProbeLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxProbeLength = midProbeLength;
|
||||
}
|
||||
diff = maxProbeLength - minProbeLength;
|
||||
}
|
||||
*pFraction = minProbeLength/ProbeLength;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
float CMFlyingMonster::FloorZ( const Vector &position )
|
||||
{
|
||||
TraceResult tr;
|
||||
|
||||
Vector down = position;
|
||||
down.z -= 2048;
|
||||
|
||||
UTIL_TraceLine( position, down, ignore_monsters, NULL, &tr );
|
||||
|
||||
if ( tr.flFraction != 1.0 )
|
||||
return tr.vecEndPos.z;
|
||||
|
||||
return down.z;
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "cmflyingmonster.h"
|
||||
#include "monsters.h"
|
||||
#include "schedule.h"
|
||||
|
||||
#define FLYING_AE_FLAP (8)
|
||||
#define FLYING_AE_FLAPSOUND (9)
|
||||
|
||||
|
||||
int CMFlyingMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, edict_t *pTarget, float *pflDist )
|
||||
{
|
||||
// UNDONE: need to check more than the endpoint
|
||||
if (FBitSet(pev->flags, FL_SWIM) && (UTIL_PointContents(vecEnd) != CONTENTS_WATER))
|
||||
{
|
||||
// ALERT(at_aiconsole, "can't swim out of water\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TraceResult tr;
|
||||
|
||||
UTIL_TraceHull( vecStart + Vector( 0, 0, 32 ), vecEnd + Vector( 0, 0, 32 ), dont_ignore_monsters, large_hull, edict(), &tr );
|
||||
|
||||
// ALERT( at_console, "%.0f %.0f %.0f : ", vecStart.x, vecStart.y, vecStart.z );
|
||||
// ALERT( at_console, "%.0f %.0f %.0f\n", vecEnd.x, vecEnd.y, vecEnd.z );
|
||||
|
||||
if (pflDist)
|
||||
{
|
||||
*pflDist = ( (tr.vecEndPos - Vector( 0, 0, 32 )) - vecStart ).Length();// get the distance.
|
||||
}
|
||||
|
||||
// ALERT( at_console, "check %d %d %f\n", tr.fStartSolid, tr.fAllSolid, tr.flFraction );
|
||||
if (tr.fStartSolid || tr.flFraction < 1.0)
|
||||
{
|
||||
if ( pTarget && (pTarget == gpGlobals->trace_ent) )
|
||||
return LOCALMOVE_VALID;
|
||||
return LOCALMOVE_INVALID;
|
||||
}
|
||||
|
||||
return LOCALMOVE_VALID;
|
||||
}
|
||||
|
||||
|
||||
BOOL CMFlyingMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, edict_t *pTargetEnt, Vector *pApex )
|
||||
{
|
||||
return CMBaseMonster::FTriangulate( vecStart, vecEnd, flDist, pTargetEnt, pApex );
|
||||
}
|
||||
|
||||
|
||||
Activity CMFlyingMonster :: GetStoppedActivity( void )
|
||||
{
|
||||
if ( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else
|
||||
return ACT_IDLE;
|
||||
|
||||
return ACT_HOVER;
|
||||
}
|
||||
|
||||
|
||||
void CMFlyingMonster :: Stop( void )
|
||||
{
|
||||
Activity stopped = GetStoppedActivity();
|
||||
if ( m_IdealActivity != stopped )
|
||||
{
|
||||
m_flightSpeed = 0;
|
||||
m_IdealActivity = stopped;
|
||||
}
|
||||
pev->angles.z = 0;
|
||||
pev->angles.x = 0;
|
||||
m_vecTravel = g_vecZero;
|
||||
}
|
||||
|
||||
|
||||
float CMFlyingMonster :: ChangeYaw( int speed )
|
||||
{
|
||||
if ( pev->movetype == MOVETYPE_FLY )
|
||||
{
|
||||
float diff = FlYawDiff();
|
||||
float target = 0;
|
||||
|
||||
if ( m_IdealActivity != GetStoppedActivity() )
|
||||
{
|
||||
if ( diff < -20 )
|
||||
target = 90;
|
||||
else if ( diff > 20 )
|
||||
target = -90;
|
||||
}
|
||||
pev->angles.z = UTIL_Approach( target, pev->angles.z, 220.0 * gpGlobals->frametime );
|
||||
}
|
||||
return CMBaseMonster::ChangeYaw( speed );
|
||||
}
|
||||
|
||||
|
||||
void CMFlyingMonster :: Killed( entvars_t *pevAttacker, int iGib )
|
||||
{
|
||||
pev->movetype = MOVETYPE_STEP;
|
||||
ClearBits( pev->flags, FL_ONGROUND );
|
||||
pev->angles.z = 0;
|
||||
pev->angles.x = 0;
|
||||
CMBaseMonster::Killed( pevAttacker, iGib );
|
||||
}
|
||||
|
||||
|
||||
void CMFlyingMonster :: HandleAnimEvent( MonsterEvent_t *pEvent )
|
||||
{
|
||||
switch( pEvent->event )
|
||||
{
|
||||
case FLYING_AE_FLAP:
|
||||
m_flightSpeed = 400;
|
||||
break;
|
||||
|
||||
case FLYING_AE_FLAPSOUND:
|
||||
if ( m_pFlapSound )
|
||||
EMIT_SOUND( edict(), CHAN_BODY, m_pFlapSound, 1, ATTN_NORM );
|
||||
break;
|
||||
|
||||
default:
|
||||
CMBaseMonster::HandleAnimEvent( pEvent );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMFlyingMonster :: Move( float flInterval )
|
||||
{
|
||||
if ( pev->movetype == MOVETYPE_FLY )
|
||||
m_flGroundSpeed = m_flightSpeed;
|
||||
CMBaseMonster::Move( flInterval );
|
||||
}
|
||||
|
||||
|
||||
BOOL CMFlyingMonster:: ShouldAdvanceRoute( float flWaypointDist )
|
||||
{
|
||||
// Get true 3D distance to the goal so we actually reach the correct height
|
||||
if ( m_Route[ m_iRouteIndex ].iType & bits_MF_IS_GOAL )
|
||||
flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length();
|
||||
|
||||
if ( flWaypointDist <= 64 + (m_flGroundSpeed * gpGlobals->frametime) )
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void CMFlyingMonster::MoveExecute( edict_t *pTargetEnt, const Vector &vecDir, float flInterval )
|
||||
{
|
||||
if ( pev->movetype == MOVETYPE_FLY )
|
||||
{
|
||||
if ( gpGlobals->time - m_stopTime > 1.0 )
|
||||
{
|
||||
if ( m_IdealActivity != m_movementActivity )
|
||||
{
|
||||
m_IdealActivity = m_movementActivity;
|
||||
m_flGroundSpeed = m_flightSpeed = 200;
|
||||
}
|
||||
}
|
||||
Vector vecMove = pev->origin + (( vecDir + (m_vecTravel * m_momentum) ).Normalize() * (m_flGroundSpeed * flInterval));
|
||||
|
||||
if ( m_IdealActivity != m_movementActivity )
|
||||
{
|
||||
m_flightSpeed = UTIL_Approach( 100, m_flightSpeed, 75 * gpGlobals->frametime );
|
||||
if ( m_flightSpeed < 100 )
|
||||
m_stopTime = gpGlobals->time;
|
||||
}
|
||||
else
|
||||
m_flightSpeed = UTIL_Approach( 20, m_flightSpeed, 300 * gpGlobals->frametime );
|
||||
|
||||
if ( CheckLocalMove ( pev->origin, vecMove, pTargetEnt, NULL ) )
|
||||
{
|
||||
m_vecTravel = (vecMove - pev->origin);
|
||||
m_vecTravel = m_vecTravel.Normalize();
|
||||
UTIL_MoveToOrigin(ENT(pev), vecMove, (m_flGroundSpeed * flInterval), MOVE_STRAFE);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_IdealActivity = GetStoppedActivity();
|
||||
m_stopTime = gpGlobals->time;
|
||||
m_vecTravel = g_vecZero;
|
||||
}
|
||||
}
|
||||
else
|
||||
CMBaseMonster::MoveExecute( pTargetEnt, vecDir, flInterval );
|
||||
}
|
||||
|
||||
|
||||
float CMFlyingMonster::CeilingZ( const Vector &position )
|
||||
{
|
||||
TraceResult tr;
|
||||
|
||||
Vector minUp = position;
|
||||
Vector maxUp = position;
|
||||
maxUp.z += 4096.0;
|
||||
|
||||
UTIL_TraceLine(position, maxUp, ignore_monsters, NULL, &tr);
|
||||
if (tr.flFraction != 1.0)
|
||||
maxUp.z = tr.vecEndPos.z;
|
||||
|
||||
if ((pev->flags) & FL_SWIM)
|
||||
{
|
||||
return UTIL_WaterLevel( position, minUp.z, maxUp.z );
|
||||
}
|
||||
return maxUp.z;
|
||||
}
|
||||
|
||||
BOOL CMFlyingMonster::ProbeZ( const Vector &position, const Vector &probe, float *pFraction)
|
||||
{
|
||||
int conPosition = UTIL_PointContents(position);
|
||||
if ( (((pev->flags) & FL_SWIM) == FL_SWIM) ^ (conPosition == CONTENTS_WATER))
|
||||
{
|
||||
// SWIMING & !WATER
|
||||
// or FLYING & WATER
|
||||
//
|
||||
*pFraction = 0.0;
|
||||
return TRUE; // We hit a water boundary because we are where we don't belong.
|
||||
}
|
||||
int conProbe = UTIL_PointContents(probe);
|
||||
if (conProbe == conPosition)
|
||||
{
|
||||
// The probe is either entirely inside the water (for fish) or entirely
|
||||
// outside the water (for birds).
|
||||
//
|
||||
*pFraction = 1.0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Vector ProbeUnit = (probe-position).Normalize();
|
||||
float ProbeLength = (probe-position).Length();
|
||||
float maxProbeLength = ProbeLength;
|
||||
float minProbeLength = 0;
|
||||
|
||||
float diff = maxProbeLength - minProbeLength;
|
||||
while (diff > 1.0)
|
||||
{
|
||||
float midProbeLength = minProbeLength + diff/2.0;
|
||||
Vector midProbeVec = midProbeLength * ProbeUnit;
|
||||
if (UTIL_PointContents(position+midProbeVec) == conPosition)
|
||||
{
|
||||
minProbeLength = midProbeLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxProbeLength = midProbeLength;
|
||||
}
|
||||
diff = maxProbeLength - minProbeLength;
|
||||
}
|
||||
*pFraction = minProbeLength/ProbeLength;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
float CMFlyingMonster::FloorZ( const Vector &position )
|
||||
{
|
||||
TraceResult tr;
|
||||
|
||||
Vector down = position;
|
||||
down.z -= 2048;
|
||||
|
||||
UTIL_TraceLine( position, down, ignore_monsters, NULL, &tr );
|
||||
|
||||
if ( tr.flFraction != 1.0 )
|
||||
return tr.vecEndPos.z;
|
||||
|
||||
return down.z;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,70 +1,70 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef FUNC_BREAK_H
|
||||
#define FUNC_BREAK_H
|
||||
|
||||
typedef enum { expRandom, expDirected} Explosions;
|
||||
typedef enum { matGlass = 0, matWood, matMetal, matFlesh, matCinderBlock, matCeilingTile, matComputer, matUnbreakableGlass, matRocks, matNone, matLastMaterial } Materials;
|
||||
|
||||
#define NUM_SHARDS 6 // this many shards spawned when breakable objects break;
|
||||
|
||||
class CMBreakable : public CMBaseDelay
|
||||
{
|
||||
public:
|
||||
// basic functions
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
void KeyValue( KeyValueData* pkvd);
|
||||
void EXPORT BreakTouch( CMBaseEntity *pOther );
|
||||
void Use( CMBaseEntity *pActivator, CMBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
void DamageSound( void );
|
||||
|
||||
// breakables use an overridden takedamage
|
||||
virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
|
||||
// To spark when hit
|
||||
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
|
||||
|
||||
BOOL IsBreakable( void );
|
||||
BOOL SparkWhenHit( void );
|
||||
|
||||
int DamageDecal( int bitsDamageType );
|
||||
|
||||
void EXPORT Die( void );
|
||||
virtual int ObjectCaps( void ) { return (CMBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); }
|
||||
|
||||
inline BOOL Explodable( void ) { return ExplosionMagnitude() > 0; }
|
||||
inline int ExplosionMagnitude( void ) { return pev->impulse; }
|
||||
inline void ExplosionSetMagnitude( int magnitude ) { pev->impulse = magnitude; }
|
||||
|
||||
static void MaterialSoundPrecache( Materials precacheMaterial );
|
||||
static void MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume );
|
||||
static const char **MaterialSoundList( Materials precacheMaterial, int &soundCount );
|
||||
|
||||
static const char *pSoundsWood[];
|
||||
static const char *pSoundsFlesh[];
|
||||
static const char *pSoundsGlass[];
|
||||
static const char *pSoundsMetal[];
|
||||
static const char *pSoundsConcrete[];
|
||||
static const char *pSpawnObjects[];
|
||||
|
||||
Materials m_Material;
|
||||
Explosions m_Explosion;
|
||||
int m_idShard;
|
||||
float m_angle;
|
||||
int m_iszGibModel;
|
||||
int m_iszSpawnObject;
|
||||
};
|
||||
|
||||
#endif // FUNC_BREAK_H
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef FUNC_BREAK_H
|
||||
#define FUNC_BREAK_H
|
||||
|
||||
typedef enum { expRandom, expDirected} Explosions;
|
||||
typedef enum { matGlass = 0, matWood, matMetal, matFlesh, matCinderBlock, matCeilingTile, matComputer, matUnbreakableGlass, matRocks, matNone, matLastMaterial } Materials;
|
||||
|
||||
#define NUM_SHARDS 6 // this many shards spawned when breakable objects break;
|
||||
|
||||
class CMBreakable : public CMBaseDelay
|
||||
{
|
||||
public:
|
||||
// basic functions
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
void KeyValue( KeyValueData* pkvd);
|
||||
void EXPORT BreakTouch( CMBaseEntity *pOther );
|
||||
void Use( CMBaseEntity *pActivator, CMBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
void DamageSound( void );
|
||||
|
||||
// breakables use an overridden takedamage
|
||||
virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
|
||||
// To spark when hit
|
||||
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
|
||||
|
||||
BOOL IsBreakable( void );
|
||||
BOOL SparkWhenHit( void );
|
||||
|
||||
int DamageDecal( int bitsDamageType );
|
||||
|
||||
void EXPORT Die( void );
|
||||
virtual int ObjectCaps( void ) { return (CMBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); }
|
||||
|
||||
inline BOOL Explodable( void ) { return ExplosionMagnitude() > 0; }
|
||||
inline int ExplosionMagnitude( void ) { return pev->impulse; }
|
||||
inline void ExplosionSetMagnitude( int magnitude ) { pev->impulse = magnitude; }
|
||||
|
||||
static void MaterialSoundPrecache( Materials precacheMaterial );
|
||||
static void MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume );
|
||||
static const char **MaterialSoundList( Materials precacheMaterial, int &soundCount );
|
||||
|
||||
static const char *pSoundsWood[];
|
||||
static const char *pSoundsFlesh[];
|
||||
static const char *pSoundsGlass[];
|
||||
static const char *pSoundsMetal[];
|
||||
static const char *pSoundsConcrete[];
|
||||
static const char *pSpawnObjects[];
|
||||
|
||||
Materials m_Material;
|
||||
Explosions m_Explosion;
|
||||
int m_idShard;
|
||||
float m_angle;
|
||||
int m_iszGibModel;
|
||||
int m_iszSpawnObject;
|
||||
};
|
||||
|
||||
#endif // FUNC_BREAK_H
|
||||
|
||||
3089
src/dlls/gargantua.cpp
Executable file → Normal file
3089
src/dlls/gargantua.cpp
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,466 +1,466 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
/*
|
||||
|
||||
===== generic grenade.cpp ========================================================
|
||||
|
||||
*/
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "monsters.h"
|
||||
#include "weapons.h"
|
||||
#include "nodes.h"
|
||||
#include "decals.h"
|
||||
#include "explode.h"
|
||||
|
||||
|
||||
//===================grenade
|
||||
|
||||
// Grenades flagged with this will be triggered when the owner calls detonateSatchelCharges
|
||||
#define SF_DETONATE 0x0001
|
||||
|
||||
//
|
||||
// Grenade Explode
|
||||
//
|
||||
void CMGrenade::Explode( Vector vecSrc, Vector vecAim )
|
||||
{
|
||||
TraceResult tr;
|
||||
UTIL_TraceLine ( pev->origin, pev->origin + Vector ( 0, 0, -32 ), ignore_monsters, ENT(pev), & tr);
|
||||
|
||||
Explode( &tr, DMG_BLAST );
|
||||
}
|
||||
|
||||
// UNDONE: temporary scorching for PreAlpha - find a less sleazy permenant solution.
|
||||
void CMGrenade::Explode( TraceResult *pTrace, int bitsDamageType )
|
||||
{
|
||||
float flRndSound;// sound randomizer
|
||||
|
||||
pev->model = iStringNull;//invisible
|
||||
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);
|
||||
}
|
||||
|
||||
int iContents = UTIL_PointContents ( pev->origin );
|
||||
|
||||
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
|
||||
WRITE_BYTE( TE_EXPLOSION ); // This makes a dynamic light and the explosion sprites/sound
|
||||
WRITE_COORD( pev->origin.x ); // Send to PAS because of the sound
|
||||
WRITE_COORD( pev->origin.y );
|
||||
WRITE_COORD( pev->origin.z );
|
||||
if (iContents != CONTENTS_WATER)
|
||||
{
|
||||
WRITE_SHORT( g_sModelIndexFireball );
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITE_SHORT( g_sModelIndexWExplosion );
|
||||
}
|
||||
WRITE_BYTE( (pev->dmg - 50) * .60 ); // scale * 10
|
||||
WRITE_BYTE( 15 ); // framerate
|
||||
WRITE_BYTE( TE_EXPLFLAG_NONE );
|
||||
MESSAGE_END();
|
||||
|
||||
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, bitsDamageType );
|
||||
|
||||
if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 )
|
||||
{
|
||||
UTIL_DecalTrace( pTrace, DECAL_SCORCH1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_DecalTrace( pTrace, DECAL_SCORCH2 );
|
||||
}
|
||||
|
||||
flRndSound = RANDOM_FLOAT( 0 , 1 );
|
||||
|
||||
switch ( RANDOM_LONG( 0, 2 ) )
|
||||
{
|
||||
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris1.wav", 0.55, ATTN_NORM); break;
|
||||
case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris2.wav", 0.55, ATTN_NORM); break;
|
||||
case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris3.wav", 0.55, ATTN_NORM); break;
|
||||
}
|
||||
|
||||
pev->effects |= EF_NODRAW;
|
||||
SetThink( &CMGrenade::Smoke );
|
||||
pev->velocity = g_vecZero;
|
||||
pev->nextthink = gpGlobals->time + 0.3;
|
||||
|
||||
/*jlb
|
||||
if (iContents != CONTENTS_WATER)
|
||||
{
|
||||
int sparkCount = RANDOM_LONG(0,3);
|
||||
for ( int i = 0; i < sparkCount; i++ )
|
||||
Create( "spark_shower", pev->origin, pTrace->vecPlaneNormal, NULL );
|
||||
}
|
||||
jlb*/
|
||||
}
|
||||
|
||||
|
||||
void CMGrenade::Smoke( void )
|
||||
{
|
||||
if (UTIL_PointContents ( pev->origin ) == CONTENTS_WATER)
|
||||
{
|
||||
UTIL_Bubbles( pev->origin - Vector( 64, 64, 64 ), pev->origin + Vector( 64, 64, 64 ), 100 );
|
||||
}
|
||||
else
|
||||
{
|
||||
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
||||
WRITE_BYTE( TE_SMOKE );
|
||||
WRITE_COORD( pev->origin.x );
|
||||
WRITE_COORD( pev->origin.y );
|
||||
WRITE_COORD( pev->origin.z );
|
||||
WRITE_SHORT( g_sModelIndexSmoke );
|
||||
WRITE_BYTE( (pev->dmg - 50) * 0.80 ); // scale * 10
|
||||
WRITE_BYTE( 12 ); // framerate
|
||||
MESSAGE_END();
|
||||
}
|
||||
UTIL_Remove( this->edict() );
|
||||
}
|
||||
|
||||
void CMGrenade::Killed( entvars_t *pevAttacker, int iGib )
|
||||
{
|
||||
Detonate( );
|
||||
}
|
||||
|
||||
|
||||
// Timed grenade, this think is called when time runs out.
|
||||
void CMGrenade::DetonateUse( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
SetThink( &CMGrenade::Detonate );
|
||||
pev->nextthink = gpGlobals->time;
|
||||
}
|
||||
|
||||
void CMGrenade::PreDetonate( void )
|
||||
{
|
||||
SetThink( &CMGrenade::Detonate );
|
||||
pev->nextthink = gpGlobals->time + 1;
|
||||
}
|
||||
|
||||
|
||||
void CMGrenade::Detonate( void )
|
||||
{
|
||||
TraceResult tr;
|
||||
Vector vecSpot;// trace starts here!
|
||||
|
||||
vecSpot = pev->origin + Vector ( 0 , 0 , 8 );
|
||||
UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -40 ), ignore_monsters, ENT(pev), & tr);
|
||||
|
||||
Explode( &tr, DMG_BLAST );
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Contact grenade, explode when it touches something
|
||||
//
|
||||
void CMGrenade::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, DMG_BLAST );
|
||||
}
|
||||
|
||||
|
||||
void CMGrenade::DangerSoundThink( void )
|
||||
{
|
||||
if (!IsInWorld())
|
||||
{
|
||||
UTIL_Remove( this->edict() );
|
||||
return;
|
||||
}
|
||||
|
||||
pev->nextthink = gpGlobals->time + 0.2;
|
||||
|
||||
if (pev->waterlevel != 0)
|
||||
{
|
||||
pev->velocity = pev->velocity * 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMGrenade::BounceTouch( edict_t *pOther )
|
||||
{
|
||||
// don't hit the guy that launched this grenade
|
||||
if ( pOther == pev->owner )
|
||||
return;
|
||||
|
||||
// only do damage if we're moving fairly fast
|
||||
if (m_flNextAttack < gpGlobals->time && pev->velocity.Length() > 100)
|
||||
{
|
||||
entvars_t *pevOwner = VARS( pev->owner );
|
||||
if (pevOwner)
|
||||
{
|
||||
TraceResult tr = UTIL_GetGlobalTrace( );
|
||||
ClearMultiDamage( );
|
||||
|
||||
if (UTIL_IsPlayer(pOther))
|
||||
UTIL_TraceAttack(pOther, pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB );
|
||||
else if (pOther->v.euser4 != NULL)
|
||||
{
|
||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||
pMonster->TraceAttack(pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB );
|
||||
}
|
||||
|
||||
ApplyMultiDamage( pev, pevOwner);
|
||||
}
|
||||
m_flNextAttack = gpGlobals->time + 1.0; // debounce
|
||||
}
|
||||
|
||||
Vector vecTestVelocity;
|
||||
// pev->avelocity = Vector (300, 300, 300);
|
||||
|
||||
// this is my heuristic for modulating the grenade velocity because grenades dropped purely vertical
|
||||
// or thrown very far tend to slow down too quickly for me to always catch just by testing velocity.
|
||||
// trimming the Z velocity a bit seems to help quite a bit.
|
||||
vecTestVelocity = pev->velocity;
|
||||
vecTestVelocity.z *= 0.45;
|
||||
|
||||
if ( !m_fRegisteredSound && vecTestVelocity.Length() <= 60 )
|
||||
{
|
||||
//ALERT( at_console, "Grenade Registered!: %f\n", vecTestVelocity.Length() );
|
||||
|
||||
// grenade is moving really slow. It's probably very close to where it will ultimately stop moving.
|
||||
// go ahead and emit the danger sound.
|
||||
|
||||
// register a radius louder than the explosion, so we make sure everyone gets out of the way
|
||||
m_fRegisteredSound = TRUE;
|
||||
}
|
||||
|
||||
if (pev->flags & FL_ONGROUND)
|
||||
{
|
||||
// add a bit of static friction
|
||||
pev->velocity = pev->velocity * 0.8;
|
||||
|
||||
pev->sequence = RANDOM_LONG( 1, 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// play bounce sound
|
||||
BounceSound();
|
||||
}
|
||||
pev->framerate = pev->velocity.Length() / 200.0;
|
||||
if (pev->framerate > 1.0)
|
||||
pev->framerate = 1;
|
||||
else if (pev->framerate < 0.5)
|
||||
pev->framerate = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CMGrenade::SlideTouch( edict_t *pOther )
|
||||
{
|
||||
// don't hit the guy that launched this grenade
|
||||
if ( pOther == pev->owner )
|
||||
return;
|
||||
|
||||
// pev->avelocity = Vector (300, 300, 300);
|
||||
|
||||
if (pev->flags & FL_ONGROUND)
|
||||
{
|
||||
// add a bit of static friction
|
||||
pev->velocity = pev->velocity * 0.95;
|
||||
|
||||
if (pev->velocity.x != 0 || pev->velocity.y != 0)
|
||||
{
|
||||
// maintain sliding sound
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BounceSound();
|
||||
}
|
||||
}
|
||||
|
||||
void CMGrenade :: BounceSound( void )
|
||||
{
|
||||
switch ( RANDOM_LONG( 0, 2 ) )
|
||||
{
|
||||
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/grenade_hit1.wav", 0.25, ATTN_NORM); break;
|
||||
case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/grenade_hit2.wav", 0.25, ATTN_NORM); break;
|
||||
case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/grenade_hit3.wav", 0.25, ATTN_NORM); break;
|
||||
}
|
||||
}
|
||||
|
||||
void CMGrenade :: TumbleThink( void )
|
||||
{
|
||||
if (!IsInWorld())
|
||||
{
|
||||
UTIL_Remove( this->edict() );
|
||||
return;
|
||||
}
|
||||
|
||||
StudioFrameAdvance( );
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
|
||||
if (pev->dmgtime <= gpGlobals->time)
|
||||
{
|
||||
SetThink( &CMGrenade::Detonate );
|
||||
}
|
||||
if (pev->waterlevel != 0)
|
||||
{
|
||||
pev->velocity = pev->velocity * 0.5;
|
||||
pev->framerate = 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMGrenade:: Spawn( void )
|
||||
{
|
||||
pev->movetype = MOVETYPE_BOUNCE;
|
||||
pev->classname = MAKE_STRING( "grenade" );
|
||||
|
||||
pev->solid = SOLID_BBOX;
|
||||
|
||||
SET_MODEL(ENT(pev), "models/grenade.mdl");
|
||||
UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0));
|
||||
|
||||
pev->dmg = 100;
|
||||
m_fRegisteredSound = FALSE;
|
||||
}
|
||||
|
||||
|
||||
CMGrenade *CMGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity )
|
||||
{
|
||||
CMGrenade *pGrenade = CreateClassPtr( (CMGrenade *)NULL );
|
||||
|
||||
if (pGrenade == NULL) // no free monster edicts left?
|
||||
return NULL;
|
||||
|
||||
pGrenade->Spawn();
|
||||
// contact grenades arc lower
|
||||
pGrenade->pev->gravity = 0.5;// lower gravity since grenade is aerodynamic and engine doesn't know it.
|
||||
UTIL_SetOrigin( pGrenade->pev, vecStart );
|
||||
pGrenade->pev->velocity = vecVelocity;
|
||||
pGrenade->pev->angles = UTIL_VecToAngles (pGrenade->pev->velocity);
|
||||
pGrenade->pev->owner = ENT(pevOwner);
|
||||
|
||||
// make monsters afaid of it while in the air
|
||||
pGrenade->SetThink( &CMGrenade::DangerSoundThink );
|
||||
pGrenade->pev->nextthink = gpGlobals->time;
|
||||
|
||||
// Tumble in air
|
||||
pGrenade->pev->avelocity.x = RANDOM_FLOAT ( -100, -500 );
|
||||
|
||||
// Explode on contact
|
||||
pGrenade->SetTouch( &CMGrenade::ExplodeTouch );
|
||||
|
||||
pGrenade->pev->dmg = gSkillData.monDmgM203Grenade;
|
||||
|
||||
return pGrenade;
|
||||
}
|
||||
|
||||
|
||||
CMGrenade * CMGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time )
|
||||
{
|
||||
CMGrenade *pGrenade = CreateClassPtr( (CMGrenade *)NULL );
|
||||
|
||||
if (pGrenade == NULL) // no free monster edicts left?
|
||||
return NULL;
|
||||
|
||||
pGrenade->Spawn();
|
||||
UTIL_SetOrigin( pGrenade->pev, vecStart );
|
||||
pGrenade->pev->velocity = vecVelocity;
|
||||
pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity);
|
||||
pGrenade->pev->owner = ENT(pevOwner);
|
||||
|
||||
pGrenade->SetTouch( &CMGrenade::BounceTouch ); // Bounce if touched
|
||||
|
||||
// Take one second off of the desired detonation time and set the think to PreDetonate. PreDetonate
|
||||
// will insert a DANGER sound into the world sound list and delay detonation for one second so that
|
||||
// the grenade explodes after the exact amount of time specified in the call to ShootTimed().
|
||||
|
||||
pGrenade->pev->dmgtime = gpGlobals->time + time;
|
||||
pGrenade->SetThink( &CMGrenade::TumbleThink );
|
||||
pGrenade->pev->nextthink = gpGlobals->time + 0.1;
|
||||
if (time < 0.1)
|
||||
{
|
||||
pGrenade->pev->nextthink = gpGlobals->time;
|
||||
pGrenade->pev->velocity = Vector( 0, 0, 0 );
|
||||
}
|
||||
|
||||
pGrenade->pev->sequence = RANDOM_LONG( 3, 6 );
|
||||
pGrenade->pev->framerate = 1.0;
|
||||
|
||||
// Tumble through the air
|
||||
// pGrenade->pev->avelocity.x = -400;
|
||||
|
||||
pGrenade->pev->gravity = 0.5;
|
||||
pGrenade->pev->friction = 0.8;
|
||||
|
||||
SET_MODEL(ENT(pGrenade->pev), "models/w_grenade.mdl");
|
||||
pGrenade->pev->dmg = 100;
|
||||
|
||||
return pGrenade;
|
||||
}
|
||||
|
||||
|
||||
CMGrenade * CMGrenade :: ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity )
|
||||
{
|
||||
CMGrenade *pGrenade = CreateClassPtr( (CMGrenade *)NULL );
|
||||
|
||||
if (pGrenade == NULL) // no free monster edicts left?
|
||||
return NULL;
|
||||
|
||||
pGrenade->pev->movetype = MOVETYPE_BOUNCE;
|
||||
pGrenade->pev->classname = MAKE_STRING( "grenade" );
|
||||
|
||||
pGrenade->pev->solid = SOLID_BBOX;
|
||||
|
||||
SET_MODEL(ENT(pGrenade->pev), "models/grenade.mdl"); // Change this to satchel charge model
|
||||
|
||||
UTIL_SetSize(pGrenade->pev, Vector( 0, 0, 0), Vector(0, 0, 0));
|
||||
|
||||
pGrenade->pev->dmg = 200;
|
||||
UTIL_SetOrigin( pGrenade->pev, vecStart );
|
||||
pGrenade->pev->velocity = vecVelocity;
|
||||
pGrenade->pev->angles = g_vecZero;
|
||||
pGrenade->pev->owner = ENT(pevOwner);
|
||||
|
||||
// Detonate in "time" seconds
|
||||
pGrenade->SetThink( &CMGrenade::SUB_DoNothing );
|
||||
pGrenade->SetUse( &CMGrenade::DetonateUse );
|
||||
pGrenade->SetTouch( &CMGrenade::SlideTouch );
|
||||
pGrenade->pev->spawnflags = SF_DETONATE;
|
||||
|
||||
pGrenade->pev->friction = 0.9;
|
||||
|
||||
return pGrenade;
|
||||
}
|
||||
|
||||
//======================end grenade
|
||||
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
/*
|
||||
|
||||
===== generic grenade.cpp ========================================================
|
||||
|
||||
*/
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "monsters.h"
|
||||
#include "weapons.h"
|
||||
#include "nodes.h"
|
||||
#include "decals.h"
|
||||
#include "explode.h"
|
||||
|
||||
|
||||
//===================grenade
|
||||
|
||||
// Grenades flagged with this will be triggered when the owner calls detonateSatchelCharges
|
||||
#define SF_DETONATE 0x0001
|
||||
|
||||
//
|
||||
// Grenade Explode
|
||||
//
|
||||
void CMGrenade::Explode( Vector vecSrc, Vector vecAim )
|
||||
{
|
||||
TraceResult tr;
|
||||
UTIL_TraceLine ( pev->origin, pev->origin + Vector ( 0, 0, -32 ), ignore_monsters, ENT(pev), & tr);
|
||||
|
||||
Explode( &tr, DMG_BLAST );
|
||||
}
|
||||
|
||||
// UNDONE: temporary scorching for PreAlpha - find a less sleazy permenant solution.
|
||||
void CMGrenade::Explode( TraceResult *pTrace, int bitsDamageType )
|
||||
{
|
||||
float flRndSound;// sound randomizer
|
||||
|
||||
pev->model = iStringNull;//invisible
|
||||
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);
|
||||
}
|
||||
|
||||
int iContents = UTIL_PointContents ( pev->origin );
|
||||
|
||||
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
|
||||
WRITE_BYTE( TE_EXPLOSION ); // This makes a dynamic light and the explosion sprites/sound
|
||||
WRITE_COORD( pev->origin.x ); // Send to PAS because of the sound
|
||||
WRITE_COORD( pev->origin.y );
|
||||
WRITE_COORD( pev->origin.z );
|
||||
if (iContents != CONTENTS_WATER)
|
||||
{
|
||||
WRITE_SHORT( g_sModelIndexFireball );
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITE_SHORT( g_sModelIndexWExplosion );
|
||||
}
|
||||
WRITE_BYTE( (pev->dmg - 50) * .60 ); // scale * 10
|
||||
WRITE_BYTE( 15 ); // framerate
|
||||
WRITE_BYTE( TE_EXPLFLAG_NONE );
|
||||
MESSAGE_END();
|
||||
|
||||
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, bitsDamageType );
|
||||
|
||||
if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 )
|
||||
{
|
||||
UTIL_DecalTrace( pTrace, DECAL_SCORCH1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_DecalTrace( pTrace, DECAL_SCORCH2 );
|
||||
}
|
||||
|
||||
flRndSound = RANDOM_FLOAT( 0 , 1 );
|
||||
|
||||
switch ( RANDOM_LONG( 0, 2 ) )
|
||||
{
|
||||
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris1.wav", 0.55, ATTN_NORM); break;
|
||||
case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris2.wav", 0.55, ATTN_NORM); break;
|
||||
case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris3.wav", 0.55, ATTN_NORM); break;
|
||||
}
|
||||
|
||||
pev->effects |= EF_NODRAW;
|
||||
SetThink( &CMGrenade::Smoke );
|
||||
pev->velocity = g_vecZero;
|
||||
pev->nextthink = gpGlobals->time + 0.3;
|
||||
|
||||
/*jlb
|
||||
if (iContents != CONTENTS_WATER)
|
||||
{
|
||||
int sparkCount = RANDOM_LONG(0,3);
|
||||
for ( int i = 0; i < sparkCount; i++ )
|
||||
Create( "spark_shower", pev->origin, pTrace->vecPlaneNormal, NULL );
|
||||
}
|
||||
jlb*/
|
||||
}
|
||||
|
||||
|
||||
void CMGrenade::Smoke( void )
|
||||
{
|
||||
if (UTIL_PointContents ( pev->origin ) == CONTENTS_WATER)
|
||||
{
|
||||
UTIL_Bubbles( pev->origin - Vector( 64, 64, 64 ), pev->origin + Vector( 64, 64, 64 ), 100 );
|
||||
}
|
||||
else
|
||||
{
|
||||
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
|
||||
WRITE_BYTE( TE_SMOKE );
|
||||
WRITE_COORD( pev->origin.x );
|
||||
WRITE_COORD( pev->origin.y );
|
||||
WRITE_COORD( pev->origin.z );
|
||||
WRITE_SHORT( g_sModelIndexSmoke );
|
||||
WRITE_BYTE( (pev->dmg - 50) * 0.80 ); // scale * 10
|
||||
WRITE_BYTE( 12 ); // framerate
|
||||
MESSAGE_END();
|
||||
}
|
||||
UTIL_Remove( this->edict() );
|
||||
}
|
||||
|
||||
void CMGrenade::Killed( entvars_t *pevAttacker, int iGib )
|
||||
{
|
||||
Detonate( );
|
||||
}
|
||||
|
||||
|
||||
// Timed grenade, this think is called when time runs out.
|
||||
void CMGrenade::DetonateUse( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
SetThink( &CMGrenade::Detonate );
|
||||
pev->nextthink = gpGlobals->time;
|
||||
}
|
||||
|
||||
void CMGrenade::PreDetonate( void )
|
||||
{
|
||||
SetThink( &CMGrenade::Detonate );
|
||||
pev->nextthink = gpGlobals->time + 1;
|
||||
}
|
||||
|
||||
|
||||
void CMGrenade::Detonate( void )
|
||||
{
|
||||
TraceResult tr;
|
||||
Vector vecSpot;// trace starts here!
|
||||
|
||||
vecSpot = pev->origin + Vector ( 0 , 0 , 8 );
|
||||
UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -40 ), ignore_monsters, ENT(pev), & tr);
|
||||
|
||||
Explode( &tr, DMG_BLAST );
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Contact grenade, explode when it touches something
|
||||
//
|
||||
void CMGrenade::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, DMG_BLAST );
|
||||
}
|
||||
|
||||
|
||||
void CMGrenade::DangerSoundThink( void )
|
||||
{
|
||||
if (!IsInWorld())
|
||||
{
|
||||
UTIL_Remove( this->edict() );
|
||||
return;
|
||||
}
|
||||
|
||||
pev->nextthink = gpGlobals->time + 0.2;
|
||||
|
||||
if (pev->waterlevel != 0)
|
||||
{
|
||||
pev->velocity = pev->velocity * 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMGrenade::BounceTouch( edict_t *pOther )
|
||||
{
|
||||
// don't hit the guy that launched this grenade
|
||||
if ( pOther == pev->owner )
|
||||
return;
|
||||
|
||||
// only do damage if we're moving fairly fast
|
||||
if (m_flNextAttack < gpGlobals->time && pev->velocity.Length() > 100)
|
||||
{
|
||||
entvars_t *pevOwner = VARS( pev->owner );
|
||||
if (pevOwner)
|
||||
{
|
||||
TraceResult tr = UTIL_GetGlobalTrace( );
|
||||
ClearMultiDamage( );
|
||||
|
||||
if (UTIL_IsPlayer(pOther))
|
||||
UTIL_TraceAttack(pOther, pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB );
|
||||
else if (pOther->v.euser4 != NULL)
|
||||
{
|
||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||
pMonster->TraceAttack(pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB );
|
||||
}
|
||||
|
||||
ApplyMultiDamage( pev, pevOwner);
|
||||
}
|
||||
m_flNextAttack = gpGlobals->time + 1.0; // debounce
|
||||
}
|
||||
|
||||
Vector vecTestVelocity;
|
||||
// pev->avelocity = Vector (300, 300, 300);
|
||||
|
||||
// this is my heuristic for modulating the grenade velocity because grenades dropped purely vertical
|
||||
// or thrown very far tend to slow down too quickly for me to always catch just by testing velocity.
|
||||
// trimming the Z velocity a bit seems to help quite a bit.
|
||||
vecTestVelocity = pev->velocity;
|
||||
vecTestVelocity.z *= 0.45;
|
||||
|
||||
if ( !m_fRegisteredSound && vecTestVelocity.Length() <= 60 )
|
||||
{
|
||||
//ALERT( at_console, "Grenade Registered!: %f\n", vecTestVelocity.Length() );
|
||||
|
||||
// grenade is moving really slow. It's probably very close to where it will ultimately stop moving.
|
||||
// go ahead and emit the danger sound.
|
||||
|
||||
// register a radius louder than the explosion, so we make sure everyone gets out of the way
|
||||
m_fRegisteredSound = TRUE;
|
||||
}
|
||||
|
||||
if (pev->flags & FL_ONGROUND)
|
||||
{
|
||||
// add a bit of static friction
|
||||
pev->velocity = pev->velocity * 0.8;
|
||||
|
||||
pev->sequence = RANDOM_LONG( 1, 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// play bounce sound
|
||||
BounceSound();
|
||||
}
|
||||
pev->framerate = pev->velocity.Length() / 200.0;
|
||||
if (pev->framerate > 1.0)
|
||||
pev->framerate = 1;
|
||||
else if (pev->framerate < 0.5)
|
||||
pev->framerate = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CMGrenade::SlideTouch( edict_t *pOther )
|
||||
{
|
||||
// don't hit the guy that launched this grenade
|
||||
if ( pOther == pev->owner )
|
||||
return;
|
||||
|
||||
// pev->avelocity = Vector (300, 300, 300);
|
||||
|
||||
if (pev->flags & FL_ONGROUND)
|
||||
{
|
||||
// add a bit of static friction
|
||||
pev->velocity = pev->velocity * 0.95;
|
||||
|
||||
if (pev->velocity.x != 0 || pev->velocity.y != 0)
|
||||
{
|
||||
// maintain sliding sound
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BounceSound();
|
||||
}
|
||||
}
|
||||
|
||||
void CMGrenade :: BounceSound( void )
|
||||
{
|
||||
switch ( RANDOM_LONG( 0, 2 ) )
|
||||
{
|
||||
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/grenade_hit1.wav", 0.25, ATTN_NORM); break;
|
||||
case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/grenade_hit2.wav", 0.25, ATTN_NORM); break;
|
||||
case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/grenade_hit3.wav", 0.25, ATTN_NORM); break;
|
||||
}
|
||||
}
|
||||
|
||||
void CMGrenade :: TumbleThink( void )
|
||||
{
|
||||
if (!IsInWorld())
|
||||
{
|
||||
UTIL_Remove( this->edict() );
|
||||
return;
|
||||
}
|
||||
|
||||
StudioFrameAdvance( );
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
|
||||
if (pev->dmgtime <= gpGlobals->time)
|
||||
{
|
||||
SetThink( &CMGrenade::Detonate );
|
||||
}
|
||||
if (pev->waterlevel != 0)
|
||||
{
|
||||
pev->velocity = pev->velocity * 0.5;
|
||||
pev->framerate = 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMGrenade:: Spawn( void )
|
||||
{
|
||||
pev->movetype = MOVETYPE_BOUNCE;
|
||||
pev->classname = MAKE_STRING( "grenade" );
|
||||
|
||||
pev->solid = SOLID_BBOX;
|
||||
|
||||
SET_MODEL(ENT(pev), "models/grenade.mdl");
|
||||
UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0));
|
||||
|
||||
pev->dmg = 100;
|
||||
m_fRegisteredSound = FALSE;
|
||||
}
|
||||
|
||||
|
||||
CMGrenade *CMGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity )
|
||||
{
|
||||
CMGrenade *pGrenade = CreateClassPtr( (CMGrenade *)NULL );
|
||||
|
||||
if (pGrenade == NULL) // no free monster edicts left?
|
||||
return NULL;
|
||||
|
||||
pGrenade->Spawn();
|
||||
// contact grenades arc lower
|
||||
pGrenade->pev->gravity = 0.5;// lower gravity since grenade is aerodynamic and engine doesn't know it.
|
||||
UTIL_SetOrigin( pGrenade->pev, vecStart );
|
||||
pGrenade->pev->velocity = vecVelocity;
|
||||
pGrenade->pev->angles = UTIL_VecToAngles (pGrenade->pev->velocity);
|
||||
pGrenade->pev->owner = ENT(pevOwner);
|
||||
|
||||
// make monsters afaid of it while in the air
|
||||
pGrenade->SetThink( &CMGrenade::DangerSoundThink );
|
||||
pGrenade->pev->nextthink = gpGlobals->time;
|
||||
|
||||
// Tumble in air
|
||||
pGrenade->pev->avelocity.x = RANDOM_FLOAT ( -100, -500 );
|
||||
|
||||
// Explode on contact
|
||||
pGrenade->SetTouch( &CMGrenade::ExplodeTouch );
|
||||
|
||||
pGrenade->pev->dmg = gSkillData.monDmgM203Grenade;
|
||||
|
||||
return pGrenade;
|
||||
}
|
||||
|
||||
|
||||
CMGrenade * CMGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time )
|
||||
{
|
||||
CMGrenade *pGrenade = CreateClassPtr( (CMGrenade *)NULL );
|
||||
|
||||
if (pGrenade == NULL) // no free monster edicts left?
|
||||
return NULL;
|
||||
|
||||
pGrenade->Spawn();
|
||||
UTIL_SetOrigin( pGrenade->pev, vecStart );
|
||||
pGrenade->pev->velocity = vecVelocity;
|
||||
pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity);
|
||||
pGrenade->pev->owner = ENT(pevOwner);
|
||||
|
||||
pGrenade->SetTouch( &CMGrenade::BounceTouch ); // Bounce if touched
|
||||
|
||||
// Take one second off of the desired detonation time and set the think to PreDetonate. PreDetonate
|
||||
// will insert a DANGER sound into the world sound list and delay detonation for one second so that
|
||||
// the grenade explodes after the exact amount of time specified in the call to ShootTimed().
|
||||
|
||||
pGrenade->pev->dmgtime = gpGlobals->time + time;
|
||||
pGrenade->SetThink( &CMGrenade::TumbleThink );
|
||||
pGrenade->pev->nextthink = gpGlobals->time + 0.1;
|
||||
if (time < 0.1)
|
||||
{
|
||||
pGrenade->pev->nextthink = gpGlobals->time;
|
||||
pGrenade->pev->velocity = Vector( 0, 0, 0 );
|
||||
}
|
||||
|
||||
pGrenade->pev->sequence = RANDOM_LONG( 3, 6 );
|
||||
pGrenade->pev->framerate = 1.0;
|
||||
|
||||
// Tumble through the air
|
||||
// pGrenade->pev->avelocity.x = -400;
|
||||
|
||||
pGrenade->pev->gravity = 0.5;
|
||||
pGrenade->pev->friction = 0.8;
|
||||
|
||||
SET_MODEL(ENT(pGrenade->pev), "models/w_grenade.mdl");
|
||||
pGrenade->pev->dmg = 100;
|
||||
|
||||
return pGrenade;
|
||||
}
|
||||
|
||||
|
||||
CMGrenade * CMGrenade :: ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity )
|
||||
{
|
||||
CMGrenade *pGrenade = CreateClassPtr( (CMGrenade *)NULL );
|
||||
|
||||
if (pGrenade == NULL) // no free monster edicts left?
|
||||
return NULL;
|
||||
|
||||
pGrenade->pev->movetype = MOVETYPE_BOUNCE;
|
||||
pGrenade->pev->classname = MAKE_STRING( "grenade" );
|
||||
|
||||
pGrenade->pev->solid = SOLID_BBOX;
|
||||
|
||||
SET_MODEL(ENT(pGrenade->pev), "models/grenade.mdl"); // Change this to satchel charge model
|
||||
|
||||
UTIL_SetSize(pGrenade->pev, Vector( 0, 0, 0), Vector(0, 0, 0));
|
||||
|
||||
pGrenade->pev->dmg = 200;
|
||||
UTIL_SetOrigin( pGrenade->pev, vecStart );
|
||||
pGrenade->pev->velocity = vecVelocity;
|
||||
pGrenade->pev->angles = g_vecZero;
|
||||
pGrenade->pev->owner = ENT(pevOwner);
|
||||
|
||||
// Detonate in "time" seconds
|
||||
pGrenade->SetThink( &CMGrenade::SUB_DoNothing );
|
||||
pGrenade->SetUse( &CMGrenade::DetonateUse );
|
||||
pGrenade->SetTouch( &CMGrenade::SlideTouch );
|
||||
pGrenade->pev->spawnflags = SF_DETONATE;
|
||||
|
||||
pGrenade->pev->friction = 0.9;
|
||||
|
||||
return pGrenade;
|
||||
}
|
||||
|
||||
//======================end grenade
|
||||
|
||||
|
||||
881
src/dlls/gonome.cpp
Normal file
881
src/dlls/gonome.cpp
Normal file
@@ -0,0 +1,881 @@
|
||||
// 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, pev, gSkillData.gonomeDmgGuts, DMG_GENERIC );
|
||||
else if (pOther->v.euser4 != NULL)
|
||||
{
|
||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||
pMonster->TakeDamage ( pev, pev, 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)
|
||||
{
|
||||
// Take 15% 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.15;
|
||||
}
|
||||
|
||||
// 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 = BLOOD_COLOR_GREEN;
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,199 +1,199 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
/*
|
||||
|
||||
h_ai.cpp - halflife specific ai code
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "monsters.h"
|
||||
|
||||
#define NUM_LATERAL_CHECKS 13 // how many checks are made on each side of a monster looking for lateral cover
|
||||
#define NUM_LATERAL_LOS_CHECKS 6 // how many checks are made on each side of a monster looking for lateral cover
|
||||
|
||||
//float flRandom = RANDOM_FLOAT(0,1);
|
||||
|
||||
DLL_GLOBAL BOOL g_fDrawLines = FALSE;
|
||||
|
||||
//=========================================================
|
||||
//
|
||||
// AI UTILITY FUNCTIONS
|
||||
//
|
||||
// !!!UNDONE - move CBaseMonster functions to monsters.cpp
|
||||
//=========================================================
|
||||
|
||||
//=========================================================
|
||||
// FBoxVisible - a more accurate ( and slower ) version
|
||||
// of FVisible.
|
||||
//
|
||||
// !!!UNDONE - make this CBaseMonster?
|
||||
//=========================================================
|
||||
BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize )
|
||||
{
|
||||
// don't look through water
|
||||
if ((pevLooker->waterlevel != 3 && pevTarget->waterlevel == 3)
|
||||
|| (pevLooker->waterlevel == 3 && pevTarget->waterlevel == 0))
|
||||
return FALSE;
|
||||
|
||||
TraceResult tr;
|
||||
Vector vecLookerOrigin = pevLooker->origin + pevLooker->view_ofs;//look through the monster's 'eyes'
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
Vector vecTarget = pevTarget->origin;
|
||||
vecTarget.x += RANDOM_FLOAT( pevTarget->mins.x + flSize, pevTarget->maxs.x - flSize);
|
||||
vecTarget.y += RANDOM_FLOAT( pevTarget->mins.y + flSize, pevTarget->maxs.y - flSize);
|
||||
vecTarget.z += RANDOM_FLOAT( pevTarget->mins.z + flSize, pevTarget->maxs.z - flSize);
|
||||
|
||||
UTIL_TraceLine(vecLookerOrigin, vecTarget, ignore_monsters, ignore_glass, ENT(pevLooker)/*pentIgnore*/, &tr);
|
||||
|
||||
if (tr.flFraction == 1.0)
|
||||
{
|
||||
vecTargetOrigin = vecTarget;
|
||||
return TRUE;// line of sight is valid.
|
||||
}
|
||||
}
|
||||
return FALSE;// Line of sight is not established
|
||||
}
|
||||
|
||||
//
|
||||
// VecCheckToss - returns the velocity at which an object should be lobbed from vecspot1 to land near vecspot2.
|
||||
// returns g_vecZero if toss is not feasible.
|
||||
//
|
||||
Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj )
|
||||
{
|
||||
TraceResult tr;
|
||||
Vector vecMidPoint;// halfway point between Spot1 and Spot2
|
||||
Vector vecApex;// highest point
|
||||
Vector vecScale;
|
||||
Vector vecGrenadeVel;
|
||||
Vector vecTemp;
|
||||
float flGravity = g_psv_gravity->value * flGravityAdj;
|
||||
|
||||
if (vecSpot2.z - vecSpot1.z > 500)
|
||||
{
|
||||
// to high, fail
|
||||
return g_vecZero;
|
||||
}
|
||||
|
||||
UTIL_MakeVectors (pev->angles);
|
||||
|
||||
// toss a little bit to the left or right, not right down on the enemy's bean (head).
|
||||
vecSpot2 = vecSpot2 + gpGlobals->v_right * ( RANDOM_FLOAT(-8,8) + RANDOM_FLOAT(-16,16) );
|
||||
vecSpot2 = vecSpot2 + gpGlobals->v_forward * ( RANDOM_FLOAT(-8,8) + RANDOM_FLOAT(-16,16) );
|
||||
|
||||
// calculate the midpoint and apex of the 'triangle'
|
||||
// UNDONE: normalize any Z position differences between spot1 and spot2 so that triangle is always RIGHT
|
||||
|
||||
// How much time does it take to get there?
|
||||
|
||||
// get a rough idea of how high it can be thrown
|
||||
vecMidPoint = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5;
|
||||
UTIL_TraceLine(vecMidPoint, vecMidPoint + Vector(0,0,500), ignore_monsters, ENT(pev), &tr);
|
||||
vecMidPoint = tr.vecEndPos;
|
||||
// (subtract 15 so the grenade doesn't hit the ceiling)
|
||||
vecMidPoint.z -= 15;
|
||||
|
||||
if (vecMidPoint.z < vecSpot1.z || vecMidPoint.z < vecSpot2.z)
|
||||
{
|
||||
// to not enough space, fail
|
||||
return g_vecZero;
|
||||
}
|
||||
|
||||
// How high should the grenade travel to reach the apex
|
||||
float distance1 = (vecMidPoint.z - vecSpot1.z);
|
||||
float distance2 = (vecMidPoint.z - vecSpot2.z);
|
||||
|
||||
// How long will it take for the grenade to travel this distance
|
||||
float time1 = sqrt( distance1 / (0.5 * flGravity) );
|
||||
float time2 = sqrt( distance2 / (0.5 * flGravity) );
|
||||
|
||||
if (time1 < 0.1)
|
||||
{
|
||||
// too close
|
||||
return g_vecZero;
|
||||
}
|
||||
|
||||
// how hard to throw sideways to get there in time.
|
||||
vecGrenadeVel = (vecSpot2 - vecSpot1) / (time1 + time2);
|
||||
// how hard upwards to reach the apex at the right time.
|
||||
vecGrenadeVel.z = flGravity * time1;
|
||||
|
||||
// find the apex
|
||||
vecApex = vecSpot1 + vecGrenadeVel * time1;
|
||||
vecApex.z = vecMidPoint.z;
|
||||
|
||||
UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr);
|
||||
if (tr.flFraction != 1.0)
|
||||
{
|
||||
// fail!
|
||||
return g_vecZero;
|
||||
}
|
||||
|
||||
// UNDONE: either ignore monsters or change it to not care if we hit our enemy
|
||||
UTIL_TraceLine(vecSpot2, vecApex, ignore_monsters, ENT(pev), &tr);
|
||||
if (tr.flFraction != 1.0)
|
||||
{
|
||||
// fail!
|
||||
return g_vecZero;
|
||||
}
|
||||
|
||||
return vecGrenadeVel;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// VecCheckThrow - returns the velocity vector at which an object should be thrown from vecspot1 to hit vecspot2.
|
||||
// returns g_vecZero if throw is not feasible.
|
||||
//
|
||||
Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj )
|
||||
{
|
||||
float flGravity = g_psv_gravity->value * flGravityAdj;
|
||||
|
||||
Vector vecGrenadeVel = (vecSpot2 - vecSpot1);
|
||||
|
||||
// throw at a constant time
|
||||
float time = vecGrenadeVel.Length( ) / flSpeed;
|
||||
vecGrenadeVel = vecGrenadeVel * (1.0 / time);
|
||||
|
||||
// adjust upward toss to compensate for gravity loss
|
||||
vecGrenadeVel.z += flGravity * time * 0.5;
|
||||
|
||||
Vector vecApex = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5;
|
||||
vecApex.z += 0.5 * flGravity * (time * 0.5) * (time * 0.5);
|
||||
|
||||
TraceResult tr;
|
||||
UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr);
|
||||
if (tr.flFraction != 1.0)
|
||||
{
|
||||
// fail!
|
||||
return g_vecZero;
|
||||
}
|
||||
|
||||
UTIL_TraceLine(vecSpot2, vecApex, ignore_monsters, ENT(pev), &tr);
|
||||
if (tr.flFraction != 1.0)
|
||||
{
|
||||
// fail!
|
||||
return g_vecZero;
|
||||
}
|
||||
|
||||
return vecGrenadeVel;
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
/*
|
||||
|
||||
h_ai.cpp - halflife specific ai code
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "monsters.h"
|
||||
|
||||
#define NUM_LATERAL_CHECKS 13 // how many checks are made on each side of a monster looking for lateral cover
|
||||
#define NUM_LATERAL_LOS_CHECKS 6 // how many checks are made on each side of a monster looking for lateral cover
|
||||
|
||||
//float flRandom = RANDOM_FLOAT(0,1);
|
||||
|
||||
DLL_GLOBAL BOOL g_fDrawLines = FALSE;
|
||||
|
||||
//=========================================================
|
||||
//
|
||||
// AI UTILITY FUNCTIONS
|
||||
//
|
||||
// !!!UNDONE - move CBaseMonster functions to monsters.cpp
|
||||
//=========================================================
|
||||
|
||||
//=========================================================
|
||||
// FBoxVisible - a more accurate ( and slower ) version
|
||||
// of FVisible.
|
||||
//
|
||||
// !!!UNDONE - make this CBaseMonster?
|
||||
//=========================================================
|
||||
BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize )
|
||||
{
|
||||
// don't look through water
|
||||
if ((pevLooker->waterlevel != 3 && pevTarget->waterlevel == 3)
|
||||
|| (pevLooker->waterlevel == 3 && pevTarget->waterlevel == 0))
|
||||
return FALSE;
|
||||
|
||||
TraceResult tr;
|
||||
Vector vecLookerOrigin = pevLooker->origin + pevLooker->view_ofs;//look through the monster's 'eyes'
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
Vector vecTarget = pevTarget->origin;
|
||||
vecTarget.x += RANDOM_FLOAT( pevTarget->mins.x + flSize, pevTarget->maxs.x - flSize);
|
||||
vecTarget.y += RANDOM_FLOAT( pevTarget->mins.y + flSize, pevTarget->maxs.y - flSize);
|
||||
vecTarget.z += RANDOM_FLOAT( pevTarget->mins.z + flSize, pevTarget->maxs.z - flSize);
|
||||
|
||||
UTIL_TraceLine(vecLookerOrigin, vecTarget, ignore_monsters, ignore_glass, ENT(pevLooker)/*pentIgnore*/, &tr);
|
||||
|
||||
if (tr.flFraction == 1.0)
|
||||
{
|
||||
vecTargetOrigin = vecTarget;
|
||||
return TRUE;// line of sight is valid.
|
||||
}
|
||||
}
|
||||
return FALSE;// Line of sight is not established
|
||||
}
|
||||
|
||||
//
|
||||
// VecCheckToss - returns the velocity at which an object should be lobbed from vecspot1 to land near vecspot2.
|
||||
// returns g_vecZero if toss is not feasible.
|
||||
//
|
||||
Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj )
|
||||
{
|
||||
TraceResult tr;
|
||||
Vector vecMidPoint;// halfway point between Spot1 and Spot2
|
||||
Vector vecApex;// highest point
|
||||
Vector vecScale;
|
||||
Vector vecGrenadeVel;
|
||||
Vector vecTemp;
|
||||
float flGravity = g_psv_gravity->value * flGravityAdj;
|
||||
|
||||
if (vecSpot2.z - vecSpot1.z > 500)
|
||||
{
|
||||
// to high, fail
|
||||
return g_vecZero;
|
||||
}
|
||||
|
||||
UTIL_MakeVectors (pev->angles);
|
||||
|
||||
// toss a little bit to the left or right, not right down on the enemy's bean (head).
|
||||
vecSpot2 = vecSpot2 + gpGlobals->v_right * ( RANDOM_FLOAT(-8,8) + RANDOM_FLOAT(-16,16) );
|
||||
vecSpot2 = vecSpot2 + gpGlobals->v_forward * ( RANDOM_FLOAT(-8,8) + RANDOM_FLOAT(-16,16) );
|
||||
|
||||
// calculate the midpoint and apex of the 'triangle'
|
||||
// UNDONE: normalize any Z position differences between spot1 and spot2 so that triangle is always RIGHT
|
||||
|
||||
// How much time does it take to get there?
|
||||
|
||||
// get a rough idea of how high it can be thrown
|
||||
vecMidPoint = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5;
|
||||
UTIL_TraceLine(vecMidPoint, vecMidPoint + Vector(0,0,500), ignore_monsters, ENT(pev), &tr);
|
||||
vecMidPoint = tr.vecEndPos;
|
||||
// (subtract 15 so the grenade doesn't hit the ceiling)
|
||||
vecMidPoint.z -= 15;
|
||||
|
||||
if (vecMidPoint.z < vecSpot1.z || vecMidPoint.z < vecSpot2.z)
|
||||
{
|
||||
// to not enough space, fail
|
||||
return g_vecZero;
|
||||
}
|
||||
|
||||
// How high should the grenade travel to reach the apex
|
||||
float distance1 = (vecMidPoint.z - vecSpot1.z);
|
||||
float distance2 = (vecMidPoint.z - vecSpot2.z);
|
||||
|
||||
// How long will it take for the grenade to travel this distance
|
||||
float time1 = sqrt( distance1 / (0.5 * flGravity) );
|
||||
float time2 = sqrt( distance2 / (0.5 * flGravity) );
|
||||
|
||||
if (time1 < 0.1)
|
||||
{
|
||||
// too close
|
||||
return g_vecZero;
|
||||
}
|
||||
|
||||
// how hard to throw sideways to get there in time.
|
||||
vecGrenadeVel = (vecSpot2 - vecSpot1) / (time1 + time2);
|
||||
// how hard upwards to reach the apex at the right time.
|
||||
vecGrenadeVel.z = flGravity * time1;
|
||||
|
||||
// find the apex
|
||||
vecApex = vecSpot1 + vecGrenadeVel * time1;
|
||||
vecApex.z = vecMidPoint.z;
|
||||
|
||||
UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr);
|
||||
if (tr.flFraction != 1.0)
|
||||
{
|
||||
// fail!
|
||||
return g_vecZero;
|
||||
}
|
||||
|
||||
// UNDONE: either ignore monsters or change it to not care if we hit our enemy
|
||||
UTIL_TraceLine(vecSpot2, vecApex, ignore_monsters, ENT(pev), &tr);
|
||||
if (tr.flFraction != 1.0)
|
||||
{
|
||||
// fail!
|
||||
return g_vecZero;
|
||||
}
|
||||
|
||||
return vecGrenadeVel;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// VecCheckThrow - returns the velocity vector at which an object should be thrown from vecspot1 to hit vecspot2.
|
||||
// returns g_vecZero if throw is not feasible.
|
||||
//
|
||||
Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj )
|
||||
{
|
||||
float flGravity = g_psv_gravity->value * flGravityAdj;
|
||||
|
||||
Vector vecGrenadeVel = (vecSpot2 - vecSpot1);
|
||||
|
||||
// throw at a constant time
|
||||
float time = vecGrenadeVel.Length( ) / flSpeed;
|
||||
vecGrenadeVel = vecGrenadeVel * (1.0 / time);
|
||||
|
||||
// adjust upward toss to compensate for gravity loss
|
||||
vecGrenadeVel.z += flGravity * time * 0.5;
|
||||
|
||||
Vector vecApex = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5;
|
||||
vecApex.z += 0.5 * flGravity * (time * 0.5) * (time * 0.5);
|
||||
|
||||
TraceResult tr;
|
||||
UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr);
|
||||
if (tr.flFraction != 1.0)
|
||||
{
|
||||
// fail!
|
||||
return g_vecZero;
|
||||
}
|
||||
|
||||
UTIL_TraceLine(vecSpot2, vecApex, ignore_monsters, ENT(pev), &tr);
|
||||
if (tr.flFraction != 1.0)
|
||||
{
|
||||
// fail!
|
||||
return g_vecZero;
|
||||
}
|
||||
|
||||
return vecGrenadeVel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
//
|
||||
// Monster Mod is a modification based on Botman's original "Monster" plugin.
|
||||
// The "forgotten" modification was made by Rick90.
|
||||
// This is an attempt to recreate the plugin so it does not become lost again.
|
||||
//
|
||||
// Recreated by Giegue.
|
||||
//
|
||||
// h_export.cpp
|
||||
//
|
||||
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 2000 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.
|
||||
*
|
||||
****/
|
||||
/*
|
||||
|
||||
===== h_export.cpp ========================================================
|
||||
|
||||
Entity classes exported by Halflife.
|
||||
|
||||
*/
|
||||
|
||||
#include "extdll.h"
|
||||
#include "h_export.h"
|
||||
|
||||
// From SDK dlls/h_export.cpp:
|
||||
|
||||
//! Holds engine functionality callbacks
|
||||
enginefuncs_t g_engfuncs;
|
||||
globalvars_t *gpGlobals;
|
||||
|
||||
// Receive engine function table from engine.
|
||||
// This appears to be the _first_ DLL routine called by the engine, so we
|
||||
// do some setup operations here.
|
||||
void WINAPI GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals )
|
||||
{
|
||||
memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t));
|
||||
gpGlobals = pGlobals;
|
||||
}
|
||||
|
||||
//
|
||||
// Monster Mod is a modification based on Botman's original "Monster" plugin.
|
||||
// The "forgotten" modification was made by Rick90.
|
||||
// This is an attempt to recreate the plugin so it does not become lost again.
|
||||
//
|
||||
// Recreated by Giegue.
|
||||
//
|
||||
// h_export.cpp
|
||||
//
|
||||
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 2000 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.
|
||||
*
|
||||
****/
|
||||
/*
|
||||
|
||||
===== h_export.cpp ========================================================
|
||||
|
||||
Entity classes exported by Halflife.
|
||||
|
||||
*/
|
||||
|
||||
#include "extdll.h"
|
||||
#include "h_export.h"
|
||||
|
||||
// From SDK dlls/h_export.cpp:
|
||||
|
||||
//! Holds engine functionality callbacks
|
||||
enginefuncs_t g_engfuncs;
|
||||
globalvars_t *gpGlobals;
|
||||
|
||||
// Receive engine function table from engine.
|
||||
// This appears to be the _first_ DLL routine called by the engine, so we
|
||||
// do some setup operations here.
|
||||
void WINAPI GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals )
|
||||
{
|
||||
memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t));
|
||||
gpGlobals = pGlobals;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
4238
src/dlls/hgrunt.cpp
4238
src/dlls/hgrunt.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,384 +1,383 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
//=========================================================
|
||||
// Hornets
|
||||
//=========================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "monsters.h"
|
||||
#include "weapons.h"
|
||||
#include "hornet.h"
|
||||
|
||||
|
||||
int iHornetTrail;
|
||||
int iHornetPuff;
|
||||
|
||||
//=========================================================
|
||||
// don't let hornets gib, ever.
|
||||
//=========================================================
|
||||
int CMHornet :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
||||
{
|
||||
// filter these bits a little.
|
||||
bitsDamageType &= ~ ( DMG_ALWAYSGIB );
|
||||
bitsDamageType |= DMG_NEVERGIB;
|
||||
|
||||
return CMBaseMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
void CMHornet :: Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
|
||||
pev->movetype = MOVETYPE_FLY;
|
||||
pev->solid = SOLID_BBOX;
|
||||
pev->takedamage = DAMAGE_YES;
|
||||
pev->flags |= FL_MONSTER; // I have a bad feeling about this
|
||||
pev->health = 1;// weak!
|
||||
|
||||
// hornets don't live as long in multiplayer
|
||||
m_flStopAttack = gpGlobals->time + 3.5;
|
||||
|
||||
m_flFieldOfView = 0.9; // +- 25 degrees
|
||||
|
||||
if ( RANDOM_LONG ( 1, 5 ) <= 2 )
|
||||
{
|
||||
m_iHornetType = HORNET_TYPE_RED;
|
||||
m_flFlySpeed = HORNET_RED_SPEED;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iHornetType = HORNET_TYPE_ORANGE;
|
||||
m_flFlySpeed = HORNET_ORANGE_SPEED;
|
||||
}
|
||||
|
||||
SET_MODEL(ENT( pev ), "models/hornet.mdl");
|
||||
UTIL_SetSize( pev, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ) );
|
||||
|
||||
SetTouch( &CMHornet::DieTouch );
|
||||
SetThink( &CMHornet::StartTrack );
|
||||
|
||||
edict_t *pSoundEnt = pev->owner;
|
||||
if ( !pSoundEnt )
|
||||
pSoundEnt = edict();
|
||||
|
||||
// no real owner, or owner isn't a client.
|
||||
pev->dmg = gSkillData.monDmgHornet;
|
||||
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
ResetSequenceInfo( );
|
||||
|
||||
pev->classname = MAKE_STRING( "hornet" );
|
||||
}
|
||||
|
||||
|
||||
void CMHornet :: Precache()
|
||||
{
|
||||
PRECACHE_MODEL("models/hornet.mdl");
|
||||
|
||||
PRECACHE_SOUND( "agrunt/ag_fire1.wav" );
|
||||
PRECACHE_SOUND( "agrunt/ag_fire2.wav" );
|
||||
PRECACHE_SOUND( "agrunt/ag_fire3.wav" );
|
||||
|
||||
PRECACHE_SOUND( "hornet/ag_buzz1.wav" );
|
||||
PRECACHE_SOUND( "hornet/ag_buzz2.wav" );
|
||||
PRECACHE_SOUND( "hornet/ag_buzz3.wav" );
|
||||
|
||||
PRECACHE_SOUND( "hornet/ag_hornethit1.wav" );
|
||||
PRECACHE_SOUND( "hornet/ag_hornethit2.wav" );
|
||||
PRECACHE_SOUND( "hornet/ag_hornethit3.wav" );
|
||||
|
||||
iHornetPuff = PRECACHE_MODEL( "sprites/muz1.spr" );
|
||||
iHornetTrail = PRECACHE_MODEL("sprites/laserbeam.spr");
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// hornets will never get mad at each other, no matter who the owner is.
|
||||
//=========================================================
|
||||
int CMHornet::IRelationship ( CMBaseEntity *pTarget )
|
||||
{
|
||||
if ( pTarget->pev->modelindex == pev->modelindex )
|
||||
{
|
||||
return R_NO;
|
||||
}
|
||||
|
||||
return CMBaseMonster :: IRelationship( pTarget );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// ID's Hornet as their owner
|
||||
//=========================================================
|
||||
int CMHornet::Classify ( void )
|
||||
{
|
||||
/*
|
||||
if ( pev->owner && pev->owner->v.flags & FL_CLIENT)
|
||||
{
|
||||
return CLASS_PLAYER_BIOWEAPON;
|
||||
}
|
||||
|
||||
return CLASS_ALIEN_BIOWEAPON;
|
||||
*/
|
||||
|
||||
// Ensure classify is consistent with the owner, in the event
|
||||
// it's classification was overriden.
|
||||
if ( pev->owner == NULL )
|
||||
return CLASS_ALIEN_BIOWEAPON;
|
||||
|
||||
// Ain't this going to make the hornets code "slow"?
|
||||
CMBaseMonster *pOwner = GetClassPtr((CMBaseMonster *)VARS(pev->owner));
|
||||
return pOwner->Classify();
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// StartTrack - starts a hornet out tracking its target
|
||||
//=========================================================
|
||||
void CMHornet :: StartTrack ( void )
|
||||
{
|
||||
IgniteTrail();
|
||||
|
||||
SetTouch( &CMHornet::TrackTouch );
|
||||
SetThink( &CMHornet::TrackTarget );
|
||||
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// StartDart - starts a hornet out just flying straight.
|
||||
//=========================================================
|
||||
void CMHornet :: StartDart ( void )
|
||||
{
|
||||
IgniteTrail();
|
||||
|
||||
SetTouch( &CMHornet::DartTouch );
|
||||
|
||||
SetThink( &CMHornet::SUB_Remove );
|
||||
pev->nextthink = gpGlobals->time + 4;
|
||||
}
|
||||
|
||||
void CMHornet::IgniteTrail( void )
|
||||
{
|
||||
/*
|
||||
|
||||
ted's suggested trail colors:
|
||||
|
||||
r161
|
||||
g25
|
||||
b97
|
||||
|
||||
r173
|
||||
g39
|
||||
b14
|
||||
|
||||
old colors
|
||||
case HORNET_TYPE_RED:
|
||||
WRITE_BYTE( 255 ); // r, g, b
|
||||
WRITE_BYTE( 128 ); // r, g, b
|
||||
WRITE_BYTE( 0 ); // r, g, b
|
||||
break;
|
||||
case HORNET_TYPE_ORANGE:
|
||||
WRITE_BYTE( 0 ); // r, g, b
|
||||
WRITE_BYTE( 100 ); // r, g, b
|
||||
WRITE_BYTE( 255 ); // r, g, b
|
||||
break;
|
||||
|
||||
*/
|
||||
|
||||
// trail
|
||||
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
||||
WRITE_BYTE( TE_BEAMFOLLOW );
|
||||
WRITE_SHORT( entindex() ); // entity
|
||||
WRITE_SHORT( iHornetTrail ); // model
|
||||
WRITE_BYTE( 10 ); // life
|
||||
WRITE_BYTE( 2 ); // width
|
||||
|
||||
switch ( m_iHornetType )
|
||||
{
|
||||
case HORNET_TYPE_RED:
|
||||
WRITE_BYTE( 179 ); // r, g, b
|
||||
WRITE_BYTE( 39 ); // r, g, b
|
||||
WRITE_BYTE( 14 ); // r, g, b
|
||||
break;
|
||||
case HORNET_TYPE_ORANGE:
|
||||
WRITE_BYTE( 255 ); // r, g, b
|
||||
WRITE_BYTE( 128 ); // r, g, b
|
||||
WRITE_BYTE( 0 ); // r, g, b
|
||||
break;
|
||||
}
|
||||
|
||||
WRITE_BYTE( 128 ); // brightness
|
||||
|
||||
MESSAGE_END();
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// Hornet is flying, gently tracking target
|
||||
//=========================================================
|
||||
void CMHornet :: TrackTarget ( void )
|
||||
{
|
||||
Vector vecFlightDir;
|
||||
Vector vecDirToEnemy;
|
||||
float flDelta;
|
||||
|
||||
StudioFrameAdvance( );
|
||||
|
||||
if (gpGlobals->time > m_flStopAttack)
|
||||
{
|
||||
SetTouch( NULL );
|
||||
SetThink( &CMHornet::SUB_Remove );
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
return;
|
||||
}
|
||||
|
||||
// UNDONE: The player pointer should come back after returning from another level
|
||||
if ( m_hEnemy == NULL )
|
||||
{// enemy is dead.
|
||||
Look( 512 );
|
||||
m_hEnemy = BestVisibleEnemy( );
|
||||
}
|
||||
|
||||
if ( m_hEnemy != NULL && UTIL_FVisible( m_hEnemy, ENT(pev) ))
|
||||
{
|
||||
m_vecEnemyLKP = UTIL_BodyTarget( m_hEnemy, pev->origin );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vecEnemyLKP = m_vecEnemyLKP + pev->velocity * m_flFlySpeed * 0.1;
|
||||
}
|
||||
|
||||
vecDirToEnemy = ( m_vecEnemyLKP - pev->origin ).Normalize();
|
||||
|
||||
if (pev->velocity.Length() < 0.1)
|
||||
vecFlightDir = vecDirToEnemy;
|
||||
else
|
||||
vecFlightDir = pev->velocity.Normalize();
|
||||
|
||||
// measure how far the turn is, the wider the turn, the slow we'll go this time.
|
||||
flDelta = DotProduct ( vecFlightDir, vecDirToEnemy );
|
||||
|
||||
if ( flDelta < 0.5 )
|
||||
{// hafta turn wide again. play sound
|
||||
switch (RANDOM_LONG(0,2))
|
||||
{
|
||||
case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break;
|
||||
case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break;
|
||||
case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( flDelta <= 0 && m_iHornetType == HORNET_TYPE_RED )
|
||||
{// no flying backwards, but we don't want to invert this, cause we'd go fast when we have to turn REAL far.
|
||||
flDelta = 0.25;
|
||||
}
|
||||
|
||||
pev->velocity = ( vecFlightDir + vecDirToEnemy).Normalize();
|
||||
|
||||
if ( pev->owner && (pev->owner->v.flags & FL_MONSTER) )
|
||||
{
|
||||
// random pattern only applies to hornets fired by monsters, not players.
|
||||
|
||||
pev->velocity.x += RANDOM_FLOAT ( -0.10, 0.10 );// scramble the flight dir a bit.
|
||||
pev->velocity.y += RANDOM_FLOAT ( -0.10, 0.10 );
|
||||
pev->velocity.z += RANDOM_FLOAT ( -0.10, 0.10 );
|
||||
}
|
||||
|
||||
switch ( m_iHornetType )
|
||||
{
|
||||
case HORNET_TYPE_RED:
|
||||
pev->velocity = pev->velocity * ( m_flFlySpeed * flDelta );// scale the dir by the ( speed * width of turn )
|
||||
pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.3 );
|
||||
break;
|
||||
case HORNET_TYPE_ORANGE:
|
||||
pev->velocity = pev->velocity * m_flFlySpeed;// do not have to slow down to turn.
|
||||
pev->nextthink = gpGlobals->time + 0.1;// fixed think time
|
||||
break;
|
||||
}
|
||||
|
||||
pev->angles = UTIL_VecToAngles (pev->velocity);
|
||||
|
||||
pev->solid = SOLID_BBOX;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// Tracking Hornet hit something
|
||||
//=========================================================
|
||||
void CMHornet :: TrackTouch ( edict_t *pOther )
|
||||
{
|
||||
if ( (pOther == pev->owner) || pOther->v.modelindex == pev->modelindex )
|
||||
{// bumped into the guy that shot it.
|
||||
pev->solid = SOLID_NOT;
|
||||
return;
|
||||
}
|
||||
|
||||
// is this NOT a player and IS a monster?
|
||||
if (!UTIL_IsPlayer(pOther) && (pOther->v.euser4 != NULL))
|
||||
{
|
||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||
|
||||
if ( IRelationship( pMonster ) <= R_NO )
|
||||
{
|
||||
// hit something we don't want to hurt, so turn around.
|
||||
|
||||
pev->velocity = pev->velocity.Normalize();
|
||||
|
||||
pev->velocity.x *= -1;
|
||||
pev->velocity.y *= -1;
|
||||
|
||||
pev->origin = pev->origin + pev->velocity * 4; // bounce the hornet off a bit.
|
||||
pev->velocity = pev->velocity * m_flFlySpeed;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DieTouch( pOther );
|
||||
}
|
||||
|
||||
void CMHornet::DartTouch( edict_t *pOther )
|
||||
{
|
||||
DieTouch( pOther );
|
||||
}
|
||||
|
||||
void CMHornet::DieTouch ( edict_t *pOther )
|
||||
{
|
||||
if ( pOther && pOther->v.takedamage )
|
||||
{// do the damage
|
||||
|
||||
switch (RANDOM_LONG(0,2))
|
||||
{// buzz when you plug someone
|
||||
case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit1.wav", 1, ATTN_NORM); break;
|
||||
case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit2.wav", 1, ATTN_NORM); break;
|
||||
case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit3.wav", 1, ATTN_NORM); break;
|
||||
}
|
||||
|
||||
if (UTIL_IsPlayer(pOther))
|
||||
UTIL_TakeDamage( pOther, pev, VARS( pev->owner ), pev->dmg, DMG_BULLET );
|
||||
else if (pOther->v.euser4 != NULL)
|
||||
{
|
||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||
pMonster->TakeDamage( 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->solid = SOLID_NOT;
|
||||
|
||||
SetThink ( &CMHornet::SUB_Remove );
|
||||
pev->nextthink = gpGlobals->time + 1;// stick around long enough for the sound to finish!
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
//=========================================================
|
||||
// Hornets
|
||||
//=========================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "monsters.h"
|
||||
#include "weapons.h"
|
||||
#include "hornet.h"
|
||||
|
||||
|
||||
int iHornetTrail;
|
||||
int iHornetPuff;
|
||||
|
||||
//=========================================================
|
||||
// don't let hornets gib, ever.
|
||||
//=========================================================
|
||||
int CMHornet :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
||||
{
|
||||
// filter these bits a little.
|
||||
bitsDamageType &= ~ ( DMG_ALWAYSGIB );
|
||||
bitsDamageType |= DMG_NEVERGIB;
|
||||
|
||||
return CMBaseMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
void CMHornet :: Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
|
||||
pev->movetype = MOVETYPE_FLY;
|
||||
pev->solid = SOLID_BBOX;
|
||||
pev->takedamage = DAMAGE_YES;
|
||||
pev->flags |= FL_MONSTER; // I have a bad feeling about this
|
||||
pev->health = 1;// weak!
|
||||
|
||||
// hornets don't live as long in multiplayer
|
||||
m_flStopAttack = gpGlobals->time + 3.5;
|
||||
|
||||
m_flFieldOfView = 0.9; // +- 25 degrees
|
||||
|
||||
if ( RANDOM_LONG ( 1, 5 ) <= 2 )
|
||||
{
|
||||
m_iHornetType = HORNET_TYPE_RED;
|
||||
m_flFlySpeed = HORNET_RED_SPEED;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iHornetType = HORNET_TYPE_ORANGE;
|
||||
m_flFlySpeed = HORNET_ORANGE_SPEED;
|
||||
}
|
||||
|
||||
SET_MODEL(ENT( pev ), "models/hornet.mdl");
|
||||
UTIL_SetSize( pev, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ) );
|
||||
|
||||
SetTouch( &CMHornet::DieTouch );
|
||||
SetThink( &CMHornet::StartTrack );
|
||||
|
||||
edict_t *pSoundEnt = pev->owner;
|
||||
if ( !pSoundEnt )
|
||||
pSoundEnt = edict();
|
||||
|
||||
// no real owner, or owner isn't a client.
|
||||
pev->dmg = gSkillData.monDmgHornet;
|
||||
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
ResetSequenceInfo( );
|
||||
|
||||
pev->classname = MAKE_STRING( "hornet" );
|
||||
}
|
||||
|
||||
|
||||
void CMHornet :: Precache()
|
||||
{
|
||||
PRECACHE_MODEL("models/hornet.mdl");
|
||||
|
||||
PRECACHE_SOUND( "agrunt/ag_fire1.wav" );
|
||||
PRECACHE_SOUND( "agrunt/ag_fire2.wav" );
|
||||
PRECACHE_SOUND( "agrunt/ag_fire3.wav" );
|
||||
|
||||
PRECACHE_SOUND( "hornet/ag_buzz1.wav" );
|
||||
PRECACHE_SOUND( "hornet/ag_buzz2.wav" );
|
||||
PRECACHE_SOUND( "hornet/ag_buzz3.wav" );
|
||||
|
||||
PRECACHE_SOUND( "hornet/ag_hornethit1.wav" );
|
||||
PRECACHE_SOUND( "hornet/ag_hornethit2.wav" );
|
||||
PRECACHE_SOUND( "hornet/ag_hornethit3.wav" );
|
||||
|
||||
iHornetPuff = PRECACHE_MODEL( "sprites/muz1.spr" );
|
||||
iHornetTrail = PRECACHE_MODEL("sprites/laserbeam.spr");
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// hornets will never get mad at each other, no matter who the owner is.
|
||||
//=========================================================
|
||||
int CMHornet::IRelationship ( CMBaseEntity *pTarget )
|
||||
{
|
||||
if ( pTarget->pev->modelindex == pev->modelindex )
|
||||
{
|
||||
return R_NO;
|
||||
}
|
||||
|
||||
return CMBaseMonster :: IRelationship( pTarget );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// ID's Hornet as their owner
|
||||
//=========================================================
|
||||
int CMHornet::Classify ( void )
|
||||
{
|
||||
/*
|
||||
if ( pev->owner && pev->owner->v.flags & FL_CLIENT)
|
||||
{
|
||||
return CLASS_PLAYER_BIOWEAPON;
|
||||
}
|
||||
|
||||
return CLASS_ALIEN_BIOWEAPON;
|
||||
*/
|
||||
|
||||
// Ensure classify is consistent with the owner, in the event
|
||||
// it's classification was overriden.
|
||||
if ( pev->owner == NULL )
|
||||
return CLASS_ALIEN_BIOWEAPON;
|
||||
|
||||
// Ain't this going to make the hornets code "slow"?
|
||||
CMBaseMonster *pOwner = GetClassPtr((CMBaseMonster *)VARS(pev->owner));
|
||||
return pOwner->Classify();
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// StartTrack - starts a hornet out tracking its target
|
||||
//=========================================================
|
||||
void CMHornet :: StartTrack ( void )
|
||||
{
|
||||
IgniteTrail();
|
||||
|
||||
SetTouch( &CMHornet::TrackTouch );
|
||||
SetThink( &CMHornet::TrackTarget );
|
||||
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// StartDart - starts a hornet out just flying straight.
|
||||
//=========================================================
|
||||
void CMHornet :: StartDart ( void )
|
||||
{
|
||||
IgniteTrail();
|
||||
|
||||
SetTouch( &CMHornet::DartTouch );
|
||||
|
||||
SetThink( &CMHornet::SUB_Remove );
|
||||
pev->nextthink = gpGlobals->time + 4;
|
||||
}
|
||||
|
||||
void CMHornet::IgniteTrail( void )
|
||||
{
|
||||
/*
|
||||
|
||||
ted's suggested trail colors:
|
||||
|
||||
r161
|
||||
g25
|
||||
b97
|
||||
|
||||
r173
|
||||
g39
|
||||
b14
|
||||
|
||||
old colors
|
||||
case HORNET_TYPE_RED:
|
||||
WRITE_BYTE( 255 ); // r, g, b
|
||||
WRITE_BYTE( 128 ); // r, g, b
|
||||
WRITE_BYTE( 0 ); // r, g, b
|
||||
break;
|
||||
case HORNET_TYPE_ORANGE:
|
||||
WRITE_BYTE( 0 ); // r, g, b
|
||||
WRITE_BYTE( 100 ); // r, g, b
|
||||
WRITE_BYTE( 255 ); // r, g, b
|
||||
break;
|
||||
|
||||
*/
|
||||
|
||||
// trail
|
||||
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
||||
WRITE_BYTE( TE_BEAMFOLLOW );
|
||||
WRITE_SHORT( entindex() ); // entity
|
||||
WRITE_SHORT( iHornetTrail ); // model
|
||||
WRITE_BYTE( 10 ); // life
|
||||
WRITE_BYTE( 2 ); // width
|
||||
|
||||
switch ( m_iHornetType )
|
||||
{
|
||||
case HORNET_TYPE_RED:
|
||||
WRITE_BYTE( 179 ); // r, g, b
|
||||
WRITE_BYTE( 39 ); // r, g, b
|
||||
WRITE_BYTE( 14 ); // r, g, b
|
||||
break;
|
||||
case HORNET_TYPE_ORANGE:
|
||||
WRITE_BYTE( 255 ); // r, g, b
|
||||
WRITE_BYTE( 128 ); // r, g, b
|
||||
WRITE_BYTE( 0 ); // r, g, b
|
||||
break;
|
||||
}
|
||||
|
||||
WRITE_BYTE( 128 ); // brightness
|
||||
|
||||
MESSAGE_END();
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// Hornet is flying, gently tracking target
|
||||
//=========================================================
|
||||
void CMHornet :: TrackTarget ( void )
|
||||
{
|
||||
Vector vecFlightDir;
|
||||
Vector vecDirToEnemy;
|
||||
float flDelta;
|
||||
|
||||
StudioFrameAdvance( );
|
||||
|
||||
if (gpGlobals->time > m_flStopAttack)
|
||||
{
|
||||
SetTouch( NULL );
|
||||
SetThink( &CMHornet::SUB_Remove );
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
return;
|
||||
}
|
||||
|
||||
// UNDONE: The player pointer should come back after returning from another level
|
||||
if ( m_hEnemy == NULL )
|
||||
{// enemy is dead.
|
||||
Look( 512 );
|
||||
m_hEnemy = BestVisibleEnemy( );
|
||||
}
|
||||
|
||||
if ( m_hEnemy != NULL && UTIL_FVisible( m_hEnemy, ENT(pev) ))
|
||||
{
|
||||
m_vecEnemyLKP = UTIL_BodyTarget( m_hEnemy, pev->origin );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vecEnemyLKP = m_vecEnemyLKP + pev->velocity * m_flFlySpeed * 0.1;
|
||||
}
|
||||
|
||||
vecDirToEnemy = ( m_vecEnemyLKP - pev->origin ).Normalize();
|
||||
|
||||
if (pev->velocity.Length() < 0.1)
|
||||
vecFlightDir = vecDirToEnemy;
|
||||
else
|
||||
vecFlightDir = pev->velocity.Normalize();
|
||||
|
||||
// measure how far the turn is, the wider the turn, the slow we'll go this time.
|
||||
flDelta = DotProduct ( vecFlightDir, vecDirToEnemy );
|
||||
|
||||
if ( flDelta < 0.5 )
|
||||
{// hafta turn wide again. play sound
|
||||
switch (RANDOM_LONG(0,2))
|
||||
{
|
||||
case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break;
|
||||
case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break;
|
||||
case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( flDelta <= 0 && m_iHornetType == HORNET_TYPE_RED )
|
||||
{// no flying backwards, but we don't want to invert this, cause we'd go fast when we have to turn REAL far.
|
||||
flDelta = 0.25;
|
||||
}
|
||||
|
||||
pev->velocity = ( vecFlightDir + vecDirToEnemy).Normalize();
|
||||
|
||||
if ( pev->owner && (pev->owner->v.flags & FL_MONSTER) )
|
||||
{
|
||||
// random pattern only applies to hornets fired by monsters, not players.
|
||||
|
||||
pev->velocity.x += RANDOM_FLOAT ( -0.10, 0.10 );// scramble the flight dir a bit.
|
||||
pev->velocity.y += RANDOM_FLOAT ( -0.10, 0.10 );
|
||||
pev->velocity.z += RANDOM_FLOAT ( -0.10, 0.10 );
|
||||
}
|
||||
|
||||
switch ( m_iHornetType )
|
||||
{
|
||||
case HORNET_TYPE_RED:
|
||||
pev->velocity = pev->velocity * ( m_flFlySpeed * flDelta );// scale the dir by the ( speed * width of turn )
|
||||
pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.3 );
|
||||
break;
|
||||
case HORNET_TYPE_ORANGE:
|
||||
pev->velocity = pev->velocity * m_flFlySpeed;// do not have to slow down to turn.
|
||||
pev->nextthink = gpGlobals->time + 0.1;// fixed think time
|
||||
break;
|
||||
}
|
||||
|
||||
pev->angles = UTIL_VecToAngles (pev->velocity);
|
||||
|
||||
pev->solid = SOLID_BBOX;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// Tracking Hornet hit something
|
||||
//=========================================================
|
||||
void CMHornet :: TrackTouch ( edict_t *pOther )
|
||||
{
|
||||
if ( (pOther == pev->owner) || pOther->v.modelindex == pev->modelindex )
|
||||
{// bumped into the guy that shot it.
|
||||
pev->solid = SOLID_NOT;
|
||||
return;
|
||||
}
|
||||
|
||||
// is this NOT a player and IS a monster?
|
||||
if (!UTIL_IsPlayer(pOther) && (pOther->v.flags & FL_MONSTER))
|
||||
{
|
||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||
if ( pMonster != NULL && IRelationship( pMonster ) <= R_NO || IRelationshipByClass( pOther->v.iuser4 ) <= R_NO )
|
||||
{
|
||||
// hit something we don't want to hurt, so turn around.
|
||||
|
||||
pev->velocity = pev->velocity.Normalize();
|
||||
|
||||
pev->velocity.x *= -1;
|
||||
pev->velocity.y *= -1;
|
||||
|
||||
pev->origin = pev->origin + pev->velocity * 4; // bounce the hornet off a bit.
|
||||
pev->velocity = pev->velocity * m_flFlySpeed;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DieTouch( pOther );
|
||||
}
|
||||
|
||||
void CMHornet::DartTouch( edict_t *pOther )
|
||||
{
|
||||
DieTouch( pOther );
|
||||
}
|
||||
|
||||
void CMHornet::DieTouch ( edict_t *pOther )
|
||||
{
|
||||
if ( pOther && pOther->v.takedamage )
|
||||
{// do the damage
|
||||
|
||||
switch (RANDOM_LONG(0,2))
|
||||
{// buzz when you plug someone
|
||||
case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit1.wav", 1, ATTN_NORM); break;
|
||||
case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit2.wav", 1, ATTN_NORM); break;
|
||||
case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit3.wav", 1, ATTN_NORM); break;
|
||||
}
|
||||
|
||||
if (UTIL_IsPlayer(pOther))
|
||||
UTIL_TakeDamage( pOther, pev, VARS( pev->owner ), pev->dmg, DMG_BULLET );
|
||||
else if (pOther->v.euser4 != NULL)
|
||||
{
|
||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||
pMonster->TakeDamage( 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->solid = SOLID_NOT;
|
||||
|
||||
SetThink ( &CMHornet::SUB_Remove );
|
||||
pev->nextthink = gpGlobals->time + 1;// stick around long enough for the sound to finish!
|
||||
}
|
||||
|
||||
|
||||
@@ -1,55 +1,55 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
//=========================================================
|
||||
// Hornets
|
||||
//=========================================================
|
||||
|
||||
//=========================================================
|
||||
// Hornet Defines
|
||||
//=========================================================
|
||||
#define HORNET_TYPE_RED 0
|
||||
#define HORNET_TYPE_ORANGE 1
|
||||
#define HORNET_RED_SPEED (float)600
|
||||
#define HORNET_ORANGE_SPEED (float)800
|
||||
#define HORNET_BUZZ_VOLUME (float)0.8
|
||||
|
||||
extern int iHornetPuff;
|
||||
|
||||
//=========================================================
|
||||
// Hornet - this is the projectile that the Alien Grunt fires.
|
||||
//=========================================================
|
||||
class CMHornet : public CMBaseMonster
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
int Classify ( void );
|
||||
int IRelationship ( CMBaseEntity *pTarget );
|
||||
|
||||
void IgniteTrail( void );
|
||||
void EXPORT StartTrack ( void );
|
||||
void EXPORT StartDart ( void );
|
||||
void EXPORT TrackTarget ( void );
|
||||
void EXPORT TrackTouch ( edict_t *pOther );
|
||||
void EXPORT DartTouch( edict_t *pOther );
|
||||
void EXPORT DieTouch ( edict_t *pOther );
|
||||
|
||||
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
|
||||
|
||||
float m_flStopAttack;
|
||||
int m_iHornetType;
|
||||
float m_flFlySpeed;
|
||||
};
|
||||
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
//=========================================================
|
||||
// Hornets
|
||||
//=========================================================
|
||||
|
||||
//=========================================================
|
||||
// Hornet Defines
|
||||
//=========================================================
|
||||
#define HORNET_TYPE_RED 0
|
||||
#define HORNET_TYPE_ORANGE 1
|
||||
#define HORNET_RED_SPEED (float)600
|
||||
#define HORNET_ORANGE_SPEED (float)800
|
||||
#define HORNET_BUZZ_VOLUME (float)0.8
|
||||
|
||||
extern int iHornetPuff;
|
||||
|
||||
//=========================================================
|
||||
// Hornet - this is the projectile that the Alien Grunt fires.
|
||||
//=========================================================
|
||||
class CMHornet : public CMBaseMonster
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
int Classify ( void );
|
||||
int IRelationship ( CMBaseEntity *pTarget );
|
||||
|
||||
void IgniteTrail( void );
|
||||
void EXPORT StartTrack ( void );
|
||||
void EXPORT StartDart ( void );
|
||||
void EXPORT TrackTarget ( void );
|
||||
void EXPORT TrackTouch ( edict_t *pOther );
|
||||
void EXPORT DartTouch( edict_t *pOther );
|
||||
void EXPORT DieTouch ( edict_t *pOther );
|
||||
|
||||
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
|
||||
|
||||
float m_flStopAttack;
|
||||
int m_iHornetType;
|
||||
float m_flFlySpeed;
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
883
src/dlls/hwgrunt.cpp
Normal file
883
src/dlls/hwgrunt.cpp
Normal file
@@ -0,0 +1,883 @@
|
||||
/***
|
||||
*
|
||||
* 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
|
||||
//=========================================================
|
||||
#define HWGRUNT_9MM_CLIP_SIZE 17 // clip ammo per gun
|
||||
#define HWGRUNT_DGL_CLIP_SIZE 7
|
||||
#define HWGRUNT_357_CLIP_SIZE 6
|
||||
|
||||
// Weapon flags
|
||||
#define HWGRUNT_MINIGUN 0
|
||||
#define HWGRUNT_PISTOL_9MM 1
|
||||
#define HWGRUNT_PISTOL_DGL 2
|
||||
#define HWGRUNT_PISTOL_357 3
|
||||
|
||||
#define GUN_GROUP 1
|
||||
|
||||
// Gun values
|
||||
#define GUN_MINIGUN 0
|
||||
#define GUN_PISTOL_9MM 1
|
||||
#define GUN_PISTOL_357 2
|
||||
#define GUN_PISTOL_DGL 3
|
||||
#define GUN_NONE 4
|
||||
|
||||
//=========================================================
|
||||
// Monster's Anim Events Go Here
|
||||
//=========================================================
|
||||
#define HWGRUNT_AE_DEATH ( 11 )
|
||||
#define HWGRUNT_AE_MINIGUN ( 5001 )
|
||||
|
||||
//=========================================================
|
||||
// monster-specific schedule types
|
||||
//=========================================================
|
||||
enum
|
||||
{
|
||||
SCHED_HWGRUNT_SUPPRESS = LAST_COMMON_SCHEDULE + 1,
|
||||
SCHED_HWGRUNT_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_HWGRUNT_SWEEP,
|
||||
SCHED_HWGRUNT_REPEL,
|
||||
SCHED_HWGRUNT_REPEL_ATTACK,
|
||||
SCHED_HWGRUNT_REPEL_LAND,
|
||||
SCHED_HWGRUNT_WAIT_FACE_ENEMY,
|
||||
SCHED_HWGRUNT_ELOF_FAIL,
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// 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 = BLOOD_COLOR_RED;
|
||||
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");
|
||||
|
||||
PRECACHE_SOUND("common/null.wav");
|
||||
|
||||
// get voice pitch
|
||||
if (RANDOM_LONG(0, 1))
|
||||
m_voicePitch = 102 + RANDOM_LONG(0, 7);
|
||||
else
|
||||
m_voicePitch = 93; // slight voice change for hwgrunt
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// AI Schedules Specific to this monster
|
||||
//=========================================================
|
||||
|
||||
//=========================================================
|
||||
// GruntFail
|
||||
//=========================================================
|
||||
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"
|
||||
},
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// Grunt 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"
|
||||
},
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// 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 }
|
||||
};
|
||||
|
||||
Schedule_t slHWGruntVictoryDance[] =
|
||||
{
|
||||
{
|
||||
tlHWGruntVictoryDance,
|
||||
ARRAYSIZE ( tlHWGruntVictoryDance ),
|
||||
bits_COND_NEW_ENEMY,
|
||||
0,
|
||||
"HWGruntVictoryDance"
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
//=========================================================
|
||||
// ELOF fail, just wait and try again
|
||||
//=========================================================
|
||||
Task_t tlHWGruntELOFFail[] =
|
||||
{
|
||||
{ TASK_STOP_MOVING, (float)0 },
|
||||
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
|
||||
{ TASK_FACE_ENEMY, (float)0 },
|
||||
{ TASK_WAIT, (float)1.5 },
|
||||
{ TASK_SET_SCHEDULE, (float)SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE },
|
||||
};
|
||||
|
||||
Schedule_t slHWGruntELOFFail[] =
|
||||
{
|
||||
{
|
||||
tlHWGruntELOFFail,
|
||||
ARRAYSIZE ( tlHWGruntELOFFail ),
|
||||
bits_COND_NEW_ENEMY |
|
||||
bits_COND_ENEMY_DEAD |
|
||||
bits_COND_CAN_RANGE_ATTACK1,
|
||||
0,
|
||||
"HWGrunt Failed ELOF"
|
||||
},
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// 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_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,
|
||||
"HWGruntEstablishLineOfFire"
|
||||
},
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// GruntCombatFace Schedule
|
||||
//=========================================================
|
||||
Task_t tlHWGruntCombatFace1[] =
|
||||
{
|
||||
{ TASK_STOP_MOVING, 0 },
|
||||
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
|
||||
{ TASK_FACE_ENEMY, (float)0 },
|
||||
{ TASK_WAIT, (float)1.5 },
|
||||
{ TASK_SET_SCHEDULE, (float)SCHED_HWGRUNT_SWEEP },
|
||||
};
|
||||
|
||||
Schedule_t slHWGruntCombatFace[] =
|
||||
{
|
||||
{
|
||||
tlHWGruntCombatFace1,
|
||||
ARRAYSIZE ( tlHWGruntCombatFace1 ),
|
||||
bits_COND_NEW_ENEMY |
|
||||
bits_COND_ENEMY_DEAD |
|
||||
bits_COND_CAN_RANGE_ATTACK1,
|
||||
0,
|
||||
"HWCombat Face"
|
||||
},
|
||||
};
|
||||
|
||||
Task_t tlHWGruntSuppress[] =
|
||||
{
|
||||
{ TASK_STOP_MOVING, 0 },
|
||||
{ TASK_FACE_ENEMY, (float)0 },
|
||||
{ TASK_RANGE_ATTACK1, (float)0 },
|
||||
{ TASK_FACE_ENEMY, (float)0 },
|
||||
{ TASK_RANGE_ATTACK1, (float)0 },
|
||||
{ TASK_FACE_ENEMY, (float)0 },
|
||||
{ TASK_RANGE_ATTACK1, (float)0 },
|
||||
{ TASK_FACE_ENEMY, (float)0 },
|
||||
{ TASK_RANGE_ATTACK1, (float)0 },
|
||||
{ TASK_FACE_ENEMY, (float)0 },
|
||||
{ TASK_RANGE_ATTACK1, (float)0 },
|
||||
};
|
||||
|
||||
Schedule_t slHWGruntSuppress[] =
|
||||
{
|
||||
{
|
||||
tlHWGruntSuppress,
|
||||
ARRAYSIZE ( tlHWGruntSuppress ),
|
||||
0,
|
||||
0,
|
||||
"HWSuppress"
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
//=========================================================
|
||||
// grunt 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,
|
||||
"HWGruntWaitInCover"
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
//=========================================================
|
||||
// Do a turning sweep of the area
|
||||
//=========================================================
|
||||
Task_t tlHWGruntSweep[] =
|
||||
{
|
||||
{ TASK_TURN_LEFT, (float)179 },
|
||||
{ TASK_WAIT, (float)1 },
|
||||
{ TASK_TURN_LEFT, (float)179 },
|
||||
{ TASK_WAIT, (float)1 },
|
||||
};
|
||||
|
||||
Schedule_t slHWGruntSweep[] =
|
||||
{
|
||||
{
|
||||
tlHWGruntSweep,
|
||||
ARRAYSIZE ( tlHWGruntSweep ),
|
||||
bits_COND_NEW_ENEMY |
|
||||
bits_COND_CAN_RANGE_ATTACK1,
|
||||
0,
|
||||
"HWGrunt Sweep"
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
//=========================================================
|
||||
// primary range attack. Overriden because base class stops attacking when the enemy is occluded.
|
||||
// grunt's grenade toss requires the enemy be occluded.
|
||||
//=========================================================
|
||||
Task_t tlHWGruntRangeAttack1B[] =
|
||||
{
|
||||
{ TASK_STOP_MOVING, (float)0 },
|
||||
{ TASK_PLAY_SEQUENCE_FACE_ENEMY,(float)ACT_IDLE_ANGRY },
|
||||
{ TASK_RANGE_ATTACK1, (float)0 },
|
||||
{ TASK_FACE_ENEMY, (float)0 },
|
||||
{ TASK_RANGE_ATTACK1, (float)0 },
|
||||
{ TASK_FACE_ENEMY, (float)0 },
|
||||
{ TASK_RANGE_ATTACK1, (float)0 },
|
||||
{ TASK_FACE_ENEMY, (float)0 },
|
||||
{ TASK_RANGE_ATTACK1, (float)0 },
|
||||
};
|
||||
|
||||
Schedule_t slHWGruntRangeAttack1B[] =
|
||||
{
|
||||
{
|
||||
tlHWGruntRangeAttack1B,
|
||||
ARRAYSIZE ( tlHWGruntRangeAttack1B ),
|
||||
bits_COND_NEW_ENEMY |
|
||||
bits_COND_ENEMY_DEAD |
|
||||
bits_COND_ENEMY_OCCLUDED,
|
||||
0,
|
||||
"HWRange Attack1B"
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
//=========================================================
|
||||
// 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,
|
||||
0,
|
||||
"HWRepel"
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
//=========================================================
|
||||
// repel
|
||||
//=========================================================
|
||||
Task_t tlHWGruntRepelAttack[] =
|
||||
{
|
||||
{ TASK_STOP_MOVING, (float)0 },
|
||||
{ TASK_FACE_ENEMY, (float)0 },
|
||||
{ TASK_PLAY_SEQUENCE, (float)ACT_FLY },
|
||||
};
|
||||
|
||||
Schedule_t slHWGruntRepelAttack[] =
|
||||
{
|
||||
{
|
||||
tlHWGruntRepelAttack,
|
||||
ARRAYSIZE ( tlHWGruntRepelAttack ),
|
||||
bits_COND_ENEMY_OCCLUDED,
|
||||
0,
|
||||
"HWRepel Attack"
|
||||
},
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// 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,
|
||||
0,
|
||||
"HWRepel Land"
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
DEFINE_CUSTOM_SCHEDULES( CMHWGrunt )
|
||||
{
|
||||
slHWGruntFail,
|
||||
slHWGruntCombatFail,
|
||||
slHWGruntVictoryDance,
|
||||
slHWGruntELOFFail,
|
||||
slHWGruntEstablishLineOfFire,
|
||||
slHWGruntCombatFace,
|
||||
slHWGruntSuppress,
|
||||
slHWGruntWaitInCover,
|
||||
slHWGruntSweep,
|
||||
slHWGruntRangeAttack1B,
|
||||
slHWGruntRepel,
|
||||
slHWGruntRepelAttack,
|
||||
slHWGruntRepelLand,
|
||||
};
|
||||
|
||||
IMPLEMENT_CUSTOM_SCHEDULES( CMHWGrunt, CMBaseMonster );
|
||||
|
||||
//=========================================================
|
||||
// SetActivity - different set than normal hgrunt, adapt
|
||||
//=========================================================
|
||||
void CMHWGrunt :: SetActivity ( Activity NewActivity )
|
||||
{
|
||||
int iSequence = ACTIVITY_NOT_AVAILABLE;
|
||||
void *pmodel = GET_MODEL_PTR( ENT(pev) );
|
||||
bool refreshActivity = TRUE;
|
||||
|
||||
// PS: This is terrible code. -Giegue
|
||||
|
||||
// Time to die?
|
||||
if ( NewActivity < ACT_DIESIMPLE )
|
||||
{
|
||||
if ( pev->sequence == LookupSequence( "attack" ) )
|
||||
{
|
||||
// I won't do anything else if I'm attacking!
|
||||
refreshActivity = FALSE;
|
||||
|
||||
// Unless the enemy has gone out of my sight
|
||||
if ( m_hEnemy == 0 || !UTIL_IsAlive( m_hEnemy ) || !UTIL_FVisible( m_hEnemy, ENT(pev) ) )
|
||||
{
|
||||
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "hassault/hw_spindown.wav", 0.8, ATTN_NORM);
|
||||
m_flMinigunSpinTime = gpGlobals->time + 1.40;
|
||||
iSequence = LookupSequence( "spindown" ); // time to relax
|
||||
}
|
||||
}
|
||||
else if ( pev->sequence == LookupSequence( "spindown" ) )
|
||||
{
|
||||
// Not yet!
|
||||
refreshActivity = FALSE;
|
||||
|
||||
// Wait until the minigun is no longer spinning before doing something else
|
||||
if ( gpGlobals->time > m_flMinigunSpinTime )
|
||||
{
|
||||
refreshActivity = TRUE;
|
||||
m_flMinigunSpinTime = 0; // do spin up again when required
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (refreshActivity)
|
||||
{
|
||||
switch (NewActivity)
|
||||
{
|
||||
case ACT_RANGE_ATTACK1:
|
||||
// if carring a gun, either standing or crouched.
|
||||
// always standing when firing minigun
|
||||
if (pev->weapons > 0) // any pistol
|
||||
{
|
||||
// same animation regardless of pistol
|
||||
if ( m_fStanding )
|
||||
{
|
||||
// get aimable sequence
|
||||
iSequence = LookupSequence( "pistol_shoot" );
|
||||
}
|
||||
else
|
||||
{
|
||||
// get crouching shoot
|
||||
iSequence = LookupSequence( "pistol_crouchshoot" );
|
||||
}
|
||||
}
|
||||
else // minigun
|
||||
{
|
||||
if ( m_flMinigunSpinTime == 0 ) // starting to spin up the minigun
|
||||
{
|
||||
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "hassault/hw_spinup.wav", 0.8, ATTN_NORM);
|
||||
m_flMinigunSpinTime = gpGlobals->time + 1.15;
|
||||
iSequence = LookupSequence( "spinup" );
|
||||
}
|
||||
else if ( gpGlobals->time > m_flMinigunSpinTime ) // spun up, ready to fire
|
||||
iSequence = LookupSequence( "attack" );
|
||||
}
|
||||
break;
|
||||
case ACT_IDLE:
|
||||
if ( m_MonsterState == MONSTERSTATE_COMBAT )
|
||||
{
|
||||
NewActivity = ACT_IDLE_ANGRY;
|
||||
}
|
||||
iSequence = LookupActivity ( NewActivity );
|
||||
break;
|
||||
case ACT_RUN:
|
||||
case ACT_WALK:
|
||||
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 if (refreshActivity)
|
||||
{
|
||||
// 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 )
|
||||
{
|
||||
// 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
|
||||
{
|
||||
// repel down a rope,
|
||||
if ( m_MonsterState == MONSTERSTATE_COMBAT )
|
||||
return GetScheduleOfType ( SCHED_HWGRUNT_REPEL_ATTACK );
|
||||
else
|
||||
return GetScheduleOfType ( SCHED_HWGRUNT_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) )
|
||||
{
|
||||
if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
|
||||
{
|
||||
return GetScheduleOfType ( SCHED_HWGRUNT_SUPPRESS );
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetScheduleOfType ( SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE );
|
||||
}
|
||||
}
|
||||
// no ammo
|
||||
else if ( HasConditions ( bits_COND_NO_AMMO_LOADED ) )
|
||||
{
|
||||
// Stop believing you have no ammo! -Giegue
|
||||
ClearConditions( bits_COND_NO_AMMO_LOADED );
|
||||
if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
|
||||
{
|
||||
return GetScheduleOfType ( SCHED_HWGRUNT_SUPPRESS );
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetScheduleOfType ( SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE );
|
||||
}
|
||||
}
|
||||
// can shoot
|
||||
else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
|
||||
{
|
||||
// Force attack!
|
||||
return GetScheduleOfType ( SCHED_HWGRUNT_SUPPRESS );
|
||||
}
|
||||
// can't see enemy
|
||||
|
||||
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_HWGRUNT_ELOF_FAIL:
|
||||
{
|
||||
// human grunt is unable to move to a position that allows him to attack the enemy.
|
||||
return &slHWGruntELOFFail[ 0 ];
|
||||
}
|
||||
break;
|
||||
case SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE:
|
||||
{
|
||||
return &slHWGruntEstablishLineOfFire[ 0 ];
|
||||
}
|
||||
break;
|
||||
case SCHED_RANGE_ATTACK1:
|
||||
{
|
||||
// no pistols yet, always do standing attack
|
||||
return &slHWGruntRangeAttack1B[ 0 ];
|
||||
}
|
||||
case SCHED_COMBAT_FACE:
|
||||
{
|
||||
return &slHWGruntCombatFace[ 0 ];
|
||||
}
|
||||
case SCHED_HWGRUNT_WAIT_FACE_ENEMY:
|
||||
{
|
||||
return &slHWGruntWaitInCover[ 0 ];
|
||||
}
|
||||
case SCHED_HWGRUNT_SWEEP:
|
||||
{
|
||||
return &slHWGruntSweep[ 0 ];
|
||||
}
|
||||
case SCHED_VICTORY_DANCE:
|
||||
{
|
||||
return &slHWGruntVictoryDance[ 0 ];
|
||||
}
|
||||
case SCHED_HWGRUNT_SUPPRESS:
|
||||
{
|
||||
return &slHWGruntSuppress[ 0 ];
|
||||
}
|
||||
case SCHED_FAIL:
|
||||
{
|
||||
if ( m_hEnemy != NULL )
|
||||
{
|
||||
// grunt 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_ATTACK:
|
||||
{
|
||||
if (pev->velocity.z > -128)
|
||||
pev->velocity.z -= 32;
|
||||
return &slHWGruntRepelAttack[ 0 ];
|
||||
}
|
||||
case SCHED_HWGRUNT_REPEL_LAND:
|
||||
{
|
||||
return &slHWGruntRepelLand[ 0 ];
|
||||
}
|
||||
default:
|
||||
{
|
||||
return CMBaseMonster :: GetScheduleOfType ( Type );
|
||||
}
|
||||
}
|
||||
}
|
||||
1526
src/dlls/islave.cpp
1526
src/dlls/islave.cpp
File diff suppressed because it is too large
Load Diff
311
src/dlls/massn.cpp
Normal file
311
src/dlls/massn.cpp
Normal file
@@ -0,0 +1,311 @@
|
||||
// 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"
|
||||
|
||||
//=========================================================
|
||||
// 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_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;
|
||||
|
||||
// BUG - For some reason that still eludes me, grunts are completely unable to reload their weapons.
|
||||
// As a temporary fix, give them infinite ammo. It will look bad I know... I gotta find a solution. -Giegue
|
||||
//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_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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
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 = BLOOD_COLOR_RED;
|
||||
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;
|
||||
}
|
||||
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();
|
||||
|
||||
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_MODEL("models/shell.mdl");// brass shell
|
||||
}
|
||||
@@ -1,163 +1,163 @@
|
||||
//
|
||||
// Monster Mod is a modification based on Botman's original "Monster" plugin.
|
||||
// The "forgotten" modification was made by Rick90.
|
||||
// This is an attempt to recreate the plugin so it does not become lost again.
|
||||
//
|
||||
// Recreated by Giegue.
|
||||
//
|
||||
// monster_api.cpp
|
||||
//
|
||||
|
||||
/*
|
||||
* This is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this code; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "extdll.h"
|
||||
#include "meta_api.h"
|
||||
#include "sdk_util.h" // UTIL_LogPrintf, etc
|
||||
|
||||
// Must provide at least one of these..
|
||||
static META_FUNCTIONS gMetaFunctionTable =
|
||||
{
|
||||
NULL, // pfnGetEntityAPI HL SDK; called before game DLL
|
||||
NULL, // pfnGetEntityAPI_Post META; called after game DLL
|
||||
GetEntityAPI2, // pfnGetEntityAPI2 HL SDK2; called before game DLL
|
||||
GetEntityAPI2_Post, // pfnGetEntityAPI2_Post META; called after game DLL
|
||||
NULL, // pfnGetNewDLLFunctions HL SDK2; called before game DLL
|
||||
NULL, // pfnGetNewDLLFunctions_Post META; called after game DLL
|
||||
GetEngineFunctions, // pfnGetEngineFunctions META; called before HL engine
|
||||
GetEngineFunctions_Post, // pfnGetEngineFunctions_Post META; called after HL engine
|
||||
};
|
||||
|
||||
// Description of plugin
|
||||
plugin_info_t Plugin_info = {
|
||||
META_INTERFACE_VERSION, // interface version
|
||||
"MonsterMod", // name
|
||||
"2.0", // version
|
||||
"03/06/2020", // date in DD/MM/YYYY format
|
||||
"botman, Rick90, Giegue", // original authors + recreation by...
|
||||
"https://github.com/JulianR0/monstermod-redo", // url
|
||||
"MONSTER", // logtag
|
||||
PT_CHANGELEVEL, // (when) loadable
|
||||
PT_CHANGELEVEL, // (when) unloadable
|
||||
};
|
||||
|
||||
char *VNAME=Plugin_info.name;
|
||||
char *VVERSION=Plugin_info.version;
|
||||
char *VDATE=Plugin_info.date;
|
||||
char *VAUTHOR=Plugin_info.author;
|
||||
char *VURL=Plugin_info.url;
|
||||
char *VLOGTAG=Plugin_info.logtag;
|
||||
char *COMPILE_TIME=__DATE__ ", " __TIME__;
|
||||
|
||||
// Global vars from metamod:
|
||||
meta_globals_t *gpMetaGlobals; // metamod globals
|
||||
gamedll_funcs_t *gpGamedllFuncs; // gameDLL function tables
|
||||
mutil_funcs_t *gpMetaUtilFuncs; // metamod utility functions
|
||||
|
||||
// CVars
|
||||
cvar_t init_dllapi_log = {"monster_log", "0", FCVAR_EXTDLL, 0, NULL};
|
||||
cvar_t *dllapi_log = NULL;
|
||||
cvar_t init_monster_spawn = {"monster_spawn", "1", FCVAR_EXTDLL, 0, 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;
|
||||
|
||||
|
||||
// Metamod requesting info about this plugin:
|
||||
// ifvers (given) interface_version metamod is using
|
||||
// pPlugInfo (requested) struct with info about plugin
|
||||
// pMetaUtilFuncs (given) table of utility functions provided by metamod
|
||||
C_DLLEXPORT int Meta_Query(char *ifvers, plugin_info_t **pPlugInfo,
|
||||
mutil_funcs_t *pMetaUtilFuncs)
|
||||
{
|
||||
if(ifvers); // to satisfy gcc -Wunused
|
||||
// Give metamod our plugin_info struct
|
||||
*pPlugInfo=&Plugin_info;
|
||||
// Get metamod utility function table.
|
||||
gpMetaUtilFuncs=pMetaUtilFuncs;
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// Metamod attaching plugin to the server.
|
||||
// now (given) current phase, ie during map, during changelevel, or at startup
|
||||
// pFunctionTable (requested) table of function tables this plugin catches
|
||||
// pMGlobals (given) global vars from metamod
|
||||
// pGamedllFuncs (given) copy of function tables from game dll
|
||||
C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs)
|
||||
{
|
||||
if(now); // to satisfy gcc -Wunused
|
||||
if(!pMGlobals)
|
||||
{
|
||||
LOG_ERROR(PLID, "Meta_Attach called with null pMGlobals");
|
||||
return(FALSE);
|
||||
}
|
||||
gpMetaGlobals=pMGlobals;
|
||||
if(!pFunctionTable)
|
||||
{
|
||||
LOG_ERROR(PLID, "Meta_Attach called with null pFunctionTable");
|
||||
return(FALSE);
|
||||
}
|
||||
memcpy(pFunctionTable, &gMetaFunctionTable, sizeof(META_FUNCTIONS));
|
||||
gpGamedllFuncs=pGamedllFuncs;
|
||||
|
||||
LOG_MESSAGE(PLID, "%s %s, %s", VNAME, VVERSION, VDATE);
|
||||
LOG_MESSAGE(PLID, "by %s", VAUTHOR);
|
||||
LOG_MESSAGE(PLID, "%s", VURL);
|
||||
LOG_MESSAGE(PLID, "compiled: %s CDT", COMPILE_TIME);
|
||||
|
||||
LOG_CONSOLE(PLID, "[%s] %s v%s, %s", VLOGTAG, VNAME, VVERSION, VDATE);
|
||||
LOG_CONSOLE(PLID, "[%s] by %s", VLOGTAG, VAUTHOR);
|
||||
|
||||
CVAR_REGISTER(&init_dllapi_log);
|
||||
dllapi_log = CVAR_GET_POINTER("monster_log");
|
||||
|
||||
CVAR_REGISTER(&init_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");
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
extern void monster_unload(void);
|
||||
|
||||
// Metamod detaching plugin from the server.
|
||||
// now (given) current phase, ie during map, etc
|
||||
// reason (given) why detaching (refresh, console unload, forced unload, etc)
|
||||
C_DLLEXPORT int Meta_Detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) {
|
||||
// remove all the monsters currently in the level...
|
||||
monster_unload();
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
//
|
||||
// Monster Mod is a modification based on Botman's original "Monster" plugin.
|
||||
// The "forgotten" modification was made by Rick90.
|
||||
// This is an attempt to recreate the plugin so it does not become lost again.
|
||||
//
|
||||
// Recreated by Giegue.
|
||||
//
|
||||
// monster_api.cpp
|
||||
//
|
||||
|
||||
/*
|
||||
* This is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this code; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "extdll.h"
|
||||
#include "meta_api.h"
|
||||
#include "sdk_util.h" // UTIL_LogPrintf, etc
|
||||
|
||||
// Must provide at least one of these..
|
||||
static META_FUNCTIONS gMetaFunctionTable =
|
||||
{
|
||||
NULL, // pfnGetEntityAPI HL SDK; called before game DLL
|
||||
NULL, // pfnGetEntityAPI_Post META; called after game DLL
|
||||
GetEntityAPI2, // pfnGetEntityAPI2 HL SDK2; called before game DLL
|
||||
GetEntityAPI2_Post, // pfnGetEntityAPI2_Post META; called after game DLL
|
||||
NULL, // pfnGetNewDLLFunctions HL SDK2; called before game DLL
|
||||
NULL, // pfnGetNewDLLFunctions_Post META; called after game DLL
|
||||
GetEngineFunctions, // pfnGetEngineFunctions META; called before HL engine
|
||||
GetEngineFunctions_Post, // pfnGetEngineFunctions_Post META; called after HL engine
|
||||
};
|
||||
|
||||
// Description of plugin
|
||||
plugin_info_t Plugin_info = {
|
||||
META_INTERFACE_VERSION, // interface version
|
||||
"MonsterMod", // name
|
||||
"3.0", // version
|
||||
"24/02/2023", // date in DD/MM/YYYY format
|
||||
"botman, Rick90, Giegue", // original authors + recreation by...
|
||||
"https://github.com/JulianR0/monstermod-redo", // url
|
||||
"MONSTER", // logtag
|
||||
PT_CHANGELEVEL, // (when) loadable
|
||||
PT_CHANGELEVEL, // (when) unloadable
|
||||
};
|
||||
|
||||
char *VNAME=Plugin_info.name;
|
||||
char *VVERSION=Plugin_info.version;
|
||||
char *VDATE=Plugin_info.date;
|
||||
char *VAUTHOR=Plugin_info.author;
|
||||
char *VURL=Plugin_info.url;
|
||||
char *VLOGTAG=Plugin_info.logtag;
|
||||
char *COMPILE_TIME=__DATE__ ", " __TIME__;
|
||||
|
||||
// Global vars from metamod:
|
||||
meta_globals_t *gpMetaGlobals; // metamod globals
|
||||
gamedll_funcs_t *gpGamedllFuncs; // gameDLL function tables
|
||||
mutil_funcs_t *gpMetaUtilFuncs; // metamod utility functions
|
||||
|
||||
// CVars
|
||||
cvar_t init_dllapi_log = {"monster_log", "0", FCVAR_EXTDLL, 0, NULL};
|
||||
cvar_t *dllapi_log = NULL;
|
||||
cvar_t init_monster_spawn = {"monster_spawn", "1", FCVAR_EXTDLL, 0, 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;
|
||||
|
||||
|
||||
// Metamod requesting info about this plugin:
|
||||
// ifvers (given) interface_version metamod is using
|
||||
// pPlugInfo (requested) struct with info about plugin
|
||||
// pMetaUtilFuncs (given) table of utility functions provided by metamod
|
||||
C_DLLEXPORT int Meta_Query(char *ifvers, plugin_info_t **pPlugInfo,
|
||||
mutil_funcs_t *pMetaUtilFuncs)
|
||||
{
|
||||
if(ifvers); // to satisfy gcc -Wunused
|
||||
// Give metamod our plugin_info struct
|
||||
*pPlugInfo=&Plugin_info;
|
||||
// Get metamod utility function table.
|
||||
gpMetaUtilFuncs=pMetaUtilFuncs;
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// Metamod attaching plugin to the server.
|
||||
// now (given) current phase, ie during map, during changelevel, or at startup
|
||||
// pFunctionTable (requested) table of function tables this plugin catches
|
||||
// pMGlobals (given) global vars from metamod
|
||||
// pGamedllFuncs (given) copy of function tables from game dll
|
||||
C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs)
|
||||
{
|
||||
if(now); // to satisfy gcc -Wunused
|
||||
if(!pMGlobals)
|
||||
{
|
||||
LOG_ERROR(PLID, "Meta_Attach called with null pMGlobals");
|
||||
return(FALSE);
|
||||
}
|
||||
gpMetaGlobals=pMGlobals;
|
||||
if(!pFunctionTable)
|
||||
{
|
||||
LOG_ERROR(PLID, "Meta_Attach called with null pFunctionTable");
|
||||
return(FALSE);
|
||||
}
|
||||
memcpy(pFunctionTable, &gMetaFunctionTable, sizeof(META_FUNCTIONS));
|
||||
gpGamedllFuncs=pGamedllFuncs;
|
||||
|
||||
LOG_MESSAGE(PLID, "%s %s, %s", VNAME, VVERSION, VDATE);
|
||||
LOG_MESSAGE(PLID, "by %s", VAUTHOR);
|
||||
LOG_MESSAGE(PLID, "%s", VURL);
|
||||
LOG_MESSAGE(PLID, "compiled: %s CDT", COMPILE_TIME);
|
||||
|
||||
LOG_CONSOLE(PLID, "[%s] %s v%s, %s", VLOGTAG, VNAME, VVERSION, VDATE);
|
||||
LOG_CONSOLE(PLID, "[%s] by %s", VLOGTAG, VAUTHOR);
|
||||
|
||||
CVAR_REGISTER(&init_dllapi_log);
|
||||
dllapi_log = CVAR_GET_POINTER("monster_log");
|
||||
|
||||
CVAR_REGISTER(&init_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");
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
extern void monster_unload(void);
|
||||
|
||||
// Metamod detaching plugin from the server.
|
||||
// now (given) current phase, ie during map, etc
|
||||
// reason (given) why detaching (refresh, console unload, forced unload, etc)
|
||||
C_DLLEXPORT int Meta_Detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) {
|
||||
// remove all the monsters currently in the level...
|
||||
monster_unload();
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,433 +1,485 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifndef __linux__
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "extdll.h"
|
||||
#include "dllapi.h"
|
||||
#include "meta_api.h"
|
||||
|
||||
#include "monster_plugin.h"
|
||||
|
||||
extern cvar_t *dllapi_log;
|
||||
|
||||
extern monster_type_t monster_types[];
|
||||
extern int monster_spawn_count;
|
||||
extern int node_spawn_count;
|
||||
|
||||
bool get_input(FILE *fp, char *input)
|
||||
{
|
||||
char line[1024];
|
||||
int len, pos;
|
||||
|
||||
while (!feof(fp))
|
||||
{
|
||||
if (fgets(line, 1023, fp) != NULL)
|
||||
{
|
||||
len = strlen(line);
|
||||
|
||||
if (len == 0)
|
||||
continue; // skip any null lines
|
||||
|
||||
// remove any trailing newline, carriage return or whitespace...
|
||||
while ((line[len-1] == '\n') || (line[len-1] == '\r') || isspace(line[len-1]))
|
||||
{
|
||||
line[len-1] = 0;
|
||||
len--;
|
||||
if (len == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
|
||||
while (isspace(line[pos]))
|
||||
pos++; // skip leading blanks
|
||||
|
||||
if ((line[pos] == '/') && (line[pos+1] == '/'))
|
||||
continue; // skip comment lines
|
||||
|
||||
if (line[pos] == 0)
|
||||
continue; // skip empty lines
|
||||
|
||||
strcpy(input, &line[pos]);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE; // no input found
|
||||
}
|
||||
|
||||
void scan_monster_cfg(FILE *fp)
|
||||
{
|
||||
// Let's make a full rework of this. -Giegue
|
||||
char input[1024];
|
||||
float x, y, z;
|
||||
bool badent, monster, node;
|
||||
|
||||
while (get_input(fp, input))
|
||||
{
|
||||
badent = monster = node = FALSE;
|
||||
if (input[0] == '{')
|
||||
{
|
||||
// Proper start, initialize entity creation
|
||||
// Temporary variables to store entity data
|
||||
pKVD *data = (pKVD*)malloc(MAX_KEYVALUES*sizeof(*data)); // Entities should not have more than this many keyvalues
|
||||
int kvd_index = 0;
|
||||
while (get_input(fp, input))
|
||||
{
|
||||
// It's the end of the entity structure?
|
||||
if (input[0] == '}')
|
||||
{
|
||||
// Check if the classname of whatever we want to spawn is valid.
|
||||
if (strcmp(data[kvd_index-1].key, "classname") == 0)
|
||||
{
|
||||
int mIndex;
|
||||
for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
|
||||
{
|
||||
if (strcmp(data[kvd_index-1].value, monster_types[mIndex].name) == 0)
|
||||
{
|
||||
// Now that I think about it this looks slow and bad code >.>
|
||||
|
||||
// A match is found. What is this?
|
||||
if (strncmp(monster_types[mIndex].name, "monster", 7) == 0)
|
||||
{
|
||||
// It's a monster, add it to the list
|
||||
if (monster_spawn_count == MAX_MONSTERS)
|
||||
{
|
||||
// Ouch! Not enough room.
|
||||
LOG_MESSAGE(PLID, "ERROR: can't add monster, reached MAX_MONSTERS!"); // It will get spammy, sadly.
|
||||
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)
|
||||
{
|
||||
// Normal node
|
||||
if (node_spawn_count == MAX_NODES)
|
||||
{
|
||||
// The map can't be THAT big can it?
|
||||
LOG_MESSAGE(PLID, "ERROR: can't add node, reached MAX_NODES!"); // zee spam bOi
|
||||
badent = TRUE;
|
||||
}
|
||||
else
|
||||
node = TRUE;
|
||||
}
|
||||
else if (strcmp(monster_types[mIndex].name, "info_node_air") == 0)
|
||||
{
|
||||
// Aerial node
|
||||
if (node_spawn_count == MAX_NODES)
|
||||
{
|
||||
// Ctrl+C --> Ctrl+V
|
||||
LOG_MESSAGE(PLID, "ERROR: can't add node, reached MAX_NODES!"); // poppo was here.
|
||||
badent = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
node_spawnpoint[node_spawn_count].is_air_node = TRUE;
|
||||
node = TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (monster_types[mIndex].name[0] == 0)
|
||||
{
|
||||
LOG_MESSAGE(PLID, "ERROR: unknown classname: %s", input); // print conflictive line
|
||||
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!");
|
||||
badent = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// What are you doing?!
|
||||
LOG_MESSAGE(PLID, "ERROR: BAD ENTITY STRUCTURE! Last line was %s", input); // print conflictive line
|
||||
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!");
|
||||
badent = TRUE;
|
||||
}
|
||||
|
||||
if (!badent)
|
||||
{
|
||||
// Make room for entity-specific keyvalues.
|
||||
if (monster)
|
||||
{
|
||||
// The line is a little too long, no?
|
||||
monster_spawnpoint[monster_spawn_count].keyvalue = (pKVD*)calloc(MAX_KEYVALUES, sizeof(*monster_spawnpoint[monster_spawn_count].keyvalue));
|
||||
}
|
||||
|
||||
// Done. Let's process the keyvalues.
|
||||
for (int i = 0; i < (kvd_index-1); i++)
|
||||
{
|
||||
// Any duplicate keyvalue is 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", input); // 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, "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)
|
||||
{
|
||||
if (monster)
|
||||
{
|
||||
if (sscanf(data[i].value, "%f %f %f", &x, &y, &z) != 3)
|
||||
{
|
||||
LOG_MESSAGE(PLID, "ERROR: invalid angles: %s", input); // 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", input); // 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
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
// Init monster
|
||||
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_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!
|
||||
// No, I'm not making this idiotproof. Classname should be the last KVD entry on an entity!
|
||||
LOG_CONSOLE(PLID, "[DEBUG] Added entity: %s", data[kvd_index-1].value);
|
||||
}
|
||||
}
|
||||
|
||||
free( data );
|
||||
break;
|
||||
}
|
||||
|
||||
// Bruteforce to remove quotes
|
||||
char parse[66] = {0};
|
||||
int skip = 0;
|
||||
for (int i = 0; i < strlen(input); i++)
|
||||
{
|
||||
if (input[i] == '"')
|
||||
{
|
||||
skip++;
|
||||
continue;
|
||||
}
|
||||
parse[i-skip] = input[i];
|
||||
}
|
||||
parse[strlen(parse)] = '\0';
|
||||
|
||||
// Copy all keyvalues to the tempvar
|
||||
// Key
|
||||
char *copy = strtok(parse, " ");
|
||||
strcpy(data[kvd_index].key, copy);
|
||||
|
||||
// Value
|
||||
copy = strtok(NULL, " ");
|
||||
strcpy(data[kvd_index].value, "");
|
||||
while (copy != NULL)
|
||||
{
|
||||
// If the value is a vector, append necessary whitespaces
|
||||
strcat(data[kvd_index].value, copy);
|
||||
copy = strtok(NULL, " ");
|
||||
if (copy != NULL)
|
||||
strcat(data[kvd_index].value, " ");
|
||||
}
|
||||
|
||||
// Next KVD
|
||||
kvd_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void process_monster_cfg(void)
|
||||
{
|
||||
char game_dir[256];
|
||||
char filename[256];
|
||||
FILE *fp = NULL;
|
||||
bool status = FALSE; // no error
|
||||
|
||||
monster_spawn_count = 0;
|
||||
|
||||
// find the directory name of the currently running MOD...
|
||||
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
||||
|
||||
strcpy(filename, game_dir);
|
||||
#ifdef __linux__
|
||||
strcat(filename, "/maps/");
|
||||
#else
|
||||
strcat(filename, "\\maps\\");
|
||||
#endif
|
||||
strcat(filename, STRING(gpGlobals->mapname));
|
||||
strcat(filename, "_monster.cfg");
|
||||
|
||||
// check if the map specific filename exists...
|
||||
if (access(filename, 0) == 0)
|
||||
{
|
||||
if (dllapi_log->value)
|
||||
{
|
||||
//META_CONS("[MONSTER] Processing config file=%s", filename);
|
||||
LOG_MESSAGE(PLID, "Processing config file=%s", filename);
|
||||
}
|
||||
|
||||
if ((fp = fopen(filename, "r")) == NULL)
|
||||
{
|
||||
//META_CONS("[MONSTER] ERROR: Could not open \"%s\"!", filename);
|
||||
LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\" file!", filename);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
scan_monster_cfg(fp);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool scan_monster_precache_cfg(FILE *fp)
|
||||
{
|
||||
char input[1024];
|
||||
bool found;
|
||||
|
||||
while (get_input(fp, input))
|
||||
{
|
||||
found = FALSE;
|
||||
|
||||
for (int index=0; monster_types[index].name[0]; index++)
|
||||
{
|
||||
if (strcmp(input, monster_types[index].name) == 0)
|
||||
{
|
||||
monster_types[index].need_to_precache = TRUE;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == FALSE)
|
||||
{
|
||||
//META_CONS("[MONSTER] ERROR: invalid precache monster name: %s", input);
|
||||
LOG_MESSAGE(PLID, "ERROR: invalid precache monster name: %s", input);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
bool process_monster_precache_cfg(void)
|
||||
{
|
||||
char game_dir[256];
|
||||
char filename[256];
|
||||
FILE *fp = NULL;
|
||||
bool status = FALSE; // no error
|
||||
|
||||
// find the directory name of the currently running MOD...
|
||||
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
||||
|
||||
strcpy(filename, game_dir);
|
||||
strcat(filename, "/monster_precache.cfg");
|
||||
|
||||
// check if the map specific filename exists...
|
||||
if (access(filename, 0) == 0)
|
||||
{
|
||||
if (dllapi_log->value)
|
||||
{
|
||||
//META_CONS("[MONSTER] Processing config file=%s", filename);
|
||||
LOG_MESSAGE(PLID, "Processing config file=%s", filename);
|
||||
}
|
||||
|
||||
if ((fp = fopen(filename, "r")) == NULL)
|
||||
{
|
||||
//META_CONS("[MONSTER] ERROR: Could not open \"%s\"!", filename);
|
||||
LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\" file!", filename);
|
||||
|
||||
return TRUE; // return bad status
|
||||
}
|
||||
|
||||
status = scan_monster_precache_cfg(fp);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifndef __linux__
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "extdll.h"
|
||||
#include "dllapi.h"
|
||||
#include "meta_api.h"
|
||||
|
||||
#include "monster_plugin.h"
|
||||
|
||||
extern cvar_t *dllapi_log;
|
||||
|
||||
extern monster_type_t monster_types[];
|
||||
extern int monster_spawn_count;
|
||||
extern int node_spawn_count;
|
||||
|
||||
bool get_input(FILE *fp, char *input)
|
||||
{
|
||||
char line[1024];
|
||||
int len, pos;
|
||||
|
||||
while (!feof(fp))
|
||||
{
|
||||
if (fgets(line, 1023, fp) != NULL)
|
||||
{
|
||||
len = strlen(line);
|
||||
|
||||
if (len == 0)
|
||||
continue; // skip any null lines
|
||||
|
||||
// remove any trailing newline, carriage return or whitespace...
|
||||
while ((line[len-1] == '\n') || (line[len-1] == '\r') || isspace(line[len-1]))
|
||||
{
|
||||
line[len-1] = 0;
|
||||
len--;
|
||||
if (len == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
|
||||
while (isspace(line[pos]))
|
||||
pos++; // skip leading blanks
|
||||
|
||||
if ((line[pos] == '/') && (line[pos+1] == '/'))
|
||||
continue; // skip comment lines
|
||||
|
||||
if (line[pos] == 0)
|
||||
continue; // skip empty lines
|
||||
|
||||
strcpy(input, &line[pos]);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE; // no input found
|
||||
}
|
||||
|
||||
void scan_monster_cfg(FILE *fp)
|
||||
{
|
||||
// Let's make a full rework of this. -Giegue
|
||||
char input[1024];
|
||||
float x, y, z;
|
||||
bool badent, monster, node;
|
||||
|
||||
while (get_input(fp, input))
|
||||
{
|
||||
badent = monster = node = FALSE;
|
||||
if (input[0] == '{')
|
||||
{
|
||||
// Proper start, initialize entity creation
|
||||
// Temporary variables to store entity data
|
||||
pKVD *data = (pKVD*)malloc(MAX_KEYVALUES*sizeof(*data)); // Entities should not have more than this many keyvalues
|
||||
int kvd_index = 0;
|
||||
while (get_input(fp, input))
|
||||
{
|
||||
// It's the end of the entity structure?
|
||||
if (input[0] == '}')
|
||||
{
|
||||
// Check if the classname of whatever we want to spawn is valid.
|
||||
if (strcmp(data[kvd_index-1].key, "classname") == 0)
|
||||
{
|
||||
int mIndex;
|
||||
for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
|
||||
{
|
||||
if (strcmp(data[kvd_index-1].value, monster_types[mIndex].name) == 0)
|
||||
{
|
||||
// Now that I think about it this looks slow and bad code >.>
|
||||
|
||||
// A match is found. What is this?
|
||||
if (strncmp(monster_types[mIndex].name, "monster_", 8) == 0)
|
||||
{
|
||||
// It's a monster, add it to the list
|
||||
if (monster_spawn_count == MAX_MONSTERS)
|
||||
{
|
||||
// Ouch! Not enough room.
|
||||
LOG_MESSAGE(PLID, "ERROR: can't add monster, reached MAX_MONSTERS!"); // It will get spammy, sadly.
|
||||
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, "monstermaker") == 0)
|
||||
{
|
||||
// A monster spawner, add it to the list
|
||||
if (monster_spawn_count == MAX_MONSTERS)
|
||||
{
|
||||
// error.exe
|
||||
LOG_MESSAGE(PLID, "ERROR: can't add monstermaker, reached MAX_MONSTERS!");
|
||||
badent = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
monster_spawnpoint[monster_spawn_count].monster = mIndex;
|
||||
monster_types[mIndex].need_to_precache = TRUE;
|
||||
monster = TRUE;
|
||||
}
|
||||
}
|
||||
else if (strcmp(monster_types[mIndex].name, "info_node") == 0)
|
||||
{
|
||||
// Normal node
|
||||
if (node_spawn_count == MAX_NODES)
|
||||
{
|
||||
// The map can't be THAT big can it?
|
||||
LOG_MESSAGE(PLID, "ERROR: can't add node, reached MAX_NODES!"); // zee spam bOi
|
||||
badent = TRUE;
|
||||
}
|
||||
else
|
||||
node = TRUE;
|
||||
}
|
||||
else if (strcmp(monster_types[mIndex].name, "info_node_air") == 0)
|
||||
{
|
||||
// Aerial node
|
||||
if (node_spawn_count == MAX_NODES)
|
||||
{
|
||||
// Ctrl+C --> Ctrl+V
|
||||
LOG_MESSAGE(PLID, "ERROR: can't add node, reached MAX_NODES!"); // poppo was here.
|
||||
badent = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
node_spawnpoint[node_spawn_count].is_air_node = TRUE;
|
||||
node = TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (monster_types[mIndex].name[0] == 0)
|
||||
{
|
||||
LOG_MESSAGE(PLID, "ERROR: unknown classname: %s", data[kvd_index-1].value); // print conflictive line
|
||||
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!");
|
||||
badent = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// What are you doing?!
|
||||
LOG_MESSAGE(PLID, "ERROR: BAD ENTITY STRUCTURE! Last line was %s", data[kvd_index-1].key); // print conflictive line
|
||||
LOG_MESSAGE(PLID, "ERROR: classname MUST be the last entry of the entity!" );
|
||||
badent = TRUE;
|
||||
}
|
||||
|
||||
if (!badent)
|
||||
{
|
||||
// Make room for entity-specific keyvalues.
|
||||
if (monster)
|
||||
{
|
||||
// The line is a little too long, no?
|
||||
monster_spawnpoint[monster_spawn_count].keyvalue = (pKVD*)calloc(MAX_KEYVALUES, sizeof(*monster_spawnpoint[monster_spawn_count].keyvalue));
|
||||
}
|
||||
|
||||
// Done. Let's process the keyvalues.
|
||||
for (int i = 0; i < (kvd_index-1); i++)
|
||||
{
|
||||
// Any duplicate keyvalue is 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", input); // 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", input); // 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", input); // 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[kvd_index-1].value, "monstermaker") != 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, "new_model") == 0)
|
||||
{
|
||||
if (monster)
|
||||
{
|
||||
// only applicable for monstermaket entity
|
||||
if (strcmp(data[kvd_index-1].value, "monstermaker") == 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)
|
||||
{
|
||||
// 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
|
||||
{
|
||||
// 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!
|
||||
// No, I'm not making this idiotproof. Classname should be the last KVD entry on an entity!
|
||||
LOG_CONSOLE(PLID, "[DEBUG] Added entity: %s", data[kvd_index-1].value);
|
||||
}
|
||||
}
|
||||
|
||||
free( data );
|
||||
break;
|
||||
}
|
||||
|
||||
// Bruteforce to remove quotes
|
||||
char parse[66] = {0};
|
||||
int skip = 0;
|
||||
for (unsigned i = 0; i < strlen(input); i++)
|
||||
{
|
||||
if (input[i] == '"')
|
||||
{
|
||||
skip++;
|
||||
continue;
|
||||
}
|
||||
parse[i-skip] = input[i];
|
||||
}
|
||||
parse[strlen(parse)] = '\0';
|
||||
|
||||
// Copy all keyvalues to the tempvar
|
||||
// Key
|
||||
char *copy = strtok(parse, " ");
|
||||
strcpy(data[kvd_index].key, copy);
|
||||
|
||||
// Value
|
||||
copy = strtok(NULL, " ");
|
||||
strcpy(data[kvd_index].value, "");
|
||||
while (copy != NULL)
|
||||
{
|
||||
// If the value is a vector, append necessary whitespaces
|
||||
strcat(data[kvd_index].value, copy);
|
||||
copy = strtok(NULL, " ");
|
||||
if (copy != NULL)
|
||||
strcat(data[kvd_index].value, " ");
|
||||
}
|
||||
|
||||
// Next KVD
|
||||
kvd_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool process_monster_cfg(void)
|
||||
{
|
||||
char game_dir[256];
|
||||
char filename[256];
|
||||
FILE *fp = NULL;
|
||||
|
||||
monster_spawn_count = 0;
|
||||
|
||||
// find the directory name of the currently running MOD...
|
||||
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
||||
|
||||
strcpy(filename, game_dir);
|
||||
#ifdef __linux__
|
||||
strcat(filename, "/maps/");
|
||||
#else
|
||||
strcat(filename, "\\maps\\");
|
||||
#endif
|
||||
strcat(filename, STRING(gpGlobals->mapname));
|
||||
strcat(filename, "_monster.cfg");
|
||||
|
||||
// check if the map specific filename exists...
|
||||
if (access(filename, 0) == 0)
|
||||
{
|
||||
if (dllapi_log->value)
|
||||
{
|
||||
//META_CONS("[MONSTER] Processing config file=%s", filename);
|
||||
LOG_MESSAGE(PLID, "Processing config file=%s", filename);
|
||||
}
|
||||
|
||||
if ((fp = fopen(filename, "r")) == NULL)
|
||||
{
|
||||
//META_CONS("[MONSTER] ERROR: Could not open \"%s\"!", filename);
|
||||
LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\" file!", filename);
|
||||
return TRUE; // error
|
||||
}
|
||||
|
||||
scan_monster_cfg(fp);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return FALSE; // all ok
|
||||
}
|
||||
|
||||
|
||||
bool scan_monster_precache_cfg(FILE *fp)
|
||||
{
|
||||
char input[1024];
|
||||
bool found;
|
||||
|
||||
while (get_input(fp, input))
|
||||
{
|
||||
found = FALSE;
|
||||
|
||||
for (int index=0; monster_types[index].name[0]; index++)
|
||||
{
|
||||
if (strcmp(input, monster_types[index].name) == 0)
|
||||
{
|
||||
monster_types[index].need_to_precache = TRUE;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == FALSE)
|
||||
{
|
||||
//META_CONS("[MONSTER] ERROR: invalid precache monster name: %s", input);
|
||||
LOG_MESSAGE(PLID, "ERROR: invalid precache monster name: %s", input);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
bool process_monster_precache_cfg(void)
|
||||
{
|
||||
char game_dir[256];
|
||||
char filename[256];
|
||||
FILE *fp = NULL;
|
||||
bool status = FALSE; // no error
|
||||
|
||||
// find the directory name of the currently running MOD...
|
||||
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
||||
|
||||
strcpy(filename, game_dir);
|
||||
strcat(filename, "/monster_precache.cfg");
|
||||
|
||||
// check if the map specific filename exists...
|
||||
if (access(filename, 0) == 0)
|
||||
{
|
||||
if (dllapi_log->value)
|
||||
{
|
||||
//META_CONS("[MONSTER] Processing config file=%s", filename);
|
||||
LOG_MESSAGE(PLID, "Processing config file=%s", filename);
|
||||
}
|
||||
|
||||
if ((fp = fopen(filename, "r")) == NULL)
|
||||
{
|
||||
//META_CONS("[MONSTER] ERROR: Could not open \"%s\"!", filename);
|
||||
LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\" file!", filename);
|
||||
|
||||
return TRUE; // return bad status
|
||||
}
|
||||
|
||||
status = scan_monster_precache_cfg(fp);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
LIBRARY monster_mm
|
||||
EXPORTS
|
||||
GiveFnptrsToDll @1
|
||||
SECTIONS
|
||||
.data READ WRITE
|
||||
LIBRARY monster_mm
|
||||
EXPORTS
|
||||
GiveFnptrsToDll @1
|
||||
SECTIONS
|
||||
.data READ WRITE
|
||||
|
||||
@@ -1,378 +1,437 @@
|
||||
# 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
|
||||
# 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"
|
||||
|
||||
!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
|
||||
|
||||
!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=.\explode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\flyingmonster.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\gargantua.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ggrenade.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\gonome.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=.\hwgrunt.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\islave.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\massn.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=.\monstermaker.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=.\otis.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\pitdrone.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\rgrunt.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\scientist.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\shock.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\shockroach.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=.\sporegrenade.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\squeakgrenade.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\strooper.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stukabat.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=.\turret.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\util.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\voltigore.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=.\activitymap.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=.\cmbaseextra.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=.\defaultai.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=.\hornet.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\monster_plugin.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\monsterevent.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=.\plane.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\schedule.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\shock.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
|
||||
|
||||
@@ -1,74 +1,71 @@
|
||||
//
|
||||
// monster_plugin.h
|
||||
//
|
||||
|
||||
#ifndef MONSTER_PLUGIN_H
|
||||
#define MONSTER_PLUGIN_H
|
||||
|
||||
typedef struct pKVD
|
||||
{
|
||||
char key[33];
|
||||
char value[33];
|
||||
};
|
||||
|
||||
#define MAX_KEYVALUES 32
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
bool need_to_precache;
|
||||
} monster_type_t;
|
||||
|
||||
|
||||
class CMBaseMonster;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int monster_index;
|
||||
edict_t *monster_pent;
|
||||
bool killed;
|
||||
int respawn_index;
|
||||
CMBaseMonster *pMonster;
|
||||
} monster_t;
|
||||
|
||||
#define MAX_MONSTER_ENTS 400 // increased from 200 so it can hold non-monster entities
|
||||
|
||||
extern monster_t monsters[MAX_MONSTER_ENTS];
|
||||
|
||||
typedef struct {
|
||||
Vector origin;
|
||||
Vector angles;
|
||||
float delay;
|
||||
unsigned char monster;
|
||||
int spawnflags;
|
||||
pKVD *keyvalue;
|
||||
float respawn_time;
|
||||
bool need_to_respawn;
|
||||
} monster_spawnpoint_t;
|
||||
|
||||
#define MAX_MONSTERS 100
|
||||
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
|
||||
typedef struct
|
||||
{
|
||||
Vector origin;
|
||||
bool is_air_node;
|
||||
} node_spawnpoint_t;
|
||||
|
||||
// nodes.cpp defines 1024 max nodes, but that amount is likely to trigger a
|
||||
// no free edicts crash if the server num_edicts is low. Increase if needed.
|
||||
#define MAX_NODES 256
|
||||
extern node_spawnpoint_t node_spawnpoint[MAX_NODES];
|
||||
|
||||
extern DLL_GLOBAL short g_sModelIndexFireball;// holds the index for the fireball
|
||||
extern DLL_GLOBAL short g_sModelIndexSmoke;// holds the index for the smoke cloud
|
||||
extern DLL_GLOBAL short g_sModelIndexWExplosion;// holds the index for the underwater explosion
|
||||
extern DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model
|
||||
extern DLL_GLOBAL short g_sModelIndexBloodDrop;// holds the sprite index for the initial blood
|
||||
extern DLL_GLOBAL short g_sModelIndexBloodSpray;// holds the sprite index for splattered blood
|
||||
extern DLL_GLOBAL short g_sModelIndexLaser;// holds the index for the laser beam
|
||||
extern DLL_GLOBAL const char *g_pModelNameLaser;
|
||||
extern DLL_GLOBAL short g_sModelIndexLaserDot;// holds the index for the laser beam dot
|
||||
|
||||
#endif
|
||||
//
|
||||
// monster_plugin.h
|
||||
//
|
||||
|
||||
#ifndef MONSTER_PLUGIN_H
|
||||
#define MONSTER_PLUGIN_H
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char key[33];
|
||||
char value[33];
|
||||
} pKVD;
|
||||
|
||||
#define MAX_KEYVALUES 32
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
bool need_to_precache;
|
||||
} monster_type_t;
|
||||
|
||||
|
||||
class CMBaseMonster;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int monster_index;
|
||||
edict_t *monster_pent;
|
||||
bool killed;
|
||||
CMBaseMonster *pMonster;
|
||||
} monster_t;
|
||||
|
||||
#define MAX_MONSTER_ENTS 400 // increased from 200 so it can hold non-monster entities
|
||||
|
||||
extern monster_t monsters[MAX_MONSTER_ENTS];
|
||||
|
||||
typedef struct {
|
||||
Vector origin;
|
||||
Vector angles;
|
||||
unsigned char monster;
|
||||
int spawnflags;
|
||||
pKVD *keyvalue;
|
||||
bool need_to_respawn;
|
||||
} monster_spawnpoint_t;
|
||||
|
||||
#define MAX_MONSTERS 100
|
||||
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
|
||||
typedef struct
|
||||
{
|
||||
Vector origin;
|
||||
bool is_air_node;
|
||||
} node_spawnpoint_t;
|
||||
|
||||
// nodes.cpp defines 1024 max nodes, but that amount is likely to trigger a
|
||||
// no free edicts crash if the server num_edicts is low. Increase if needed.
|
||||
#define MAX_NODES 256
|
||||
extern node_spawnpoint_t node_spawnpoint[MAX_NODES];
|
||||
|
||||
extern DLL_GLOBAL short g_sModelIndexFireball;// holds the index for the fireball
|
||||
extern DLL_GLOBAL short g_sModelIndexSmoke;// holds the index for the smoke cloud
|
||||
extern DLL_GLOBAL short g_sModelIndexWExplosion;// holds the index for the underwater explosion
|
||||
extern DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model
|
||||
extern DLL_GLOBAL short g_sModelIndexBloodDrop;// holds the sprite index for the initial blood
|
||||
extern DLL_GLOBAL short g_sModelIndexBloodSpray;// holds the sprite index for splattered blood
|
||||
extern DLL_GLOBAL short g_sModelIndexLaser;// holds the index for the laser beam
|
||||
extern DLL_GLOBAL const char *g_pModelNameLaser;
|
||||
extern DLL_GLOBAL short g_sModelIndexLaserDot;// holds the index for the laser beam dot
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef MONSTEREVENT_H
|
||||
#define MONSTEREVENT_H
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int event;
|
||||
char *options;
|
||||
} MonsterEvent_t;
|
||||
|
||||
#define EVENT_SPECIFIC 0
|
||||
#define EVENT_SCRIPTED 1000
|
||||
#define EVENT_SHARED 2000
|
||||
#define EVENT_CLIENT 5000
|
||||
|
||||
#define MONSTER_EVENT_BODYDROP_LIGHT 2001
|
||||
#define MONSTER_EVENT_BODYDROP_HEAVY 2002
|
||||
|
||||
#define MONSTER_EVENT_SWISHSOUND 2010
|
||||
|
||||
#endif // MONSTEREVENT_H
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef MONSTEREVENT_H
|
||||
#define MONSTEREVENT_H
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int event;
|
||||
char *options;
|
||||
} MonsterEvent_t;
|
||||
|
||||
#define EVENT_SPECIFIC 0
|
||||
#define EVENT_SCRIPTED 1000
|
||||
#define EVENT_SHARED 2000
|
||||
#define EVENT_CLIENT 5000
|
||||
|
||||
#define MONSTER_EVENT_BODYDROP_LIGHT 2001
|
||||
#define MONSTER_EVENT_BODYDROP_HEAVY 2002
|
||||
|
||||
#define MONSTER_EVENT_SWISHSOUND 2010
|
||||
|
||||
#endif // MONSTEREVENT_H
|
||||
|
||||
255
src/dlls/monstermaker.cpp
Normal file
255
src/dlls/monstermaker.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
/***
|
||||
*
|
||||
* 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
|
||||
}
|
||||
}
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if ( FStrEq(pkvd->szKeyName, "new_model") )
|
||||
{
|
||||
m_iszCustomModel = ALLOC_STRING(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else
|
||||
CMBaseMonster::KeyValue( pkvd );
|
||||
}
|
||||
|
||||
|
||||
void CMMonsterMaker :: Spawn( )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void CMMonsterMaker :: Precache( void )
|
||||
{
|
||||
CMBaseMonster::Precache();
|
||||
// choosen monster is auto-precached
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// MakeMonster- this is the code that drops the monster
|
||||
//=========================================================
|
||||
void CMMonsterMaker::MakeMonster( void )
|
||||
{
|
||||
edict_t *pent;
|
||||
pKVD keyvalue[1]; // 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;
|
||||
|
||||
// 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 ));
|
||||
}
|
||||
|
||||
// Attempt to spawn monster
|
||||
pent = spawn_monster(m_iMonsterIndex, pev->origin, pev->angles, createSF, keyvalue);
|
||||
if ( pent == NULL )
|
||||
{
|
||||
ALERT ( at_console, "NULL Ent in MonsterMaker!\n" );
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,180 +1,181 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef MONSTERS_H
|
||||
#define MONSTERS_H
|
||||
|
||||
/*
|
||||
|
||||
===== monsters.h ========================================================
|
||||
|
||||
Header file for monster-related utility code
|
||||
|
||||
*/
|
||||
|
||||
// CHECKLOCALMOVE result types
|
||||
#define LOCALMOVE_INVALID 0 // move is not possible
|
||||
#define LOCALMOVE_INVALID_DONT_TRIANGULATE 1 // move is not possible, don't try to triangulate
|
||||
#define LOCALMOVE_VALID 2 // move is possible
|
||||
|
||||
// Hit Group standards
|
||||
#define HITGROUP_GENERIC 0
|
||||
#define HITGROUP_HEAD 1
|
||||
#define HITGROUP_CHEST 2
|
||||
#define HITGROUP_STOMACH 3
|
||||
#define HITGROUP_LEFTARM 4
|
||||
#define HITGROUP_RIGHTARM 5
|
||||
#define HITGROUP_LEFTLEG 6
|
||||
#define HITGROUP_RIGHTLEG 7
|
||||
|
||||
|
||||
// Monster Spawnflags
|
||||
#define SF_MONSTER_WAIT_TILL_SEEN 1// spawnflag that makes monsters wait until player can see them before attacking.
|
||||
#define SF_MONSTER_GAG 2 // no idle noises from this monster
|
||||
#define SF_MONSTER_HITMONSTERCLIP 4
|
||||
// 8
|
||||
#define SF_MONSTER_PRISONER 16 // monster won't attack anyone, no one will attacke him.
|
||||
// 32
|
||||
// 64
|
||||
#define SF_MONSTER_WAIT_FOR_SCRIPT 128 //spawnflag that makes monsters wait to check for attacking until the script is done or they've been attacked
|
||||
#define SF_MONSTER_PREDISASTER 256 //this is a predisaster scientist or barney. Influences how they speak.
|
||||
#define SF_MONSTER_FADECORPSE 512 // Fade out corpse after death
|
||||
#define SF_MONSTER_FALL_TO_GROUND 0x80000000
|
||||
|
||||
// specialty spawnflags
|
||||
#define SF_MONSTER_TURRET_AUTOACTIVATE 32
|
||||
#define SF_MONSTER_TURRET_STARTINACTIVE 64
|
||||
#define SF_MONSTER_WAIT_UNTIL_PROVOKED 64 // don't attack the player unless provoked
|
||||
|
||||
|
||||
|
||||
// MoveToOrigin stuff
|
||||
#define MOVE_START_TURN_DIST 64 // when this far away from moveGoal, start turning to face next goal
|
||||
#define MOVE_STUCK_DIST 32 // if a monster can't step this far, it is stuck.
|
||||
|
||||
|
||||
// MoveToOrigin stuff
|
||||
#define MOVE_NORMAL 0// normal move in the direction monster is facing
|
||||
#define MOVE_STRAFE 1// moves in direction specified, no matter which way monster is facing
|
||||
|
||||
// spawn flags 256 and above are already taken by the engine
|
||||
extern void UTIL_MoveToOrigin( edict_t* pent, const Vector &vecGoal, float flDist, int iMoveType );
|
||||
|
||||
Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj = 1.0 );
|
||||
Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj = 1.0 );
|
||||
extern DLL_GLOBAL Vector g_vecAttackDir;
|
||||
extern DLL_GLOBAL CONSTANT float g_flMeleeRange;
|
||||
extern DLL_GLOBAL CONSTANT float g_flMediumRange;
|
||||
extern DLL_GLOBAL CONSTANT float g_flLongRange;
|
||||
extern void EjectBrass (const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype );
|
||||
extern void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count );
|
||||
|
||||
BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget );
|
||||
BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize = 0.0 );
|
||||
|
||||
// monster to monster relationship types
|
||||
#define R_AL -2 // (ALLY) pals. Good alternative to R_NO when applicable.
|
||||
#define R_FR -1// (FEAR)will run
|
||||
#define R_NO 0// (NO RELATIONSHIP) disregard
|
||||
#define R_DL 1// (DISLIKE) will attack
|
||||
#define R_HT 2// (HATE)will attack this character instead of any visible DISLIKEd characters
|
||||
#define R_NM 3// (NEMESIS) A monster Will ALWAYS attack its nemsis, no matter what
|
||||
|
||||
|
||||
// these bits represent the monster's memory
|
||||
#define MEMORY_CLEAR 0
|
||||
#define bits_MEMORY_PROVOKED ( 1 << 0 )// right now only used for houndeyes.
|
||||
#define bits_MEMORY_INCOVER ( 1 << 1 )// monster knows it is in a covered position.
|
||||
#define bits_MEMORY_SUSPICIOUS ( 1 << 2 )// Ally is suspicious of the player, and will move to provoked more easily
|
||||
#define bits_MEMORY_PATH_FINISHED ( 1 << 3 )// Finished monster path (just used by big momma for now)
|
||||
#define bits_MEMORY_ON_PATH ( 1 << 4 )// Moving on a path
|
||||
#define bits_MEMORY_MOVE_FAILED ( 1 << 5 )// Movement has already failed
|
||||
#define bits_MEMORY_FLINCHED ( 1 << 6 )// Has already flinched
|
||||
#define bits_MEMORY_KILLED ( 1 << 7 )// HACKHACK -- remember that I've already called my Killed()
|
||||
#define bits_MEMORY_CUSTOM4 ( 1 << 28 ) // Monster-specific memory
|
||||
#define bits_MEMORY_CUSTOM3 ( 1 << 29 ) // Monster-specific memory
|
||||
#define bits_MEMORY_CUSTOM2 ( 1 << 30 ) // Monster-specific memory
|
||||
#define bits_MEMORY_CUSTOM1 ( 1 << 31 ) // Monster-specific memory
|
||||
|
||||
// trigger conditions for scripted AI
|
||||
// these MUST match the CHOICES interface in halflife.fgd for the base monster
|
||||
enum
|
||||
{
|
||||
AITRIGGER_NONE = 0,
|
||||
AITRIGGER_SEEPLAYER_ANGRY_AT_PLAYER,
|
||||
AITRIGGER_TAKEDAMAGE,
|
||||
AITRIGGER_HALFHEALTH,
|
||||
AITRIGGER_DEATH,
|
||||
AITRIGGER_SQUADMEMBERDIE,
|
||||
AITRIGGER_SQUADLEADERDIE,
|
||||
AITRIGGER_HEARWORLD,
|
||||
AITRIGGER_HEARPLAYER,
|
||||
AITRIGGER_HEARCOMBAT,
|
||||
AITRIGGER_SEEPLAYER_UNCONDITIONAL,
|
||||
AITRIGGER_SEEPLAYER_NOT_IN_COMBAT,
|
||||
};
|
||||
/*
|
||||
0 : "No Trigger"
|
||||
1 : "See Player"
|
||||
2 : "Take Damage"
|
||||
3 : "50% Health Remaining"
|
||||
4 : "Death"
|
||||
5 : "Squad Member Dead"
|
||||
6 : "Squad Leader Dead"
|
||||
7 : "Hear World"
|
||||
8 : "Hear Player"
|
||||
9 : "Hear Combat"
|
||||
*/
|
||||
|
||||
//
|
||||
// A gib is a chunk of a body, or a piece of wood/metal/rocks/etc.
|
||||
//
|
||||
class CMGib : public CMBaseEntity
|
||||
{
|
||||
public:
|
||||
void Spawn( const char *szGibModel );
|
||||
void EXPORT BounceGibTouch ( edict_t *pOther );
|
||||
void EXPORT StickyGibTouch ( edict_t *pOther );
|
||||
void EXPORT WaitTillLand( void );
|
||||
void LimitVelocity( void );
|
||||
|
||||
virtual int ObjectCaps( void ) { return (CMBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; }
|
||||
static void SpawnHeadGib( entvars_t *pevVictim );
|
||||
static void SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human );
|
||||
static void SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs );
|
||||
|
||||
int m_bloodColor;
|
||||
int m_cBloodDecals;
|
||||
int m_material;
|
||||
float m_lifeTime;
|
||||
};
|
||||
|
||||
|
||||
#define CUSTOM_SCHEDULES\
|
||||
virtual Schedule_t *ScheduleFromName( const char *pName );\
|
||||
static Schedule_t *m_scheduleList[];
|
||||
|
||||
#define DEFINE_CUSTOM_SCHEDULES(derivedClass)\
|
||||
Schedule_t *derivedClass::m_scheduleList[] =
|
||||
|
||||
#define IMPLEMENT_CUSTOM_SCHEDULES(derivedClass, baseClass)\
|
||||
Schedule_t *derivedClass::ScheduleFromName( const char *pName )\
|
||||
{\
|
||||
Schedule_t *pSchedule = ScheduleInList( pName, m_scheduleList, ARRAYSIZE(m_scheduleList) );\
|
||||
if ( !pSchedule )\
|
||||
return baseClass::ScheduleFromName(pName);\
|
||||
return pSchedule;\
|
||||
}
|
||||
|
||||
#endif //MONSTERS_H
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef MONSTERS_H
|
||||
#define MONSTERS_H
|
||||
|
||||
/*
|
||||
|
||||
===== monsters.h ========================================================
|
||||
|
||||
Header file for monster-related utility code
|
||||
|
||||
*/
|
||||
|
||||
// CHECKLOCALMOVE result types
|
||||
#define LOCALMOVE_INVALID 0 // move is not possible
|
||||
#define LOCALMOVE_INVALID_DONT_TRIANGULATE 1 // move is not possible, don't try to triangulate
|
||||
#define LOCALMOVE_VALID 2 // move is possible
|
||||
|
||||
// Hit Group standards
|
||||
#define HITGROUP_GENERIC 0
|
||||
#define HITGROUP_HEAD 1
|
||||
#define HITGROUP_CHEST 2
|
||||
#define HITGROUP_STOMACH 3
|
||||
#define HITGROUP_LEFTARM 4
|
||||
#define HITGROUP_RIGHTARM 5
|
||||
#define HITGROUP_LEFTLEG 6
|
||||
#define HITGROUP_RIGHTLEG 7
|
||||
|
||||
|
||||
// Monster Spawnflags
|
||||
#define SF_MONSTER_WAIT_TILL_SEEN 1// spawnflag that makes monsters wait until player can see them before attacking.
|
||||
#define SF_MONSTER_GAG 2 // no idle noises from this monster
|
||||
#define SF_MONSTER_HITMONSTERCLIP 4
|
||||
// 8
|
||||
#define SF_MONSTER_PRISONER 16 // monster won't attack anyone, no one will attacke him.
|
||||
// 32
|
||||
// 64
|
||||
#define SF_MONSTER_WAIT_FOR_SCRIPT 128 //spawnflag that makes monsters wait to check for attacking until the script is done or they've been attacked
|
||||
#define SF_MONSTER_PREDISASTER 256 //this is a predisaster scientist or barney. Influences how they speak.
|
||||
#define SF_MONSTER_FADECORPSE 512 // Fade out corpse after death
|
||||
#define SF_MONSTER_FALL_TO_GROUND 0x80000000
|
||||
|
||||
// specialty spawnflags
|
||||
#define SF_MONSTER_TURRET_AUTOACTIVATE 32
|
||||
#define SF_MONSTER_TURRET_STARTINACTIVE 64
|
||||
#define SF_MONSTER_WAIT_UNTIL_PROVOKED 64 // don't attack the player unless provoked
|
||||
|
||||
|
||||
|
||||
// MoveToOrigin stuff
|
||||
#define MOVE_START_TURN_DIST 64 // when this far away from moveGoal, start turning to face next goal
|
||||
#define MOVE_STUCK_DIST 32 // if a monster can't step this far, it is stuck.
|
||||
|
||||
|
||||
// MoveToOrigin stuff
|
||||
#define MOVE_NORMAL 0// normal move in the direction monster is facing
|
||||
#define MOVE_STRAFE 1// moves in direction specified, no matter which way monster is facing
|
||||
|
||||
// spawn flags 256 and above are already taken by the engine
|
||||
extern void UTIL_MoveToOrigin( edict_t* pent, const Vector &vecGoal, float flDist, int iMoveType );
|
||||
|
||||
Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj = 1.0 );
|
||||
Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj = 1.0 );
|
||||
extern DLL_GLOBAL Vector g_vecAttackDir;
|
||||
extern DLL_GLOBAL CONSTANT float g_flMeleeRange;
|
||||
extern DLL_GLOBAL CONSTANT float g_flMediumRange;
|
||||
extern DLL_GLOBAL CONSTANT float g_flLongRange;
|
||||
extern void EjectBrass (const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype );
|
||||
extern void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count );
|
||||
|
||||
BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget );
|
||||
BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize = 0.0 );
|
||||
|
||||
// monster to monster relationship types
|
||||
#define R_AL -2 // (ALLY) pals. Good alternative to R_NO when applicable.
|
||||
#define R_FR -1// (FEAR)will run
|
||||
#define R_NO 0// (NO RELATIONSHIP) disregard
|
||||
#define R_DL 1// (DISLIKE) will attack
|
||||
#define R_HT 2// (HATE)will attack this character instead of any visible DISLIKEd characters
|
||||
#define R_NM 3// (NEMESIS) A monster Will ALWAYS attack its nemsis, no matter what
|
||||
|
||||
|
||||
// these bits represent the monster's memory
|
||||
#define MEMORY_CLEAR 0
|
||||
#define bits_MEMORY_PROVOKED ( 1 << 0 )// right now only used for houndeyes.
|
||||
#define bits_MEMORY_INCOVER ( 1 << 1 )// monster knows it is in a covered position.
|
||||
#define bits_MEMORY_SUSPICIOUS ( 1 << 2 )// Ally is suspicious of the player, and will move to provoked more easily
|
||||
#define bits_MEMORY_PATH_FINISHED ( 1 << 3 )// Finished monster path (just used by big momma for now)
|
||||
#define bits_MEMORY_ON_PATH ( 1 << 4 )// Moving on a path
|
||||
#define bits_MEMORY_MOVE_FAILED ( 1 << 5 )// Movement has already failed
|
||||
#define bits_MEMORY_FLINCHED ( 1 << 6 )// Has already flinched
|
||||
#define bits_MEMORY_KILLED ( 1 << 7 )// HACKHACK -- remember that I've already called my Killed()
|
||||
#define bits_MEMORY_CUSTOM4 ( 1 << 28 ) // Monster-specific memory
|
||||
#define bits_MEMORY_CUSTOM3 ( 1 << 29 ) // Monster-specific memory
|
||||
#define bits_MEMORY_CUSTOM2 ( 1 << 30 ) // Monster-specific memory
|
||||
#define bits_MEMORY_CUSTOM1 ( 1 << 31 ) // Monster-specific memory
|
||||
|
||||
// trigger conditions for scripted AI
|
||||
// these MUST match the CHOICES interface in halflife.fgd for the base monster
|
||||
enum
|
||||
{
|
||||
AITRIGGER_NONE = 0,
|
||||
AITRIGGER_SEEPLAYER_ANGRY_AT_PLAYER,
|
||||
AITRIGGER_TAKEDAMAGE,
|
||||
AITRIGGER_HALFHEALTH,
|
||||
AITRIGGER_DEATH,
|
||||
AITRIGGER_SQUADMEMBERDIE,
|
||||
AITRIGGER_SQUADLEADERDIE,
|
||||
AITRIGGER_HEARWORLD,
|
||||
AITRIGGER_HEARPLAYER,
|
||||
AITRIGGER_HEARCOMBAT,
|
||||
AITRIGGER_SEEPLAYER_UNCONDITIONAL,
|
||||
AITRIGGER_SEEPLAYER_NOT_IN_COMBAT,
|
||||
};
|
||||
/*
|
||||
0 : "No Trigger"
|
||||
1 : "See Player"
|
||||
2 : "Take Damage"
|
||||
3 : "50% Health Remaining"
|
||||
4 : "Death"
|
||||
5 : "Squad Member Dead"
|
||||
6 : "Squad Leader Dead"
|
||||
7 : "Hear World"
|
||||
8 : "Hear Player"
|
||||
9 : "Hear Combat"
|
||||
*/
|
||||
|
||||
//
|
||||
// A gib is a chunk of a body, or a piece of wood/metal/rocks/etc.
|
||||
//
|
||||
class CMGib : public CMBaseEntity
|
||||
{
|
||||
public:
|
||||
void Spawn( const char *szGibModel );
|
||||
void EXPORT BounceGibTouch ( edict_t *pOther );
|
||||
void EXPORT StickyGibTouch ( edict_t *pOther );
|
||||
void EXPORT WaitTillLand( void );
|
||||
void LimitVelocity( void );
|
||||
|
||||
virtual int ObjectCaps( void ) { return (CMBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; }
|
||||
static void SpawnHeadGib( entvars_t *pevVictim );
|
||||
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 );
|
||||
|
||||
int m_bloodColor;
|
||||
int m_cBloodDecals;
|
||||
int m_material;
|
||||
float m_lifeTime;
|
||||
};
|
||||
|
||||
|
||||
#define CUSTOM_SCHEDULES\
|
||||
virtual Schedule_t *ScheduleFromName( const char *pName );\
|
||||
static Schedule_t *m_scheduleList[];
|
||||
|
||||
#define DEFINE_CUSTOM_SCHEDULES(derivedClass)\
|
||||
Schedule_t *derivedClass::m_scheduleList[] =
|
||||
|
||||
#define IMPLEMENT_CUSTOM_SCHEDULES(derivedClass, baseClass)\
|
||||
Schedule_t *derivedClass::ScheduleFromName( const char *pName )\
|
||||
{\
|
||||
Schedule_t *pSchedule = ScheduleInList( pName, m_scheduleList, ARRAYSIZE(m_scheduleList) );\
|
||||
if ( !pSchedule )\
|
||||
return baseClass::ScheduleFromName(pName);\
|
||||
return pSchedule;\
|
||||
}
|
||||
|
||||
#endif //MONSTERS_H
|
||||
|
||||
@@ -1,214 +1,214 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
//=========================================================
|
||||
// monsterstate.cpp - base class monster functions for
|
||||
// controlling core AI.
|
||||
//=========================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "nodes.h"
|
||||
#include "monsters.h"
|
||||
#include "animation.h"
|
||||
|
||||
//=========================================================
|
||||
// SetState
|
||||
//=========================================================
|
||||
void CMBaseMonster :: SetState ( MONSTERSTATE State )
|
||||
{
|
||||
/*
|
||||
if ( State != m_MonsterState )
|
||||
{
|
||||
ALERT ( at_aiconsole, "State Changed to %d\n", State );
|
||||
}
|
||||
*/
|
||||
|
||||
switch( State )
|
||||
{
|
||||
|
||||
// Drop enemy pointers when going to idle
|
||||
case MONSTERSTATE_IDLE:
|
||||
|
||||
if (( m_hEnemy != NULL ) &&
|
||||
( strcmp(STRING(pev->model), "models/scientist.mdl") != 0))
|
||||
{
|
||||
m_hEnemy = NULL;// not allowed to have an enemy anymore.
|
||||
ALERT ( at_aiconsole, "Stripped\n" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
m_MonsterState = State;
|
||||
m_IdealMonsterState = State;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// RunAI
|
||||
//=========================================================
|
||||
void CMBaseMonster :: RunAI ( void )
|
||||
{
|
||||
// to test model's eye height
|
||||
//UTIL_ParticleEffect ( pev->origin + pev->view_ofs, g_vecZero, 255, 10 );
|
||||
|
||||
// IDLE sound permitted in ALERT state is because monsters were silent in ALERT state. Only play IDLE sound in IDLE state
|
||||
// once we have sounds for that state.
|
||||
if ( ( m_MonsterState == MONSTERSTATE_IDLE || m_MonsterState == MONSTERSTATE_ALERT ) && RANDOM_LONG(0,99) == 0 && !(pev->flags & SF_MONSTER_GAG) )
|
||||
{
|
||||
IdleSound();
|
||||
}
|
||||
|
||||
if ( m_MonsterState != MONSTERSTATE_NONE &&
|
||||
m_MonsterState != MONSTERSTATE_PRONE &&
|
||||
m_MonsterState != MONSTERSTATE_DEAD )// don't bother with this crap if monster is prone.
|
||||
{
|
||||
// collect some sensory Condition information.
|
||||
// don't let monsters outside of the player's PVS act up, or most of the interesting
|
||||
// things will happen before the player gets there!
|
||||
// UPDATE: We now let COMBAT state monsters think and act fully outside of player PVS. This allows the player to leave
|
||||
// an area where monsters are fighting, and the fight will continue.
|
||||
if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) || ( m_MonsterState == MONSTERSTATE_COMBAT ) )
|
||||
{
|
||||
Look( m_flDistLook );
|
||||
//jlb Listen();// check for audible sounds.
|
||||
|
||||
// now filter conditions.
|
||||
ClearConditions( IgnoreConditions() );
|
||||
|
||||
GetEnemy();
|
||||
}
|
||||
|
||||
// do these calculations if monster has an enemy.
|
||||
if ( m_hEnemy != NULL )
|
||||
{
|
||||
CheckEnemy( m_hEnemy );
|
||||
}
|
||||
|
||||
CheckAmmo();
|
||||
}
|
||||
|
||||
FCheckAITrigger();
|
||||
|
||||
PrescheduleThink();
|
||||
|
||||
MaintainSchedule();
|
||||
|
||||
// if the monster didn't use these conditions during the above call to MaintainSchedule() or CheckAITrigger()
|
||||
// we throw them out cause we don't want them sitting around through the lifespan of a schedule
|
||||
// that doesn't use them.
|
||||
m_afConditions &= ~( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// GetIdealState - surveys the Conditions information available
|
||||
// and finds the best new state for a monster.
|
||||
//=========================================================
|
||||
MONSTERSTATE CMBaseMonster :: GetIdealState ( void )
|
||||
{
|
||||
int iConditions;
|
||||
|
||||
iConditions = IScheduleFlags();
|
||||
|
||||
// If no schedule conditions, the new ideal state is probably the reason we're in here.
|
||||
switch ( m_MonsterState )
|
||||
{
|
||||
case MONSTERSTATE_IDLE:
|
||||
|
||||
/*
|
||||
IDLE goes to ALERT upon hearing a sound
|
||||
-IDLE goes to ALERT upon being injured
|
||||
IDLE goes to ALERT upon seeing food
|
||||
-IDLE goes to COMBAT upon sighting an enemy
|
||||
IDLE goes to HUNT upon smelling food
|
||||
*/
|
||||
{
|
||||
if ( iConditions & bits_COND_NEW_ENEMY )
|
||||
{
|
||||
// new enemy! This means an idle monster has seen someone it dislikes, or
|
||||
// that a monster in combat has found a more suitable target to attack
|
||||
m_IdealMonsterState = MONSTERSTATE_COMBAT;
|
||||
}
|
||||
else if ( iConditions & bits_COND_LIGHT_DAMAGE )
|
||||
{
|
||||
MakeIdealYaw ( m_vecEnemyLKP );
|
||||
m_IdealMonsterState = MONSTERSTATE_ALERT;
|
||||
}
|
||||
else if ( iConditions & bits_COND_HEAVY_DAMAGE )
|
||||
{
|
||||
MakeIdealYaw ( m_vecEnemyLKP );
|
||||
m_IdealMonsterState = MONSTERSTATE_ALERT;
|
||||
}
|
||||
else if ( iConditions & bits_COND_HEAR_SOUND )
|
||||
{
|
||||
}
|
||||
else if ( iConditions & (bits_COND_SMELL | bits_COND_SMELL_FOOD) )
|
||||
{
|
||||
m_IdealMonsterState = MONSTERSTATE_ALERT;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MONSTERSTATE_ALERT:
|
||||
/*
|
||||
ALERT goes to IDLE upon becoming bored
|
||||
-ALERT goes to COMBAT upon sighting an enemy
|
||||
ALERT goes to HUNT upon hearing a noise
|
||||
*/
|
||||
{
|
||||
if ( iConditions & (bits_COND_NEW_ENEMY|bits_COND_SEE_ENEMY) )
|
||||
{
|
||||
// see an enemy we MUST attack
|
||||
m_IdealMonsterState = MONSTERSTATE_COMBAT;
|
||||
}
|
||||
else if ( iConditions & bits_COND_HEAR_SOUND )
|
||||
{
|
||||
m_IdealMonsterState = MONSTERSTATE_ALERT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MONSTERSTATE_COMBAT:
|
||||
/*
|
||||
COMBAT goes to HUNT upon losing sight of enemy
|
||||
COMBAT goes to ALERT upon death of enemy
|
||||
*/
|
||||
{
|
||||
if ( m_hEnemy == NULL )
|
||||
{
|
||||
m_IdealMonsterState = MONSTERSTATE_ALERT;
|
||||
// pev->effects = EF_BRIGHTFIELD;
|
||||
ALERT ( at_aiconsole, "***Combat state with no enemy!\n" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MONSTERSTATE_HUNT:
|
||||
/*
|
||||
HUNT goes to ALERT upon seeing food
|
||||
HUNT goes to ALERT upon being injured
|
||||
HUNT goes to IDLE if goal touched
|
||||
HUNT goes to COMBAT upon seeing enemy
|
||||
*/
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case MONSTERSTATE_DEAD:
|
||||
m_IdealMonsterState = MONSTERSTATE_DEAD;
|
||||
break;
|
||||
}
|
||||
|
||||
return m_IdealMonsterState;
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
//=========================================================
|
||||
// monsterstate.cpp - base class monster functions for
|
||||
// controlling core AI.
|
||||
//=========================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "nodes.h"
|
||||
#include "monsters.h"
|
||||
#include "animation.h"
|
||||
|
||||
//=========================================================
|
||||
// SetState
|
||||
//=========================================================
|
||||
void CMBaseMonster :: SetState ( MONSTERSTATE State )
|
||||
{
|
||||
/*
|
||||
if ( State != m_MonsterState )
|
||||
{
|
||||
ALERT ( at_aiconsole, "State Changed to %d\n", State );
|
||||
}
|
||||
*/
|
||||
|
||||
switch( State )
|
||||
{
|
||||
|
||||
// Drop enemy pointers when going to idle
|
||||
case MONSTERSTATE_IDLE:
|
||||
|
||||
if (( m_hEnemy != NULL ) &&
|
||||
( strcmp(STRING(pev->model), "models/scientist.mdl") != 0))
|
||||
{
|
||||
m_hEnemy = NULL;// not allowed to have an enemy anymore.
|
||||
ALERT ( at_aiconsole, "Stripped\n" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
m_MonsterState = State;
|
||||
m_IdealMonsterState = State;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// RunAI
|
||||
//=========================================================
|
||||
void CMBaseMonster :: RunAI ( void )
|
||||
{
|
||||
// to test model's eye height
|
||||
//UTIL_ParticleEffect ( pev->origin + pev->view_ofs, g_vecZero, 255, 10 );
|
||||
|
||||
// IDLE sound permitted in ALERT state is because monsters were silent in ALERT state. Only play IDLE sound in IDLE state
|
||||
// once we have sounds for that state.
|
||||
if ( ( m_MonsterState == MONSTERSTATE_IDLE || m_MonsterState == MONSTERSTATE_ALERT ) && RANDOM_LONG(0,99) == 0 && !(pev->flags & SF_MONSTER_GAG) )
|
||||
{
|
||||
IdleSound();
|
||||
}
|
||||
|
||||
if ( m_MonsterState != MONSTERSTATE_NONE &&
|
||||
m_MonsterState != MONSTERSTATE_PRONE &&
|
||||
m_MonsterState != MONSTERSTATE_DEAD )// don't bother with this crap if monster is prone.
|
||||
{
|
||||
// collect some sensory Condition information.
|
||||
// don't let monsters outside of the player's PVS act up, or most of the interesting
|
||||
// things will happen before the player gets there!
|
||||
// UPDATE: We now let COMBAT state monsters think and act fully outside of player PVS. This allows the player to leave
|
||||
// an area where monsters are fighting, and the fight will continue.
|
||||
if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) || ( m_MonsterState == MONSTERSTATE_COMBAT ) )
|
||||
{
|
||||
Look( m_flDistLook );
|
||||
//jlb Listen();// check for audible sounds.
|
||||
|
||||
// now filter conditions.
|
||||
ClearConditions( IgnoreConditions() );
|
||||
|
||||
GetEnemy();
|
||||
}
|
||||
|
||||
// do these calculations if monster has an enemy.
|
||||
if ( m_hEnemy != NULL )
|
||||
{
|
||||
CheckEnemy( m_hEnemy );
|
||||
}
|
||||
|
||||
CheckAmmo();
|
||||
}
|
||||
|
||||
FCheckAITrigger();
|
||||
|
||||
PrescheduleThink();
|
||||
|
||||
MaintainSchedule();
|
||||
|
||||
// if the monster didn't use these conditions during the above call to MaintainSchedule() or CheckAITrigger()
|
||||
// we throw them out cause we don't want them sitting around through the lifespan of a schedule
|
||||
// that doesn't use them.
|
||||
m_afConditions &= ~( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// GetIdealState - surveys the Conditions information available
|
||||
// and finds the best new state for a monster.
|
||||
//=========================================================
|
||||
MONSTERSTATE CMBaseMonster :: GetIdealState ( void )
|
||||
{
|
||||
int iConditions;
|
||||
|
||||
iConditions = IScheduleFlags();
|
||||
|
||||
// If no schedule conditions, the new ideal state is probably the reason we're in here.
|
||||
switch ( m_MonsterState )
|
||||
{
|
||||
case MONSTERSTATE_IDLE:
|
||||
|
||||
/*
|
||||
IDLE goes to ALERT upon hearing a sound
|
||||
-IDLE goes to ALERT upon being injured
|
||||
IDLE goes to ALERT upon seeing food
|
||||
-IDLE goes to COMBAT upon sighting an enemy
|
||||
IDLE goes to HUNT upon smelling food
|
||||
*/
|
||||
{
|
||||
if ( iConditions & bits_COND_NEW_ENEMY )
|
||||
{
|
||||
// new enemy! This means an idle monster has seen someone it dislikes, or
|
||||
// that a monster in combat has found a more suitable target to attack
|
||||
m_IdealMonsterState = MONSTERSTATE_COMBAT;
|
||||
}
|
||||
else if ( iConditions & bits_COND_LIGHT_DAMAGE )
|
||||
{
|
||||
MakeIdealYaw ( m_vecEnemyLKP );
|
||||
m_IdealMonsterState = MONSTERSTATE_ALERT;
|
||||
}
|
||||
else if ( iConditions & bits_COND_HEAVY_DAMAGE )
|
||||
{
|
||||
MakeIdealYaw ( m_vecEnemyLKP );
|
||||
m_IdealMonsterState = MONSTERSTATE_ALERT;
|
||||
}
|
||||
else if ( iConditions & bits_COND_HEAR_SOUND )
|
||||
{
|
||||
}
|
||||
else if ( iConditions & (bits_COND_SMELL | bits_COND_SMELL_FOOD) )
|
||||
{
|
||||
m_IdealMonsterState = MONSTERSTATE_ALERT;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MONSTERSTATE_ALERT:
|
||||
/*
|
||||
ALERT goes to IDLE upon becoming bored
|
||||
-ALERT goes to COMBAT upon sighting an enemy
|
||||
ALERT goes to HUNT upon hearing a noise
|
||||
*/
|
||||
{
|
||||
if ( iConditions & (bits_COND_NEW_ENEMY|bits_COND_SEE_ENEMY) )
|
||||
{
|
||||
// see an enemy we MUST attack
|
||||
m_IdealMonsterState = MONSTERSTATE_COMBAT;
|
||||
}
|
||||
else if ( iConditions & bits_COND_HEAR_SOUND )
|
||||
{
|
||||
m_IdealMonsterState = MONSTERSTATE_ALERT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MONSTERSTATE_COMBAT:
|
||||
/*
|
||||
COMBAT goes to HUNT upon losing sight of enemy
|
||||
COMBAT goes to ALERT upon death of enemy
|
||||
*/
|
||||
{
|
||||
if ( m_hEnemy == NULL )
|
||||
{
|
||||
m_IdealMonsterState = MONSTERSTATE_ALERT;
|
||||
// pev->effects = EF_BRIGHTFIELD;
|
||||
ALERT ( at_aiconsole, "***Combat state with no enemy!\n" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MONSTERSTATE_HUNT:
|
||||
/*
|
||||
HUNT goes to ALERT upon seeing food
|
||||
HUNT goes to ALERT upon being injured
|
||||
HUNT goes to IDLE if goal touched
|
||||
HUNT goes to COMBAT upon seeing enemy
|
||||
*/
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case MONSTERSTATE_DEAD:
|
||||
m_IdealMonsterState = MONSTERSTATE_DEAD;
|
||||
break;
|
||||
}
|
||||
|
||||
return m_IdealMonsterState;
|
||||
}
|
||||
|
||||
|
||||
7260
src/dlls/nodes.cpp
7260
src/dlls/nodes.cpp
File diff suppressed because it is too large
Load Diff
794
src/dlls/nodes.h
794
src/dlls/nodes.h
@@ -1,397 +1,397 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
//=========================================================
|
||||
// nodes.h
|
||||
//=========================================================
|
||||
|
||||
//=========================================================
|
||||
// DEFINE
|
||||
//=========================================================
|
||||
#define MAX_STACK_NODES 100
|
||||
#define NO_NODE -1
|
||||
#define MAX_NODE_HULLS 4
|
||||
|
||||
#define bits_NODE_LAND ( 1 << 0 ) // Land node, so nudge if necessary.
|
||||
#define bits_NODE_AIR ( 1 << 1 ) // Air node, don't nudge.
|
||||
#define bits_NODE_WATER ( 1 << 2 ) // Water node, don't nudge.
|
||||
#define bits_NODE_GROUP_REALM (bits_NODE_LAND | bits_NODE_AIR | bits_NODE_WATER)
|
||||
|
||||
//=========================================================
|
||||
// Instance of a node.
|
||||
//=========================================================
|
||||
class CNode
|
||||
{
|
||||
public:
|
||||
Vector m_vecOrigin;// location of this node in space
|
||||
Vector m_vecOriginPeek; // location of this node (LAND nodes are NODE_HEIGHT higher).
|
||||
BYTE m_Region[3]; // Which of 256 regions do each of the coordinate belong?
|
||||
int m_afNodeInfo;// bits that tell us more about this location
|
||||
|
||||
int m_cNumLinks; // how many links this node has
|
||||
int m_iFirstLink;// index of this node's first link in the link pool.
|
||||
|
||||
// Where to start looking in the compressed routing table (offset into m_pRouteInfo).
|
||||
// (4 hull sizes -- smallest to largest + fly/swim), and secondly, door capability.
|
||||
//
|
||||
int m_pNextBestNode[MAX_NODE_HULLS][2];
|
||||
|
||||
// Used in finding the shortest path. m_fClosestSoFar is -1 if not visited.
|
||||
// Then it is the distance to the source. If another path uses this node
|
||||
// and has a closer distance, then m_iPreviousNode is also updated.
|
||||
//
|
||||
float m_flClosestSoFar; // Used in finding the shortest path.
|
||||
int m_iPreviousNode;
|
||||
|
||||
short m_sHintType;// there is something interesting in the world at this node's position
|
||||
short m_sHintActivity;// there is something interesting in the world at this node's position
|
||||
float m_flHintYaw;// monster on this node should face this yaw to face the hint.
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// CLink - A link between 2 nodes
|
||||
//=========================================================
|
||||
#define bits_LINK_SMALL_HULL ( 1 << 0 )// headcrab box can fit through this connection
|
||||
#define bits_LINK_HUMAN_HULL ( 1 << 1 )// player box can fit through this connection
|
||||
#define bits_LINK_LARGE_HULL ( 1 << 2 )// big box can fit through this connection
|
||||
#define bits_LINK_FLY_HULL ( 1 << 3 )// a flying big box can fit through this connection
|
||||
#define bits_LINK_DISABLED ( 1 << 4 )// link is not valid when the set
|
||||
|
||||
#define NODE_SMALL_HULL 0
|
||||
#define NODE_HUMAN_HULL 1
|
||||
#define NODE_LARGE_HULL 2
|
||||
#define NODE_FLY_HULL 3
|
||||
|
||||
class CLink
|
||||
{
|
||||
public:
|
||||
int m_iSrcNode;// the node that 'owns' this link ( keeps us from having to make reverse lookups )
|
||||
int m_iDestNode;// the node on the other end of the link.
|
||||
|
||||
entvars_t *m_pLinkEnt;// the entity that blocks this connection (doors, etc)
|
||||
|
||||
// m_szLinkEntModelname is not necessarily NULL terminated (so we can store it in a more alignment-friendly 4 bytes)
|
||||
char m_szLinkEntModelname[ 4 ];// the unique name of the brush model that blocks the connection (this is kept for save/restore)
|
||||
|
||||
int m_afLinkInfo;// information about this link
|
||||
float m_flWeight;// length of the link line segment
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int m_SortedBy[3];
|
||||
int m_CheckedEvent;
|
||||
} DIST_INFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Vector v;
|
||||
short n; // Nearest node or -1 if no node found.
|
||||
} CACHE_ENTRY;
|
||||
|
||||
//=========================================================
|
||||
// CGraph
|
||||
//=========================================================
|
||||
#define GRAPH_VERSION (int)16// !!!increment this whever graph/node/link classes change, to obsolesce older disk files.
|
||||
class CGraph
|
||||
{
|
||||
public:
|
||||
|
||||
// the graph has two flags, and should not be accessed unless both flags are TRUE!
|
||||
BOOL m_fGraphPresent;// is the graph in memory?
|
||||
BOOL m_fGraphPointersSet;// are the entity pointers for the graph all set?
|
||||
BOOL m_fRoutingComplete; // are the optimal routes computed, yet?
|
||||
|
||||
CNode *m_pNodes;// pointer to the memory block that contains all node info
|
||||
CLink *m_pLinkPool;// big list of all node connections
|
||||
char *m_pRouteInfo; // compressed routing information the nodes use.
|
||||
|
||||
int m_cNodes;// total number of nodes
|
||||
int m_cLinks;// total number of links
|
||||
int m_nRouteInfo; // size of m_pRouteInfo in bytes.
|
||||
|
||||
// Tables for making nearest node lookup faster. SortedBy provided nodes in a
|
||||
// order of a particular coordinate. Instead of doing a binary search, RangeStart
|
||||
// and RangeEnd let you get to the part of SortedBy that you are interested in.
|
||||
//
|
||||
// Once you have a point of interest, the only way you'll find a closer point is
|
||||
// if at least one of the coordinates is closer than the ones you have now. So we
|
||||
// search each range. After the search is exhausted, we know we have the closest
|
||||
// node.
|
||||
//
|
||||
#define CACHE_SIZE 128
|
||||
#define NUM_RANGES 256
|
||||
DIST_INFO *m_di; // This is m_cNodes long, but the entries don't correspond to CNode entries.
|
||||
int m_RangeStart[3][NUM_RANGES];
|
||||
int m_RangeEnd[3][NUM_RANGES];
|
||||
float m_flShortest;
|
||||
int m_iNearest;
|
||||
int m_minX, m_minY, m_minZ, m_maxX, m_maxY, m_maxZ;
|
||||
int m_minBoxX, m_minBoxY, m_minBoxZ, m_maxBoxX, m_maxBoxY, m_maxBoxZ;
|
||||
int m_CheckedCounter;
|
||||
float m_RegionMin[3], m_RegionMax[3]; // The range of nodes.
|
||||
CACHE_ENTRY m_Cache[CACHE_SIZE];
|
||||
|
||||
|
||||
int m_HashPrimes[16];
|
||||
short *m_pHashLinks;
|
||||
int m_nHashLinks;
|
||||
|
||||
|
||||
// kinda sleazy. In order to allow variety in active idles for monster groups in a room with more than one node,
|
||||
// we keep track of the last node we searched from and store it here. Subsequent searches by other monsters will pick
|
||||
// up where the last search stopped.
|
||||
int m_iLastActiveIdleSearch;
|
||||
|
||||
// another such system used to track the search for cover nodes, helps greatly with two monsters trying to get to the same node.
|
||||
int m_iLastCoverSearch;
|
||||
|
||||
// functions to create the graph
|
||||
int LinkVisibleNodes ( CLink *pLinkPool, FILE *file, int *piBadNode );
|
||||
int RejectInlineLinks ( CLink *pLinkPool, FILE *file );
|
||||
int FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, int afCapMask);
|
||||
int FindNearestNode ( const Vector &vecOrigin, CMBaseEntity *pEntity );
|
||||
int FindNearestNode ( const Vector &vecOrigin, int afNodeTypes );
|
||||
//int FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, BOOL *pfAlongLine );
|
||||
float PathLength( int iStart, int iDest, int iHull, int afCapMask );
|
||||
int NextNodeInRoute( int iCurrentNode, int iDest, int iHull, int iCap );
|
||||
|
||||
enum NODEQUERY { NODEGRAPH_DYNAMIC, NODEGRAPH_STATIC };
|
||||
// A static query means we're asking about the possiblity of handling this entity at ANY time
|
||||
// A dynamic query means we're asking about it RIGHT NOW. So we should query the current state
|
||||
int HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, NODEQUERY queryType );
|
||||
entvars_t* LinkEntForLink ( CLink *pLink, CNode *pNode );
|
||||
void ShowNodeConnections ( int iNode );
|
||||
void InitGraph( void );
|
||||
int AllocNodes ( void );
|
||||
|
||||
int CheckNODFile(char *szMapName);
|
||||
int FLoadGraph(char *szMapName);
|
||||
int FSaveGraph(char *szMapName);
|
||||
int FSetGraphPointers(void);
|
||||
void CheckNode(Vector vecOrigin, int iNode);
|
||||
|
||||
void BuildRegionTables(void);
|
||||
void ComputeStaticRoutingTables(void);
|
||||
void TestRoutingTables(void);
|
||||
|
||||
void HashInsert(int iSrcNode, int iDestNode, int iKey);
|
||||
void HashSearch(int iSrcNode, int iDestNode, int &iKey);
|
||||
void HashChoosePrimes(int TableSize);
|
||||
void BuildLinkLookups(void);
|
||||
|
||||
void SortNodes(void);
|
||||
|
||||
int HullIndex( const CMBaseEntity *pEntity ); // what hull the monster uses
|
||||
int NodeType( const CMBaseEntity *pEntity ); // what node type the monster uses
|
||||
inline int CapIndex( int afCapMask )
|
||||
{
|
||||
if (afCapMask & (bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
inline CNode &Node( int i )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if ( !m_pNodes || i < 0 || i > m_cNodes )
|
||||
ALERT( at_error, "Bad Node!\n" );
|
||||
#endif
|
||||
return m_pNodes[i];
|
||||
}
|
||||
|
||||
inline CLink &Link( int i )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if ( !m_pLinkPool || i < 0 || i > m_cLinks )
|
||||
ALERT( at_error, "Bad link!\n" );
|
||||
#endif
|
||||
return m_pLinkPool[i];
|
||||
}
|
||||
|
||||
inline CLink &NodeLink( int iNode, int iLink )
|
||||
{
|
||||
return Link( Node( iNode ).m_iFirstLink + iLink );
|
||||
}
|
||||
|
||||
inline CLink &NodeLink( const CNode &node, int iLink )
|
||||
{
|
||||
return Link( node.m_iFirstLink + iLink );
|
||||
}
|
||||
|
||||
inline int INodeLink ( int iNode, int iLink )
|
||||
{
|
||||
return NodeLink( iNode, iLink ).m_iDestNode;
|
||||
}
|
||||
|
||||
#if 0
|
||||
inline CNode &SourceNode( int iNode, int iLink )
|
||||
{
|
||||
return Node( NodeLink( iNode, iLink ).m_iSrcNode );
|
||||
}
|
||||
|
||||
inline CNode &DestNode( int iNode, int iLink )
|
||||
{
|
||||
return Node( NodeLink( iNode, iLink ).m_iDestNode );
|
||||
}
|
||||
|
||||
inline CNode *PNodeLink ( int iNode, int iLink )
|
||||
{
|
||||
return &DestNode( iNode, iLink );
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// Nodes start out as ents in the level. The node graph
|
||||
// is built, then these ents are discarded.
|
||||
//=========================================================
|
||||
class CNodeEnt : public CMBaseEntity
|
||||
{
|
||||
void Spawn( void );
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
virtual int ObjectCaps( void ) { return CMBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
|
||||
|
||||
short m_sHintType;
|
||||
short m_sHintActivity;
|
||||
};
|
||||
|
||||
|
||||
//=========================================================
|
||||
// Node viewer
|
||||
//=========================================================
|
||||
class CNodeViewer : public CMBaseEntity
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
|
||||
int m_iBaseNode;
|
||||
int m_iDraw;
|
||||
int m_nVisited;
|
||||
int m_aFrom[128];
|
||||
int m_aTo[128];
|
||||
int m_iHull;
|
||||
int m_afNodeType;
|
||||
Vector m_vecColor;
|
||||
|
||||
void FindNodeConnections( int iNode );
|
||||
void AddNode( int iFrom, int iTo );
|
||||
void EXPORT DrawThink( void );
|
||||
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// CStack - last in, first out.
|
||||
//=========================================================
|
||||
class CStack
|
||||
{
|
||||
public:
|
||||
CStack( void );
|
||||
void Push( int value );
|
||||
int Pop( void );
|
||||
int Top( void );
|
||||
int Empty( void ) { return m_level==0; }
|
||||
int Size( void ) { return m_level; }
|
||||
void CopyToArray ( int *piArray );
|
||||
|
||||
private:
|
||||
int m_stack[ MAX_STACK_NODES ];
|
||||
int m_level;
|
||||
};
|
||||
|
||||
|
||||
//=========================================================
|
||||
// CQueue - first in, first out.
|
||||
//=========================================================
|
||||
class CQueue
|
||||
{
|
||||
public:
|
||||
|
||||
CQueue( void );// constructor
|
||||
inline int Full ( void ) { return ( m_cSize == MAX_STACK_NODES ); }
|
||||
inline int Empty ( void ) { return ( m_cSize == 0 ); }
|
||||
//inline int Tail ( void ) { return ( m_queue[ m_tail ] ); }
|
||||
inline int Size ( void ) { return ( m_cSize ); }
|
||||
void Insert( int, float );
|
||||
int Remove( float & );
|
||||
|
||||
private:
|
||||
int m_cSize;
|
||||
struct tag_QUEUE_NODE
|
||||
{
|
||||
int Id;
|
||||
float Priority;
|
||||
} m_queue[ MAX_STACK_NODES ];
|
||||
int m_head;
|
||||
int m_tail;
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// CQueuePriority - Priority queue (smallest item out first).
|
||||
//
|
||||
//=========================================================
|
||||
class CQueuePriority
|
||||
{
|
||||
public:
|
||||
|
||||
CQueuePriority( void );// constructor
|
||||
inline int Full ( void ) { return ( m_cSize == MAX_STACK_NODES ); }
|
||||
inline int Empty ( void ) { return ( m_cSize == 0 ); }
|
||||
//inline int Tail ( float & ) { return ( m_queue[ m_tail ].Id ); }
|
||||
inline int Size ( void ) { return ( m_cSize ); }
|
||||
void Insert( int, float );
|
||||
int Remove( float &);
|
||||
|
||||
private:
|
||||
int m_cSize;
|
||||
struct tag_HEAP_NODE
|
||||
{
|
||||
int Id;
|
||||
float Priority;
|
||||
} m_heap[ MAX_STACK_NODES ];
|
||||
void Heap_SiftDown(int);
|
||||
void Heap_SiftUp(void);
|
||||
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// hints - these MUST coincide with the HINTS listed under
|
||||
// info_node in the FGD file!
|
||||
//=========================================================
|
||||
enum
|
||||
{
|
||||
HINT_NONE = 0,
|
||||
HINT_WORLD_DOOR,
|
||||
HINT_WORLD_WINDOW,
|
||||
HINT_WORLD_BUTTON,
|
||||
HINT_WORLD_MACHINERY,
|
||||
HINT_WORLD_LEDGE,
|
||||
HINT_WORLD_LIGHT_SOURCE,
|
||||
HINT_WORLD_HEAT_SOURCE,
|
||||
HINT_WORLD_BLINKING_LIGHT,
|
||||
HINT_WORLD_BRIGHT_COLORS,
|
||||
HINT_WORLD_HUMAN_BLOOD,
|
||||
HINT_WORLD_ALIEN_BLOOD,
|
||||
|
||||
HINT_TACTICAL_EXIT = 100,
|
||||
HINT_TACTICAL_VANTAGE,
|
||||
HINT_TACTICAL_AMBUSH,
|
||||
|
||||
HINT_STUKA_PERCH = 300,
|
||||
HINT_STUKA_LANDING,
|
||||
};
|
||||
|
||||
extern CGraph WorldGraph;
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
//=========================================================
|
||||
// nodes.h
|
||||
//=========================================================
|
||||
|
||||
//=========================================================
|
||||
// DEFINE
|
||||
//=========================================================
|
||||
#define MAX_STACK_NODES 100
|
||||
#define NO_NODE -1
|
||||
#define MAX_NODE_HULLS 4
|
||||
|
||||
#define bits_NODE_LAND ( 1 << 0 ) // Land node, so nudge if necessary.
|
||||
#define bits_NODE_AIR ( 1 << 1 ) // Air node, don't nudge.
|
||||
#define bits_NODE_WATER ( 1 << 2 ) // Water node, don't nudge.
|
||||
#define bits_NODE_GROUP_REALM (bits_NODE_LAND | bits_NODE_AIR | bits_NODE_WATER)
|
||||
|
||||
//=========================================================
|
||||
// Instance of a node.
|
||||
//=========================================================
|
||||
class CNode
|
||||
{
|
||||
public:
|
||||
Vector m_vecOrigin;// location of this node in space
|
||||
Vector m_vecOriginPeek; // location of this node (LAND nodes are NODE_HEIGHT higher).
|
||||
BYTE m_Region[3]; // Which of 256 regions do each of the coordinate belong?
|
||||
int m_afNodeInfo;// bits that tell us more about this location
|
||||
|
||||
int m_cNumLinks; // how many links this node has
|
||||
int m_iFirstLink;// index of this node's first link in the link pool.
|
||||
|
||||
// Where to start looking in the compressed routing table (offset into m_pRouteInfo).
|
||||
// (4 hull sizes -- smallest to largest + fly/swim), and secondly, door capability.
|
||||
//
|
||||
int m_pNextBestNode[MAX_NODE_HULLS][2];
|
||||
|
||||
// Used in finding the shortest path. m_fClosestSoFar is -1 if not visited.
|
||||
// Then it is the distance to the source. If another path uses this node
|
||||
// and has a closer distance, then m_iPreviousNode is also updated.
|
||||
//
|
||||
float m_flClosestSoFar; // Used in finding the shortest path.
|
||||
int m_iPreviousNode;
|
||||
|
||||
short m_sHintType;// there is something interesting in the world at this node's position
|
||||
short m_sHintActivity;// there is something interesting in the world at this node's position
|
||||
float m_flHintYaw;// monster on this node should face this yaw to face the hint.
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// CLink - A link between 2 nodes
|
||||
//=========================================================
|
||||
#define bits_LINK_SMALL_HULL ( 1 << 0 )// headcrab box can fit through this connection
|
||||
#define bits_LINK_HUMAN_HULL ( 1 << 1 )// player box can fit through this connection
|
||||
#define bits_LINK_LARGE_HULL ( 1 << 2 )// big box can fit through this connection
|
||||
#define bits_LINK_FLY_HULL ( 1 << 3 )// a flying big box can fit through this connection
|
||||
#define bits_LINK_DISABLED ( 1 << 4 )// link is not valid when the set
|
||||
|
||||
#define NODE_SMALL_HULL 0
|
||||
#define NODE_HUMAN_HULL 1
|
||||
#define NODE_LARGE_HULL 2
|
||||
#define NODE_FLY_HULL 3
|
||||
|
||||
class CLink
|
||||
{
|
||||
public:
|
||||
int m_iSrcNode;// the node that 'owns' this link ( keeps us from having to make reverse lookups )
|
||||
int m_iDestNode;// the node on the other end of the link.
|
||||
|
||||
entvars_t *m_pLinkEnt;// the entity that blocks this connection (doors, etc)
|
||||
|
||||
// m_szLinkEntModelname is not necessarily NULL terminated (so we can store it in a more alignment-friendly 4 bytes)
|
||||
char m_szLinkEntModelname[ 4 ];// the unique name of the brush model that blocks the connection (this is kept for save/restore)
|
||||
|
||||
int m_afLinkInfo;// information about this link
|
||||
float m_flWeight;// length of the link line segment
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int m_SortedBy[3];
|
||||
int m_CheckedEvent;
|
||||
} DIST_INFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Vector v;
|
||||
short n; // Nearest node or -1 if no node found.
|
||||
} CACHE_ENTRY;
|
||||
|
||||
//=========================================================
|
||||
// CGraph
|
||||
//=========================================================
|
||||
#define GRAPH_VERSION (int)16// !!!increment this whever graph/node/link classes change, to obsolesce older disk files.
|
||||
class CGraph
|
||||
{
|
||||
public:
|
||||
|
||||
// the graph has two flags, and should not be accessed unless both flags are TRUE!
|
||||
BOOL m_fGraphPresent;// is the graph in memory?
|
||||
BOOL m_fGraphPointersSet;// are the entity pointers for the graph all set?
|
||||
BOOL m_fRoutingComplete; // are the optimal routes computed, yet?
|
||||
|
||||
CNode *m_pNodes;// pointer to the memory block that contains all node info
|
||||
CLink *m_pLinkPool;// big list of all node connections
|
||||
char *m_pRouteInfo; // compressed routing information the nodes use.
|
||||
|
||||
int m_cNodes;// total number of nodes
|
||||
int m_cLinks;// total number of links
|
||||
int m_nRouteInfo; // size of m_pRouteInfo in bytes.
|
||||
|
||||
// Tables for making nearest node lookup faster. SortedBy provided nodes in a
|
||||
// order of a particular coordinate. Instead of doing a binary search, RangeStart
|
||||
// and RangeEnd let you get to the part of SortedBy that you are interested in.
|
||||
//
|
||||
// Once you have a point of interest, the only way you'll find a closer point is
|
||||
// if at least one of the coordinates is closer than the ones you have now. So we
|
||||
// search each range. After the search is exhausted, we know we have the closest
|
||||
// node.
|
||||
//
|
||||
#define CACHE_SIZE 128
|
||||
#define NUM_RANGES 256
|
||||
DIST_INFO *m_di; // This is m_cNodes long, but the entries don't correspond to CNode entries.
|
||||
int m_RangeStart[3][NUM_RANGES];
|
||||
int m_RangeEnd[3][NUM_RANGES];
|
||||
float m_flShortest;
|
||||
int m_iNearest;
|
||||
int m_minX, m_minY, m_minZ, m_maxX, m_maxY, m_maxZ;
|
||||
int m_minBoxX, m_minBoxY, m_minBoxZ, m_maxBoxX, m_maxBoxY, m_maxBoxZ;
|
||||
int m_CheckedCounter;
|
||||
float m_RegionMin[3], m_RegionMax[3]; // The range of nodes.
|
||||
CACHE_ENTRY m_Cache[CACHE_SIZE];
|
||||
|
||||
|
||||
int m_HashPrimes[16];
|
||||
short *m_pHashLinks;
|
||||
int m_nHashLinks;
|
||||
|
||||
|
||||
// kinda sleazy. In order to allow variety in active idles for monster groups in a room with more than one node,
|
||||
// we keep track of the last node we searched from and store it here. Subsequent searches by other monsters will pick
|
||||
// up where the last search stopped.
|
||||
int m_iLastActiveIdleSearch;
|
||||
|
||||
// another such system used to track the search for cover nodes, helps greatly with two monsters trying to get to the same node.
|
||||
int m_iLastCoverSearch;
|
||||
|
||||
// functions to create the graph
|
||||
int LinkVisibleNodes ( CLink *pLinkPool, FILE *file, int *piBadNode );
|
||||
int RejectInlineLinks ( CLink *pLinkPool, FILE *file );
|
||||
int FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, int afCapMask);
|
||||
int FindNearestNode ( const Vector &vecOrigin, CMBaseEntity *pEntity );
|
||||
int FindNearestNode ( const Vector &vecOrigin, int afNodeTypes );
|
||||
//int FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, BOOL *pfAlongLine );
|
||||
float PathLength( int iStart, int iDest, int iHull, int afCapMask );
|
||||
int NextNodeInRoute( int iCurrentNode, int iDest, int iHull, int iCap );
|
||||
|
||||
enum NODEQUERY { NODEGRAPH_DYNAMIC, NODEGRAPH_STATIC };
|
||||
// A static query means we're asking about the possiblity of handling this entity at ANY time
|
||||
// A dynamic query means we're asking about it RIGHT NOW. So we should query the current state
|
||||
int HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, NODEQUERY queryType );
|
||||
entvars_t* LinkEntForLink ( CLink *pLink, CNode *pNode );
|
||||
void ShowNodeConnections ( int iNode );
|
||||
void InitGraph( void );
|
||||
int AllocNodes ( void );
|
||||
|
||||
int CheckNODFile(char *szMapName);
|
||||
int FLoadGraph(char *szMapName);
|
||||
int FSaveGraph(char *szMapName);
|
||||
int FSetGraphPointers(void);
|
||||
void CheckNode(Vector vecOrigin, int iNode);
|
||||
|
||||
void BuildRegionTables(void);
|
||||
void ComputeStaticRoutingTables(void);
|
||||
void TestRoutingTables(void);
|
||||
|
||||
void HashInsert(int iSrcNode, int iDestNode, int iKey);
|
||||
void HashSearch(int iSrcNode, int iDestNode, int &iKey);
|
||||
void HashChoosePrimes(int TableSize);
|
||||
void BuildLinkLookups(void);
|
||||
|
||||
void SortNodes(void);
|
||||
|
||||
int HullIndex( const CMBaseEntity *pEntity ); // what hull the monster uses
|
||||
int NodeType( const CMBaseEntity *pEntity ); // what node type the monster uses
|
||||
inline int CapIndex( int afCapMask )
|
||||
{
|
||||
if (afCapMask & (bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
inline CNode &Node( int i )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if ( !m_pNodes || i < 0 || i > m_cNodes )
|
||||
ALERT( at_error, "Bad Node!\n" );
|
||||
#endif
|
||||
return m_pNodes[i];
|
||||
}
|
||||
|
||||
inline CLink &Link( int i )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if ( !m_pLinkPool || i < 0 || i > m_cLinks )
|
||||
ALERT( at_error, "Bad link!\n" );
|
||||
#endif
|
||||
return m_pLinkPool[i];
|
||||
}
|
||||
|
||||
inline CLink &NodeLink( int iNode, int iLink )
|
||||
{
|
||||
return Link( Node( iNode ).m_iFirstLink + iLink );
|
||||
}
|
||||
|
||||
inline CLink &NodeLink( const CNode &node, int iLink )
|
||||
{
|
||||
return Link( node.m_iFirstLink + iLink );
|
||||
}
|
||||
|
||||
inline int INodeLink ( int iNode, int iLink )
|
||||
{
|
||||
return NodeLink( iNode, iLink ).m_iDestNode;
|
||||
}
|
||||
|
||||
#if 0
|
||||
inline CNode &SourceNode( int iNode, int iLink )
|
||||
{
|
||||
return Node( NodeLink( iNode, iLink ).m_iSrcNode );
|
||||
}
|
||||
|
||||
inline CNode &DestNode( int iNode, int iLink )
|
||||
{
|
||||
return Node( NodeLink( iNode, iLink ).m_iDestNode );
|
||||
}
|
||||
|
||||
inline CNode *PNodeLink ( int iNode, int iLink )
|
||||
{
|
||||
return &DestNode( iNode, iLink );
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// Nodes start out as ents in the level. The node graph
|
||||
// is built, then these ents are discarded.
|
||||
//=========================================================
|
||||
class CNodeEnt : public CMBaseEntity
|
||||
{
|
||||
void Spawn( void );
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
virtual int ObjectCaps( void ) { return CMBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
|
||||
|
||||
short m_sHintType;
|
||||
short m_sHintActivity;
|
||||
};
|
||||
|
||||
|
||||
//=========================================================
|
||||
// Node viewer
|
||||
//=========================================================
|
||||
class CNodeViewer : public CMBaseEntity
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
|
||||
int m_iBaseNode;
|
||||
int m_iDraw;
|
||||
int m_nVisited;
|
||||
int m_aFrom[128];
|
||||
int m_aTo[128];
|
||||
int m_iHull;
|
||||
int m_afNodeType;
|
||||
Vector m_vecColor;
|
||||
|
||||
void FindNodeConnections( int iNode );
|
||||
void AddNode( int iFrom, int iTo );
|
||||
void EXPORT DrawThink( void );
|
||||
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// CStack - last in, first out.
|
||||
//=========================================================
|
||||
class CStack
|
||||
{
|
||||
public:
|
||||
CStack( void );
|
||||
void Push( int value );
|
||||
int Pop( void );
|
||||
int Top( void );
|
||||
int Empty( void ) { return m_level==0; }
|
||||
int Size( void ) { return m_level; }
|
||||
void CopyToArray ( int *piArray );
|
||||
|
||||
private:
|
||||
int m_stack[ MAX_STACK_NODES ];
|
||||
int m_level;
|
||||
};
|
||||
|
||||
|
||||
//=========================================================
|
||||
// CQueue - first in, first out.
|
||||
//=========================================================
|
||||
class CQueue
|
||||
{
|
||||
public:
|
||||
|
||||
CQueue( void );// constructor
|
||||
inline int Full ( void ) { return ( m_cSize == MAX_STACK_NODES ); }
|
||||
inline int Empty ( void ) { return ( m_cSize == 0 ); }
|
||||
//inline int Tail ( void ) { return ( m_queue[ m_tail ] ); }
|
||||
inline int Size ( void ) { return ( m_cSize ); }
|
||||
void Insert( int, float );
|
||||
int Remove( float & );
|
||||
|
||||
private:
|
||||
int m_cSize;
|
||||
struct tag_QUEUE_NODE
|
||||
{
|
||||
int Id;
|
||||
float Priority;
|
||||
} m_queue[ MAX_STACK_NODES ];
|
||||
int m_head;
|
||||
int m_tail;
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// CQueuePriority - Priority queue (smallest item out first).
|
||||
//
|
||||
//=========================================================
|
||||
class CQueuePriority
|
||||
{
|
||||
public:
|
||||
|
||||
CQueuePriority( void );// constructor
|
||||
inline int Full ( void ) { return ( m_cSize == MAX_STACK_NODES ); }
|
||||
inline int Empty ( void ) { return ( m_cSize == 0 ); }
|
||||
//inline int Tail ( float & ) { return ( m_queue[ m_tail ].Id ); }
|
||||
inline int Size ( void ) { return ( m_cSize ); }
|
||||
void Insert( int, float );
|
||||
int Remove( float &);
|
||||
|
||||
private:
|
||||
int m_cSize;
|
||||
struct tag_HEAP_NODE
|
||||
{
|
||||
int Id;
|
||||
float Priority;
|
||||
} m_heap[ MAX_STACK_NODES ];
|
||||
void Heap_SiftDown(int);
|
||||
void Heap_SiftUp(void);
|
||||
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// hints - these MUST coincide with the HINTS listed under
|
||||
// info_node in the FGD file!
|
||||
//=========================================================
|
||||
enum
|
||||
{
|
||||
HINT_NONE = 0,
|
||||
HINT_WORLD_DOOR,
|
||||
HINT_WORLD_WINDOW,
|
||||
HINT_WORLD_BUTTON,
|
||||
HINT_WORLD_MACHINERY,
|
||||
HINT_WORLD_LEDGE,
|
||||
HINT_WORLD_LIGHT_SOURCE,
|
||||
HINT_WORLD_HEAT_SOURCE,
|
||||
HINT_WORLD_BLINKING_LIGHT,
|
||||
HINT_WORLD_BRIGHT_COLORS,
|
||||
HINT_WORLD_HUMAN_BLOOD,
|
||||
HINT_WORLD_ALIEN_BLOOD,
|
||||
|
||||
HINT_TACTICAL_EXIT = 100,
|
||||
HINT_TACTICAL_VANTAGE,
|
||||
HINT_TACTICAL_AMBUSH,
|
||||
|
||||
HINT_STUKA_PERCH = 300,
|
||||
HINT_STUKA_LANDING,
|
||||
};
|
||||
|
||||
extern CGraph WorldGraph;
|
||||
|
||||
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 = BLOOD_COLOR_RED;
|
||||
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);
|
||||
}
|
||||
1064
src/dlls/pitdrone.cpp
Normal file
1064
src/dlls/pitdrone.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,43 +1,43 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef PLANE_H
|
||||
#define PLANE_H
|
||||
|
||||
//=========================================================
|
||||
// Plane
|
||||
//=========================================================
|
||||
class CPlane
|
||||
{
|
||||
public:
|
||||
CPlane ( void );
|
||||
|
||||
//=========================================================
|
||||
// InitializePlane - Takes a normal for the plane and a
|
||||
// point on the plane and
|
||||
//=========================================================
|
||||
void InitializePlane ( const Vector &vecNormal, const Vector &vecPoint );
|
||||
|
||||
//=========================================================
|
||||
// PointInFront - determines whether the given vector is
|
||||
// in front of the plane.
|
||||
//=========================================================
|
||||
BOOL PointInFront ( const Vector &vecPoint );
|
||||
|
||||
Vector m_vecNormal;
|
||||
float m_flDist;
|
||||
BOOL m_fInitialized;
|
||||
};
|
||||
|
||||
#endif // PLANE_H
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#ifndef PLANE_H
|
||||
#define PLANE_H
|
||||
|
||||
//=========================================================
|
||||
// Plane
|
||||
//=========================================================
|
||||
class CPlane
|
||||
{
|
||||
public:
|
||||
CPlane ( void );
|
||||
|
||||
//=========================================================
|
||||
// InitializePlane - Takes a normal for the plane and a
|
||||
// point on the plane and
|
||||
//=========================================================
|
||||
void InitializePlane ( const Vector &vecNormal, const Vector &vecPoint );
|
||||
|
||||
//=========================================================
|
||||
// PointInFront - determines whether the given vector is
|
||||
// in front of the plane.
|
||||
//=========================================================
|
||||
BOOL PointInFront ( const Vector &vecPoint );
|
||||
|
||||
Vector m_vecNormal;
|
||||
float m_flDist;
|
||||
BOOL m_fInitialized;
|
||||
};
|
||||
|
||||
#endif // PLANE_H
|
||||
|
||||
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
|
||||
|
||||
//=========================================================
|
||||
// These sounds are muted for Robo Grunts
|
||||
//=========================================================
|
||||
BOOL CMRGrunt::FOkToSpeak(void)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void CMRGrunt::IdleSound(void)
|
||||
{
|
||||
}
|
||||
|
||||
void CMRGrunt::PainSound(void)
|
||||
{
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// 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_MODEL( "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
|
||||
if (RANDOM_LONG(0, 1))
|
||||
m_voicePitch = 109 + RANDOM_LONG(0, 7);
|
||||
else
|
||||
m_voicePitch = 100;
|
||||
*/
|
||||
|
||||
m_iBrassShell = PRECACHE_MODEL("models/shell.mdl");// brass shell
|
||||
}
|
||||
@@ -1,290 +1,290 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
//=========================================================
|
||||
// Scheduling
|
||||
//=========================================================
|
||||
|
||||
#ifndef SCHEDULE_H
|
||||
#define SCHEDULE_H
|
||||
|
||||
#define TASKSTATUS_NEW 0 // Just started
|
||||
#define TASKSTATUS_RUNNING 1 // Running task & movement
|
||||
#define TASKSTATUS_RUNNING_MOVEMENT 2 // Just running movement
|
||||
#define TASKSTATUS_RUNNING_TASK 3 // Just running task
|
||||
#define TASKSTATUS_COMPLETE 4 // Completed, get next task
|
||||
|
||||
|
||||
//=========================================================
|
||||
// These are the schedule types
|
||||
//=========================================================
|
||||
typedef enum
|
||||
{
|
||||
SCHED_NONE = 0,
|
||||
SCHED_IDLE_STAND,
|
||||
SCHED_IDLE_WALK,
|
||||
SCHED_WAKE_ANGRY,
|
||||
SCHED_WAKE_CALLED,
|
||||
SCHED_ALERT_FACE,
|
||||
SCHED_ALERT_SMALL_FLINCH,
|
||||
SCHED_ALERT_BIG_FLINCH,
|
||||
SCHED_ALERT_STAND,
|
||||
SCHED_INVESTIGATE_SOUND,
|
||||
SCHED_COMBAT_FACE,
|
||||
SCHED_COMBAT_STAND,
|
||||
SCHED_CHASE_ENEMY,
|
||||
SCHED_CHASE_ENEMY_FAILED,
|
||||
SCHED_VICTORY_DANCE,
|
||||
SCHED_TARGET_FACE,
|
||||
SCHED_TARGET_CHASE,
|
||||
SCHED_SMALL_FLINCH,
|
||||
SCHED_TAKE_COVER_FROM_ENEMY,
|
||||
SCHED_TAKE_COVER_FROM_BEST_SOUND,
|
||||
SCHED_TAKE_COVER_FROM_ORIGIN,
|
||||
SCHED_COWER, // usually a last resort!
|
||||
SCHED_MELEE_ATTACK1,
|
||||
SCHED_MELEE_ATTACK2,
|
||||
SCHED_RANGE_ATTACK1,
|
||||
SCHED_RANGE_ATTACK2,
|
||||
SCHED_SPECIAL_ATTACK1,
|
||||
SCHED_SPECIAL_ATTACK2,
|
||||
SCHED_STANDOFF,
|
||||
SCHED_ARM_WEAPON,
|
||||
SCHED_RELOAD,
|
||||
SCHED_GUARD,
|
||||
SCHED_AMBUSH,
|
||||
SCHED_DIE,
|
||||
SCHED_WAIT_TRIGGER,
|
||||
SCHED_FOLLOW,
|
||||
SCHED_SLEEP,
|
||||
SCHED_WAKE,
|
||||
SCHED_BARNACLE_VICTIM_GRAB,
|
||||
SCHED_BARNACLE_VICTIM_CHOMP,
|
||||
SCHED_AISCRIPT,
|
||||
SCHED_FAIL,
|
||||
|
||||
LAST_COMMON_SCHEDULE // Leave this at the bottom
|
||||
} SCHEDULE_TYPE;
|
||||
|
||||
//=========================================================
|
||||
// These are the shared tasks
|
||||
//=========================================================
|
||||
typedef enum
|
||||
{
|
||||
TASK_INVALID = 0,
|
||||
TASK_WAIT,
|
||||
TASK_WAIT_FACE_ENEMY,
|
||||
TASK_WAIT_PVS,
|
||||
TASK_SUGGEST_STATE,
|
||||
TASK_WALK_TO_TARGET,
|
||||
TASK_RUN_TO_TARGET,
|
||||
TASK_MOVE_TO_TARGET_RANGE,
|
||||
TASK_GET_PATH_TO_ENEMY,
|
||||
TASK_GET_PATH_TO_ENEMY_LKP,
|
||||
TASK_GET_PATH_TO_ENEMY_CORPSE,
|
||||
TASK_GET_PATH_TO_LEADER,
|
||||
TASK_GET_PATH_TO_SPOT,
|
||||
TASK_GET_PATH_TO_TARGET,
|
||||
TASK_GET_PATH_TO_HINTNODE,
|
||||
TASK_GET_PATH_TO_LASTPOSITION,
|
||||
TASK_GET_PATH_TO_BESTSOUND,
|
||||
TASK_GET_PATH_TO_BESTSCENT,
|
||||
TASK_RUN_PATH,
|
||||
TASK_WALK_PATH,
|
||||
TASK_STRAFE_PATH,
|
||||
TASK_CLEAR_MOVE_WAIT,
|
||||
TASK_STORE_LASTPOSITION,
|
||||
TASK_CLEAR_LASTPOSITION,
|
||||
TASK_PLAY_ACTIVE_IDLE,
|
||||
TASK_FIND_HINTNODE,
|
||||
TASK_CLEAR_HINTNODE,
|
||||
TASK_SMALL_FLINCH,
|
||||
TASK_FACE_IDEAL,
|
||||
TASK_FACE_ROUTE,
|
||||
TASK_FACE_ENEMY,
|
||||
TASK_FACE_HINTNODE,
|
||||
TASK_FACE_TARGET,
|
||||
TASK_FACE_LASTPOSITION,
|
||||
TASK_RANGE_ATTACK1,
|
||||
TASK_RANGE_ATTACK2,
|
||||
TASK_MELEE_ATTACK1,
|
||||
TASK_MELEE_ATTACK2,
|
||||
TASK_RELOAD,
|
||||
TASK_RANGE_ATTACK1_NOTURN,
|
||||
TASK_RANGE_ATTACK2_NOTURN,
|
||||
TASK_MELEE_ATTACK1_NOTURN,
|
||||
TASK_MELEE_ATTACK2_NOTURN,
|
||||
TASK_RELOAD_NOTURN,
|
||||
TASK_SPECIAL_ATTACK1,
|
||||
TASK_SPECIAL_ATTACK2,
|
||||
TASK_CROUCH,
|
||||
TASK_STAND,
|
||||
TASK_GUARD,
|
||||
TASK_STEP_LEFT,
|
||||
TASK_STEP_RIGHT,
|
||||
TASK_STEP_FORWARD,
|
||||
TASK_STEP_BACK,
|
||||
TASK_DODGE_LEFT,
|
||||
TASK_DODGE_RIGHT,
|
||||
TASK_SOUND_ANGRY,
|
||||
TASK_SOUND_DEATH,
|
||||
TASK_SET_ACTIVITY,
|
||||
TASK_SET_SCHEDULE,
|
||||
TASK_SET_FAIL_SCHEDULE,
|
||||
TASK_CLEAR_FAIL_SCHEDULE,
|
||||
TASK_PLAY_SEQUENCE,
|
||||
TASK_PLAY_SEQUENCE_FACE_ENEMY,
|
||||
TASK_PLAY_SEQUENCE_FACE_TARGET,
|
||||
TASK_SOUND_IDLE,
|
||||
TASK_SOUND_WAKE,
|
||||
TASK_SOUND_PAIN,
|
||||
TASK_SOUND_DIE,
|
||||
TASK_FIND_COVER_FROM_BEST_SOUND,// tries lateral cover first, then node cover
|
||||
TASK_FIND_COVER_FROM_ENEMY,// tries lateral cover first, then node cover
|
||||
TASK_FIND_LATERAL_COVER_FROM_ENEMY,
|
||||
TASK_FIND_NODE_COVER_FROM_ENEMY,
|
||||
TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY,// data for this one is the MAXIMUM acceptable distance to the cover.
|
||||
TASK_FIND_FAR_NODE_COVER_FROM_ENEMY,// data for this one is there MINIMUM aceptable distance to the cover.
|
||||
TASK_FIND_COVER_FROM_ORIGIN,
|
||||
TASK_EAT,
|
||||
TASK_DIE,
|
||||
TASK_WAIT_FOR_SCRIPT,
|
||||
TASK_PLAY_SCRIPT,
|
||||
TASK_ENABLE_SCRIPT,
|
||||
TASK_PLANT_ON_SCRIPT,
|
||||
TASK_FACE_SCRIPT,
|
||||
TASK_WAIT_RANDOM,
|
||||
TASK_WAIT_INDEFINITE,
|
||||
TASK_STOP_MOVING,
|
||||
TASK_TURN_LEFT,
|
||||
TASK_TURN_RIGHT,
|
||||
TASK_REMEMBER,
|
||||
TASK_FORGET,
|
||||
TASK_WAIT_FOR_MOVEMENT, // wait until MovementIsComplete()
|
||||
LAST_COMMON_TASK, // LEAVE THIS AT THE BOTTOM!! (sjb)
|
||||
} SHARED_TASKS;
|
||||
|
||||
|
||||
// These go in the flData member of the TASK_WALK_TO_TARGET, TASK_RUN_TO_TARGET
|
||||
enum
|
||||
{
|
||||
TARGET_MOVE_NORMAL = 0,
|
||||
TARGET_MOVE_SCRIPTED = 1,
|
||||
};
|
||||
|
||||
|
||||
// A goal should be used for a task that requires several schedules to complete.
|
||||
// The goal index should indicate which schedule (ordinally) the monster is running.
|
||||
// That way, when tasks fail, the AI can make decisions based on the context of the
|
||||
// current goal and sequence rather than just the current schedule.
|
||||
enum
|
||||
{
|
||||
GOAL_ATTACK_ENEMY,
|
||||
GOAL_MOVE,
|
||||
GOAL_TAKE_COVER,
|
||||
GOAL_MOVE_TARGET,
|
||||
GOAL_EAT,
|
||||
};
|
||||
|
||||
// an array of tasks is a task list
|
||||
// an array of schedules is a schedule list
|
||||
struct Task_t
|
||||
{
|
||||
|
||||
int iTask;
|
||||
float flData;
|
||||
};
|
||||
|
||||
struct Schedule_t
|
||||
{
|
||||
|
||||
Task_t *pTasklist;
|
||||
int cTasks;
|
||||
int iInterruptMask;// a bit mask of conditions that can interrupt this schedule
|
||||
|
||||
// a more specific mask that indicates which TYPES of sounds will interrupt the schedule in the
|
||||
// event that the schedule is broken by COND_HEAR_SOUND
|
||||
int iSoundMask;
|
||||
const char *pName;
|
||||
};
|
||||
|
||||
// an array of waypoints makes up the monster's route.
|
||||
// !!!LATER- this declaration doesn't belong in this file.
|
||||
struct WayPoint_t
|
||||
{
|
||||
Vector vecLocation;
|
||||
int iType;
|
||||
};
|
||||
|
||||
// these MoveFlag values are assigned to a WayPoint's TYPE in order to demonstrate the
|
||||
// type of movement the monster should use to get there.
|
||||
#define bits_MF_TO_TARGETENT ( 1 << 0 ) // local move to targetent.
|
||||
#define bits_MF_TO_ENEMY ( 1 << 1 ) // local move to enemy
|
||||
#define bits_MF_TO_COVER ( 1 << 2 ) // local move to a hiding place
|
||||
#define bits_MF_TO_DETOUR ( 1 << 3 ) // local move to detour point.
|
||||
#define bits_MF_TO_PATHCORNER ( 1 << 4 ) // local move to a path corner
|
||||
#define bits_MF_TO_NODE ( 1 << 5 ) // local move to a node
|
||||
#define bits_MF_TO_LOCATION ( 1 << 6 ) // local move to an arbitrary point
|
||||
#define bits_MF_IS_GOAL ( 1 << 7 ) // this waypoint is the goal of the whole move.
|
||||
#define bits_MF_DONT_SIMPLIFY ( 1 << 8 ) // Don't let the route code simplify this waypoint
|
||||
|
||||
// If you define any flags that aren't _TO_ flags, add them here so we can mask
|
||||
// them off when doing compares.
|
||||
#define bits_MF_NOT_TO_MASK (bits_MF_IS_GOAL | bits_MF_DONT_SIMPLIFY)
|
||||
|
||||
#define MOVEGOAL_NONE (0)
|
||||
#define MOVEGOAL_TARGETENT (bits_MF_TO_TARGETENT)
|
||||
#define MOVEGOAL_ENEMY (bits_MF_TO_ENEMY)
|
||||
#define MOVEGOAL_PATHCORNER (bits_MF_TO_PATHCORNER)
|
||||
#define MOVEGOAL_LOCATION (bits_MF_TO_LOCATION)
|
||||
#define MOVEGOAL_NODE (bits_MF_TO_NODE)
|
||||
|
||||
// these bits represent conditions that may befall the monster, of which some are allowed
|
||||
// to interrupt certain schedules.
|
||||
#define bits_COND_NO_AMMO_LOADED ( 1 << 0 ) // weapon needs to be reloaded!
|
||||
#define bits_COND_SEE_HATE ( 1 << 1 ) // see something that you hate
|
||||
#define bits_COND_SEE_FEAR ( 1 << 2 ) // see something that you are afraid of
|
||||
#define bits_COND_SEE_DISLIKE ( 1 << 3 ) // see something that you dislike
|
||||
#define bits_COND_SEE_ENEMY ( 1 << 4 ) // target entity is in full view.
|
||||
#define bits_COND_ENEMY_OCCLUDED ( 1 << 5 ) // target entity occluded by the world
|
||||
#define bits_COND_SMELL_FOOD ( 1 << 6 )
|
||||
#define bits_COND_ENEMY_TOOFAR ( 1 << 7 )
|
||||
#define bits_COND_LIGHT_DAMAGE ( 1 << 8 ) // hurt a little
|
||||
#define bits_COND_HEAVY_DAMAGE ( 1 << 9 ) // hurt a lot
|
||||
#define bits_COND_CAN_RANGE_ATTACK1 ( 1 << 10)
|
||||
#define bits_COND_CAN_MELEE_ATTACK1 ( 1 << 11)
|
||||
#define bits_COND_CAN_RANGE_ATTACK2 ( 1 << 12)
|
||||
#define bits_COND_CAN_MELEE_ATTACK2 ( 1 << 13)
|
||||
// #define bits_COND_CAN_RANGE_ATTACK3 ( 1 << 14)
|
||||
#define bits_COND_PROVOKED ( 1 << 15)
|
||||
#define bits_COND_NEW_ENEMY ( 1 << 16)
|
||||
#define bits_COND_HEAR_SOUND ( 1 << 17) // there is an interesting sound
|
||||
#define bits_COND_SMELL ( 1 << 18) // there is an interesting scent
|
||||
#define bits_COND_ENEMY_FACING_ME ( 1 << 19) // enemy is facing me
|
||||
#define bits_COND_ENEMY_DEAD ( 1 << 20) // enemy was killed. If you get this in combat, try to find another enemy. If you get it in alert, victory dance.
|
||||
#define bits_COND_SEE_CLIENT ( 1 << 21) // see a client
|
||||
#define bits_COND_SEE_NEMESIS ( 1 << 22) // see my nemesis
|
||||
|
||||
#define bits_COND_SPECIAL1 ( 1 << 28) // Defined by individual monster
|
||||
#define bits_COND_SPECIAL2 ( 1 << 29) // Defined by individual monster
|
||||
|
||||
#define bits_COND_TASK_FAILED ( 1 << 30)
|
||||
#define bits_COND_SCHEDULE_DONE ( 1 << 31)
|
||||
|
||||
|
||||
#define bits_COND_ALL_SPECIAL (bits_COND_SPECIAL1 | bits_COND_SPECIAL2)
|
||||
|
||||
#define bits_COND_CAN_ATTACK (bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_MELEE_ATTACK1 | bits_COND_CAN_RANGE_ATTACK2 | bits_COND_CAN_MELEE_ATTACK2)
|
||||
|
||||
#endif // SCHEDULE_H
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
//=========================================================
|
||||
// Scheduling
|
||||
//=========================================================
|
||||
|
||||
#ifndef SCHEDULE_H
|
||||
#define SCHEDULE_H
|
||||
|
||||
#define TASKSTATUS_NEW 0 // Just started
|
||||
#define TASKSTATUS_RUNNING 1 // Running task & movement
|
||||
#define TASKSTATUS_RUNNING_MOVEMENT 2 // Just running movement
|
||||
#define TASKSTATUS_RUNNING_TASK 3 // Just running task
|
||||
#define TASKSTATUS_COMPLETE 4 // Completed, get next task
|
||||
|
||||
|
||||
//=========================================================
|
||||
// These are the schedule types
|
||||
//=========================================================
|
||||
typedef enum
|
||||
{
|
||||
SCHED_NONE = 0,
|
||||
SCHED_IDLE_STAND,
|
||||
SCHED_IDLE_WALK,
|
||||
SCHED_WAKE_ANGRY,
|
||||
SCHED_WAKE_CALLED,
|
||||
SCHED_ALERT_FACE,
|
||||
SCHED_ALERT_SMALL_FLINCH,
|
||||
SCHED_ALERT_BIG_FLINCH,
|
||||
SCHED_ALERT_STAND,
|
||||
SCHED_INVESTIGATE_SOUND,
|
||||
SCHED_COMBAT_FACE,
|
||||
SCHED_COMBAT_STAND,
|
||||
SCHED_CHASE_ENEMY,
|
||||
SCHED_CHASE_ENEMY_FAILED,
|
||||
SCHED_VICTORY_DANCE,
|
||||
SCHED_TARGET_FACE,
|
||||
SCHED_TARGET_CHASE,
|
||||
SCHED_SMALL_FLINCH,
|
||||
SCHED_TAKE_COVER_FROM_ENEMY,
|
||||
SCHED_TAKE_COVER_FROM_BEST_SOUND,
|
||||
SCHED_TAKE_COVER_FROM_ORIGIN,
|
||||
SCHED_COWER, // usually a last resort!
|
||||
SCHED_MELEE_ATTACK1,
|
||||
SCHED_MELEE_ATTACK2,
|
||||
SCHED_RANGE_ATTACK1,
|
||||
SCHED_RANGE_ATTACK2,
|
||||
SCHED_SPECIAL_ATTACK1,
|
||||
SCHED_SPECIAL_ATTACK2,
|
||||
SCHED_STANDOFF,
|
||||
SCHED_ARM_WEAPON,
|
||||
SCHED_RELOAD,
|
||||
SCHED_GUARD,
|
||||
SCHED_AMBUSH,
|
||||
SCHED_DIE,
|
||||
SCHED_WAIT_TRIGGER,
|
||||
SCHED_FOLLOW,
|
||||
SCHED_SLEEP,
|
||||
SCHED_WAKE,
|
||||
SCHED_BARNACLE_VICTIM_GRAB,
|
||||
SCHED_BARNACLE_VICTIM_CHOMP,
|
||||
SCHED_AISCRIPT,
|
||||
SCHED_FAIL,
|
||||
|
||||
LAST_COMMON_SCHEDULE // Leave this at the bottom
|
||||
} SCHEDULE_TYPE;
|
||||
|
||||
//=========================================================
|
||||
// These are the shared tasks
|
||||
//=========================================================
|
||||
typedef enum
|
||||
{
|
||||
TASK_INVALID = 0,
|
||||
TASK_WAIT,
|
||||
TASK_WAIT_FACE_ENEMY,
|
||||
TASK_WAIT_PVS,
|
||||
TASK_SUGGEST_STATE,
|
||||
TASK_WALK_TO_TARGET,
|
||||
TASK_RUN_TO_TARGET,
|
||||
TASK_MOVE_TO_TARGET_RANGE,
|
||||
TASK_GET_PATH_TO_ENEMY,
|
||||
TASK_GET_PATH_TO_ENEMY_LKP,
|
||||
TASK_GET_PATH_TO_ENEMY_CORPSE,
|
||||
TASK_GET_PATH_TO_LEADER,
|
||||
TASK_GET_PATH_TO_SPOT,
|
||||
TASK_GET_PATH_TO_TARGET,
|
||||
TASK_GET_PATH_TO_HINTNODE,
|
||||
TASK_GET_PATH_TO_LASTPOSITION,
|
||||
TASK_GET_PATH_TO_BESTSOUND,
|
||||
TASK_GET_PATH_TO_BESTSCENT,
|
||||
TASK_RUN_PATH,
|
||||
TASK_WALK_PATH,
|
||||
TASK_STRAFE_PATH,
|
||||
TASK_CLEAR_MOVE_WAIT,
|
||||
TASK_STORE_LASTPOSITION,
|
||||
TASK_CLEAR_LASTPOSITION,
|
||||
TASK_PLAY_ACTIVE_IDLE,
|
||||
TASK_FIND_HINTNODE,
|
||||
TASK_CLEAR_HINTNODE,
|
||||
TASK_SMALL_FLINCH,
|
||||
TASK_FACE_IDEAL,
|
||||
TASK_FACE_ROUTE,
|
||||
TASK_FACE_ENEMY,
|
||||
TASK_FACE_HINTNODE,
|
||||
TASK_FACE_TARGET,
|
||||
TASK_FACE_LASTPOSITION,
|
||||
TASK_RANGE_ATTACK1,
|
||||
TASK_RANGE_ATTACK2,
|
||||
TASK_MELEE_ATTACK1,
|
||||
TASK_MELEE_ATTACK2,
|
||||
TASK_RELOAD,
|
||||
TASK_RANGE_ATTACK1_NOTURN,
|
||||
TASK_RANGE_ATTACK2_NOTURN,
|
||||
TASK_MELEE_ATTACK1_NOTURN,
|
||||
TASK_MELEE_ATTACK2_NOTURN,
|
||||
TASK_RELOAD_NOTURN,
|
||||
TASK_SPECIAL_ATTACK1,
|
||||
TASK_SPECIAL_ATTACK2,
|
||||
TASK_CROUCH,
|
||||
TASK_STAND,
|
||||
TASK_GUARD,
|
||||
TASK_STEP_LEFT,
|
||||
TASK_STEP_RIGHT,
|
||||
TASK_STEP_FORWARD,
|
||||
TASK_STEP_BACK,
|
||||
TASK_DODGE_LEFT,
|
||||
TASK_DODGE_RIGHT,
|
||||
TASK_SOUND_ANGRY,
|
||||
TASK_SOUND_DEATH,
|
||||
TASK_SET_ACTIVITY,
|
||||
TASK_SET_SCHEDULE,
|
||||
TASK_SET_FAIL_SCHEDULE,
|
||||
TASK_CLEAR_FAIL_SCHEDULE,
|
||||
TASK_PLAY_SEQUENCE,
|
||||
TASK_PLAY_SEQUENCE_FACE_ENEMY,
|
||||
TASK_PLAY_SEQUENCE_FACE_TARGET,
|
||||
TASK_SOUND_IDLE,
|
||||
TASK_SOUND_WAKE,
|
||||
TASK_SOUND_PAIN,
|
||||
TASK_SOUND_DIE,
|
||||
TASK_FIND_COVER_FROM_BEST_SOUND,// tries lateral cover first, then node cover
|
||||
TASK_FIND_COVER_FROM_ENEMY,// tries lateral cover first, then node cover
|
||||
TASK_FIND_LATERAL_COVER_FROM_ENEMY,
|
||||
TASK_FIND_NODE_COVER_FROM_ENEMY,
|
||||
TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY,// data for this one is the MAXIMUM acceptable distance to the cover.
|
||||
TASK_FIND_FAR_NODE_COVER_FROM_ENEMY,// data for this one is there MINIMUM aceptable distance to the cover.
|
||||
TASK_FIND_COVER_FROM_ORIGIN,
|
||||
TASK_EAT,
|
||||
TASK_DIE,
|
||||
TASK_WAIT_FOR_SCRIPT,
|
||||
TASK_PLAY_SCRIPT,
|
||||
TASK_ENABLE_SCRIPT,
|
||||
TASK_PLANT_ON_SCRIPT,
|
||||
TASK_FACE_SCRIPT,
|
||||
TASK_WAIT_RANDOM,
|
||||
TASK_WAIT_INDEFINITE,
|
||||
TASK_STOP_MOVING,
|
||||
TASK_TURN_LEFT,
|
||||
TASK_TURN_RIGHT,
|
||||
TASK_REMEMBER,
|
||||
TASK_FORGET,
|
||||
TASK_WAIT_FOR_MOVEMENT, // wait until MovementIsComplete()
|
||||
LAST_COMMON_TASK, // LEAVE THIS AT THE BOTTOM!! (sjb)
|
||||
} SHARED_TASKS;
|
||||
|
||||
|
||||
// These go in the flData member of the TASK_WALK_TO_TARGET, TASK_RUN_TO_TARGET
|
||||
enum
|
||||
{
|
||||
TARGET_MOVE_NORMAL = 0,
|
||||
TARGET_MOVE_SCRIPTED = 1,
|
||||
};
|
||||
|
||||
|
||||
// A goal should be used for a task that requires several schedules to complete.
|
||||
// The goal index should indicate which schedule (ordinally) the monster is running.
|
||||
// That way, when tasks fail, the AI can make decisions based on the context of the
|
||||
// current goal and sequence rather than just the current schedule.
|
||||
enum
|
||||
{
|
||||
GOAL_ATTACK_ENEMY,
|
||||
GOAL_MOVE,
|
||||
GOAL_TAKE_COVER,
|
||||
GOAL_MOVE_TARGET,
|
||||
GOAL_EAT,
|
||||
};
|
||||
|
||||
// an array of tasks is a task list
|
||||
// an array of schedules is a schedule list
|
||||
struct Task_t
|
||||
{
|
||||
|
||||
int iTask;
|
||||
float flData;
|
||||
};
|
||||
|
||||
struct Schedule_t
|
||||
{
|
||||
|
||||
Task_t *pTasklist;
|
||||
int cTasks;
|
||||
int iInterruptMask;// a bit mask of conditions that can interrupt this schedule
|
||||
|
||||
// a more specific mask that indicates which TYPES of sounds will interrupt the schedule in the
|
||||
// event that the schedule is broken by COND_HEAR_SOUND
|
||||
int iSoundMask;
|
||||
const char *pName;
|
||||
};
|
||||
|
||||
// an array of waypoints makes up the monster's route.
|
||||
// !!!LATER- this declaration doesn't belong in this file.
|
||||
struct WayPoint_t
|
||||
{
|
||||
Vector vecLocation;
|
||||
int iType;
|
||||
};
|
||||
|
||||
// these MoveFlag values are assigned to a WayPoint's TYPE in order to demonstrate the
|
||||
// type of movement the monster should use to get there.
|
||||
#define bits_MF_TO_TARGETENT ( 1 << 0 ) // local move to targetent.
|
||||
#define bits_MF_TO_ENEMY ( 1 << 1 ) // local move to enemy
|
||||
#define bits_MF_TO_COVER ( 1 << 2 ) // local move to a hiding place
|
||||
#define bits_MF_TO_DETOUR ( 1 << 3 ) // local move to detour point.
|
||||
#define bits_MF_TO_PATHCORNER ( 1 << 4 ) // local move to a path corner
|
||||
#define bits_MF_TO_NODE ( 1 << 5 ) // local move to a node
|
||||
#define bits_MF_TO_LOCATION ( 1 << 6 ) // local move to an arbitrary point
|
||||
#define bits_MF_IS_GOAL ( 1 << 7 ) // this waypoint is the goal of the whole move.
|
||||
#define bits_MF_DONT_SIMPLIFY ( 1 << 8 ) // Don't let the route code simplify this waypoint
|
||||
|
||||
// If you define any flags that aren't _TO_ flags, add them here so we can mask
|
||||
// them off when doing compares.
|
||||
#define bits_MF_NOT_TO_MASK (bits_MF_IS_GOAL | bits_MF_DONT_SIMPLIFY)
|
||||
|
||||
#define MOVEGOAL_NONE (0)
|
||||
#define MOVEGOAL_TARGETENT (bits_MF_TO_TARGETENT)
|
||||
#define MOVEGOAL_ENEMY (bits_MF_TO_ENEMY)
|
||||
#define MOVEGOAL_PATHCORNER (bits_MF_TO_PATHCORNER)
|
||||
#define MOVEGOAL_LOCATION (bits_MF_TO_LOCATION)
|
||||
#define MOVEGOAL_NODE (bits_MF_TO_NODE)
|
||||
|
||||
// these bits represent conditions that may befall the monster, of which some are allowed
|
||||
// to interrupt certain schedules.
|
||||
#define bits_COND_NO_AMMO_LOADED ( 1 << 0 ) // weapon needs to be reloaded!
|
||||
#define bits_COND_SEE_HATE ( 1 << 1 ) // see something that you hate
|
||||
#define bits_COND_SEE_FEAR ( 1 << 2 ) // see something that you are afraid of
|
||||
#define bits_COND_SEE_DISLIKE ( 1 << 3 ) // see something that you dislike
|
||||
#define bits_COND_SEE_ENEMY ( 1 << 4 ) // target entity is in full view.
|
||||
#define bits_COND_ENEMY_OCCLUDED ( 1 << 5 ) // target entity occluded by the world
|
||||
#define bits_COND_SMELL_FOOD ( 1 << 6 )
|
||||
#define bits_COND_ENEMY_TOOFAR ( 1 << 7 )
|
||||
#define bits_COND_LIGHT_DAMAGE ( 1 << 8 ) // hurt a little
|
||||
#define bits_COND_HEAVY_DAMAGE ( 1 << 9 ) // hurt a lot
|
||||
#define bits_COND_CAN_RANGE_ATTACK1 ( 1 << 10)
|
||||
#define bits_COND_CAN_MELEE_ATTACK1 ( 1 << 11)
|
||||
#define bits_COND_CAN_RANGE_ATTACK2 ( 1 << 12)
|
||||
#define bits_COND_CAN_MELEE_ATTACK2 ( 1 << 13)
|
||||
// #define bits_COND_CAN_RANGE_ATTACK3 ( 1 << 14)
|
||||
#define bits_COND_PROVOKED ( 1 << 15)
|
||||
#define bits_COND_NEW_ENEMY ( 1 << 16)
|
||||
#define bits_COND_HEAR_SOUND ( 1 << 17) // there is an interesting sound
|
||||
#define bits_COND_SMELL ( 1 << 18) // there is an interesting scent
|
||||
#define bits_COND_ENEMY_FACING_ME ( 1 << 19) // enemy is facing me
|
||||
#define bits_COND_ENEMY_DEAD ( 1 << 20) // enemy was killed. If you get this in combat, try to find another enemy. If you get it in alert, victory dance.
|
||||
#define bits_COND_SEE_CLIENT ( 1 << 21) // see a client
|
||||
#define bits_COND_SEE_NEMESIS ( 1 << 22) // see my nemesis
|
||||
|
||||
#define bits_COND_SPECIAL1 ( 1 << 28) // Defined by individual monster
|
||||
#define bits_COND_SPECIAL2 ( 1 << 29) // Defined by individual monster
|
||||
|
||||
#define bits_COND_TASK_FAILED ( 1 << 30)
|
||||
#define bits_COND_SCHEDULE_DONE ( 1 << 31)
|
||||
|
||||
|
||||
#define bits_COND_ALL_SPECIAL (bits_COND_SPECIAL1 | bits_COND_SPECIAL2)
|
||||
|
||||
#define bits_COND_CAN_ATTACK (bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_MELEE_ATTACK1 | bits_COND_CAN_RANGE_ATTACK2 | bits_COND_CAN_MELEE_ATTACK2)
|
||||
|
||||
#endif // SCHEDULE_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
233
src/dlls/shock.cpp
Normal file
233
src/dlls/shock.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
// 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 );
|
||||
}
|
||||
|
||||
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
|
||||
223
src/dlls/shockroach.cpp
Normal file
223
src/dlls/shockroach.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
// 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"
|
||||
|
||||
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_GREEN;
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
void CMShockRoach::AttackSound()
|
||||
{
|
||||
EMIT_SOUND_DYN(edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch());
|
||||
}
|
||||
@@ -1,256 +1,355 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifndef __linux__
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "extdll.h"
|
||||
#include "dllapi.h"
|
||||
#include "meta_api.h"
|
||||
#include "skill.h"
|
||||
|
||||
extern cvar_t *dllapi_log;
|
||||
|
||||
skilldata_t gSkillData;
|
||||
|
||||
struct skill_cfg_t
|
||||
{
|
||||
char *name;
|
||||
float *value;
|
||||
};
|
||||
|
||||
skill_cfg_t skill_cfg[] = {
|
||||
{"sk_agrunt_health", &gSkillData.agruntHealth},
|
||||
{"sk_agrunt_dmg_punch", &gSkillData.agruntDmgPunch},
|
||||
{"sk_apache_health", &gSkillData.apacheHealth},
|
||||
{"sk_barney_health", &gSkillData.barneyHealth},
|
||||
{"sk_bigmomma_health_factor", &gSkillData.bigmommaHealthFactor},
|
||||
{"sk_bigmomma_dmg_slash", &gSkillData.bigmommaDmgSlash},
|
||||
{"sk_bigmomma_dmg_blast", &gSkillData.bigmommaDmgBlast},
|
||||
{"sk_bigmomma_radius_blast", &gSkillData.bigmommaRadiusBlast},
|
||||
{"sk_bullsquid_health", &gSkillData.bullsquidHealth},
|
||||
{"sk_bullsquid_dmg_bite", &gSkillData.bullsquidDmgBite},
|
||||
{"sk_bullsquid_dmg_whip", &gSkillData.bullsquidDmgWhip},
|
||||
{"sk_bullsquid_dmg_spit", &gSkillData.bullsquidDmgSpit},
|
||||
{"sk_gargantua_health", &gSkillData.gargantuaHealth},
|
||||
{"sk_gargantua_armor", &gSkillData.gargantuaArmor},
|
||||
{"sk_gargantua_dmg_slash", &gSkillData.gargantuaDmgSlash},
|
||||
{"sk_gargantua_dmg_fire", &gSkillData.gargantuaDmgFire},
|
||||
{"sk_gargantua_dmg_stomp", &gSkillData.gargantuaDmgStomp},
|
||||
{"sk_hassassin_health", &gSkillData.hassassinHealth},
|
||||
{"sk_headcrab_health", &gSkillData.headcrabHealth},
|
||||
{"sk_headcrab_dmg_bite", &gSkillData.headcrabDmgBite},
|
||||
{"sk_hgrunt_health", &gSkillData.hgruntHealth},
|
||||
{"sk_hgrunt_kick", &gSkillData.hgruntDmgKick},
|
||||
{"sk_hgrunt_pellets", &gSkillData.hgruntShotgunPellets},
|
||||
{"sk_hgrunt_gspeed", &gSkillData.hgruntGrenadeSpeed},
|
||||
{"sk_houndeye_health", &gSkillData.houndeyeHealth},
|
||||
{"sk_houndeye_dmg_blast", &gSkillData.houndeyeDmgBlast},
|
||||
{"sk_islave_health", &gSkillData.slaveHealth},
|
||||
{"sk_islave_dmg_claw", &gSkillData.slaveDmgClaw},
|
||||
{"sk_islave_dmg_clawrake", &gSkillData.slaveDmgClawrake},
|
||||
{"sk_islave_dmg_zap", &gSkillData.slaveDmgZap},
|
||||
{"sk_ichthyosaur_health", &gSkillData.ichthyosaurHealth},
|
||||
{"sk_ichthyosaur_shake", &gSkillData.ichthyosaurDmgShake},
|
||||
{"sk_controller_health", &gSkillData.controllerHealth},
|
||||
{"sk_controller_dmgzap", &gSkillData.controllerDmgZap},
|
||||
{"sk_controller_speedball", &gSkillData.controllerSpeedBall},
|
||||
{"sk_controller_dmgball", &gSkillData.controllerDmgBall},
|
||||
{"sk_scientist_health", &gSkillData.scientistHealth},
|
||||
{"sk_scientist_heal", &gSkillData.scientistHeal},
|
||||
{"sk_snark_health", &gSkillData.snarkHealth},
|
||||
{"sk_snark_dmg_bite", &gSkillData.snarkDmgBite},
|
||||
{"sk_snark_dmg_pop", &gSkillData.snarkDmgPop},
|
||||
{"sk_zombie_health", &gSkillData.zombieHealth},
|
||||
{"sk_zombie_dmg_one_slash", &gSkillData.zombieDmgOneSlash},
|
||||
{"sk_zombie_dmg_both_slash", &gSkillData.zombieDmgBothSlash},
|
||||
{"sk_turret_health", &gSkillData.turretHealth},
|
||||
{"sk_miniturret_health", &gSkillData.miniturretHealth},
|
||||
{"sk_sentry_health", &gSkillData.sentryHealth},
|
||||
{"sk_12mm_bullet", &gSkillData.monDmg9MM},
|
||||
{"sk_9mmAR_bullet", &gSkillData.monDmgMP5},
|
||||
{"sk_9mm_bullet", &gSkillData.monDmg12MM},
|
||||
{"sk_9mmAR_grenade", &gSkillData.monDmgM203Grenade},
|
||||
{"sk_hornet_dmg", &gSkillData.monDmgHornet},
|
||||
{"", NULL}
|
||||
};
|
||||
|
||||
bool get_input(FILE *fp, char *input);
|
||||
|
||||
|
||||
void scan_monster_skill(FILE *fp)
|
||||
{
|
||||
char input[1024];
|
||||
int index, len, pos;
|
||||
bool found;
|
||||
|
||||
while (get_input(fp, input))
|
||||
{
|
||||
index = 0;
|
||||
found = FALSE;
|
||||
|
||||
while (skill_cfg[index].name[0])
|
||||
{
|
||||
len = strlen(skill_cfg[index].name);
|
||||
if (strncmp(input, skill_cfg[index].name, len) == 0)
|
||||
{
|
||||
found = TRUE;
|
||||
pos = len;
|
||||
sscanf(&input[pos], "%f", skill_cfg[index].value);
|
||||
|
||||
if (dllapi_log->value)
|
||||
LOG_MESSAGE(PLID, "skill setting %s set to %f",
|
||||
skill_cfg[index].name, *skill_cfg[index].value);
|
||||
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
//META_CONS("[MONSTER] ERROR: unknown monster_skill.cfg item: %s", input);
|
||||
LOG_MESSAGE(PLID, "ERROR: unknown monster_skill.cfg item: %s", input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void monster_skill_init(void)
|
||||
{
|
||||
char game_dir[256];
|
||||
char filename[256];
|
||||
FILE *fp = NULL;
|
||||
|
||||
// Alien Grunt
|
||||
gSkillData.agruntHealth = 90.0f;
|
||||
gSkillData.agruntDmgPunch = 20.0f;
|
||||
|
||||
// Apache
|
||||
gSkillData.apacheHealth = 250.0f;
|
||||
|
||||
// Barney
|
||||
gSkillData.barneyHealth = 35.0f;
|
||||
|
||||
// Big momma
|
||||
gSkillData.bigmommaHealthFactor = 1.5f;
|
||||
gSkillData.bigmommaDmgSlash = 60.0f;
|
||||
gSkillData.bigmommaDmgBlast = 120.0f;
|
||||
gSkillData.bigmommaRadiusBlast = 250.0f;
|
||||
|
||||
// Bullsquid
|
||||
gSkillData.bullsquidHealth = 40.0f;
|
||||
gSkillData.bullsquidDmgBite = 25.0f;
|
||||
gSkillData.bullsquidDmgWhip = 35.0f;
|
||||
gSkillData.bullsquidDmgSpit = 10.0f;
|
||||
|
||||
// Gargantua
|
||||
gSkillData.gargantuaHealth = 800.0f;
|
||||
gSkillData.gargantuaArmor = 0.85f;
|
||||
gSkillData.gargantuaDmgSlash = 30.0f;
|
||||
gSkillData.gargantuaDmgFire = 5.0f;
|
||||
gSkillData.gargantuaDmgStomp = 100.0f;
|
||||
|
||||
// Hassassin (Female Assassin)
|
||||
gSkillData.hassassinHealth = 50.0f;
|
||||
|
||||
// Headcrab
|
||||
gSkillData.headcrabHealth = 10.0f;
|
||||
gSkillData.headcrabDmgBite = 10.0f;
|
||||
|
||||
// Hgrunt (Human Grunt)
|
||||
gSkillData.hgruntHealth = 50.0f;
|
||||
gSkillData.hgruntDmgKick = 10.0f;
|
||||
gSkillData.hgruntShotgunPellets = 5.0f;
|
||||
gSkillData.hgruntGrenadeSpeed = 600.0f;
|
||||
|
||||
// Houndeye
|
||||
gSkillData.houndeyeHealth = 20.0f;
|
||||
gSkillData.houndeyeDmgBlast = 15.0f;
|
||||
|
||||
// Alien Slave
|
||||
gSkillData.slaveHealth = 30.0f;
|
||||
gSkillData.slaveDmgClaw = 10.0f;
|
||||
gSkillData.slaveDmgClawrake = 25.0f;
|
||||
gSkillData.slaveDmgZap = 10.0f;
|
||||
|
||||
// Icthyosaur
|
||||
gSkillData.ichthyosaurHealth = 200.0f;
|
||||
gSkillData.ichthyosaurDmgShake = 35.0f;
|
||||
|
||||
// Controller
|
||||
gSkillData.controllerHealth = 60.0f;
|
||||
gSkillData.controllerDmgZap = 25.0f;
|
||||
gSkillData.controllerSpeedBall = 800.0f;
|
||||
gSkillData.controllerDmgBall = 4.0f;
|
||||
|
||||
// Scientist
|
||||
gSkillData.scientistHealth = 20.0f;
|
||||
gSkillData.scientistHeal = 25.0f;
|
||||
|
||||
// Snark
|
||||
gSkillData.snarkHealth = 2.0f;
|
||||
gSkillData.snarkDmgBite = 10.0f;
|
||||
gSkillData.snarkDmgPop = 5.0f;
|
||||
|
||||
// Zombie
|
||||
gSkillData.zombieHealth = 50.0f;
|
||||
gSkillData.zombieDmgOneSlash = 20.0f;
|
||||
gSkillData.zombieDmgBothSlash = 40.0f;
|
||||
|
||||
// Turret
|
||||
gSkillData.turretHealth = 50.0f;
|
||||
|
||||
// Mini-Turret
|
||||
gSkillData.miniturretHealth = 40.0f;
|
||||
|
||||
// Sentry
|
||||
gSkillData.sentryHealth = 40.0f;
|
||||
|
||||
// MONSTER WEAPONS
|
||||
gSkillData.monDmg9MM = 5.0f;
|
||||
gSkillData.monDmgMP5 = 4.0f;
|
||||
gSkillData.monDmg12MM = 10.0f;
|
||||
gSkillData.monDmgM203Grenade = 100.0f;
|
||||
|
||||
// HORNET
|
||||
gSkillData.monDmgHornet = 5.0f;
|
||||
|
||||
|
||||
// find the directory name of the currently running MOD...
|
||||
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
||||
|
||||
strcpy(filename, game_dir);
|
||||
strcat(filename, "/monster_skill.cfg");
|
||||
|
||||
// check if the map specific filename exists...
|
||||
if (access(filename, 0) == 0)
|
||||
{
|
||||
if (dllapi_log->value)
|
||||
{
|
||||
//META_CONS("[MONSTER] Processing monster skill file=%s", filename);
|
||||
LOG_MESSAGE(PLID, "Processing monster skill file=%s", filename);
|
||||
}
|
||||
|
||||
if ((fp = fopen(filename, "r")) == NULL)
|
||||
{
|
||||
//META_CONS("[MONSTER] ERROR: Could not open \"%s\"!", filename);
|
||||
LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\"!", filename);
|
||||
}
|
||||
|
||||
scan_monster_skill(fp);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
//META_CONS("[MONSTER] ERROR: Could not find \"%s\" (default skill used)", filename);
|
||||
LOG_MESSAGE(PLID, "ERROR: Could not find \"%s\" (default skill used)", filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifndef __linux__
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "extdll.h"
|
||||
#include "dllapi.h"
|
||||
#include "meta_api.h"
|
||||
#include "skill.h"
|
||||
|
||||
extern cvar_t *dllapi_log;
|
||||
|
||||
skilldata_t gSkillData;
|
||||
|
||||
struct skill_cfg_t
|
||||
{
|
||||
char *name;
|
||||
float *value;
|
||||
};
|
||||
|
||||
skill_cfg_t skill_cfg[] = {
|
||||
{"sk_agrunt_health", &gSkillData.agruntHealth},
|
||||
{"sk_agrunt_dmg_punch", &gSkillData.agruntDmgPunch},
|
||||
{"sk_apache_health", &gSkillData.apacheHealth},
|
||||
{"sk_barney_health", &gSkillData.barneyHealth},
|
||||
{"sk_bigmomma_health_factor", &gSkillData.bigmommaHealthFactor},
|
||||
{"sk_bigmomma_dmg_slash", &gSkillData.bigmommaDmgSlash},
|
||||
{"sk_bigmomma_dmg_blast", &gSkillData.bigmommaDmgBlast},
|
||||
{"sk_bigmomma_radius_blast", &gSkillData.bigmommaRadiusBlast},
|
||||
{"sk_bullsquid_health", &gSkillData.bullsquidHealth},
|
||||
{"sk_bullsquid_dmg_bite", &gSkillData.bullsquidDmgBite},
|
||||
{"sk_bullsquid_dmg_whip", &gSkillData.bullsquidDmgWhip},
|
||||
{"sk_bullsquid_dmg_spit", &gSkillData.bullsquidDmgSpit},
|
||||
{"sk_gargantua_health", &gSkillData.gargantuaHealth},
|
||||
{"sk_gargantua_armor", &gSkillData.gargantuaArmor},
|
||||
{"sk_gargantua_dmg_slash", &gSkillData.gargantuaDmgSlash},
|
||||
{"sk_gargantua_dmg_fire", &gSkillData.gargantuaDmgFire},
|
||||
{"sk_gargantua_dmg_stomp", &gSkillData.gargantuaDmgStomp},
|
||||
{"sk_hassassin_health", &gSkillData.hassassinHealth},
|
||||
{"sk_headcrab_health", &gSkillData.headcrabHealth},
|
||||
{"sk_headcrab_dmg_bite", &gSkillData.headcrabDmgBite},
|
||||
{"sk_hgrunt_health", &gSkillData.hgruntHealth},
|
||||
{"sk_hgrunt_kick", &gSkillData.hgruntDmgKick},
|
||||
{"sk_hgrunt_pellets", &gSkillData.hgruntShotgunPellets},
|
||||
{"sk_hgrunt_gspeed", &gSkillData.hgruntGrenadeSpeed},
|
||||
{"sk_houndeye_health", &gSkillData.houndeyeHealth},
|
||||
{"sk_houndeye_dmg_blast", &gSkillData.houndeyeDmgBlast},
|
||||
{"sk_islave_health", &gSkillData.slaveHealth},
|
||||
{"sk_islave_dmg_claw", &gSkillData.slaveDmgClaw},
|
||||
{"sk_islave_dmg_clawrake", &gSkillData.slaveDmgClawrake},
|
||||
{"sk_islave_dmg_zap", &gSkillData.slaveDmgZap},
|
||||
{"sk_ichthyosaur_health", &gSkillData.ichthyosaurHealth},
|
||||
{"sk_ichthyosaur_shake", &gSkillData.ichthyosaurDmgShake},
|
||||
{"sk_controller_health", &gSkillData.controllerHealth},
|
||||
{"sk_controller_dmgzap", &gSkillData.controllerDmgZap},
|
||||
{"sk_controller_speedball", &gSkillData.controllerSpeedBall},
|
||||
{"sk_controller_dmgball", &gSkillData.controllerDmgBall},
|
||||
{"sk_scientist_health", &gSkillData.scientistHealth},
|
||||
{"sk_scientist_heal", &gSkillData.scientistHeal},
|
||||
{"sk_snark_health", &gSkillData.snarkHealth},
|
||||
{"sk_snark_dmg_bite", &gSkillData.snarkDmgBite},
|
||||
{"sk_snark_dmg_pop", &gSkillData.snarkDmgPop},
|
||||
{"sk_zombie_health", &gSkillData.zombieHealth},
|
||||
{"sk_zombie_dmg_one_slash", &gSkillData.zombieDmgOneSlash},
|
||||
{"sk_zombie_dmg_both_slash", &gSkillData.zombieDmgBothSlash},
|
||||
{"sk_turret_health", &gSkillData.turretHealth},
|
||||
{"sk_miniturret_health", &gSkillData.miniturretHealth},
|
||||
{"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_9mmAR_bullet", &gSkillData.monDmgMP5},
|
||||
{"sk_9mm_bullet", &gSkillData.monDmg12MM},
|
||||
{"sk_9mmAR_grenade", &gSkillData.monDmgM203Grenade},
|
||||
{"sk_762_bullet", &gSkillData.monDmg762},
|
||||
{"sk_357_bullet", &gSkillData.monDmg357},
|
||||
{"sk_hornet_dmg", &gSkillData.monDmgHornet},
|
||||
{"sk_shock_dmg", &gSkillData.monDmgShockroach},
|
||||
{"sk_spore_dmg", &gSkillData.monDmgSpore},
|
||||
{"", NULL}
|
||||
};
|
||||
|
||||
bool get_input(FILE *fp, char *input);
|
||||
|
||||
|
||||
void scan_monster_skill(FILE *fp)
|
||||
{
|
||||
char input[1024];
|
||||
int index, len, pos;
|
||||
bool found;
|
||||
|
||||
while (get_input(fp, input))
|
||||
{
|
||||
index = 0;
|
||||
found = FALSE;
|
||||
|
||||
while (skill_cfg[index].name[0])
|
||||
{
|
||||
len = strlen(skill_cfg[index].name);
|
||||
if (strncmp(input, skill_cfg[index].name, len) == 0)
|
||||
{
|
||||
found = TRUE;
|
||||
pos = len;
|
||||
sscanf(&input[pos], "%f", skill_cfg[index].value);
|
||||
|
||||
if (dllapi_log->value)
|
||||
LOG_MESSAGE(PLID, "skill setting %s set to %f",
|
||||
skill_cfg[index].name, *skill_cfg[index].value);
|
||||
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
//META_CONS("[MONSTER] ERROR: unknown monster_skill.cfg item: %s", input);
|
||||
LOG_MESSAGE(PLID, "ERROR: unknown monster_skill.cfg item: %s", input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void monster_skill_init(void)
|
||||
{
|
||||
char game_dir[256];
|
||||
char filename[256];
|
||||
FILE *fp = NULL;
|
||||
|
||||
// Alien Grunt
|
||||
gSkillData.agruntHealth = 90.0f;
|
||||
gSkillData.agruntDmgPunch = 20.0f;
|
||||
|
||||
// Apache
|
||||
gSkillData.apacheHealth = 250.0f;
|
||||
|
||||
// Barney
|
||||
gSkillData.barneyHealth = 35.0f;
|
||||
|
||||
// Big momma
|
||||
gSkillData.bigmommaHealthFactor = 1.5f;
|
||||
gSkillData.bigmommaDmgSlash = 60.0f;
|
||||
gSkillData.bigmommaDmgBlast = 120.0f;
|
||||
gSkillData.bigmommaRadiusBlast = 250.0f;
|
||||
|
||||
// Bullsquid
|
||||
gSkillData.bullsquidHealth = 40.0f;
|
||||
gSkillData.bullsquidDmgBite = 25.0f;
|
||||
gSkillData.bullsquidDmgWhip = 35.0f;
|
||||
gSkillData.bullsquidDmgSpit = 10.0f;
|
||||
|
||||
// Gargantua
|
||||
gSkillData.gargantuaHealth = 800.0f;
|
||||
gSkillData.gargantuaArmor = 0.85f;
|
||||
gSkillData.gargantuaDmgSlash = 30.0f;
|
||||
gSkillData.gargantuaDmgFire = 5.0f;
|
||||
gSkillData.gargantuaDmgStomp = 100.0f;
|
||||
|
||||
// Hassassin (Female Assassin)
|
||||
gSkillData.hassassinHealth = 50.0f;
|
||||
|
||||
// Headcrab
|
||||
gSkillData.headcrabHealth = 10.0f;
|
||||
gSkillData.headcrabDmgBite = 10.0f;
|
||||
|
||||
// Hgrunt (Human Grunt)
|
||||
gSkillData.hgruntHealth = 50.0f;
|
||||
gSkillData.hgruntDmgKick = 10.0f;
|
||||
gSkillData.hgruntShotgunPellets = 5.0f;
|
||||
gSkillData.hgruntGrenadeSpeed = 600.0f;
|
||||
|
||||
// Houndeye
|
||||
gSkillData.houndeyeHealth = 20.0f;
|
||||
gSkillData.houndeyeDmgBlast = 15.0f;
|
||||
|
||||
// Alien Slave
|
||||
gSkillData.slaveHealth = 30.0f;
|
||||
gSkillData.slaveDmgClaw = 10.0f;
|
||||
gSkillData.slaveDmgClawrake = 25.0f;
|
||||
gSkillData.slaveDmgZap = 10.0f;
|
||||
|
||||
// Icthyosaur
|
||||
gSkillData.ichthyosaurHealth = 200.0f;
|
||||
gSkillData.ichthyosaurDmgShake = 35.0f;
|
||||
|
||||
// Controller
|
||||
gSkillData.controllerHealth = 60.0f;
|
||||
gSkillData.controllerDmgZap = 25.0f;
|
||||
gSkillData.controllerSpeedBall = 800.0f;
|
||||
gSkillData.controllerDmgBall = 4.0f;
|
||||
|
||||
// Scientist
|
||||
gSkillData.scientistHealth = 20.0f;
|
||||
gSkillData.scientistHeal = 25.0f;
|
||||
|
||||
// Snark
|
||||
gSkillData.snarkHealth = 2.0f;
|
||||
gSkillData.snarkDmgBite = 10.0f;
|
||||
gSkillData.snarkDmgPop = 5.0f;
|
||||
|
||||
// Zombie
|
||||
gSkillData.zombieHealth = 50.0f;
|
||||
gSkillData.zombieDmgOneSlash = 20.0f;
|
||||
gSkillData.zombieDmgBothSlash = 40.0f;
|
||||
|
||||
// Turret
|
||||
gSkillData.turretHealth = 50.0f;
|
||||
|
||||
// Mini-Turret
|
||||
gSkillData.miniturretHealth = 40.0f;
|
||||
|
||||
// Sentry
|
||||
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
|
||||
gSkillData.monDmg9MM = 5.0f;
|
||||
gSkillData.monDmgMP5 = 4.0f;
|
||||
gSkillData.monDmg12MM = 10.0f;
|
||||
gSkillData.monDmgM203Grenade = 100.0f;
|
||||
gSkillData.monDmg762 = 100.0f;
|
||||
gSkillData.monDmg357 = 40.0f;
|
||||
|
||||
// HORNET
|
||||
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...
|
||||
(*g_engfuncs.pfnGetGameDir)(game_dir);
|
||||
|
||||
strcpy(filename, game_dir);
|
||||
strcat(filename, "/monster_skill.cfg");
|
||||
|
||||
// check if the map specific filename exists...
|
||||
if (access(filename, 0) == 0)
|
||||
{
|
||||
if (dllapi_log->value)
|
||||
{
|
||||
//META_CONS("[MONSTER] Processing monster skill file=%s", filename);
|
||||
LOG_MESSAGE(PLID, "Processing monster skill file=%s", filename);
|
||||
}
|
||||
|
||||
if ((fp = fopen(filename, "r")) == NULL)
|
||||
{
|
||||
//META_CONS("[MONSTER] ERROR: Could not open \"%s\"!", filename);
|
||||
LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\"!", filename);
|
||||
}
|
||||
|
||||
scan_monster_skill(fp);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
//META_CONS("[MONSTER] ERROR: Could not find \"%s\" (default skill used)", filename);
|
||||
LOG_MESSAGE(PLID, "ERROR: Could not find \"%s\" (default skill used)", filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
256
src/dlls/skill.h
256
src/dlls/skill.h
@@ -1,102 +1,154 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
//=========================================================
|
||||
// skill.h - skill level concerns
|
||||
//=========================================================
|
||||
|
||||
#ifndef SKILL_H
|
||||
#define SKILL_H
|
||||
|
||||
struct skilldata_t
|
||||
{
|
||||
// Monster Health & Damage
|
||||
float agruntHealth;
|
||||
float agruntDmgPunch;
|
||||
|
||||
float apacheHealth;
|
||||
|
||||
float barneyHealth;
|
||||
|
||||
float bigmommaHealthFactor; // Multiply each node's health by this
|
||||
float bigmommaDmgSlash; // melee attack damage
|
||||
float bigmommaDmgBlast; // mortar attack damage
|
||||
float bigmommaRadiusBlast; // mortar attack radius
|
||||
|
||||
float bullsquidHealth;
|
||||
float bullsquidDmgBite;
|
||||
float bullsquidDmgWhip;
|
||||
float bullsquidDmgSpit;
|
||||
|
||||
float gargantuaHealth;
|
||||
float gargantuaArmor; // Non-explosives will deal this much damage
|
||||
float gargantuaDmgSlash;
|
||||
float gargantuaDmgFire;
|
||||
float gargantuaDmgStomp;
|
||||
|
||||
float hassassinHealth;
|
||||
|
||||
float headcrabHealth;
|
||||
float headcrabDmgBite;
|
||||
|
||||
float hgruntHealth;
|
||||
float hgruntDmgKick;
|
||||
float hgruntShotgunPellets;
|
||||
float hgruntGrenadeSpeed;
|
||||
|
||||
float houndeyeHealth;
|
||||
float houndeyeDmgBlast;
|
||||
|
||||
float slaveHealth;
|
||||
float slaveDmgClaw;
|
||||
float slaveDmgClawrake;
|
||||
float slaveDmgZap;
|
||||
|
||||
float ichthyosaurHealth;
|
||||
float ichthyosaurDmgShake;
|
||||
|
||||
float controllerHealth;
|
||||
float controllerDmgZap;
|
||||
float controllerSpeedBall;
|
||||
float controllerDmgBall;
|
||||
|
||||
float scientistHealth;
|
||||
float scientistHeal;
|
||||
|
||||
float snarkHealth;
|
||||
float snarkDmgBite;
|
||||
float snarkDmgPop;
|
||||
|
||||
float zombieHealth;
|
||||
float zombieDmgOneSlash;
|
||||
float zombieDmgBothSlash;
|
||||
|
||||
float turretHealth;
|
||||
float miniturretHealth;
|
||||
float sentryHealth;
|
||||
|
||||
// weapons shared by monsters
|
||||
float monDmg9MM;
|
||||
float monDmgMP5;
|
||||
float monDmg12MM;
|
||||
float monDmgM203Grenade;
|
||||
|
||||
float monDmgHornet;
|
||||
};
|
||||
|
||||
extern DLL_GLOBAL skilldata_t gSkillData;
|
||||
|
||||
void monster_skill_init(void);
|
||||
|
||||
#endif
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
//=========================================================
|
||||
// skill.h - skill level concerns
|
||||
//=========================================================
|
||||
|
||||
#ifndef SKILL_H
|
||||
#define SKILL_H
|
||||
|
||||
struct skilldata_t
|
||||
{
|
||||
// Monster Health & Damage
|
||||
float agruntHealth;
|
||||
float agruntDmgPunch;
|
||||
|
||||
float apacheHealth;
|
||||
|
||||
float barneyHealth;
|
||||
|
||||
float bigmommaHealthFactor; // Multiply each node's health by this
|
||||
float bigmommaDmgSlash; // melee attack damage
|
||||
float bigmommaDmgBlast; // mortar attack damage
|
||||
float bigmommaRadiusBlast; // mortar attack radius
|
||||
|
||||
float bullsquidHealth;
|
||||
float bullsquidDmgBite;
|
||||
float bullsquidDmgWhip;
|
||||
float bullsquidDmgSpit;
|
||||
|
||||
float gargantuaHealth;
|
||||
float gargantuaArmor; // Non-explosives will deal this much damage
|
||||
float gargantuaDmgSlash;
|
||||
float gargantuaDmgFire;
|
||||
float gargantuaDmgStomp;
|
||||
|
||||
float hassassinHealth;
|
||||
|
||||
float headcrabHealth;
|
||||
float headcrabDmgBite;
|
||||
|
||||
float hgruntHealth;
|
||||
float hgruntDmgKick;
|
||||
float hgruntShotgunPellets;
|
||||
float hgruntGrenadeSpeed;
|
||||
|
||||
float houndeyeHealth;
|
||||
float houndeyeDmgBlast;
|
||||
|
||||
float slaveHealth;
|
||||
float slaveDmgClaw;
|
||||
float slaveDmgClawrake;
|
||||
float slaveDmgZap;
|
||||
|
||||
float ichthyosaurHealth;
|
||||
float ichthyosaurDmgShake;
|
||||
|
||||
float controllerHealth;
|
||||
float controllerDmgZap;
|
||||
float controllerSpeedBall;
|
||||
float controllerDmgBall;
|
||||
|
||||
float scientistHealth;
|
||||
float scientistHeal;
|
||||
|
||||
float snarkHealth;
|
||||
float snarkDmgBite;
|
||||
float snarkDmgPop;
|
||||
|
||||
float zombieHealth;
|
||||
float zombieDmgOneSlash;
|
||||
float zombieDmgBothSlash;
|
||||
|
||||
float turretHealth;
|
||||
float miniturretHealth;
|
||||
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
|
||||
float monDmg9MM;
|
||||
float monDmgMP5;
|
||||
float monDmg12MM;
|
||||
float monDmgM203Grenade;
|
||||
float monDmg762;
|
||||
float monDmg357;
|
||||
|
||||
float monDmgHornet;
|
||||
float monDmgShockroach;
|
||||
float monDmgSpore;
|
||||
};
|
||||
|
||||
extern DLL_GLOBAL skilldata_t gSkillData;
|
||||
|
||||
void monster_skill_init(void);
|
||||
|
||||
#endif
|
||||
|
||||
1836
src/dlls/sound.cpp
1836
src/dlls/sound.cpp
File diff suppressed because it is too large
Load Diff
345
src/dlls/sporegrenade.cpp
Normal file
345
src/dlls/sporegrenade.cpp
Normal file
@@ -0,0 +1,345 @@
|
||||
// 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_MODEL("sprites/tinyspit.spr");
|
||||
gSporeExplode = PRECACHE_MODEL("sprites/spore_exp_01.spr");
|
||||
gSporeExplodeC = PRECACHE_MODEL("sprites/spore_exp_c_01.spr");
|
||||
PRECACHE_SOUND("weapons/splauncher_bounce.wav");
|
||||
PRECACHE_SOUND("weapons/splauncher_impact.wav");
|
||||
}
|
||||
|
||||
void CMSporeGrenade::Explode(TraceResult *pTrace)
|
||||
{
|
||||
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()
|
||||
{
|
||||
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->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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@@ -1,350 +1,350 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD )
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "monsters.h"
|
||||
#include "weapons.h"
|
||||
#include "nodes.h"
|
||||
|
||||
enum w_squeak_e {
|
||||
WSQUEAK_IDLE1 = 0,
|
||||
WSQUEAK_FIDGET,
|
||||
WSQUEAK_JUMP,
|
||||
WSQUEAK_RUN,
|
||||
};
|
||||
|
||||
enum squeak_e {
|
||||
SQUEAK_IDLE1 = 0,
|
||||
SQUEAK_FIDGETFIT,
|
||||
SQUEAK_FIDGETNIP,
|
||||
SQUEAK_DOWN,
|
||||
SQUEAK_UP,
|
||||
SQUEAK_THROW
|
||||
};
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
|
||||
float CMSqueakGrenade::m_flNextBounceSoundTime = 0;
|
||||
|
||||
#define SQUEEK_DETONATE_DELAY 15.0
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void CMSqueakGrenade :: Spawn( void )
|
||||
{
|
||||
Precache( );
|
||||
// motor
|
||||
pev->movetype = MOVETYPE_BOUNCE;
|
||||
pev->solid = SOLID_BBOX;
|
||||
|
||||
SET_MODEL(ENT(pev), "models/w_squeak.mdl");
|
||||
UTIL_SetSize(pev, Vector( -4, -4, 0), Vector(4, 4, 8));
|
||||
UTIL_SetOrigin( pev, pev->origin );
|
||||
|
||||
SetTouch( &CMSqueakGrenade::SuperBounceTouch );
|
||||
SetThink( &CMSqueakGrenade::HuntThink );
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
m_flNextHunt = gpGlobals->time + 1E6;
|
||||
|
||||
pev->flags |= FL_MONSTER;
|
||||
pev->takedamage = DAMAGE_AIM;
|
||||
pev->health = gSkillData.snarkHealth;
|
||||
pev->gravity = 0.5;
|
||||
pev->friction = 0.5;
|
||||
|
||||
pev->dmg = gSkillData.snarkDmgPop;
|
||||
|
||||
m_flDie = gpGlobals->time + SQUEEK_DETONATE_DELAY;
|
||||
|
||||
m_flFieldOfView = 0; // 180 degrees
|
||||
|
||||
m_flNextBounceSoundTime = gpGlobals->time;// reset each time a snark is spawned.
|
||||
|
||||
pev->sequence = WSQUEAK_RUN;
|
||||
ResetSequenceInfo( );
|
||||
|
||||
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 )
|
||||
{
|
||||
PRECACHE_MODEL("models/w_squeak.mdl");
|
||||
PRECACHE_SOUND("squeek/sqk_blast1.wav");
|
||||
PRECACHE_SOUND("common/bodysplat.wav");
|
||||
PRECACHE_SOUND("squeek/sqk_die1.wav");
|
||||
PRECACHE_SOUND("squeek/sqk_hunt1.wav");
|
||||
PRECACHE_SOUND("squeek/sqk_hunt2.wav");
|
||||
PRECACHE_SOUND("squeek/sqk_hunt3.wav");
|
||||
PRECACHE_SOUND("squeek/sqk_deploy1.wav");
|
||||
}
|
||||
|
||||
|
||||
void CMSqueakGrenade :: Killed( entvars_t *pevAttacker, int iGib )
|
||||
{
|
||||
pev->model = iStringNull;// make invisible
|
||||
SetThink( &CMSqueakGrenade::SUB_Remove );
|
||||
SetTouch( NULL );
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
|
||||
// since squeak grenades never leave a body behind, clear out their takedamage now.
|
||||
// Squeaks do a bit of radius damage when they pop, and that radius damage will
|
||||
// continue to call this function unless we acknowledge the Squeak's death now. (sjb)
|
||||
pev->takedamage = DAMAGE_NO;
|
||||
|
||||
// play squeek blast
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "squeek/sqk_blast1.wav", 1, 0.5, 0, PITCH_NORM);
|
||||
|
||||
UTIL_BloodDrips( pev->origin, g_vecZero, BloodColor(), 80 );
|
||||
|
||||
RadiusDamage ( pev, pev, pev->dmg, CLASS_NONE, DMG_BLAST );
|
||||
|
||||
CMBaseMonster :: Killed( pevAttacker, GIB_ALWAYS );
|
||||
}
|
||||
|
||||
void CMSqueakGrenade :: GibMonster( void )
|
||||
{
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CMSqueakGrenade::HuntThink( void )
|
||||
{
|
||||
// ALERT( at_console, "think\n" );
|
||||
|
||||
if (!IsInWorld())
|
||||
{
|
||||
SetTouch( NULL );
|
||||
UTIL_Remove( this->edict() );
|
||||
return;
|
||||
}
|
||||
|
||||
StudioFrameAdvance( );
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
|
||||
// explode when ready
|
||||
if (gpGlobals->time >= m_flDie)
|
||||
{
|
||||
g_vecAttackDir = pev->velocity.Normalize( );
|
||||
pev->health = -1;
|
||||
Killed( pev, 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
// float
|
||||
if (pev->waterlevel != 0)
|
||||
{
|
||||
if (pev->movetype == MOVETYPE_BOUNCE)
|
||||
{
|
||||
pev->movetype = MOVETYPE_FLY;
|
||||
}
|
||||
pev->velocity = pev->velocity * 0.9;
|
||||
pev->velocity.z += 8.0;
|
||||
}
|
||||
else if (pev->movetype = MOVETYPE_FLY)
|
||||
{
|
||||
pev->movetype = MOVETYPE_BOUNCE;
|
||||
}
|
||||
|
||||
// return if not time to hunt
|
||||
if (m_flNextHunt > gpGlobals->time)
|
||||
return;
|
||||
|
||||
m_flNextHunt = gpGlobals->time + 2.0;
|
||||
|
||||
Vector vecDir;
|
||||
TraceResult tr;
|
||||
|
||||
Vector vecFlat = pev->velocity;
|
||||
vecFlat.z = 0;
|
||||
vecFlat = vecFlat.Normalize( );
|
||||
|
||||
UTIL_MakeVectors( pev->angles );
|
||||
|
||||
if (m_hEnemy == NULL || !UTIL_IsAlive(m_hEnemy))
|
||||
{
|
||||
// find target, bounce a bit towards it.
|
||||
Look( 512 );
|
||||
m_hEnemy = BestVisibleEnemy( );
|
||||
}
|
||||
|
||||
// squeek if it's about time blow up
|
||||
if ((m_flDie - gpGlobals->time <= 0.5) && (m_flDie - gpGlobals->time >= 0.3))
|
||||
{
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_die1.wav", 1, ATTN_NORM, 0, 100 + RANDOM_LONG(0,0x3F));
|
||||
}
|
||||
|
||||
// higher pitch as squeeker gets closer to detonation time
|
||||
float flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY);
|
||||
if (flpitch < 80)
|
||||
flpitch = 80;
|
||||
|
||||
if (m_hEnemy != NULL)
|
||||
{
|
||||
if (UTIL_FVisible( m_hEnemy, ENT(pev) ))
|
||||
{
|
||||
vecDir = (m_hEnemy->v.origin + m_hEnemy->v.view_ofs) - pev->origin;
|
||||
m_vecTarget = vecDir.Normalize( );
|
||||
}
|
||||
|
||||
float flVel = pev->velocity.Length();
|
||||
float flAdj = 50.0 / (flVel + 10.0);
|
||||
|
||||
if (flAdj > 1.2)
|
||||
flAdj = 1.2;
|
||||
|
||||
// ALERT( at_console, "think : enemy\n");
|
||||
|
||||
// ALERT( at_console, "%.0f %.2f %.2f %.2f\n", flVel, m_vecTarget.x, m_vecTarget.y, m_vecTarget.z );
|
||||
|
||||
pev->velocity = pev->velocity * flAdj + m_vecTarget * 300;
|
||||
}
|
||||
|
||||
if (pev->flags & FL_ONGROUND)
|
||||
{
|
||||
pev->avelocity = Vector( 0, 0, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pev->avelocity == Vector( 0, 0, 0))
|
||||
{
|
||||
pev->avelocity.x = RANDOM_FLOAT( -100, 100 );
|
||||
pev->avelocity.z = RANDOM_FLOAT( -100, 100 );
|
||||
}
|
||||
}
|
||||
|
||||
if ((pev->origin - m_posPrev).Length() < 1.0)
|
||||
{
|
||||
pev->velocity.x = RANDOM_FLOAT( -100, 100 );
|
||||
pev->velocity.y = RANDOM_FLOAT( -100, 100 );
|
||||
}
|
||||
m_posPrev = pev->origin;
|
||||
|
||||
pev->angles = UTIL_VecToAngles( pev->velocity );
|
||||
pev->angles.z = 0;
|
||||
pev->angles.x = 0;
|
||||
}
|
||||
|
||||
|
||||
void CMSqueakGrenade::SuperBounceTouch( edict_t *pOther )
|
||||
{
|
||||
float flpitch;
|
||||
|
||||
TraceResult tr = UTIL_GetGlobalTrace( );
|
||||
|
||||
// don't hit the guy that launched this grenade
|
||||
if ( pev->owner && (pOther == pev->owner) )
|
||||
return;
|
||||
|
||||
// at least until we've bounced once
|
||||
pev->owner = NULL;
|
||||
|
||||
pev->angles.x = 0;
|
||||
pev->angles.z = 0;
|
||||
|
||||
// avoid bouncing too much
|
||||
if (m_flNextHit > gpGlobals->time)
|
||||
return;
|
||||
|
||||
// higher pitch as squeeker gets closer to detonation time
|
||||
flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY);
|
||||
|
||||
if ( pOther->v.takedamage && m_flNextAttack < gpGlobals->time )
|
||||
{
|
||||
// attack!
|
||||
|
||||
// make sure it's me who has touched them
|
||||
if (tr.pHit == pOther)
|
||||
{
|
||||
// and it's not another squeakgrenade
|
||||
if (tr.pHit->v.modelindex != pev->modelindex)
|
||||
{
|
||||
// ALERT( at_console, "hit enemy\n");
|
||||
ClearMultiDamage( );
|
||||
|
||||
if (UTIL_IsPlayer(pOther))
|
||||
UTIL_TraceAttack(pOther, pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH );
|
||||
else if (pOther->v.euser4 != NULL)
|
||||
{
|
||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||
pMonster->TraceAttack(pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH );
|
||||
}
|
||||
|
||||
ApplyMultiDamage( pev, pev );
|
||||
|
||||
pev->dmg += gSkillData.snarkDmgPop; // add more explosion damage
|
||||
// m_flDie += 2.0; // add more life
|
||||
|
||||
// make bite sound
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "squeek/sqk_deploy1.wav", 1.0, ATTN_NORM, 0, (int)flpitch);
|
||||
m_flNextAttack = gpGlobals->time + 0.5;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ALERT( at_console, "been hit\n");
|
||||
}
|
||||
}
|
||||
|
||||
m_flNextHit = gpGlobals->time + 0.1;
|
||||
m_flNextHunt = gpGlobals->time;
|
||||
|
||||
// in multiplayer, we limit how often snarks can make their bounce sounds to prevent overflows.
|
||||
if ( gpGlobals->time < m_flNextBounceSoundTime )
|
||||
{
|
||||
// too soon!
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(pev->flags & FL_ONGROUND))
|
||||
{
|
||||
// play bounce sound
|
||||
float flRndSound = RANDOM_FLOAT ( 0 , 1 );
|
||||
|
||||
if ( flRndSound <= 0.33 )
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt1.wav", 1, ATTN_NORM, 0, (int)flpitch);
|
||||
else if (flRndSound <= 0.66)
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, (int)flpitch);
|
||||
else
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, (int)flpitch);
|
||||
}
|
||||
|
||||
m_flNextBounceSoundTime = gpGlobals->time + 0.5;// half second.
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD )
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "cmbasemonster.h"
|
||||
#include "monsters.h"
|
||||
#include "weapons.h"
|
||||
#include "nodes.h"
|
||||
|
||||
enum w_squeak_e {
|
||||
WSQUEAK_IDLE1 = 0,
|
||||
WSQUEAK_FIDGET,
|
||||
WSQUEAK_JUMP,
|
||||
WSQUEAK_RUN,
|
||||
};
|
||||
|
||||
enum squeak_e {
|
||||
SQUEAK_IDLE1 = 0,
|
||||
SQUEAK_FIDGETFIT,
|
||||
SQUEAK_FIDGETNIP,
|
||||
SQUEAK_DOWN,
|
||||
SQUEAK_UP,
|
||||
SQUEAK_THROW
|
||||
};
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
||||
|
||||
float CMSqueakGrenade::m_flNextBounceSoundTime = 0;
|
||||
|
||||
#define SQUEEK_DETONATE_DELAY 15.0
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void CMSqueakGrenade :: Spawn( void )
|
||||
{
|
||||
Precache( );
|
||||
// motor
|
||||
pev->movetype = MOVETYPE_BOUNCE;
|
||||
pev->solid = SOLID_BBOX;
|
||||
|
||||
SET_MODEL(ENT(pev), "models/w_squeak.mdl");
|
||||
UTIL_SetSize(pev, Vector( -4, -4, 0), Vector(4, 4, 8));
|
||||
UTIL_SetOrigin( pev, pev->origin );
|
||||
|
||||
SetTouch( &CMSqueakGrenade::SuperBounceTouch );
|
||||
SetThink( &CMSqueakGrenade::HuntThink );
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
m_flNextHunt = gpGlobals->time + 1E6;
|
||||
|
||||
pev->flags |= FL_MONSTER;
|
||||
pev->takedamage = DAMAGE_AIM;
|
||||
pev->health = gSkillData.snarkHealth;
|
||||
pev->gravity = 0.5;
|
||||
pev->friction = 0.5;
|
||||
|
||||
pev->dmg = gSkillData.snarkDmgPop;
|
||||
|
||||
m_flDie = gpGlobals->time + SQUEEK_DETONATE_DELAY;
|
||||
|
||||
m_flFieldOfView = 0; // 180 degrees
|
||||
|
||||
m_flNextBounceSoundTime = gpGlobals->time;// reset each time a snark is spawned.
|
||||
|
||||
pev->sequence = WSQUEAK_RUN;
|
||||
ResetSequenceInfo( );
|
||||
|
||||
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 )
|
||||
{
|
||||
PRECACHE_MODEL("models/w_squeak.mdl");
|
||||
PRECACHE_SOUND("squeek/sqk_blast1.wav");
|
||||
PRECACHE_SOUND("common/bodysplat.wav");
|
||||
PRECACHE_SOUND("squeek/sqk_die1.wav");
|
||||
PRECACHE_SOUND("squeek/sqk_hunt1.wav");
|
||||
PRECACHE_SOUND("squeek/sqk_hunt2.wav");
|
||||
PRECACHE_SOUND("squeek/sqk_hunt3.wav");
|
||||
PRECACHE_SOUND("squeek/sqk_deploy1.wav");
|
||||
}
|
||||
|
||||
|
||||
void CMSqueakGrenade :: Killed( entvars_t *pevAttacker, int iGib )
|
||||
{
|
||||
pev->model = iStringNull;// make invisible
|
||||
SetThink( &CMSqueakGrenade::SUB_Remove );
|
||||
SetTouch( NULL );
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
|
||||
// since squeak grenades never leave a body behind, clear out their takedamage now.
|
||||
// Squeaks do a bit of radius damage when they pop, and that radius damage will
|
||||
// continue to call this function unless we acknowledge the Squeak's death now. (sjb)
|
||||
pev->takedamage = DAMAGE_NO;
|
||||
|
||||
// play squeek blast
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "squeek/sqk_blast1.wav", 1, 0.5, 0, PITCH_NORM);
|
||||
|
||||
UTIL_BloodDrips( pev->origin, g_vecZero, BloodColor(), 80 );
|
||||
|
||||
RadiusDamage ( pev, pev, pev->dmg, CLASS_NONE, DMG_BLAST );
|
||||
|
||||
CMBaseMonster :: Killed( pevAttacker, GIB_ALWAYS );
|
||||
}
|
||||
|
||||
void CMSqueakGrenade :: GibMonster( void )
|
||||
{
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CMSqueakGrenade::HuntThink( void )
|
||||
{
|
||||
// ALERT( at_console, "think\n" );
|
||||
|
||||
if (!IsInWorld())
|
||||
{
|
||||
SetTouch( NULL );
|
||||
UTIL_Remove( this->edict() );
|
||||
return;
|
||||
}
|
||||
|
||||
StudioFrameAdvance( );
|
||||
pev->nextthink = gpGlobals->time + 0.1;
|
||||
|
||||
// explode when ready
|
||||
if (gpGlobals->time >= m_flDie)
|
||||
{
|
||||
g_vecAttackDir = pev->velocity.Normalize( );
|
||||
pev->health = -1;
|
||||
Killed( pev, 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
// float
|
||||
if (pev->waterlevel != 0)
|
||||
{
|
||||
if (pev->movetype == MOVETYPE_BOUNCE)
|
||||
{
|
||||
pev->movetype = MOVETYPE_FLY;
|
||||
}
|
||||
pev->velocity = pev->velocity * 0.9;
|
||||
pev->velocity.z += 8.0;
|
||||
}
|
||||
else if (pev->movetype = MOVETYPE_FLY)
|
||||
{
|
||||
pev->movetype = MOVETYPE_BOUNCE;
|
||||
}
|
||||
|
||||
// return if not time to hunt
|
||||
if (m_flNextHunt > gpGlobals->time)
|
||||
return;
|
||||
|
||||
m_flNextHunt = gpGlobals->time + 2.0;
|
||||
|
||||
Vector vecDir;
|
||||
TraceResult tr;
|
||||
|
||||
Vector vecFlat = pev->velocity;
|
||||
vecFlat.z = 0;
|
||||
vecFlat = vecFlat.Normalize( );
|
||||
|
||||
UTIL_MakeVectors( pev->angles );
|
||||
|
||||
if (m_hEnemy == NULL || !UTIL_IsAlive(m_hEnemy))
|
||||
{
|
||||
// find target, bounce a bit towards it.
|
||||
Look( 512 );
|
||||
m_hEnemy = BestVisibleEnemy( );
|
||||
}
|
||||
|
||||
// squeek if it's about time blow up
|
||||
if ((m_flDie - gpGlobals->time <= 0.5) && (m_flDie - gpGlobals->time >= 0.3))
|
||||
{
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_die1.wav", 1, ATTN_NORM, 0, 100 + RANDOM_LONG(0,0x3F));
|
||||
}
|
||||
|
||||
// higher pitch as squeeker gets closer to detonation time
|
||||
float flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY);
|
||||
if (flpitch < 80)
|
||||
flpitch = 80;
|
||||
|
||||
if (m_hEnemy != NULL)
|
||||
{
|
||||
if (UTIL_FVisible( m_hEnemy, ENT(pev) ))
|
||||
{
|
||||
vecDir = (m_hEnemy->v.origin + m_hEnemy->v.view_ofs) - pev->origin;
|
||||
m_vecTarget = vecDir.Normalize( );
|
||||
}
|
||||
|
||||
float flVel = pev->velocity.Length();
|
||||
float flAdj = 50.0 / (flVel + 10.0);
|
||||
|
||||
if (flAdj > 1.2)
|
||||
flAdj = 1.2;
|
||||
|
||||
// ALERT( at_console, "think : enemy\n");
|
||||
|
||||
// ALERT( at_console, "%.0f %.2f %.2f %.2f\n", flVel, m_vecTarget.x, m_vecTarget.y, m_vecTarget.z );
|
||||
|
||||
pev->velocity = pev->velocity * flAdj + m_vecTarget * 300;
|
||||
}
|
||||
|
||||
if (pev->flags & FL_ONGROUND)
|
||||
{
|
||||
pev->avelocity = Vector( 0, 0, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pev->avelocity == Vector( 0, 0, 0))
|
||||
{
|
||||
pev->avelocity.x = RANDOM_FLOAT( -100, 100 );
|
||||
pev->avelocity.z = RANDOM_FLOAT( -100, 100 );
|
||||
}
|
||||
}
|
||||
|
||||
if ((pev->origin - m_posPrev).Length() < 1.0)
|
||||
{
|
||||
pev->velocity.x = RANDOM_FLOAT( -100, 100 );
|
||||
pev->velocity.y = RANDOM_FLOAT( -100, 100 );
|
||||
}
|
||||
m_posPrev = pev->origin;
|
||||
|
||||
pev->angles = UTIL_VecToAngles( pev->velocity );
|
||||
pev->angles.z = 0;
|
||||
pev->angles.x = 0;
|
||||
}
|
||||
|
||||
|
||||
void CMSqueakGrenade::SuperBounceTouch( edict_t *pOther )
|
||||
{
|
||||
float flpitch;
|
||||
|
||||
TraceResult tr = UTIL_GetGlobalTrace( );
|
||||
|
||||
// don't hit the guy that launched this grenade
|
||||
if ( pev->owner && (pOther == pev->owner) )
|
||||
return;
|
||||
|
||||
// at least until we've bounced once
|
||||
pev->owner = NULL;
|
||||
|
||||
pev->angles.x = 0;
|
||||
pev->angles.z = 0;
|
||||
|
||||
// avoid bouncing too much
|
||||
if (m_flNextHit > gpGlobals->time)
|
||||
return;
|
||||
|
||||
// higher pitch as squeeker gets closer to detonation time
|
||||
flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY);
|
||||
|
||||
if ( pOther->v.takedamage && m_flNextAttack < gpGlobals->time )
|
||||
{
|
||||
// attack!
|
||||
|
||||
// make sure it's me who has touched them
|
||||
if (tr.pHit == pOther)
|
||||
{
|
||||
// and it's not another squeakgrenade
|
||||
if (tr.pHit->v.modelindex != pev->modelindex)
|
||||
{
|
||||
// ALERT( at_console, "hit enemy\n");
|
||||
ClearMultiDamage( );
|
||||
|
||||
if (UTIL_IsPlayer(pOther))
|
||||
UTIL_TraceAttack(pOther, pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH );
|
||||
else if (pOther->v.euser4 != NULL)
|
||||
{
|
||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||
pMonster->TraceAttack(pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH );
|
||||
}
|
||||
|
||||
ApplyMultiDamage( pev, pev );
|
||||
|
||||
pev->dmg += gSkillData.snarkDmgPop; // add more explosion damage
|
||||
// m_flDie += 2.0; // add more life
|
||||
|
||||
// make bite sound
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "squeek/sqk_deploy1.wav", 1.0, ATTN_NORM, 0, (int)flpitch);
|
||||
m_flNextAttack = gpGlobals->time + 0.5;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ALERT( at_console, "been hit\n");
|
||||
}
|
||||
}
|
||||
|
||||
m_flNextHit = gpGlobals->time + 0.1;
|
||||
m_flNextHunt = gpGlobals->time;
|
||||
|
||||
// in multiplayer, we limit how often snarks can make their bounce sounds to prevent overflows.
|
||||
if ( gpGlobals->time < m_flNextBounceSoundTime )
|
||||
{
|
||||
// too soon!
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(pev->flags & FL_ONGROUND))
|
||||
{
|
||||
// play bounce sound
|
||||
float flRndSound = RANDOM_FLOAT ( 0 , 1 );
|
||||
|
||||
if ( flRndSound <= 0.33 )
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt1.wav", 1, ATTN_NORM, 0, (int)flpitch);
|
||||
else if (flRndSound <= 0.66)
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, (int)flpitch);
|
||||
else
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, (int)flpitch);
|
||||
}
|
||||
|
||||
m_flNextBounceSoundTime = gpGlobals->time + 0.5;// half second.
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
899
src/dlls/strooper.cpp
Normal file
899
src/dlls/strooper.cpp
Normal file
@@ -0,0 +1,899 @@
|
||||
// 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);
|
||||
|
||||
//CBaseEntity *pShock = CBaseEntity::Create("shock_beam", vecShootOrigin, vecGunAngles, edict());
|
||||
CMShock *pShock = CreateClassPtr((CMShock *)NULL);
|
||||
|
||||
if (pShock != NULL)
|
||||
{
|
||||
pShock->pev->origin = vecShootOrigin;
|
||||
|
||||
vecGunAngles.z += RANDOM_FLOAT( -0.05, 0 );
|
||||
pShock->pev->angles = UTIL_VecToAngles( vecGunAngles );
|
||||
pShock->pev->owner = edict();
|
||||
|
||||
// Initialize these for entities who don't link to the world
|
||||
pShock->pev->absmin = pShock->pev->origin - Vector(1,1,1);
|
||||
pShock->pev->absmax = pShock->pev->origin + Vector(1,1,1);
|
||||
|
||||
pShock->Spawn();
|
||||
|
||||
pShock->pev->velocity = vecShootDir * 2000;
|
||||
pShock->pev->nextthink = gpGlobals->time;
|
||||
}
|
||||
|
||||
m_cAmmoLoaded--;
|
||||
SetBlending( 0, vecGunAngles.x );
|
||||
|
||||
// Play fire sound.
|
||||
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/shock_fire.wav", 1, ATTN_NORM);
|
||||
}
|
||||
}
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
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 = BLOOD_COLOR_GREEN;
|
||||
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_MODEL(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_MODEL("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)
|
||||
{
|
||||
roach->pev->origin = vecPos;
|
||||
roach->pev->angles = UTIL_VecToAngles( vecDropAngles );
|
||||
|
||||
// Initialize these for entities who don't link to the world
|
||||
roach->pev->absmin = roach->pev->origin - Vector(1,1,1);
|
||||
roach->pev->absmax = roach->pev->origin + Vector(1,1,1);
|
||||
|
||||
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))
|
||||
{
|
||||
//!!!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), "HG_COVER", HGRUNT_SENTENCE_VOLUME, GRUNT_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
|
||||
{
|
||||
// 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
|
||||
{
|
||||
//!!!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;
|
||||
}
|
||||
}
|
||||
259
src/dlls/stukabat.cpp
Normal file
259
src/dlls/stukabat.cpp
Normal file
@@ -0,0 +1,259 @@
|
||||
/***
|
||||
*
|
||||
* 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 = BLOOD_COLOR_YELLOW;
|
||||
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 = "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 */
|
||||
Task_t tlStukabatChaseEnemy[] =
|
||||
{
|
||||
{ TASK_GET_PATH_TO_ENEMY, (float)128 }, // is the 128 number really used?
|
||||
{ TASK_SET_ACTIVITY, (float)ACT_FLY },
|
||||
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
|
||||
|
||||
};
|
||||
Schedule_t slStukabatChaseEnemy[] =
|
||||
{
|
||||
{
|
||||
tlStukabatChaseEnemy,
|
||||
ARRAYSIZE ( tlStukabatChaseEnemy ),
|
||||
bits_COND_NEW_ENEMY |
|
||||
bits_COND_TASK_FAILED,
|
||||
0,
|
||||
"StukabatChaseEnemy"
|
||||
},
|
||||
};
|
||||
|
||||
/* Fail */
|
||||
Task_t tlStukabatFail[] =
|
||||
{
|
||||
{ TASK_STOP_MOVING, 0 },
|
||||
{ TASK_SET_ACTIVITY, (float)ACT_HOVER },
|
||||
{ TASK_WAIT, (float)2 },
|
||||
{ TASK_WAIT_PVS, (float)0 },
|
||||
};
|
||||
Schedule_t slStukabatFail[] =
|
||||
{
|
||||
{
|
||||
tlStukabatFail,
|
||||
ARRAYSIZE ( tlStukabatFail ),
|
||||
0,
|
||||
0,
|
||||
"StukabatFail"
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
DEFINE_CUSTOM_SCHEDULES( CMStukabat )
|
||||
{
|
||||
slStukabatChaseEnemy,
|
||||
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_FLY:
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=========================================================
|
||||
// GetScheduleOfType
|
||||
//=========================================================
|
||||
Schedule_t* CMStukabat :: GetScheduleOfType ( int Type )
|
||||
{
|
||||
switch ( Type )
|
||||
{
|
||||
case SCHED_CHASE_ENEMY:
|
||||
return slStukabatChaseEnemy;
|
||||
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;
|
||||
}
|
||||
@@ -1,470 +1,470 @@
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
/*
|
||||
|
||||
===== subs.cpp ========================================================
|
||||
|
||||
frequently used global functions
|
||||
|
||||
*/
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "nodes.h"
|
||||
#include "doors.h"
|
||||
|
||||
extern CGraph WorldGraph;
|
||||
|
||||
extern BOOL FEntIsVisible(entvars_t* pev, entvars_t* pevTarget);
|
||||
|
||||
void Remove_Entity(edict_t *pEdict);
|
||||
|
||||
|
||||
// Landmark class
|
||||
void CMPointEntity :: Spawn( void )
|
||||
{
|
||||
pev->solid = SOLID_NOT;
|
||||
// UTIL_SetSize(pev, g_vecZero, g_vecZero);
|
||||
}
|
||||
|
||||
|
||||
// This updates global tables that need to know about entities being removed
|
||||
void CMBaseEntity::UpdateOnRemove( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( FBitSet( pev->flags, FL_GRAPHED ) )
|
||||
{
|
||||
// this entity was a LinkEnt in the world node graph, so we must remove it from
|
||||
// the graph since we are removing it from the world.
|
||||
for ( i = 0 ; i < WorldGraph.m_cLinks ; i++ )
|
||||
{
|
||||
if ( WorldGraph.m_pLinkPool [ i ].m_pLinkEnt == pev )
|
||||
{
|
||||
// if this link has a link ent which is the same ent that is removing itself, remove it!
|
||||
WorldGraph.m_pLinkPool [ i ].m_pLinkEnt = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
//jlb if ( pev->globalname )
|
||||
//jlb gGlobalState.EntitySetState( pev->globalname, GLOBAL_DEAD );
|
||||
}
|
||||
|
||||
// Convenient way to delay removing oneself
|
||||
void CMBaseEntity :: SUB_Remove( void )
|
||||
{
|
||||
UpdateOnRemove();
|
||||
if (pev->health > 0)
|
||||
{
|
||||
// this situation can screw up monsters who can't tell their entity pointers are invalid.
|
||||
pev->health = 0;
|
||||
ALERT( at_aiconsole, "SUB_Remove called on entity with health > 0\n");
|
||||
}
|
||||
|
||||
// REMOVE_ENTITY(ENT(pev));
|
||||
Remove_Entity(ENT(pev));
|
||||
}
|
||||
|
||||
|
||||
// Convenient way to explicitly do nothing (passed to functions that require a method)
|
||||
void CMBaseEntity :: SUB_DoNothing( void )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CMBaseDelay :: KeyValue( KeyValueData *pkvd )
|
||||
{
|
||||
if (FStrEq(pkvd->szKeyName, "delay"))
|
||||
{
|
||||
m_flDelay = atof( pkvd->szValue );
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "killtarget"))
|
||||
{
|
||||
m_iszKillTarget = ALLOC_STRING(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
CMBaseEntity::KeyValue( pkvd );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============================
|
||||
SUB_UseTargets
|
||||
|
||||
If self.delay is set, a DelayedUse entity will be created that will actually
|
||||
do the SUB_UseTargets after that many seconds have passed.
|
||||
|
||||
Removes all entities with a targetname that match self.killtarget,
|
||||
and removes them, so some events can remove other triggers.
|
||||
|
||||
Search for (string)targetname in all entities that
|
||||
match (string)self.target and call their .use function (if they have one)
|
||||
|
||||
==============================
|
||||
*/
|
||||
void CMBaseEntity :: SUB_UseTargets( edict_t *pActivator, USE_TYPE useType, float value )
|
||||
{
|
||||
//
|
||||
// fire targets
|
||||
//
|
||||
if (!FStringNull(pev->target))
|
||||
{
|
||||
FireTargets( STRING(pev->target), pActivator, this->edict(), useType, value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FireTargets( const char *targetName, edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
edict_t *pentTarget = NULL;
|
||||
if ( !targetName )
|
||||
return;
|
||||
|
||||
ALERT( at_aiconsole, "Firing: (%s)\n", targetName );
|
||||
|
||||
for (;;)
|
||||
{
|
||||
pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, targetName);
|
||||
if (FNullEnt(pentTarget))
|
||||
break;
|
||||
|
||||
CMBaseEntity *pTarget = CMBaseEntity::Instance( pentTarget );
|
||||
if ( pTarget && !(pTarget->pev->flags & FL_KILLME) ) // Don't use dying ents
|
||||
{
|
||||
ALERT( at_aiconsole, "Found: %s, firing (%s)\n", STRING(pTarget->pev->classname), targetName );
|
||||
pTarget->Use( pActivator, pCaller, useType, value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CMBaseDelay :: SUB_UseTargets( edict_t *pActivator, USE_TYPE useType, float value )
|
||||
{
|
||||
//
|
||||
// exit immediatly if we don't have a target or kill target
|
||||
//
|
||||
if (FStringNull(pev->target) && !m_iszKillTarget)
|
||||
return;
|
||||
|
||||
//
|
||||
// check for a delay
|
||||
//
|
||||
if (m_flDelay != 0)
|
||||
{
|
||||
// create a temp object to fire at a later time
|
||||
CMBaseDelay *pTemp = CreateClassPtr( (CMBaseDelay *)NULL);
|
||||
|
||||
if (pTemp == NULL)
|
||||
return;
|
||||
|
||||
pTemp->pev->classname = MAKE_STRING("DelayedUse");
|
||||
|
||||
pTemp->pev->nextthink = gpGlobals->time + m_flDelay;
|
||||
|
||||
pTemp->SetThink( &CMBaseDelay::DelayThink );
|
||||
|
||||
// Save the useType
|
||||
pTemp->pev->button = (int)useType;
|
||||
pTemp->m_iszKillTarget = m_iszKillTarget;
|
||||
pTemp->m_flDelay = 0; // prevent "recursion"
|
||||
pTemp->pev->target = pev->target;
|
||||
|
||||
// HACKHACK
|
||||
// This wasn't in the release build of Half-Life. We should have moved m_hActivator into this class
|
||||
// but changing member variable hierarchy would break save/restore without some ugly code.
|
||||
// This code is not as ugly as that code
|
||||
if ( pActivator && UTIL_IsPlayer(pActivator) ) // If a player activates, then save it
|
||||
{
|
||||
pTemp->pev->owner = pActivator;
|
||||
}
|
||||
else
|
||||
{
|
||||
pTemp->pev->owner = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// kill the killtargets
|
||||
//
|
||||
|
||||
if ( m_iszKillTarget )
|
||||
{
|
||||
edict_t *pentKillTarget = NULL;
|
||||
|
||||
ALERT( at_aiconsole, "KillTarget: %s\n", STRING(m_iszKillTarget) );
|
||||
pentKillTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_iszKillTarget) );
|
||||
while ( !FNullEnt(pentKillTarget) )
|
||||
{
|
||||
UTIL_Remove( CMBaseEntity::Instance(pentKillTarget)->edict() );
|
||||
|
||||
ALERT( at_aiconsole, "killing %s\n", STRING( pentKillTarget->v.classname ) );
|
||||
pentKillTarget = FIND_ENTITY_BY_TARGETNAME( pentKillTarget, STRING(m_iszKillTarget) );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// fire targets
|
||||
//
|
||||
if (!FStringNull(pev->target))
|
||||
{
|
||||
FireTargets( STRING(pev->target), pActivator, this->edict(), useType, value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
QuakeEd only writes a single float for angles (bad idea), so up and down are
|
||||
just constant angles.
|
||||
*/
|
||||
void SetMovedir( entvars_t *pev )
|
||||
{
|
||||
if (pev->angles == Vector(0, -1, 0))
|
||||
{
|
||||
pev->movedir = Vector(0, 0, 1);
|
||||
}
|
||||
else if (pev->angles == Vector(0, -2, 0))
|
||||
{
|
||||
pev->movedir = Vector(0, 0, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_MakeVectors(pev->angles);
|
||||
pev->movedir = gpGlobals->v_forward;
|
||||
}
|
||||
|
||||
pev->angles = g_vecZero;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CMBaseDelay::DelayThink( void )
|
||||
{
|
||||
edict_t *pActivator = NULL;
|
||||
|
||||
if ( pev->owner != NULL ) // A player activated this on delay
|
||||
{
|
||||
pActivator = ENT(pev->owner);
|
||||
}
|
||||
// The use type is cached (and stashed) in pev->button
|
||||
SUB_UseTargets( pActivator, (USE_TYPE)pev->button, 0 );
|
||||
// REMOVE_ENTITY(ENT(pev));
|
||||
Remove_Entity(ENT(pev));
|
||||
}
|
||||
|
||||
|
||||
void CMBaseToggle::KeyValue( KeyValueData *pkvd )
|
||||
{
|
||||
if (FStrEq(pkvd->szKeyName, "lip"))
|
||||
{
|
||||
m_flLip = atof(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "wait"))
|
||||
{
|
||||
m_flWait = atof(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "master"))
|
||||
{
|
||||
m_sMaster = ALLOC_STRING(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "distance"))
|
||||
{
|
||||
m_flMoveDistance = atof(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else
|
||||
CMBaseDelay::KeyValue( pkvd );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
LinearMove
|
||||
|
||||
calculate pev->velocity and pev->nextthink to reach vecDest from
|
||||
pev->origin traveling at flSpeed
|
||||
===============
|
||||
*/
|
||||
void CMBaseToggle :: LinearMove( Vector vecDest, float flSpeed )
|
||||
{
|
||||
ASSERTSZ(flSpeed != 0, "LinearMove: no speed is defined!");
|
||||
// ASSERTSZ(m_pfnCallWhenMoveDone != NULL, "LinearMove: no post-move function defined");
|
||||
|
||||
m_vecFinalDest = vecDest;
|
||||
|
||||
// Already there?
|
||||
if (vecDest == pev->origin)
|
||||
{
|
||||
LinearMoveDone();
|
||||
return;
|
||||
}
|
||||
|
||||
// set destdelta to the vector needed to move
|
||||
Vector vecDestDelta = vecDest - pev->origin;
|
||||
|
||||
// divide vector length by speed to get time to reach dest
|
||||
float flTravelTime = vecDestDelta.Length() / flSpeed;
|
||||
|
||||
// set nextthink to trigger a call to LinearMoveDone when dest is reached
|
||||
pev->nextthink = pev->ltime + flTravelTime;
|
||||
SetThink( &CMBaseToggle::LinearMoveDone );
|
||||
|
||||
// scale the destdelta vector by the time spent traveling to get velocity
|
||||
pev->velocity = vecDestDelta / flTravelTime;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
After moving, set origin to exact final destination, call "move done" function
|
||||
============
|
||||
*/
|
||||
void CMBaseToggle :: LinearMoveDone( void )
|
||||
{
|
||||
UTIL_SetOrigin(pev, m_vecFinalDest);
|
||||
pev->velocity = g_vecZero;
|
||||
pev->nextthink = -1;
|
||||
if ( m_pfnCallWhenMoveDone )
|
||||
(this->*m_pfnCallWhenMoveDone)();
|
||||
}
|
||||
|
||||
BOOL CMBaseToggle :: IsLockedByMaster( void )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
AngularMove
|
||||
|
||||
calculate pev->velocity and pev->nextthink to reach vecDest from
|
||||
pev->origin traveling at flSpeed
|
||||
Just like LinearMove, but rotational.
|
||||
===============
|
||||
*/
|
||||
void CMBaseToggle :: AngularMove( Vector vecDestAngle, float flSpeed )
|
||||
{
|
||||
ASSERTSZ(flSpeed != 0, "AngularMove: no speed is defined!");
|
||||
// ASSERTSZ(m_pfnCallWhenMoveDone != NULL, "AngularMove: no post-move function defined");
|
||||
|
||||
m_vecFinalAngle = vecDestAngle;
|
||||
|
||||
// Already there?
|
||||
if (vecDestAngle == pev->angles)
|
||||
{
|
||||
AngularMoveDone();
|
||||
return;
|
||||
}
|
||||
|
||||
// set destdelta to the vector needed to move
|
||||
Vector vecDestDelta = vecDestAngle - pev->angles;
|
||||
|
||||
// divide by speed to get time to reach dest
|
||||
float flTravelTime = vecDestDelta.Length() / flSpeed;
|
||||
|
||||
// set nextthink to trigger a call to AngularMoveDone when dest is reached
|
||||
pev->nextthink = pev->ltime + flTravelTime;
|
||||
SetThink( &CMBaseToggle::AngularMoveDone );
|
||||
|
||||
// scale the destdelta vector by the time spent traveling to get velocity
|
||||
pev->avelocity = vecDestDelta / flTravelTime;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
After rotating, set angle to exact final angle, call "move done" function
|
||||
============
|
||||
*/
|
||||
void CMBaseToggle :: AngularMoveDone( void )
|
||||
{
|
||||
pev->angles = m_vecFinalAngle;
|
||||
pev->avelocity = g_vecZero;
|
||||
pev->nextthink = -1;
|
||||
if ( m_pfnCallWhenMoveDone )
|
||||
(this->*m_pfnCallWhenMoveDone)();
|
||||
}
|
||||
|
||||
|
||||
float CMBaseToggle :: AxisValue( int flags, const Vector &angles )
|
||||
{
|
||||
if ( FBitSet(flags, SF_DOOR_ROTATE_Z) )
|
||||
return angles.z;
|
||||
if ( FBitSet(flags, SF_DOOR_ROTATE_X) )
|
||||
return angles.x;
|
||||
|
||||
return angles.y;
|
||||
}
|
||||
|
||||
|
||||
void CMBaseToggle :: AxisDir( entvars_t *pev )
|
||||
{
|
||||
if ( FBitSet(pev->spawnflags, SF_DOOR_ROTATE_Z) )
|
||||
pev->movedir = Vector ( 0, 0, 1 ); // around z-axis
|
||||
else if ( FBitSet(pev->spawnflags, SF_DOOR_ROTATE_X) )
|
||||
pev->movedir = Vector ( 1, 0, 0 ); // around x-axis
|
||||
else
|
||||
pev->movedir = Vector ( 0, 1, 0 ); // around y-axis
|
||||
}
|
||||
|
||||
|
||||
float CMBaseToggle :: AxisDelta( int flags, const Vector &angle1, const Vector &angle2 )
|
||||
{
|
||||
if ( FBitSet (flags, SF_DOOR_ROTATE_Z) )
|
||||
return angle1.z - angle2.z;
|
||||
|
||||
if ( FBitSet (flags, SF_DOOR_ROTATE_X) )
|
||||
return angle1.x - angle2.x;
|
||||
|
||||
return angle1.y - angle2.y;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
FEntIsVisible
|
||||
|
||||
returns TRUE if the passed entity is visible to caller, even if not infront ()
|
||||
=============
|
||||
*/
|
||||
BOOL
|
||||
FEntIsVisible(
|
||||
entvars_t* pev,
|
||||
entvars_t* pevTarget)
|
||||
{
|
||||
Vector vecSpot1 = pev->origin + pev->view_ofs;
|
||||
Vector vecSpot2 = pevTarget->origin + pevTarget->view_ofs;
|
||||
TraceResult tr;
|
||||
|
||||
UTIL_TraceLine(vecSpot1, vecSpot2, ignore_monsters, ENT(pev), &tr);
|
||||
|
||||
if (tr.fInOpen && tr.fInWater)
|
||||
return FALSE; // sight line crossed contents
|
||||
|
||||
if (tr.flFraction == 1)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****/
|
||||
/*
|
||||
|
||||
===== subs.cpp ========================================================
|
||||
|
||||
frequently used global functions
|
||||
|
||||
*/
|
||||
|
||||
#include "extdll.h"
|
||||
#include "util.h"
|
||||
#include "cmbase.h"
|
||||
#include "nodes.h"
|
||||
#include "doors.h"
|
||||
|
||||
extern CGraph WorldGraph;
|
||||
|
||||
extern BOOL FEntIsVisible(entvars_t* pev, entvars_t* pevTarget);
|
||||
|
||||
void Remove_Entity(edict_t *pEdict);
|
||||
|
||||
|
||||
// Landmark class
|
||||
void CMPointEntity :: Spawn( void )
|
||||
{
|
||||
pev->solid = SOLID_NOT;
|
||||
// UTIL_SetSize(pev, g_vecZero, g_vecZero);
|
||||
}
|
||||
|
||||
|
||||
// This updates global tables that need to know about entities being removed
|
||||
void CMBaseEntity::UpdateOnRemove( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( FBitSet( pev->flags, FL_GRAPHED ) )
|
||||
{
|
||||
// this entity was a LinkEnt in the world node graph, so we must remove it from
|
||||
// the graph since we are removing it from the world.
|
||||
for ( i = 0 ; i < WorldGraph.m_cLinks ; i++ )
|
||||
{
|
||||
if ( WorldGraph.m_pLinkPool [ i ].m_pLinkEnt == pev )
|
||||
{
|
||||
// if this link has a link ent which is the same ent that is removing itself, remove it!
|
||||
WorldGraph.m_pLinkPool [ i ].m_pLinkEnt = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
//jlb if ( pev->globalname )
|
||||
//jlb gGlobalState.EntitySetState( pev->globalname, GLOBAL_DEAD );
|
||||
}
|
||||
|
||||
// Convenient way to delay removing oneself
|
||||
void CMBaseEntity :: SUB_Remove( void )
|
||||
{
|
||||
UpdateOnRemove();
|
||||
if (pev->health > 0)
|
||||
{
|
||||
// this situation can screw up monsters who can't tell their entity pointers are invalid.
|
||||
pev->health = 0;
|
||||
ALERT( at_aiconsole, "SUB_Remove called on entity with health > 0\n");
|
||||
}
|
||||
|
||||
// REMOVE_ENTITY(ENT(pev));
|
||||
Remove_Entity(ENT(pev));
|
||||
}
|
||||
|
||||
|
||||
// Convenient way to explicitly do nothing (passed to functions that require a method)
|
||||
void CMBaseEntity :: SUB_DoNothing( void )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CMBaseDelay :: KeyValue( KeyValueData *pkvd )
|
||||
{
|
||||
if (FStrEq(pkvd->szKeyName, "delay"))
|
||||
{
|
||||
m_flDelay = atof( pkvd->szValue );
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "killtarget"))
|
||||
{
|
||||
m_iszKillTarget = ALLOC_STRING(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
CMBaseEntity::KeyValue( pkvd );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============================
|
||||
SUB_UseTargets
|
||||
|
||||
If self.delay is set, a DelayedUse entity will be created that will actually
|
||||
do the SUB_UseTargets after that many seconds have passed.
|
||||
|
||||
Removes all entities with a targetname that match self.killtarget,
|
||||
and removes them, so some events can remove other triggers.
|
||||
|
||||
Search for (string)targetname in all entities that
|
||||
match (string)self.target and call their .use function (if they have one)
|
||||
|
||||
==============================
|
||||
*/
|
||||
void CMBaseEntity :: SUB_UseTargets( edict_t *pActivator, USE_TYPE useType, float value )
|
||||
{
|
||||
//
|
||||
// fire targets
|
||||
//
|
||||
if (!FStringNull(pev->target))
|
||||
{
|
||||
FireTargets( STRING(pev->target), pActivator, this->edict(), useType, value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FireTargets( const char *targetName, edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
edict_t *pentTarget = NULL;
|
||||
if ( !targetName )
|
||||
return;
|
||||
|
||||
ALERT( at_aiconsole, "Firing: (%s)\n", targetName );
|
||||
|
||||
for (;;)
|
||||
{
|
||||
pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, targetName);
|
||||
if (FNullEnt(pentTarget))
|
||||
break;
|
||||
|
||||
CMBaseEntity *pTarget = CMBaseEntity::Instance( pentTarget );
|
||||
if ( pTarget && !(pTarget->pev->flags & FL_KILLME) ) // Don't use dying ents
|
||||
{
|
||||
ALERT( at_aiconsole, "Found: %s, firing (%s)\n", STRING(pTarget->pev->classname), targetName );
|
||||
pTarget->Use( pActivator, pCaller, useType, value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CMBaseDelay :: SUB_UseTargets( edict_t *pActivator, USE_TYPE useType, float value )
|
||||
{
|
||||
//
|
||||
// exit immediatly if we don't have a target or kill target
|
||||
//
|
||||
if (FStringNull(pev->target) && !m_iszKillTarget)
|
||||
return;
|
||||
|
||||
//
|
||||
// check for a delay
|
||||
//
|
||||
if (m_flDelay != 0)
|
||||
{
|
||||
// create a temp object to fire at a later time
|
||||
CMBaseDelay *pTemp = CreateClassPtr( (CMBaseDelay *)NULL);
|
||||
|
||||
if (pTemp == NULL)
|
||||
return;
|
||||
|
||||
pTemp->pev->classname = MAKE_STRING("DelayedUse");
|
||||
|
||||
pTemp->pev->nextthink = gpGlobals->time + m_flDelay;
|
||||
|
||||
pTemp->SetThink( &CMBaseDelay::DelayThink );
|
||||
|
||||
// Save the useType
|
||||
pTemp->pev->button = (int)useType;
|
||||
pTemp->m_iszKillTarget = m_iszKillTarget;
|
||||
pTemp->m_flDelay = 0; // prevent "recursion"
|
||||
pTemp->pev->target = pev->target;
|
||||
|
||||
// HACKHACK
|
||||
// This wasn't in the release build of Half-Life. We should have moved m_hActivator into this class
|
||||
// but changing member variable hierarchy would break save/restore without some ugly code.
|
||||
// This code is not as ugly as that code
|
||||
if ( pActivator && UTIL_IsPlayer(pActivator) ) // If a player activates, then save it
|
||||
{
|
||||
pTemp->pev->owner = pActivator;
|
||||
}
|
||||
else
|
||||
{
|
||||
pTemp->pev->owner = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// kill the killtargets
|
||||
//
|
||||
|
||||
if ( m_iszKillTarget )
|
||||
{
|
||||
edict_t *pentKillTarget = NULL;
|
||||
|
||||
ALERT( at_aiconsole, "KillTarget: %s\n", STRING(m_iszKillTarget) );
|
||||
pentKillTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_iszKillTarget) );
|
||||
while ( !FNullEnt(pentKillTarget) )
|
||||
{
|
||||
UTIL_Remove( CMBaseEntity::Instance(pentKillTarget)->edict() );
|
||||
|
||||
ALERT( at_aiconsole, "killing %s\n", STRING( pentKillTarget->v.classname ) );
|
||||
pentKillTarget = FIND_ENTITY_BY_TARGETNAME( pentKillTarget, STRING(m_iszKillTarget) );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// fire targets
|
||||
//
|
||||
if (!FStringNull(pev->target))
|
||||
{
|
||||
FireTargets( STRING(pev->target), pActivator, this->edict(), useType, value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
QuakeEd only writes a single float for angles (bad idea), so up and down are
|
||||
just constant angles.
|
||||
*/
|
||||
void SetMovedir( entvars_t *pev )
|
||||
{
|
||||
if (pev->angles == Vector(0, -1, 0))
|
||||
{
|
||||
pev->movedir = Vector(0, 0, 1);
|
||||
}
|
||||
else if (pev->angles == Vector(0, -2, 0))
|
||||
{
|
||||
pev->movedir = Vector(0, 0, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_MakeVectors(pev->angles);
|
||||
pev->movedir = gpGlobals->v_forward;
|
||||
}
|
||||
|
||||
pev->angles = g_vecZero;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CMBaseDelay::DelayThink( void )
|
||||
{
|
||||
edict_t *pActivator = NULL;
|
||||
|
||||
if ( pev->owner != NULL ) // A player activated this on delay
|
||||
{
|
||||
pActivator = ENT(pev->owner);
|
||||
}
|
||||
// The use type is cached (and stashed) in pev->button
|
||||
SUB_UseTargets( pActivator, (USE_TYPE)pev->button, 0 );
|
||||
// REMOVE_ENTITY(ENT(pev));
|
||||
Remove_Entity(ENT(pev));
|
||||
}
|
||||
|
||||
|
||||
void CMBaseToggle::KeyValue( KeyValueData *pkvd )
|
||||
{
|
||||
if (FStrEq(pkvd->szKeyName, "lip"))
|
||||
{
|
||||
m_flLip = atof(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "wait"))
|
||||
{
|
||||
m_flWait = atof(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "master"))
|
||||
{
|
||||
m_sMaster = ALLOC_STRING(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "distance"))
|
||||
{
|
||||
m_flMoveDistance = atof(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else
|
||||
CMBaseDelay::KeyValue( pkvd );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
LinearMove
|
||||
|
||||
calculate pev->velocity and pev->nextthink to reach vecDest from
|
||||
pev->origin traveling at flSpeed
|
||||
===============
|
||||
*/
|
||||
void CMBaseToggle :: LinearMove( Vector vecDest, float flSpeed )
|
||||
{
|
||||
ASSERTSZ(flSpeed != 0, "LinearMove: no speed is defined!");
|
||||
// ASSERTSZ(m_pfnCallWhenMoveDone != NULL, "LinearMove: no post-move function defined");
|
||||
|
||||
m_vecFinalDest = vecDest;
|
||||
|
||||
// Already there?
|
||||
if (vecDest == pev->origin)
|
||||
{
|
||||
LinearMoveDone();
|
||||
return;
|
||||
}
|
||||
|
||||
// set destdelta to the vector needed to move
|
||||
Vector vecDestDelta = vecDest - pev->origin;
|
||||
|
||||
// divide vector length by speed to get time to reach dest
|
||||
float flTravelTime = vecDestDelta.Length() / flSpeed;
|
||||
|
||||
// set nextthink to trigger a call to LinearMoveDone when dest is reached
|
||||
pev->nextthink = pev->ltime + flTravelTime;
|
||||
SetThink( &CMBaseToggle::LinearMoveDone );
|
||||
|
||||
// scale the destdelta vector by the time spent traveling to get velocity
|
||||
pev->velocity = vecDestDelta / flTravelTime;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
After moving, set origin to exact final destination, call "move done" function
|
||||
============
|
||||
*/
|
||||
void CMBaseToggle :: LinearMoveDone( void )
|
||||
{
|
||||
UTIL_SetOrigin(pev, m_vecFinalDest);
|
||||
pev->velocity = g_vecZero;
|
||||
pev->nextthink = -1;
|
||||
if ( m_pfnCallWhenMoveDone )
|
||||
(this->*m_pfnCallWhenMoveDone)();
|
||||
}
|
||||
|
||||
BOOL CMBaseToggle :: IsLockedByMaster( void )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
AngularMove
|
||||
|
||||
calculate pev->velocity and pev->nextthink to reach vecDest from
|
||||
pev->origin traveling at flSpeed
|
||||
Just like LinearMove, but rotational.
|
||||
===============
|
||||
*/
|
||||
void CMBaseToggle :: AngularMove( Vector vecDestAngle, float flSpeed )
|
||||
{
|
||||
ASSERTSZ(flSpeed != 0, "AngularMove: no speed is defined!");
|
||||
// ASSERTSZ(m_pfnCallWhenMoveDone != NULL, "AngularMove: no post-move function defined");
|
||||
|
||||
m_vecFinalAngle = vecDestAngle;
|
||||
|
||||
// Already there?
|
||||
if (vecDestAngle == pev->angles)
|
||||
{
|
||||
AngularMoveDone();
|
||||
return;
|
||||
}
|
||||
|
||||
// set destdelta to the vector needed to move
|
||||
Vector vecDestDelta = vecDestAngle - pev->angles;
|
||||
|
||||
// divide by speed to get time to reach dest
|
||||
float flTravelTime = vecDestDelta.Length() / flSpeed;
|
||||
|
||||
// set nextthink to trigger a call to AngularMoveDone when dest is reached
|
||||
pev->nextthink = pev->ltime + flTravelTime;
|
||||
SetThink( &CMBaseToggle::AngularMoveDone );
|
||||
|
||||
// scale the destdelta vector by the time spent traveling to get velocity
|
||||
pev->avelocity = vecDestDelta / flTravelTime;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
After rotating, set angle to exact final angle, call "move done" function
|
||||
============
|
||||
*/
|
||||
void CMBaseToggle :: AngularMoveDone( void )
|
||||
{
|
||||
pev->angles = m_vecFinalAngle;
|
||||
pev->avelocity = g_vecZero;
|
||||
pev->nextthink = -1;
|
||||
if ( m_pfnCallWhenMoveDone )
|
||||
(this->*m_pfnCallWhenMoveDone)();
|
||||
}
|
||||
|
||||
|
||||
float CMBaseToggle :: AxisValue( int flags, const Vector &angles )
|
||||
{
|
||||
if ( FBitSet(flags, SF_DOOR_ROTATE_Z) )
|
||||
return angles.z;
|
||||
if ( FBitSet(flags, SF_DOOR_ROTATE_X) )
|
||||
return angles.x;
|
||||
|
||||
return angles.y;
|
||||
}
|
||||
|
||||
|
||||
void CMBaseToggle :: AxisDir( entvars_t *pev )
|
||||
{
|
||||
if ( FBitSet(pev->spawnflags, SF_DOOR_ROTATE_Z) )
|
||||
pev->movedir = Vector ( 0, 0, 1 ); // around z-axis
|
||||
else if ( FBitSet(pev->spawnflags, SF_DOOR_ROTATE_X) )
|
||||
pev->movedir = Vector ( 1, 0, 0 ); // around x-axis
|
||||
else
|
||||
pev->movedir = Vector ( 0, 1, 0 ); // around y-axis
|
||||
}
|
||||
|
||||
|
||||
float CMBaseToggle :: AxisDelta( int flags, const Vector &angle1, const Vector &angle2 )
|
||||
{
|
||||
if ( FBitSet (flags, SF_DOOR_ROTATE_Z) )
|
||||
return angle1.z - angle2.z;
|
||||
|
||||
if ( FBitSet (flags, SF_DOOR_ROTATE_X) )
|
||||
return angle1.x - angle2.x;
|
||||
|
||||
return angle1.y - angle2.y;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
FEntIsVisible
|
||||
|
||||
returns TRUE if the passed entity is visible to caller, even if not infront ()
|
||||
=============
|
||||
*/
|
||||
BOOL
|
||||
FEntIsVisible(
|
||||
entvars_t* pev,
|
||||
entvars_t* pevTarget)
|
||||
{
|
||||
Vector vecSpot1 = pev->origin + pev->view_ofs;
|
||||
Vector vecSpot2 = pevTarget->origin + pevTarget->view_ofs;
|
||||
TraceResult tr;
|
||||
|
||||
UTIL_TraceLine(vecSpot1, vecSpot2, ignore_monsters, ENT(pev), &tr);
|
||||
|
||||
if (tr.fInOpen && tr.fInWater)
|
||||
return FALSE; // sight line crossed contents
|
||||
|
||||
if (tr.flFraction == 1)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
2324
src/dlls/turret.cpp
Executable file → Normal file
2324
src/dlls/turret.cpp
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
3954
src/dlls/util.cpp
3954
src/dlls/util.cpp
File diff suppressed because it is too large
Load Diff
1081
src/dlls/util.h
1081
src/dlls/util.h
File diff suppressed because it is too large
Load Diff
@@ -1,112 +1,112 @@
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 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.
|
||||
*
|
||||
****/
|
||||
#ifndef VECTOR_H
|
||||
#define VECTOR_H
|
||||
|
||||
//=========================================================
|
||||
// 2DVector - used for many pathfinding and many other
|
||||
// operations that are treated as planar rather than 3d.
|
||||
//=========================================================
|
||||
class Vector2D
|
||||
{
|
||||
public:
|
||||
inline Vector2D(void) { }
|
||||
inline Vector2D(float X, float Y) { x = X; y = Y; }
|
||||
inline Vector2D operator+(const Vector2D& v) const { return Vector2D(x+v.x, y+v.y); }
|
||||
inline Vector2D operator-(const Vector2D& v) const { return Vector2D(x-v.x, y-v.y); }
|
||||
inline Vector2D operator*(float fl) const { return Vector2D(x*fl, y*fl); }
|
||||
inline Vector2D operator/(float fl) const { return Vector2D(x/fl, y/fl); }
|
||||
|
||||
inline float Length(void) const { return sqrt(x*x + y*y ); }
|
||||
|
||||
inline Vector2D Normalize ( void ) const
|
||||
{
|
||||
Vector2D vec2;
|
||||
|
||||
float flLen = Length();
|
||||
if ( flLen == 0 )
|
||||
{
|
||||
return Vector2D( 0, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
flLen = 1 / flLen;
|
||||
return Vector2D( x * flLen, y * flLen );
|
||||
}
|
||||
}
|
||||
|
||||
vec_t x, y;
|
||||
};
|
||||
|
||||
inline float DotProduct(const Vector2D& a, const Vector2D& b) { return( a.x*b.x + a.y*b.y ); }
|
||||
inline Vector2D operator*(float fl, const Vector2D& v) { return v * fl; }
|
||||
|
||||
//=========================================================
|
||||
// 3D Vector
|
||||
//=========================================================
|
||||
class Vector // same data-layout as engine's vec3_t,
|
||||
{ // which is a vec_t[3]
|
||||
public:
|
||||
// Construction/destruction
|
||||
inline Vector(void) { }
|
||||
inline Vector(float X, float Y, float Z) { x = X; y = Y; z = Z; }
|
||||
//inline Vector(double X, double Y, double Z) { x = (float)X; y = (float)Y; z = (float)Z; }
|
||||
//inline Vector(int X, int Y, int Z) { x = (float)X; y = (float)Y; z = (float)Z; }
|
||||
inline Vector(const Vector& v) { x = v.x; y = v.y; z = v.z; }
|
||||
inline Vector(float rgfl[3]) { x = rgfl[0]; y = rgfl[1]; z = rgfl[2]; }
|
||||
|
||||
// Operators
|
||||
inline Vector operator-(void) const { return Vector(-x,-y,-z); }
|
||||
inline int operator==(const Vector& v) const { return x==v.x && y==v.y && z==v.z; }
|
||||
inline int operator!=(const Vector& v) const { return !(*this==v); }
|
||||
inline Vector operator+(const Vector& v) const { return Vector(x+v.x, y+v.y, z+v.z); }
|
||||
inline Vector operator-(const Vector& v) const { return Vector(x-v.x, y-v.y, z-v.z); }
|
||||
inline Vector operator*(float fl) const { return Vector(x*fl, y*fl, z*fl); }
|
||||
inline Vector operator/(float fl) const { return Vector(x/fl, y/fl, z/fl); }
|
||||
|
||||
// Methods
|
||||
inline void CopyToArray(float* rgfl) const { rgfl[0] = x, rgfl[1] = y, rgfl[2] = z; }
|
||||
inline float Length(void) const { return sqrt(x*x + y*y + z*z); }
|
||||
operator float *() { return &x; } // Vectors will now automatically convert to float * when needed
|
||||
operator const float *() const { return &x; } // Vectors will now automatically convert to float * when needed
|
||||
inline Vector Normalize(void) const
|
||||
{
|
||||
float flLen = Length();
|
||||
if (flLen == 0) return Vector(0,0,1); // ????
|
||||
flLen = 1 / flLen;
|
||||
return Vector(x * flLen, y * flLen, z * flLen);
|
||||
}
|
||||
|
||||
inline Vector2D Make2D ( void ) const
|
||||
{
|
||||
Vector2D Vec2;
|
||||
|
||||
Vec2.x = x;
|
||||
Vec2.y = y;
|
||||
|
||||
return Vec2;
|
||||
}
|
||||
inline float Length2D(void) const { return sqrt(x*x + y*y); }
|
||||
|
||||
// Members
|
||||
vec_t x, y, z;
|
||||
};
|
||||
inline Vector operator*(float fl, const Vector& v) { return v * fl; }
|
||||
inline float DotProduct(const Vector& a, const Vector& b) { return(a.x*b.x+a.y*b.y+a.z*b.z); }
|
||||
inline Vector CrossProduct(const Vector& a, const Vector& b) { return Vector( a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x ); }
|
||||
|
||||
|
||||
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1999, 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.
|
||||
*
|
||||
****/
|
||||
#ifndef VECTOR_H
|
||||
#define VECTOR_H
|
||||
|
||||
//=========================================================
|
||||
// 2DVector - used for many pathfinding and many other
|
||||
// operations that are treated as planar rather than 3d.
|
||||
//=========================================================
|
||||
class Vector2D
|
||||
{
|
||||
public:
|
||||
inline Vector2D(void) { }
|
||||
inline Vector2D(float X, float Y) { x = X; y = Y; }
|
||||
inline Vector2D operator+(const Vector2D& v) const { return Vector2D(x+v.x, y+v.y); }
|
||||
inline Vector2D operator-(const Vector2D& v) const { return Vector2D(x-v.x, y-v.y); }
|
||||
inline Vector2D operator*(float fl) const { return Vector2D(x*fl, y*fl); }
|
||||
inline Vector2D operator/(float fl) const { return Vector2D(x/fl, y/fl); }
|
||||
|
||||
inline float Length(void) const { return sqrt(x*x + y*y ); }
|
||||
|
||||
inline Vector2D Normalize ( void ) const
|
||||
{
|
||||
Vector2D vec2;
|
||||
|
||||
float flLen = Length();
|
||||
if ( flLen == 0 )
|
||||
{
|
||||
return Vector2D( 0, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
flLen = 1 / flLen;
|
||||
return Vector2D( x * flLen, y * flLen );
|
||||
}
|
||||
}
|
||||
|
||||
vec_t x, y;
|
||||
};
|
||||
|
||||
inline float DotProduct(const Vector2D& a, const Vector2D& b) { return( a.x*b.x + a.y*b.y ); }
|
||||
inline Vector2D operator*(float fl, const Vector2D& v) { return v * fl; }
|
||||
|
||||
//=========================================================
|
||||
// 3D Vector
|
||||
//=========================================================
|
||||
class Vector // same data-layout as engine's vec3_t,
|
||||
{ // which is a vec_t[3]
|
||||
public:
|
||||
// Construction/destruction
|
||||
inline Vector(void) { }
|
||||
inline Vector(float X, float Y, float Z) { x = X; y = Y; z = Z; }
|
||||
//inline Vector(double X, double Y, double Z) { x = (float)X; y = (float)Y; z = (float)Z; }
|
||||
//inline Vector(int X, int Y, int Z) { x = (float)X; y = (float)Y; z = (float)Z; }
|
||||
inline Vector(const Vector& v) { x = v.x; y = v.y; z = v.z; }
|
||||
inline Vector(float rgfl[3]) { x = rgfl[0]; y = rgfl[1]; z = rgfl[2]; }
|
||||
|
||||
// Operators
|
||||
inline Vector operator-(void) const { return Vector(-x,-y,-z); }
|
||||
inline int operator==(const Vector& v) const { return x==v.x && y==v.y && z==v.z; }
|
||||
inline int operator!=(const Vector& v) const { return !(*this==v); }
|
||||
inline Vector operator+(const Vector& v) const { return Vector(x+v.x, y+v.y, z+v.z); }
|
||||
inline Vector operator-(const Vector& v) const { return Vector(x-v.x, y-v.y, z-v.z); }
|
||||
inline Vector operator*(float fl) const { return Vector(x*fl, y*fl, z*fl); }
|
||||
inline Vector operator/(float fl) const { return Vector(x/fl, y/fl, z/fl); }
|
||||
|
||||
// Methods
|
||||
inline void CopyToArray(float* rgfl) const { rgfl[0] = x, rgfl[1] = y, rgfl[2] = z; }
|
||||
inline float Length(void) const { return sqrt(x*x + y*y + z*z); }
|
||||
operator float *() { return &x; } // Vectors will now automatically convert to float * when needed
|
||||
operator const float *() const { return &x; } // Vectors will now automatically convert to float * when needed
|
||||
inline Vector Normalize(void) const
|
||||
{
|
||||
float flLen = Length();
|
||||
if (flLen == 0) return Vector(0,0,1); // ????
|
||||
flLen = 1 / flLen;
|
||||
return Vector(x * flLen, y * flLen, z * flLen);
|
||||
}
|
||||
|
||||
inline Vector2D Make2D ( void ) const
|
||||
{
|
||||
Vector2D Vec2;
|
||||
|
||||
Vec2.x = x;
|
||||
Vec2.y = y;
|
||||
|
||||
return Vec2;
|
||||
}
|
||||
inline float Length2D(void) const { return sqrt(x*x + y*y); }
|
||||
|
||||
// Members
|
||||
vec_t x, y, z;
|
||||
};
|
||||
inline Vector operator*(float fl, const Vector& v) { return v * fl; }
|
||||
inline float DotProduct(const Vector& a, const Vector& b) { return(a.x*b.x+a.y*b.y+a.z*b.z); }
|
||||
inline Vector CrossProduct(const Vector& a, const Vector& b) { return Vector( a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x ); }
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
1323
src/dlls/voltigore.cpp
Normal file
1323
src/dlls/voltigore.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user