Compare commits
8 Commits
tier-3-bet
...
tier-3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c7579c3e2 | ||
|
|
035e70e776 | ||
|
|
d4ecb16bf7 | ||
|
|
513cde6231 | ||
|
|
e33eaf4d1e | ||
|
|
e29e79052d | ||
|
|
8d28e23e16 | ||
|
|
0622ccc638 |
20
README.md
20
README.md
@@ -35,17 +35,19 @@ Under no circumstances shall we allow this project to fade away and become lost
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
*NOTE: Outdated. Ideally, users should be able to use the plugin "out-of-the-box" without the need to do the complicated mess explained below.*
|
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.
|
||||||
|
|
||||||
*TODO: Add build instructions, just using 'make' on G++ 4.8 is really vague.*
|
**Windows:**
|
||||||
|
`win32 addons\monstermod\monster_mm.dll`
|
||||||
|
|
||||||
If you are trying to use the compiled binary, you must know that it has been compiled with a mayor GCC version and it will be highly unlikely that it will run on a vanilla HLDS server. If the plugin fails to load due to libstdc++ not having CXXABI_1.X.X or similar, read on. HLDS uses it's own libstdc++ library. Any plugins compiled with GCC versions 5.x and greater will not work with the outdated library.
|
**Linux:**
|
||||||
|
`linux addons/monstermod/monster_mm_i386.so`
|
||||||
|
|
||||||
To remedy this issue you have two options:
|
Additional configuration files are included in the release files, each explaining it's usage and installation instructions.
|
||||||
|
|
||||||
You can recompile the source code under g++ 4.8 and use the newly generated binary. Make sure to edit the Makefile so it points to that version of g++. Compilation is done by simply running `make` on the `src/dlls` folder.
|
## Build Instructions
|
||||||
|
|
||||||
Alternatively, you can "remove" the outdated library to force HLDS to use the libstdc++ provided by the linux distro, which is generally more up to date. You might need to install GCC/G++ on the operating system if it doesn't work.
|
*TODO: Add build instructions.*
|
||||||
|
|
||||||
## MonsterMod and ReHLDS
|
## MonsterMod and ReHLDS
|
||||||
|
|
||||||
@@ -55,7 +57,7 @@ Keeping track of the number of precached content will allow you to maximize the
|
|||||||
|
|
||||||
## Using MonsterMod on Counter-Strike
|
## Using MonsterMod on Counter-Strike
|
||||||
|
|
||||||
Counter-Strike precaches non trivial 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. Since these sounds are handled client-side by the models themselves, theres is no need to be kept precached on the server. Only the weapons fire sounds are needed.
|
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:
|
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:
|
||||||
|
|
||||||
@@ -193,8 +195,8 @@ Current milestones are separated by "Tiers", which are as follows:
|
|||||||
- Update source code so it can compile AND run **ON WINDOWS**. **[DONE]**
|
- Update source code so it can compile AND run **ON WINDOWS**. **[DONE]**
|
||||||
- Implement *-almost-* all Opposing Force monsters. **[DONE]**
|
- Implement *-almost-* all Opposing Force monsters. **[DONE]**
|
||||||
- Implement *-almost-* all default Sven Co-op monsters. **[DONE]**
|
- Implement *-almost-* all default Sven Co-op monsters. **[DONE]**
|
||||||
- Make MonsterMod aware of normal game entities. *-For those who want to use the plugin in vanilla HL.-*
|
- Make MonsterMod aware of normal game entities. *-For those wanting to use this in vanilla HL.-* **[DONE]**
|
||||||
- Custom model support.
|
- Custom model support. **[DONE]**
|
||||||
|
|
||||||
### Tier 4
|
### Tier 4
|
||||||
|
|
||||||
|
|||||||
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,12 +3,11 @@
|
|||||||
// Send this new file to your maps folder.
|
// Send this new file to your maps folder.
|
||||||
//
|
//
|
||||||
// To add entries to this file, just pretend it's ripent.
|
// 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.
|
// "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:
|
// "classify" to change the monster's default classification, use one of these values:
|
||||||
//
|
//
|
||||||
// CLASS_NONE -1
|
// CLASS_NONE -1
|
||||||
|
|||||||
@@ -32,6 +32,9 @@
|
|||||||
//monster_otis
|
//monster_otis
|
||||||
//monster_pitdrone
|
//monster_pitdrone
|
||||||
//monster_shocktrooper
|
//monster_shocktrooper
|
||||||
//monster_voltigore
|
//monster_alien_voltigore
|
||||||
//monster_baby_voltigore
|
//monster_alien_babyvoltigore
|
||||||
//monster_babygarg
|
//monster_babygarg
|
||||||
|
//monster_hwgrunt
|
||||||
|
//monster_robogrunt
|
||||||
|
//monster_stukabat
|
||||||
|
|||||||
@@ -139,6 +139,18 @@ sk_babygarg_dmg_slash 24
|
|||||||
sk_babygarg_dmg_fire 4
|
sk_babygarg_dmg_fire 4
|
||||||
sk_babygarg_dmg_stomp 80
|
sk_babygarg_dmg_stomp 80
|
||||||
|
|
||||||
|
// Heavy Weapons Grunt
|
||||||
|
sk_hwgrunt_health 100
|
||||||
|
|
||||||
|
// Robo Grunt
|
||||||
|
sk_rgrunt_health 50
|
||||||
|
sk_rgrunt_armor 0.75
|
||||||
|
|
||||||
|
// Stukabat
|
||||||
|
sk_stukabat_health 80
|
||||||
|
sk_stukabat_dmg_bite 11
|
||||||
|
sk_stukabat_speed 400
|
||||||
|
|
||||||
|
|
||||||
// MONSTER WEAPON DAMAGE
|
// MONSTER WEAPON DAMAGE
|
||||||
sk_9mm_bullet 5
|
sk_9mm_bullet 5
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ void CMApache :: Spawn( void )
|
|||||||
pev->movetype = MOVETYPE_FLY;
|
pev->movetype = MOVETYPE_FLY;
|
||||||
pev->solid = SOLID_BBOX;
|
pev->solid = SOLID_BBOX;
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/apache.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/apache.mdl"));
|
||||||
UTIL_SetSize( pev, Vector( -32, -32, -64 ), Vector( 32, 32, 0 ) );
|
UTIL_SetSize( pev, Vector( -32, -32, -64 ), Vector( 32, 32, 0 ) );
|
||||||
UTIL_SetOrigin( pev, pev->origin );
|
UTIL_SetOrigin( pev, pev->origin );
|
||||||
|
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ void CMBarney :: Spawn()
|
|||||||
// when a level is loaded, nobody will talk (time is reset to 0)
|
// when a level is loaded, nobody will talk (time is reset to 0)
|
||||||
TalkInit();
|
TalkInit();
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/barney.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/barney.mdl"));
|
||||||
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -603,7 +603,7 @@ void CMBigMomma :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/big_mom.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/big_mom.mdl"));
|
||||||
// UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
|
// UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
|
||||||
UTIL_SetSize( pev, Vector( -64, -64, 0 ), Vector( 64, 64, 128 ) );
|
UTIL_SetSize( pev, Vector( -64, -64, 0 ), Vector( 64, 64, 128 ) );
|
||||||
|
|
||||||
|
|||||||
@@ -608,7 +608,7 @@ void CMBullsquid :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/bullsquid.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/bullsquid.mdl"));
|
||||||
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
|
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -601,7 +601,6 @@ template <class T> T * CreateClassPtr( T *a )
|
|||||||
// store the class pointer in the array here!!!
|
// store the class pointer in the array here!!!
|
||||||
monsters[monster_index].monster_index = edict_index;
|
monsters[monster_index].monster_index = edict_index;
|
||||||
monsters[monster_index].monster_pent = temp_edict;
|
monsters[monster_index].monster_pent = temp_edict;
|
||||||
monsters[monster_index].respawn_index = -1;
|
|
||||||
monsters[monster_index].pMonster = (CMBaseMonster *)a;
|
monsters[monster_index].pMonster = (CMBaseMonster *)a;
|
||||||
|
|
||||||
// get the private data
|
// get the private data
|
||||||
|
|||||||
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
|
||||||
@@ -580,7 +580,7 @@ void CMBaseMonster::CallGibMonster( void )
|
|||||||
if (pev->health < -99)
|
if (pev->health < -99)
|
||||||
{
|
{
|
||||||
pev->health = 0;
|
pev->health = 0;
|
||||||
pev->fuser4 = pev->health;
|
pev->fuser4 = pev->health;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ShouldFadeOnDeath() && !fade )
|
if ( ShouldFadeOnDeath() && !fade )
|
||||||
@@ -618,14 +618,11 @@ void CMBaseMonster :: Killed( entvars_t *pevAttacker, int iGib )
|
|||||||
SetConditions( bits_COND_LIGHT_DAMAGE );
|
SetConditions( bits_COND_LIGHT_DAMAGE );
|
||||||
|
|
||||||
// tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality.
|
// tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality.
|
||||||
/*jlb monstermaker
|
|
||||||
CMBaseEntity *pOwner = CMBaseEntity::Instance(pev->owner);
|
CMBaseEntity *pOwner = CMBaseEntity::Instance(pev->owner);
|
||||||
if ( pOwner )
|
if ( pOwner )
|
||||||
{
|
{
|
||||||
//jlb it crashes here sometimes!!!
|
|
||||||
pOwner->DeathNotice( pev );
|
pOwner->DeathNotice( pev );
|
||||||
}
|
}
|
||||||
jlb*/
|
|
||||||
|
|
||||||
if ( ShouldGibMonster( iGib ) )
|
if ( ShouldGibMonster( iGib ) )
|
||||||
{
|
{
|
||||||
@@ -642,7 +639,7 @@ jlb*/
|
|||||||
if (pev->health < -99)
|
if (pev->health < -99)
|
||||||
{
|
{
|
||||||
pev->health = 0;
|
pev->health = 0;
|
||||||
pev->fuser4 = pev->health;
|
pev->fuser4 = pev->health;
|
||||||
}
|
}
|
||||||
|
|
||||||
//pev->enemy = ENT( pevAttacker );//why? (sjb)
|
//pev->enemy = ENT( pevAttacker );//why? (sjb)
|
||||||
@@ -894,8 +891,8 @@ int CMBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker
|
|||||||
// do the damage
|
// do the damage
|
||||||
pev->health -= flTake;
|
pev->health -= flTake;
|
||||||
|
|
||||||
if (pev->flags & FL_MONSTER)
|
if (pev->flags & FL_MONSTER)
|
||||||
pev->fuser4 = pev->health;
|
pev->fuser4 = pev->health;
|
||||||
|
|
||||||
// HACKHACK Don't kill monsters in a script. Let them break their scripts first
|
// HACKHACK Don't kill monsters in a script. Let them break their scripts first
|
||||||
if ( m_MonsterState == MONSTERSTATE_SCRIPT )
|
if ( m_MonsterState == MONSTERSTATE_SCRIPT )
|
||||||
@@ -1005,13 +1002,13 @@ int CMBaseMonster :: DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAtta
|
|||||||
if ( pev->health <= flDamage )
|
if ( pev->health <= flDamage )
|
||||||
{
|
{
|
||||||
pev->health = -50;
|
pev->health = -50;
|
||||||
pev->fuser4 = pev->health;
|
pev->fuser4 = pev->health;
|
||||||
Killed( pevAttacker, GIB_ALWAYS );
|
Killed( pevAttacker, GIB_ALWAYS );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Accumulate corpse gibbing damage, so you can gib with multiple hits
|
// Accumulate corpse gibbing damage, so you can gib with multiple hits
|
||||||
pev->health -= flDamage * 0.1;
|
pev->health -= flDamage * 0.1;
|
||||||
pev->fuser4 = pev->health;
|
pev->fuser4 = pev->health;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1154,11 +1151,8 @@ void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacke
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!UTIL_IsPlayer(pEntity))
|
else
|
||||||
{
|
{
|
||||||
// I'm doing really bad copypastes instead of making the code clean!
|
|
||||||
// Remind me to refactor this, this is not how this is supposed to be written!
|
|
||||||
// -Giegue
|
|
||||||
edict_t *pMonster = pEntity;
|
edict_t *pMonster = pEntity;
|
||||||
|
|
||||||
if ( iClassIgnore != CLASS_NONE && pMonster->v.iuser4 == iClassIgnore )
|
if ( iClassIgnore != CLASS_NONE && pMonster->v.iuser4 == iClassIgnore )
|
||||||
@@ -1260,7 +1254,7 @@ edict_t* CMBaseMonster :: CheckTraceHullAttack( float flDist, int iDamage, int i
|
|||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
|
||||||
pMonster->TakeDamage( pev, pev, iDamage, iDmgType );
|
pMonster->TakeDamage( pev, pev, iDamage, iDmgType );
|
||||||
}
|
}
|
||||||
else if (!UTIL_IsPlayer(pEntity))
|
else
|
||||||
UTIL_TakeDamageExternal( pEntity, pev, pev, iDamage, iDmgType );
|
UTIL_TakeDamageExternal( pEntity, pev, pev, iDamage, iDmgType );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1571,7 +1565,7 @@ void CMBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShootin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!UTIL_IsPlayer(tr.pHit)) // normal game monster
|
else // normal game entity
|
||||||
{
|
{
|
||||||
edict_t *pMonster = tr.pHit;
|
edict_t *pMonster = tr.pHit;
|
||||||
|
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ void CMController :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/controller.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/controller.mdl"));
|
||||||
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ));
|
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ));
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
#include "cmbase.h"
|
#include "cmbase.h"
|
||||||
#include "cmbasemonster.h"
|
#include "cmbasemonster.h"
|
||||||
|
#include "cmbaseextra.h"
|
||||||
#include "monsters.h"
|
#include "monsters.h"
|
||||||
#include "weapons.h"
|
#include "weapons.h"
|
||||||
#include "hornet.h"
|
#include "hornet.h"
|
||||||
@@ -68,7 +69,6 @@ int g_DamageVictim;
|
|||||||
edict_t *g_DamageAttacker[33];
|
edict_t *g_DamageAttacker[33];
|
||||||
int g_DamageBits[33];
|
int g_DamageBits[33];
|
||||||
bool g_PlayerKilled[33];
|
bool g_PlayerKilled[33];
|
||||||
float g_flWaitTillMessage[33];
|
|
||||||
|
|
||||||
// DeathMsg
|
// DeathMsg
|
||||||
int g_DeathMsg;
|
int g_DeathMsg;
|
||||||
@@ -158,14 +158,15 @@ monster_type_t monster_types[]=
|
|||||||
"monster_pitdrone", FALSE,
|
"monster_pitdrone", FALSE,
|
||||||
"monster_shockroach", FALSE,
|
"monster_shockroach", FALSE,
|
||||||
"monster_shocktrooper", FALSE,
|
"monster_shocktrooper", FALSE,
|
||||||
"monster_voltigore", FALSE,
|
"monster_alien_voltigore", FALSE,
|
||||||
"monster_baby_voltigore", FALSE,
|
"monster_alien_babyvoltigore", FALSE,
|
||||||
"monster_babygarg", FALSE, // Sven Co-op Monsters
|
"monster_babygarg", FALSE, // Sven Co-op Monsters
|
||||||
"monster_hwgrunt", FALSE,
|
"monster_hwgrunt", FALSE,
|
||||||
"monster_robogrunt", FALSE,
|
"monster_robogrunt", FALSE,
|
||||||
"monster_stukabat", FALSE,
|
"monster_stukabat", FALSE,
|
||||||
"info_node", FALSE, // Nodes
|
"info_node", FALSE, // Nodes
|
||||||
"info_node_air", FALSE,
|
"info_node_air", FALSE,
|
||||||
|
"monstermaker", FALSE, // Extra entities
|
||||||
"", FALSE
|
"", FALSE
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -179,6 +180,7 @@ node_spawnpoint_t node_spawnpoint[MAX_NODES];
|
|||||||
int node_spawn_count = 0;
|
int node_spawn_count = 0;
|
||||||
|
|
||||||
float check_respawn_time;
|
float check_respawn_time;
|
||||||
|
float check_graph_time;
|
||||||
|
|
||||||
bool process_monster_cfg(void);
|
bool process_monster_cfg(void);
|
||||||
bool process_monster_precache_cfg(void);
|
bool process_monster_precache_cfg(void);
|
||||||
@@ -209,15 +211,6 @@ int GetMonsterIndex(void)
|
|||||||
|
|
||||||
void FreeMonsterIndex(int index)
|
void FreeMonsterIndex(int index)
|
||||||
{
|
{
|
||||||
int idx = monsters[index].respawn_index;
|
|
||||||
|
|
||||||
if (idx != -1)
|
|
||||||
{
|
|
||||||
monster_spawnpoint[idx].need_to_respawn = TRUE;
|
|
||||||
monster_spawnpoint[idx].respawn_time = gpGlobals->time +
|
|
||||||
monster_spawnpoint[idx].delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete monsters[index].pMonster;
|
delete monsters[index].pMonster;
|
||||||
|
|
||||||
monsters[index].monster_index = 0;
|
monsters[index].monster_index = 0;
|
||||||
@@ -400,17 +393,36 @@ void check_player_dead( edict_t *pPlayer )
|
|||||||
// Killed by a monster?
|
// Killed by a monster?
|
||||||
if ( pAttacker->v.flags & FL_MONSTER )
|
if ( pAttacker->v.flags & FL_MONSTER )
|
||||||
{
|
{
|
||||||
// Check the first character for 'aeiou'.
|
// Try to get the name of the monster
|
||||||
|
char szName[129], szCheck[2];
|
||||||
|
|
||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pAttacker));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pAttacker));
|
||||||
char szCheck[2];
|
if ( pMonster != NULL )
|
||||||
strncpy( szCheck, STRING( pMonster->m_szMonsterName ), 1 );
|
{
|
||||||
|
// One of our monsters
|
||||||
|
strcpy(szName, STRING( pMonster->m_szMonsterName ));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// SOMETHING that is a monster
|
||||||
|
if ( !FStringNull( pAttacker->v.netname ) )
|
||||||
|
strcpy(szName, STRING( pAttacker->v.netname ));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No netname, use classname
|
||||||
|
strcpy(szName, STRING( pAttacker->v.classname ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, copy the first character to check for 'aeiou'.
|
||||||
|
strncpy( szCheck, szName, 1 );
|
||||||
|
|
||||||
// Make the first character lowercase
|
// Make this character lowercase and inspect it. Select which message.
|
||||||
szCheck[0] = tolower( szCheck[ 0 ] );
|
szCheck[0] = tolower( szCheck[ 0 ] );
|
||||||
if ( strncmp( szCheck, "a", 1 ) == 0 || strncmp( szCheck, "e", 1 ) == 0 || strncmp( szCheck, "i", 1 ) == 0 || strncmp( szCheck, "o", 1 ) == 0 || strncmp( szCheck, "u", 1 ) == 0 )
|
if ( strncmp( szCheck, "a", 1 ) == 0 || strncmp( szCheck, "e", 1 ) == 0 || strncmp( szCheck, "i", 1 ) == 0 || strncmp( szCheck, "o", 1 ) == 0 || strncmp( szCheck, "u", 1 ) == 0 )
|
||||||
sprintf( szMessage, "* %s was killed by an %s.\n", szPlayerName, STRING( pMonster->m_szMonsterName ) );
|
sprintf( szMessage, "* %s was killed by an %s.\n", szPlayerName, szName );
|
||||||
else
|
else
|
||||||
sprintf( szMessage, "* %s was killed by a %s.\n", szPlayerName, STRING( pMonster->m_szMonsterName ) );
|
sprintf( szMessage, "* %s was killed by a %s.\n", szPlayerName, szName );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -469,8 +481,6 @@ void check_player_dead( edict_t *pPlayer )
|
|||||||
sprintf( szMessage, "* %s died of hypothermia.\n", szPlayerName );
|
sprintf( szMessage, "* %s died of hypothermia.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] & DMG_MORTAR )
|
else if ( g_DamageBits[ iPlayerIndex ] & DMG_MORTAR )
|
||||||
sprintf( szMessage, "* %s blew its missile pet.\n", szPlayerName );
|
sprintf( szMessage, "* %s blew its missile pet.\n", szPlayerName );
|
||||||
else if ( g_DamageBits[ iPlayerIndex ] == (1 << 30) ) // (1 << 30) = 1073741824. For custom death messages
|
|
||||||
sprintf( szMessage, "* %s %s.\n", szPlayerName, STRING( pAttacker->v.noise ) );
|
|
||||||
else // other mods could have more DMG_ variants that aren't registered here.
|
else // other mods could have more DMG_ variants that aren't registered here.
|
||||||
sprintf( szMessage, "* %s deadly died.\n", szPlayerName );
|
sprintf( szMessage, "* %s deadly died.\n", szPlayerName );
|
||||||
}
|
}
|
||||||
@@ -520,44 +530,86 @@ void check_monster_info( edict_t *pPlayer )
|
|||||||
// Hit an entity?
|
// Hit an entity?
|
||||||
if (tr.pHit != NULL)
|
if (tr.pHit != NULL)
|
||||||
{
|
{
|
||||||
// Must be a monster
|
// It should be alive
|
||||||
if (tr.pHit->v.flags & FL_MONSTER)
|
if ( UTIL_IsAlive( tr.pHit ) )
|
||||||
{
|
{
|
||||||
// Get monster info
|
// Must be a monster
|
||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit));
|
if (tr.pHit->v.flags & FL_MONSTER)
|
||||||
|
{
|
||||||
char szInfo[512];
|
char szName[129];
|
||||||
sprintf(szInfo, "Enemy: %s\nHealth: %.0f\nFrags: %.0f\n", STRING( pMonster->m_szMonsterName ), pMonster->pev->health, pMonster->pev->frags );
|
float monsterHealth, monsterFrags;
|
||||||
|
int classify;
|
||||||
// Create a TE_TEXTMESSAGE and show the monster information
|
BOOL isAlly = FALSE;
|
||||||
MESSAGE_BEGIN( MSG_ONE, SVC_TEMPENTITY, NULL, pPlayer );
|
|
||||||
WRITE_BYTE( TE_TEXTMESSAGE );
|
// Get monster info
|
||||||
WRITE_BYTE( 3 ); // Channel
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit));
|
||||||
WRITE_SHORT( 327 ); // X
|
if ( pMonster != NULL )
|
||||||
WRITE_SHORT( 4771 ); // Y
|
{
|
||||||
WRITE_BYTE( 0 ); // Effect
|
strcpy(szName, STRING( pMonster->m_szMonsterName ));
|
||||||
WRITE_BYTE( 171 ); // R1
|
classify = pMonster->Classify();
|
||||||
WRITE_BYTE( 23 ); // G1
|
}
|
||||||
WRITE_BYTE( 7 ); // B1
|
else
|
||||||
WRITE_BYTE( 0 ); // A1
|
{
|
||||||
WRITE_BYTE( 207 ); // R2
|
// A monster that we do not recognize, use its netname
|
||||||
WRITE_BYTE( 23 ); // G2
|
if ( !FStringNull( tr.pHit->v.netname ) )
|
||||||
WRITE_BYTE( 7 ); // B2
|
strcpy(szName, STRING( tr.pHit->v.netname ));
|
||||||
WRITE_BYTE( 255 ); // A2
|
else
|
||||||
WRITE_SHORT( 0 ); // Fade-in Time
|
{
|
||||||
WRITE_SHORT( 15 ); // Fade-out Time
|
// If all else fails, use classname as monster name
|
||||||
WRITE_SHORT( 448 ); // Hold time
|
strcpy(szName, STRING( tr.pHit->v.classname ));
|
||||||
WRITE_STRING( szInfo ); // Message
|
}
|
||||||
MESSAGE_END();
|
classify = tr.pHit->v.iuser4;
|
||||||
|
}
|
||||||
// Delay till next scan
|
monsterHealth = tr.pHit->v.health;
|
||||||
g_NextMessage[ ENTINDEX( pPlayer ) ] = gpGlobals->time + 0.8;
|
monsterFrags = tr.pHit->v.frags;
|
||||||
|
|
||||||
|
// Unless it is strictly ally to us, treat as enemy monster
|
||||||
|
if ( classify == CLASS_HUMAN_PASSIVE || classify == CLASS_PLAYER_ALLY )
|
||||||
|
isAlly = TRUE;
|
||||||
|
|
||||||
|
// Prepare the message
|
||||||
|
char szInfo[257];
|
||||||
|
sprintf(szInfo, "%s: %s\nHealth: %.0f\nFrags: %.0f\n", ( isAlly ? "Friend" : "Enemy" ), szName, monsterHealth, monsterFrags );
|
||||||
|
|
||||||
|
// Create a TE_TEXTMESSAGE and show the monster information
|
||||||
|
MESSAGE_BEGIN( MSG_ONE, SVC_TEMPENTITY, NULL, pPlayer );
|
||||||
|
WRITE_BYTE( TE_TEXTMESSAGE );
|
||||||
|
WRITE_BYTE( 3 ); // Channel
|
||||||
|
WRITE_SHORT( 327 ); // X
|
||||||
|
WRITE_SHORT( 4771 ); // Y
|
||||||
|
WRITE_BYTE( 0 ); // Effect
|
||||||
|
if ( isAlly )
|
||||||
|
{
|
||||||
|
WRITE_BYTE( 9 ); // R1
|
||||||
|
WRITE_BYTE( 172 ); // G1
|
||||||
|
WRITE_BYTE( 96 ); // B1
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WRITE_BYTE( 171 ); // R1
|
||||||
|
WRITE_BYTE( 23 ); // G1
|
||||||
|
WRITE_BYTE( 7 ); // B1
|
||||||
|
}
|
||||||
|
WRITE_BYTE( 0 ); // A1
|
||||||
|
WRITE_BYTE( 207 ); // R2
|
||||||
|
WRITE_BYTE( 23 ); // G2
|
||||||
|
WRITE_BYTE( 7 ); // B2
|
||||||
|
WRITE_BYTE( 255 ); // A2
|
||||||
|
WRITE_SHORT( 0 ); // Fade-in Time
|
||||||
|
WRITE_SHORT( 15 ); // Fade-out Time
|
||||||
|
WRITE_SHORT( 448 ); // Hold time
|
||||||
|
WRITE_STRING( szInfo ); // Message
|
||||||
|
MESSAGE_END();
|
||||||
|
|
||||||
|
// Delay till next scan
|
||||||
|
g_NextMessage[ ENTINDEX( pPlayer ) ] = gpGlobals->time + 0.30;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_index, int spawnflags, pKVD *keyvalue)
|
edict_t* spawn_monster(int monster_type, Vector origin, Vector angles, int spawnflags, pKVD *keyvalue)
|
||||||
{
|
{
|
||||||
int monster_index;
|
int monster_index;
|
||||||
edict_t *monster_pent;
|
edict_t *monster_pent;
|
||||||
@@ -567,7 +619,7 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i
|
|||||||
{
|
{
|
||||||
//META_CONS("[MONSTER] ERROR: No FREE Monster edicts!");
|
//META_CONS("[MONSTER] ERROR: No FREE Monster edicts!");
|
||||||
LOG_MESSAGE(PLID, "ERROR: No FREE Monster edicts!");
|
LOG_MESSAGE(PLID, "ERROR: No FREE Monster edicts!");
|
||||||
return TRUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// was this monster NOT precached?
|
// was this monster NOT precached?
|
||||||
@@ -601,11 +653,12 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i
|
|||||||
LOG_MESSAGE(PLID, "%s", msg);
|
LOG_MESSAGE(PLID, "%s", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (monster_type)
|
switch (monster_type)
|
||||||
{
|
{
|
||||||
|
// Monsters
|
||||||
case 0: monsters[monster_index].pMonster = CreateClassPtr((CMAGrunt *)NULL); break;
|
case 0: monsters[monster_index].pMonster = CreateClassPtr((CMAGrunt *)NULL); break;
|
||||||
case 1: monsters[monster_index].pMonster = CreateClassPtr((CMApache *)NULL); break;
|
case 1: monsters[monster_index].pMonster = CreateClassPtr((CMApache *)NULL); break;
|
||||||
case 2: monsters[monster_index].pMonster = CreateClassPtr((CMBarney *)NULL); break;
|
case 2: monsters[monster_index].pMonster = CreateClassPtr((CMBarney *)NULL); break;
|
||||||
@@ -636,17 +689,17 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i
|
|||||||
case 27: monsters[monster_index].pMonster = CreateClassPtr((CMHWGrunt *)NULL); break;
|
case 27: monsters[monster_index].pMonster = CreateClassPtr((CMHWGrunt *)NULL); break;
|
||||||
case 28: monsters[monster_index].pMonster = CreateClassPtr((CMRGrunt *)NULL); break;
|
case 28: monsters[monster_index].pMonster = CreateClassPtr((CMRGrunt *)NULL); break;
|
||||||
case 29: monsters[monster_index].pMonster = CreateClassPtr((CMStukabat *)NULL); break;
|
case 29: monsters[monster_index].pMonster = CreateClassPtr((CMStukabat *)NULL); break;
|
||||||
|
// Extra entities
|
||||||
|
case 32: monsters[monster_index].pMonster = CreateClassPtr((CMMonsterMaker *)NULL); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (monsters[monster_index].pMonster == NULL)
|
if (monsters[monster_index].pMonster == NULL)
|
||||||
{
|
{
|
||||||
//META_CONS("[MONSTER] ERROR: Error Creating Monster!" );
|
//META_CONS("[MONSTER] ERROR: Error Creating Monster!" );
|
||||||
LOG_MESSAGE(PLID, "ERROR: Error Creating Monster!");
|
LOG_MESSAGE(PLID, "ERROR: Error Creating Monster!");
|
||||||
return TRUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
monsters[monster_index].respawn_index = respawn_index;
|
|
||||||
|
|
||||||
monster_pent = ENT(monsters[monster_index].pMonster->pev);
|
monster_pent = ENT(monsters[monster_index].pMonster->pev);
|
||||||
monsters[monster_index].monster_pent = monster_pent;
|
monsters[monster_index].monster_pent = monster_pent;
|
||||||
|
|
||||||
@@ -673,15 +726,19 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i
|
|||||||
|
|
||||||
monsters[monster_index].pMonster->Spawn();
|
monsters[monster_index].pMonster->Spawn();
|
||||||
|
|
||||||
// Reverse fadecorpse behaviour
|
// Only modify starting spawnflags for monsters, not for entities!
|
||||||
if ( ( spawnflags & SF_MONSTER_FADECORPSE ) )
|
if ( monster_index <= 29 )
|
||||||
monster_pent->v.spawnflags &= ~SF_MONSTER_FADECORPSE;
|
{
|
||||||
else
|
// Reverse fadecorpse behaviour
|
||||||
monster_pent->v.spawnflags |= SF_MONSTER_FADECORPSE;
|
if ( ( spawnflags & SF_MONSTER_FADECORPSE ) )
|
||||||
|
monster_pent->v.spawnflags &= ~SF_MONSTER_FADECORPSE;
|
||||||
|
else
|
||||||
|
monster_pent->v.spawnflags |= SF_MONSTER_FADECORPSE;
|
||||||
|
}
|
||||||
|
|
||||||
monster_pent->v.fuser4 = monster_pent->v.health; // save the original health
|
monster_pent->v.fuser4 = monster_pent->v.health; // save the original health
|
||||||
|
|
||||||
return FALSE;
|
return monster_pent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -698,8 +755,7 @@ void check_respawn(void)
|
|||||||
|
|
||||||
for (int index=0; index < monster_spawn_count; index++)
|
for (int index=0; index < monster_spawn_count; index++)
|
||||||
{
|
{
|
||||||
if (monster_spawnpoint[index].need_to_respawn &&
|
if (monster_spawnpoint[index].need_to_respawn)
|
||||||
(monster_spawnpoint[index].respawn_time <= gpGlobals->time))
|
|
||||||
{
|
{
|
||||||
monster_spawnpoint[index].need_to_respawn = FALSE;
|
monster_spawnpoint[index].need_to_respawn = FALSE;
|
||||||
|
|
||||||
@@ -713,12 +769,10 @@ void check_respawn(void)
|
|||||||
|
|
||||||
keyvalue = monster_spawnpoint[index].keyvalue;
|
keyvalue = monster_spawnpoint[index].keyvalue;
|
||||||
|
|
||||||
if (spawn_monster(monster_type, origin, angles, index, spawnflags, keyvalue))
|
if (spawn_monster(monster_type, origin, angles, spawnflags, keyvalue) == NULL)
|
||||||
{
|
{
|
||||||
// spawn_monster failed, retry again after delay...
|
// spawn_monster failed
|
||||||
monster_spawnpoint[index].need_to_respawn = TRUE;
|
ALERT( at_error, "Failed to spawn %s at origin %f %f %f\n", monster_types[monster_type].name, origin.x, origin.y, origin.z );
|
||||||
monster_spawnpoint[index].respawn_time = gpGlobals->time +
|
|
||||||
monster_spawnpoint[index].delay;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -752,7 +806,6 @@ void world_precache(void)
|
|||||||
PRECACHE_MODEL ("models/w_grenade.mdl");
|
PRECACHE_MODEL ("models/w_grenade.mdl");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MonsterCommand(void)
|
void MonsterCommand(void)
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
@@ -886,7 +939,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -914,9 +967,9 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -942,7 +995,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -969,7 +1022,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -996,7 +1049,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1023,7 +1076,7 @@ void MonsterCommand(void)
|
|||||||
if (monster_angle.y < 0)
|
if (monster_angle.y < 0)
|
||||||
monster_angle.y += 360;
|
monster_angle.y += 360;
|
||||||
|
|
||||||
spawn_monster(monster_type, v_src, monster_angle, -1, spawnflags, NULL);
|
spawn_monster(monster_type, v_src, monster_angle, spawnflags, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1205,33 +1258,13 @@ int mmDispatchSpawn( edict_t *pent )
|
|||||||
process_monster_precache_cfg();
|
process_monster_precache_cfg();
|
||||||
|
|
||||||
process_monster_cfg();
|
process_monster_cfg();
|
||||||
|
|
||||||
// node support. -Giegue
|
// node support. -Giegue
|
||||||
// init the WorldGraph.
|
// init the WorldGraph.
|
||||||
WorldGraph.InitGraph();
|
WorldGraph.InitGraph();
|
||||||
|
check_graph_time = gpGlobals->time + 2.00; // give enough gap
|
||||||
|
|
||||||
// make sure the .NOD file is newer than the .BSP file.
|
check_respawn_time = gpGlobals->time + 4.00;
|
||||||
if ( !WorldGraph.CheckNODFile ( ( char * )STRING( gpGlobals->mapname ) ) )
|
|
||||||
{
|
|
||||||
// NOD file is not present, or is older than the BSP file.
|
|
||||||
WorldGraph.AllocNodes();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Load the node graph for this level
|
|
||||||
if ( !WorldGraph.FLoadGraph ( (char *)STRING( gpGlobals->mapname ) ) )
|
|
||||||
{
|
|
||||||
// couldn't load, so alloc and prepare to build a graph.
|
|
||||||
ALERT ( at_console, "*Error opening .NOD file\n" );
|
|
||||||
WorldGraph.AllocNodes();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ALERT ( at_console, "\n*Graph Loaded!\n" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
check_respawn_time = 0.0;
|
|
||||||
|
|
||||||
for (index = 0; index < MAX_MONSTER_ENTS; index++)
|
for (index = 0; index < MAX_MONSTER_ENTS; index++)
|
||||||
{
|
{
|
||||||
@@ -1294,8 +1327,9 @@ void mmDispatchTouch( edict_t *pentTouched, edict_t *pentOther )
|
|||||||
void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
CMAGrunt agrunt;
|
// Monsters
|
||||||
|
CMAGrunt agrunt; // 0
|
||||||
CMApache apache;
|
CMApache apache;
|
||||||
CMBarney barney;
|
CMBarney barney;
|
||||||
CMBigMomma bigmomma;
|
CMBigMomma bigmomma;
|
||||||
@@ -1324,7 +1358,10 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
|||||||
CMBabyGargantua babygargantua;
|
CMBabyGargantua babygargantua;
|
||||||
CMHWGrunt hwgrunt;
|
CMHWGrunt hwgrunt;
|
||||||
CMRGrunt rgrunt;
|
CMRGrunt rgrunt;
|
||||||
CMStukabat stukabat;
|
CMStukabat stukabat; // 29
|
||||||
|
|
||||||
|
// Extra entities
|
||||||
|
CMMonsterMaker monstermaker; // 32
|
||||||
|
|
||||||
g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" );
|
g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" );
|
||||||
|
|
||||||
@@ -1372,6 +1409,7 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
|||||||
case 27: hwgrunt.Precache(); break;
|
case 27: hwgrunt.Precache(); break;
|
||||||
case 28: rgrunt.Precache(); break;
|
case 28: rgrunt.Precache(); break;
|
||||||
case 29: stukabat.Precache(); break;
|
case 29: stukabat.Precache(); break;
|
||||||
|
case 32: monstermaker.Precache(); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1383,38 +1421,89 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
|||||||
monsters[index].killed = FALSE; // not killed yet
|
monsters[index].killed = FALSE; // not killed yet
|
||||||
monsters[index].pMonster = NULL;
|
monsters[index].pMonster = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (index = 0; index < 33; index++)
|
||||||
|
{
|
||||||
|
g_DamageAttacker[index] = NULL;
|
||||||
|
g_DamageBits[index] = 0;
|
||||||
|
g_PlayerKilled[index] = false;
|
||||||
|
g_NextMessage[index] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
monster_ents_used = 0;
|
monster_ents_used = 0;
|
||||||
|
|
||||||
// spawn nodes
|
|
||||||
for (index = 0; index < node_spawn_count; index++)
|
|
||||||
{
|
|
||||||
CMBaseEntity *pNode;
|
|
||||||
pNode = CreateClassPtr((CNodeEnt *)NULL);
|
|
||||||
|
|
||||||
if (pNode == NULL)
|
|
||||||
{
|
|
||||||
//META_CONS("[MONSTER] ERROR: Error Creating Node!" );
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: Error Creating Node!");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pNode->pev->origin = node_spawnpoint[index].origin;
|
|
||||||
|
|
||||||
if (node_spawnpoint[index].is_air_node)
|
|
||||||
pNode->pev->classname = MAKE_STRING("info_node_air");
|
|
||||||
else
|
|
||||||
pNode->pev->classname = MAKE_STRING("info_node");
|
|
||||||
|
|
||||||
pNode->Spawn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
RETURN_META(MRES_IGNORED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mmStartFrame( void )
|
void mmStartFrame( void )
|
||||||
{
|
{
|
||||||
|
// Don't generate node graph right away
|
||||||
|
if (check_graph_time != -1 && check_graph_time <= gpGlobals->time)
|
||||||
|
{
|
||||||
|
BOOL generateNodes = FALSE;
|
||||||
|
|
||||||
|
check_graph_time = -1; // only once
|
||||||
|
|
||||||
|
// it could be possible that the mod can generate the node graph
|
||||||
|
// on it's own, so we wait a bit before attempting to create ours.
|
||||||
|
// if we can use the game's generated graph, stick to that one.
|
||||||
|
// if not, then do standard node allocation and spawns. -Giegue
|
||||||
|
|
||||||
|
// make sure the .NOD file is newer than the .BSP file.
|
||||||
|
if ( !WorldGraph.CheckNODFile ( ( char * )STRING( gpGlobals->mapname ) ) )
|
||||||
|
{
|
||||||
|
// NOD file is not present, or is older than the BSP file.
|
||||||
|
generateNodes = TRUE;
|
||||||
|
WorldGraph.AllocNodes();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Load the node graph for this level
|
||||||
|
if ( !WorldGraph.FLoadGraph ( (char *)STRING( gpGlobals->mapname ) ) )
|
||||||
|
{
|
||||||
|
// couldn't load, so alloc and prepare to build a graph.
|
||||||
|
generateNodes = TRUE;
|
||||||
|
ALERT ( at_console, "*Error opening .NOD file\n" );
|
||||||
|
WorldGraph.AllocNodes();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// node graph is OK, we can spawn the monsters instantly
|
||||||
|
check_respawn_time = 0.0;
|
||||||
|
ALERT ( at_console, "\n[MONSTER] Graph Loaded!\n" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( generateNodes )
|
||||||
|
{
|
||||||
|
// spawn nodes
|
||||||
|
int index;
|
||||||
|
for (index = 0; index < node_spawn_count; index++)
|
||||||
|
{
|
||||||
|
CMBaseEntity *pNode;
|
||||||
|
pNode = CreateClassPtr((CNodeEnt *)NULL);
|
||||||
|
|
||||||
|
if (pNode == NULL)
|
||||||
|
{
|
||||||
|
//META_CONS("[MONSTER] ERROR: Error Creating Node!" );
|
||||||
|
LOG_MESSAGE(PLID, "ERROR: Error Creating Node!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pNode->pev->origin = node_spawnpoint[index].origin;
|
||||||
|
|
||||||
|
if (node_spawnpoint[index].is_air_node)
|
||||||
|
pNode->pev->classname = MAKE_STRING("info_node_air");
|
||||||
|
else
|
||||||
|
pNode->pev->classname = MAKE_STRING("info_node");
|
||||||
|
|
||||||
|
pNode->Spawn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for node graph before spawning the monsters
|
||||||
if (check_respawn_time <= gpGlobals->time)
|
if (check_respawn_time <= gpGlobals->time)
|
||||||
{
|
{
|
||||||
check_respawn_time = gpGlobals->time + 1.0;
|
check_respawn_time = gpGlobals->time + 1.0;
|
||||||
|
|||||||
@@ -664,7 +664,7 @@ void CMGargantua :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/garg.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/garg.mdl"));
|
||||||
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
|
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
@@ -1327,7 +1327,7 @@ void CMBabyGargantua::Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/babygarg.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/babygarg.mdl"));
|
||||||
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
|
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -616,7 +616,7 @@ void CMGonome::Spawn()
|
|||||||
{
|
{
|
||||||
Precache();
|
Precache();
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/gonome.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/gonome.mdl"));
|
||||||
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ void CMHAssassin :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/hassassin.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/hassassin.mdl"));
|
||||||
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ void CMHeadCrab :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/headcrab.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/headcrab.mdl"));
|
||||||
UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24));
|
UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24));
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
@@ -461,7 +461,7 @@ Schedule_t* CMHeadCrab :: GetScheduleOfType ( int Type )
|
|||||||
void CMBabyCrab :: Spawn( void )
|
void CMBabyCrab :: Spawn( void )
|
||||||
{
|
{
|
||||||
CMHeadCrab::Spawn();
|
CMHeadCrab::Spawn();
|
||||||
SET_MODEL(ENT(pev), "models/baby_headcrab.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/baby_headcrab.mdl"));
|
||||||
pev->rendermode = kRenderTransTexture;
|
pev->rendermode = kRenderTransTexture;
|
||||||
pev->renderamt = 192;
|
pev->renderamt = 192;
|
||||||
UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24));
|
UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24));
|
||||||
|
|||||||
@@ -831,7 +831,7 @@ void CMHGrunt :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/hgrunt.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/hgrunt.mdl"));
|
||||||
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -326,11 +326,10 @@ void CMHornet :: TrackTouch ( edict_t *pOther )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// is this NOT a player and IS a monster?
|
// is this NOT a player and IS a monster?
|
||||||
if (!UTIL_IsPlayer(pOther) && (pOther->v.euser4 != NULL))
|
if (!UTIL_IsPlayer(pOther) && (pOther->v.flags & FL_MONSTER))
|
||||||
{
|
{
|
||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
|
||||||
|
if ( pMonster != NULL && IRelationship( pMonster ) <= R_NO || IRelationshipByClass( pOther->v.iuser4 ) <= R_NO )
|
||||||
if ( IRelationship( pMonster ) <= R_NO )
|
|
||||||
{
|
{
|
||||||
// hit something we don't want to hurt, so turn around.
|
// hit something we don't want to hurt, so turn around.
|
||||||
|
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ void CMHoundeye :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/houndeye.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/houndeye.mdl"));
|
||||||
UTIL_SetSize(pev, Vector ( -16, -16, 0 ), Vector ( 16, 16, 36 ) );
|
UTIL_SetSize(pev, Vector ( -16, -16, 0 ), Vector ( 16, 16, 36 ) );
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ void CMHWGrunt::Spawn()
|
|||||||
{
|
{
|
||||||
Precache();
|
Precache();
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/hwgrunt.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/hwgrunt.mdl"));
|
||||||
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
@@ -816,50 +816,41 @@ Schedule_t* CMHWGrunt :: GetScheduleOfType ( int Type )
|
|||||||
case SCHED_HWGRUNT_ELOF_FAIL:
|
case SCHED_HWGRUNT_ELOF_FAIL:
|
||||||
{
|
{
|
||||||
// human grunt is unable to move to a position that allows him to attack the enemy.
|
// human grunt is unable to move to a position that allows him to attack the enemy.
|
||||||
UTIL_ClientPrintAll( HUD_PRINTTALK, "* DEBUG: SCHED_HWGRUNT_ELOF_FAIL\n" );
|
|
||||||
return &slHWGruntELOFFail[ 0 ];
|
return &slHWGruntELOFFail[ 0 ];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE:
|
case SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE:
|
||||||
{
|
{
|
||||||
UTIL_ClientPrintAll( HUD_PRINTTALK, "* DEBUG: SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE\n" );
|
|
||||||
return &slHWGruntEstablishLineOfFire[ 0 ];
|
return &slHWGruntEstablishLineOfFire[ 0 ];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SCHED_RANGE_ATTACK1:
|
case SCHED_RANGE_ATTACK1:
|
||||||
{
|
{
|
||||||
// no pistols yet, always do standing attack
|
// no pistols yet, always do standing attack
|
||||||
UTIL_ClientPrintAll( HUD_PRINTTALK, "* DEBUG: SCHED_RANGE_ATTACK1\n" );
|
|
||||||
return &slHWGruntRangeAttack1B[ 0 ];
|
return &slHWGruntRangeAttack1B[ 0 ];
|
||||||
}
|
}
|
||||||
case SCHED_COMBAT_FACE:
|
case SCHED_COMBAT_FACE:
|
||||||
{
|
{
|
||||||
UTIL_ClientPrintAll( HUD_PRINTTALK, "* DEBUG: SCHED_COMBAT_FACE\n" );
|
|
||||||
return &slHWGruntCombatFace[ 0 ];
|
return &slHWGruntCombatFace[ 0 ];
|
||||||
}
|
}
|
||||||
case SCHED_HWGRUNT_WAIT_FACE_ENEMY:
|
case SCHED_HWGRUNT_WAIT_FACE_ENEMY:
|
||||||
{
|
{
|
||||||
UTIL_ClientPrintAll( HUD_PRINTTALK, "* DEBUG: SCHED_HWGRUNT_WAIT_FACE_ENEMY\n" );
|
|
||||||
return &slHWGruntWaitInCover[ 0 ];
|
return &slHWGruntWaitInCover[ 0 ];
|
||||||
}
|
}
|
||||||
case SCHED_HWGRUNT_SWEEP:
|
case SCHED_HWGRUNT_SWEEP:
|
||||||
{
|
{
|
||||||
UTIL_ClientPrintAll( HUD_PRINTTALK, "* DEBUG: SCHED_HWGRUNT_SWEEP\n" );
|
|
||||||
return &slHWGruntSweep[ 0 ];
|
return &slHWGruntSweep[ 0 ];
|
||||||
}
|
}
|
||||||
case SCHED_VICTORY_DANCE:
|
case SCHED_VICTORY_DANCE:
|
||||||
{
|
{
|
||||||
UTIL_ClientPrintAll( HUD_PRINTTALK, "* DEBUG: SCHED_VICTORY_DANCE\n" );
|
|
||||||
return &slHWGruntVictoryDance[ 0 ];
|
return &slHWGruntVictoryDance[ 0 ];
|
||||||
}
|
}
|
||||||
case SCHED_HWGRUNT_SUPPRESS:
|
case SCHED_HWGRUNT_SUPPRESS:
|
||||||
{
|
{
|
||||||
UTIL_ClientPrintAll( HUD_PRINTTALK, "* DEBUG: SCHED_HWGRUNT_SUPPRESS\n" );
|
|
||||||
return &slHWGruntSuppress[ 0 ];
|
return &slHWGruntSuppress[ 0 ];
|
||||||
}
|
}
|
||||||
case SCHED_FAIL:
|
case SCHED_FAIL:
|
||||||
{
|
{
|
||||||
UTIL_ClientPrintAll( HUD_PRINTTALK, "* DEBUG: SCHED_FAIL\n" );
|
|
||||||
if ( m_hEnemy != NULL )
|
if ( m_hEnemy != NULL )
|
||||||
{
|
{
|
||||||
// grunt has an enemy, so pick a different default fail schedule most likely to help recover.
|
// grunt has an enemy, so pick a different default fail schedule most likely to help recover.
|
||||||
|
|||||||
@@ -416,7 +416,7 @@ void CMISlave :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/islave.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/islave.mdl"));
|
||||||
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ void CMMassn::Spawn()
|
|||||||
{
|
{
|
||||||
Precache();
|
Precache();
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/massn.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/massn.mdl"));
|
||||||
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ static META_FUNCTIONS gMetaFunctionTable =
|
|||||||
plugin_info_t Plugin_info = {
|
plugin_info_t Plugin_info = {
|
||||||
META_INTERFACE_VERSION, // interface version
|
META_INTERFACE_VERSION, // interface version
|
||||||
"MonsterMod", // name
|
"MonsterMod", // name
|
||||||
"2.0", // version
|
"3.0", // version
|
||||||
"03/06/2020", // date in DD/MM/YYYY format
|
"24/02/2023", // date in DD/MM/YYYY format
|
||||||
"botman, Rick90, Giegue", // original authors + recreation by...
|
"botman, Rick90, Giegue", // original authors + recreation by...
|
||||||
"https://github.com/JulianR0/monstermod-redo", // url
|
"https://github.com/JulianR0/monstermod-redo", // url
|
||||||
"MONSTER", // logtag
|
"MONSTER", // logtag
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
// Now that I think about it this looks slow and bad code >.>
|
// Now that I think about it this looks slow and bad code >.>
|
||||||
|
|
||||||
// A match is found. What is this?
|
// A match is found. What is this?
|
||||||
if (strncmp(monster_types[mIndex].name, "monster", 7) == 0)
|
if (strncmp(monster_types[mIndex].name, "monster_", 8) == 0)
|
||||||
{
|
{
|
||||||
// It's a monster, add it to the list
|
// It's a monster, add it to the list
|
||||||
if (monster_spawn_count == MAX_MONSTERS)
|
if (monster_spawn_count == MAX_MONSTERS)
|
||||||
@@ -110,6 +110,22 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
monster = 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)
|
else if (strcmp(monster_types[mIndex].name, "info_node") == 0)
|
||||||
{
|
{
|
||||||
// Normal node
|
// Normal node
|
||||||
@@ -142,7 +158,7 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
}
|
}
|
||||||
if (monster_types[mIndex].name[0] == 0)
|
if (monster_types[mIndex].name[0] == 0)
|
||||||
{
|
{
|
||||||
LOG_MESSAGE(PLID, "ERROR: unknown classname: %s", input); // print conflictive line
|
LOG_MESSAGE(PLID, "ERROR: unknown classname: %s", data[kvd_index-1].value); // print conflictive line
|
||||||
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!");
|
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!");
|
||||||
badent = TRUE;
|
badent = TRUE;
|
||||||
}
|
}
|
||||||
@@ -150,8 +166,8 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// What are you doing?!
|
// What are you doing?!
|
||||||
LOG_MESSAGE(PLID, "ERROR: BAD ENTITY STRUCTURE! Last line was %s", input); // print conflictive line
|
LOG_MESSAGE(PLID, "ERROR: BAD ENTITY STRUCTURE! Last line was %s", data[kvd_index-1].key); // print conflictive line
|
||||||
LOG_MESSAGE(PLID, "ERROR: nothing will spawn here!");
|
LOG_MESSAGE(PLID, "ERROR: classname MUST be the last entry of the entity!" );
|
||||||
badent = TRUE;
|
badent = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,23 +208,6 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
node_spawnpoint[node_spawn_count].origin[2] = z;
|
node_spawnpoint[node_spawn_count].origin[2] = z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strcmp(data[i].key, "delay") == 0)
|
|
||||||
{
|
|
||||||
// ToDo: Remove this keyvalue.
|
|
||||||
// Monsters spawned directly should not respawn.
|
|
||||||
if (monster)
|
|
||||||
{
|
|
||||||
if (sscanf(data[i].value, "%f", &x) != 1)
|
|
||||||
{
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: invalid delay: %s", input); // print conflictive line
|
|
||||||
|
|
||||||
// default to 30 seconds
|
|
||||||
LOG_MESSAGE(PLID, "ERROR: entity respawn frequency will be set to 30 seconds");
|
|
||||||
x = 30;
|
|
||||||
}
|
|
||||||
monster_spawnpoint[monster_spawn_count].delay = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(data[i].key, "angles") == 0)
|
else if (strcmp(data[i].key, "angles") == 0)
|
||||||
{
|
{
|
||||||
if (monster)
|
if (monster)
|
||||||
@@ -241,6 +240,62 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
monster_spawnpoint[monster_spawn_count].spawnflags = x;
|
monster_spawnpoint[monster_spawn_count].spawnflags = x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcmp(data[i].key, "model") == 0)
|
||||||
|
{
|
||||||
|
if (monster)
|
||||||
|
{
|
||||||
|
// only applicable for normal monsters
|
||||||
|
if (strcmp(data[kvd_index-1].value, "monstermaker") != 0)
|
||||||
|
{
|
||||||
|
// 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
|
else
|
||||||
{
|
{
|
||||||
// We do not know this keyvalue, but an specific entity might use it.
|
// We do not know this keyvalue, but an specific entity might use it.
|
||||||
@@ -255,8 +310,7 @@ void scan_monster_cfg(FILE *fp)
|
|||||||
|
|
||||||
if (monster)
|
if (monster)
|
||||||
{
|
{
|
||||||
// Init monster
|
// Spawn right away
|
||||||
monster_spawnpoint[monster_spawn_count].respawn_time = gpGlobals->time + 0.1; // spawn (nearly) right away
|
|
||||||
monster_spawnpoint[monster_spawn_count].need_to_respawn = TRUE;
|
monster_spawnpoint[monster_spawn_count].need_to_respawn = TRUE;
|
||||||
monster_spawn_count++;
|
monster_spawn_count++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,6 +218,10 @@ SOURCE=.\monster_config.cpp
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\monstermaker.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\monsters.cpp
|
SOURCE=.\monsters.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
@@ -274,6 +278,10 @@ SOURCE=.\strooper.cpp
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\stukabat.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\subs.cpp
|
SOURCE=.\subs.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
@@ -326,6 +334,10 @@ SOURCE=.\cmbase.h
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\cmbaseextra.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\cmbasemonster.h
|
SOURCE=.\cmbasemonster.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ typedef struct
|
|||||||
int monster_index;
|
int monster_index;
|
||||||
edict_t *monster_pent;
|
edict_t *monster_pent;
|
||||||
bool killed;
|
bool killed;
|
||||||
int respawn_index;
|
|
||||||
CMBaseMonster *pMonster;
|
CMBaseMonster *pMonster;
|
||||||
} monster_t;
|
} monster_t;
|
||||||
|
|
||||||
@@ -38,11 +37,9 @@ extern monster_t monsters[MAX_MONSTER_ENTS];
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
Vector origin;
|
Vector origin;
|
||||||
Vector angles;
|
Vector angles;
|
||||||
float delay;
|
|
||||||
unsigned char monster;
|
unsigned char monster;
|
||||||
int spawnflags;
|
int spawnflags;
|
||||||
pKVD *keyvalue;
|
pKVD *keyvalue;
|
||||||
float respawn_time;
|
|
||||||
bool need_to_respawn;
|
bool need_to_respawn;
|
||||||
} monster_spawnpoint_t;
|
} monster_spawnpoint_t;
|
||||||
|
|
||||||
|
|||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -207,7 +207,7 @@ void CMBaseMonster :: Look ( int iDistance )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!UTIL_IsPlayer(pSightEnt))
|
else
|
||||||
{
|
{
|
||||||
/* MonsterMod monster looking at a NON-MonsterMod monster */
|
/* MonsterMod monster looking at a NON-MonsterMod monster */
|
||||||
|
|
||||||
@@ -2081,17 +2081,30 @@ edict_t *CMBaseMonster :: BestVisibleEnemy ( void )
|
|||||||
while (edictList_index < m_edictList_count)
|
while (edictList_index < m_edictList_count)
|
||||||
{
|
{
|
||||||
pEnt = m_edictList[edictList_index];
|
pEnt = m_edictList[edictList_index];
|
||||||
|
|
||||||
if ( UTIL_IsPlayer(pEnt) )
|
if ( UTIL_IsPlayer(pEnt) )
|
||||||
{
|
{
|
||||||
// it's a player...
|
// it's a player...
|
||||||
iDist = ( pEnt->v.origin - pev->origin ).Length();
|
if ( UTIL_IsAlive(pEnt) )
|
||||||
|
|
||||||
if ( iDist <= iNearest )
|
|
||||||
{
|
{
|
||||||
iNearest = iDist;
|
// repeat2
|
||||||
iBestRelationship = R_NM; // player is always nemesis
|
if ( IRelationshipByClass( CLASS_PLAYER ) > iBestRelationship )
|
||||||
pReturn = pEnt;
|
{
|
||||||
|
iBestRelationship = IRelationshipByClass( CLASS_PLAYER );
|
||||||
|
iNearest = ( pEnt->v.origin - pev->origin ).Length();
|
||||||
|
pReturn = pEnt;
|
||||||
|
}
|
||||||
|
else if ( IRelationshipByClass( CLASS_PLAYER ) == iBestRelationship )
|
||||||
|
{
|
||||||
|
iDist = ( pEnt->v.origin - pev->origin ).Length();
|
||||||
|
|
||||||
|
if ( iDist <= iNearest )
|
||||||
|
{
|
||||||
|
iNearest = iDist;
|
||||||
|
iBestRelationship = IRelationshipByClass( CLASS_PLAYER );
|
||||||
|
pReturn = pEnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pEnt->v.euser4 != NULL)
|
else if (pEnt->v.euser4 != NULL)
|
||||||
@@ -2125,12 +2138,12 @@ edict_t *CMBaseMonster :: BestVisibleEnemy ( void )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!UTIL_IsPlayer(pEnt))
|
else
|
||||||
{
|
{
|
||||||
// it's a game default monster...
|
// it's a normal game entity...
|
||||||
if ( UTIL_IsAlive(pEnt) )
|
if ( UTIL_IsAlive(pEnt) )
|
||||||
{
|
{
|
||||||
//repeat2
|
//repeat3
|
||||||
if ( IRelationship( pEnt->v.iuser4 ) > iBestRelationship )
|
if ( IRelationship( pEnt->v.iuser4 ) > iBestRelationship )
|
||||||
{
|
{
|
||||||
iBestRelationship = IRelationship( pEnt->v.iuser4 );
|
iBestRelationship = IRelationship( pEnt->v.iuser4 );
|
||||||
@@ -2596,6 +2609,11 @@ void CMBaseMonster :: KeyValue( KeyValueData *pkvd )
|
|||||||
m_iClassifyOverride = atoi( pkvd->szValue );
|
m_iClassifyOverride = atoi( pkvd->szValue );
|
||||||
pkvd->fHandled = TRUE;
|
pkvd->fHandled = TRUE;
|
||||||
}
|
}
|
||||||
|
else if (FStrEq(pkvd->szKeyName, "model"))
|
||||||
|
{
|
||||||
|
pev->model = ALLOC_STRING( pkvd->szValue );
|
||||||
|
pkvd->fHandled = TRUE;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CMBaseToggle::KeyValue( pkvd );
|
CMBaseToggle::KeyValue( pkvd );
|
||||||
@@ -2959,8 +2977,13 @@ BOOL CMBaseMonster :: GetEnemy ( void )
|
|||||||
if (HasConditions(bits_COND_SEE_CLIENT) && (m_hEnemy == NULL))
|
if (HasConditions(bits_COND_SEE_CLIENT) && (m_hEnemy == NULL))
|
||||||
{
|
{
|
||||||
m_hEnemy = BestVisibleEnemy();
|
m_hEnemy = BestVisibleEnemy();
|
||||||
m_hTargetEnt = m_hEnemy;
|
|
||||||
m_vecEnemyLKP = m_hEnemy->v.origin;
|
// the player we've just seen might not always be our enemy
|
||||||
|
if ( m_hEnemy != NULL )
|
||||||
|
{
|
||||||
|
m_hTargetEnt = m_hEnemy;
|
||||||
|
m_vecEnemyLKP = m_hEnemy->v.origin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remember old enemies
|
// remember old enemies
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ void CMOtis::Spawn()
|
|||||||
{
|
{
|
||||||
Precache();
|
Precache();
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/otis.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/otis.mdl"));
|
||||||
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -563,7 +563,7 @@ void CMPitdrone::Spawn()
|
|||||||
{
|
{
|
||||||
Precache();
|
Precache();
|
||||||
|
|
||||||
SET_MODEL( ENT(pev), "models/pit_drone.mdl" );
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/pit_drone.mdl"));
|
||||||
UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 48));
|
UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 48));
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -312,7 +312,7 @@ void CMRGrunt::Spawn()
|
|||||||
{
|
{
|
||||||
Precache();
|
Precache();
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/rgrunt.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/rgrunt.mdl"));
|
||||||
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -596,7 +596,7 @@ void CMScientist :: Spawn( void )
|
|||||||
// when a level is loaded, nobody will talk (time is reset to 0)
|
// when a level is loaded, nobody will talk (time is reset to 0)
|
||||||
TalkInit();
|
TalkInit();
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/scientist.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/scientist.mdl"));
|
||||||
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ void CMStrooper::Spawn()
|
|||||||
{
|
{
|
||||||
Precache();
|
Precache();
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/strooper.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/strooper.mdl"));
|
||||||
UTIL_SetSize( pev, Vector(-24, -24, 0), Vector(24, 24, 72) );
|
UTIL_SetSize( pev, Vector(-24, -24, 0), Vector(24, 24, 72) );
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ void CMStukabat :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/stukabat.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/stukabat.mdl"));
|
||||||
UTIL_SetSize( pev, Vector( -12, -12, 0 ), Vector( 12, 12, 24 ) );
|
UTIL_SetSize( pev, Vector( -12, -12, 0 ), Vector( 12, 12, 24 ) );
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ void CMBaseTurret::Precache( )
|
|||||||
void CMTurret::Spawn()
|
void CMTurret::Spawn()
|
||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
SET_MODEL(ENT(pev), "models/turret.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/turret.mdl"));
|
||||||
pev->health = gSkillData.turretHealth;
|
pev->health = gSkillData.turretHealth;
|
||||||
m_HackedGunPos = Vector( 0, 0, 12.75 );
|
m_HackedGunPos = Vector( 0, 0, 12.75 );
|
||||||
m_flMaxSpin = TURRET_MAXSPIN;
|
m_flMaxSpin = TURRET_MAXSPIN;
|
||||||
@@ -161,7 +161,7 @@ void CMTurret::Precache()
|
|||||||
void CMMiniTurret::Spawn()
|
void CMMiniTurret::Spawn()
|
||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
SET_MODEL(ENT(pev), "models/miniturret.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/miniturret.mdl"));
|
||||||
pev->health = gSkillData.miniturretHealth;
|
pev->health = gSkillData.miniturretHealth;
|
||||||
m_HackedGunPos = Vector( 0, 0, 12.75 );
|
m_HackedGunPos = Vector( 0, 0, 12.75 );
|
||||||
m_flMaxSpin = 0;
|
m_flMaxSpin = 0;
|
||||||
@@ -1014,7 +1014,7 @@ void CMSentry::Precache()
|
|||||||
void CMSentry::Spawn()
|
void CMSentry::Spawn()
|
||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
SET_MODEL(ENT(pev), "models/sentry.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/sentry.mdl"));
|
||||||
pev->health = gSkillData.sentryHealth;
|
pev->health = gSkillData.sentryHealth;
|
||||||
m_HackedGunPos = Vector( 0, 0, 48 );
|
m_HackedGunPos = Vector( 0, 0, 48 );
|
||||||
pev->view_ofs.z = 48;
|
pev->view_ofs.z = 48;
|
||||||
|
|||||||
@@ -1520,15 +1520,13 @@ Vector VecBModelOrigin( entvars_t* pevBModel )
|
|||||||
|
|
||||||
bool UTIL_IsAlive(entvars_t *pev)
|
bool UTIL_IsAlive(entvars_t *pev)
|
||||||
{
|
{
|
||||||
return ((pev->deadflag == DEAD_NO) && (pev->health > 0) &&
|
return ((pev->deadflag == DEAD_NO) && (pev->health > 0));
|
||||||
((pev->flags & FL_NOTARGET) == 0) && (pev->takedamage != 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool UTIL_IsAlive(edict_t *pEdict)
|
bool UTIL_IsAlive(edict_t *pEdict)
|
||||||
{
|
{
|
||||||
return ((pEdict->v.deadflag == DEAD_NO) && (pEdict->v.health > 0) &&
|
return ((pEdict->v.deadflag == DEAD_NO) && (pEdict->v.health > 0));
|
||||||
((pEdict->v.flags & FL_NOTARGET) == 0) && (pEdict->v.takedamage != 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1540,10 +1538,10 @@ bool UTIL_IsPlayer(edict_t *pEdict)
|
|||||||
|
|
||||||
Vector UTIL_BodyTarget(edict_t *pEdict, Vector posSrc)
|
Vector UTIL_BodyTarget(edict_t *pEdict, Vector posSrc)
|
||||||
{
|
{
|
||||||
if (pEdict->v.flags & FL_CLIENT)
|
if (pEdict->v.flags & FL_CLIENT)
|
||||||
return pEdict->v.origin + (pEdict->v.view_ofs * RANDOM_FLOAT(0.5, 1.1));
|
return pEdict->v.origin + (pEdict->v.view_ofs * RANDOM_FLOAT(0.5, 1.1));
|
||||||
else
|
else
|
||||||
return (pEdict->v.origin + ((pEdict->v.mins + pEdict->v.maxs) * 0.5));
|
return (pEdict->v.origin + ((pEdict->v.mins + pEdict->v.maxs) * 0.5));
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================================
|
//=========================================================
|
||||||
@@ -1677,8 +1675,8 @@ int UTIL_TakeDamage( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAtt
|
|||||||
flBonus = ARMOR_BONUS;
|
flBonus = ARMOR_BONUS;
|
||||||
flRatio = ARMOR_RATIO;
|
flRatio = ARMOR_RATIO;
|
||||||
|
|
||||||
if (!pEdict->v.takedamage)
|
if (!pEdict->v.takedamage || (pEdict->v.flags & FL_GODMODE))
|
||||||
return 0;
|
return 0; // refuse the damage
|
||||||
|
|
||||||
if ( ( bitsDamageType & DMG_BLAST ) )
|
if ( ( bitsDamageType & DMG_BLAST ) )
|
||||||
{
|
{
|
||||||
@@ -1875,7 +1873,11 @@ void UTIL_TraceBleed( edict_t *pEdict, float flDamage, Vector vecDir, TraceResul
|
|||||||
|
|
||||||
if ( Bloodtr.flFraction != 1.0 )
|
if ( Bloodtr.flFraction != 1.0 )
|
||||||
{
|
{
|
||||||
UTIL_BloodDecalTrace( &Bloodtr, BLOOD_COLOR_RED );
|
int bloodColor = pEdict->v.iuser3;
|
||||||
|
if ( !bloodColor )
|
||||||
|
bloodColor = BLOOD_COLOR_RED;
|
||||||
|
|
||||||
|
UTIL_BloodDecalTrace( &Bloodtr, bloodColor );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1886,9 +1888,13 @@ void UTIL_TraceAttack( edict_t *pEdict, entvars_t *pevAttacker, float flDamage,
|
|||||||
|
|
||||||
if ( pEdict->v.takedamage )
|
if ( pEdict->v.takedamage )
|
||||||
{
|
{
|
||||||
|
int bloodColor = pEdict->v.iuser3;
|
||||||
|
if ( !bloodColor )
|
||||||
|
bloodColor = BLOOD_COLOR_RED;
|
||||||
|
|
||||||
AddMultiDamage( pevAttacker, pEdict, flDamage, bitsDamageType );
|
AddMultiDamage( pevAttacker, pEdict, flDamage, bitsDamageType );
|
||||||
|
|
||||||
SpawnBlood(ptr->vecEndPos, BLOOD_COLOR_RED, flDamage);// a little surface blood.
|
SpawnBlood(ptr->vecEndPos, bloodColor, flDamage);// a little surface blood.
|
||||||
|
|
||||||
UTIL_TraceBleed( pEdict, flDamage, vecDir, ptr, bitsDamageType );
|
UTIL_TraceBleed( pEdict, flDamage, vecDir, ptr, bitsDamageType );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,9 +33,6 @@
|
|||||||
|
|
||||||
#define VOLTIGORE_MAX_BEAMS 8
|
#define VOLTIGORE_MAX_BEAMS 8
|
||||||
|
|
||||||
#define VOLTIGORE_CLASSNAME "monster_alien_voltigore"
|
|
||||||
#define VOLTIGORE_BABY_CLASSNAME "monster_alien_babyvoltigore"
|
|
||||||
|
|
||||||
#define VOLTIGORE_ZAP_RED 180
|
#define VOLTIGORE_ZAP_RED 180
|
||||||
#define VOLTIGORE_ZAP_GREEN 16
|
#define VOLTIGORE_ZAP_GREEN 16
|
||||||
#define VOLTIGORE_ZAP_BLUE 255
|
#define VOLTIGORE_ZAP_BLUE 255
|
||||||
@@ -629,7 +626,7 @@ void CMVoltigore::Spawn()
|
|||||||
{
|
{
|
||||||
Precache();
|
Precache();
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/voltigore.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/voltigore.mdl"));
|
||||||
UTIL_SetSize(pev, Vector(-80, -80, 0), Vector(80, 80, 90));
|
UTIL_SetSize(pev, Vector(-80, -80, 0), Vector(80, 80, 90));
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
@@ -1135,7 +1132,7 @@ void CMBabyVoltigore::Spawn()
|
|||||||
{
|
{
|
||||||
Precache();
|
Precache();
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/baby_voltigore.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/baby_voltigore.mdl"));
|
||||||
UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 36));
|
UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 36));
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker )
|
|||||||
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(gMultiDamage.pEntity));
|
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(gMultiDamage.pEntity));
|
||||||
pMonster->TakeDamage(pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type );
|
pMonster->TakeDamage(pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type );
|
||||||
}
|
}
|
||||||
else if (!UTIL_IsPlayer(gMultiDamage.pEntity))
|
else
|
||||||
UTIL_TakeDamageExternal(gMultiDamage.pEntity, pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type );
|
UTIL_TakeDamageExternal(gMultiDamage.pEntity, pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ void CMZombie :: Spawn()
|
|||||||
{
|
{
|
||||||
Precache( );
|
Precache( );
|
||||||
|
|
||||||
SET_MODEL(ENT(pev), "models/zombie.mdl");
|
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/zombie.mdl"));
|
||||||
UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX );
|
UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX );
|
||||||
|
|
||||||
pev->solid = SOLID_SLIDEBOX;
|
pev->solid = SOLID_SLIDEBOX;
|
||||||
|
|||||||
Reference in New Issue
Block a user