52 Commits

Author SHA1 Message Date
Giegue
efb7a1117b Merge pull request #18 from JulianR0/tier4
Tier4
2023-09-12 17:08:06 -03:00
Giegue
91f34169b5 Update some texts. 2023-09-12 16:43:12 -03:00
Giegue
272482c5e7 A long overdue update...
- Fixed Alien Grunt's hornets being silent.
- Fixed many, many, many, many ... many GSR crashes.
- Fixed voltigore's beams not being cleared upon gibbing/removal.
- Prepare for T4 release.
2023-09-12 13:51:25 -03:00
Giegue
12f8eea011 Yet another GMR/GSR fix.
Monster maximum viewable distance is now customizable.
2023-07-01 18:23:59 -03:00
Giegue
1d2a284197 Fixed mistyped monster_bullchicken classname.
Fixed ambient_music not stopping sounds during mapchange.
Fixed monster_gargantua crashing the server upon death.
Fixed GMR/GSR being prone to crashing.
Fixed monster_human_grunt melee attack not damaging non-mm entities.
Fixed monster_male_assassin doing sentence speeches.
Fixed monster_shockroach using headcrab sounds for attack.
Removed CGraph::HandleLinkEnt capabilities as they crash the server.
Increased monster_alien_voltigore lightning attack range.
2023-07-01 16:27:32 -03:00
Giegue
fbe70a5691 Fix sound replacements crashing the server. 2023-06-01 19:46:02 -03:00
Giegue
b87538ff59 Fix monstermaker attempting to spawn alien grunt when monster type is undefined or invalid. 2023-06-01 10:32:28 -03:00
Giegue
fa39abd61c Fix BSP reader crashing the server, again. 2023-05-31 16:16:37 -03:00
Giegue
95461427b2 Add sentences support. 2023-05-02 23:40:00 -03:00
Giegue
c782c2aaf5 Fixed a heap corruption. 2023-04-30 11:32:12 -03:00
Giegue
efd801bdea Add "soundlist" keyvalue for individual sound replacements. 2023-04-29 02:04:40 -03:00
Giegue
92d14a6fd3 Update extra AMXX plugins. 2023-04-29 01:58:47 -03:00
Giegue
ba9414ea6e Add missing keyvalue in monstermaker.
Fix duplicate entity spawn in Half-Life.
2023-04-27 13:02:23 -03:00
Giegue
f751720e59 Recompile AMXX plugins (Did I forget to update them?). 2023-04-27 12:59:29 -03:00
Giegue
0ac8fc00d5 Merge branch 'tier4' of https://github.com/JulianR0/monstermod-redo into tier4 2023-04-26 01:45:28 -03:00
Giegue
5da691b5fe Fix apache/turrets not triggering their targets on death.
Fix apache not giving score upon kill.
Fix monster trigger target crashing the server.
Add "squadmaker" alias entity.
Added plenty of keyvalues to monstermaker, similar to SC's squadmaker.
2023-04-26 01:44:36 -03:00
Giegue
ec45c6f23b Merge branch 'tier4' of https://github.com/JulianR0/monstermod-redo into tier4 2023-04-25 22:33:53 -03:00
Giegue
d00fec91b8 Update extra AMXX plugins. 2023-04-25 22:32:36 -03:00
Giegue
e1e2a48f89 Fix Alien Grunt's TraceAttack method.
Fix extra cfg file crashing the server.
Added custom blood color for monsters.
2023-04-24 13:17:49 -03:00
Giegue
1d8a6768aa Fix monster blood not working.
Fix monster hitboxes not working.
2023-04-24 01:30:52 -03:00
Giegue
2cf22ab66b Fix Makefiles. 2023-04-23 13:43:10 -03:00
Giegue
bfa59a2419 Fix Male Assassin unable to use the Sniper Rifle.
Partially fixed the Stukabat being unable to move when target is unreachable.
Removed zombie/gonome bullet resistance.
Add Global Model Replacement and Global Sound Replacement.
Update Tier milestones.
2023-04-21 20:55:47 -03:00
Giegue
66be4861a3 Fix male assassin unable to use weapons properly.
Remove zombie/gonome bullet resistance.
Make it slighly harder to gib monsters.
Small navigation fix.
Fix compilation on Visual Studio 2015 and 2017.
Fix "use_monstermod" keyvalue not working.
2023-04-15 19:23:20 -03:00
Giegue
fb92c2369f Remove unsupported door info in AI navigation.
Fix keyvalue length being too small.
2023-04-03 12:51:01 -03:00
Giegue
62c17b14e4 Even more BSP reader fixes.
Also fix project file not including all files.
2023-04-01 23:57:11 -03:00
Giegue
28c18952f8 Fix BSP reader breaking when there are too many entities. 2023-04-01 03:03:17 -03:00
Giegue
18268776ae This objetive is complete. 2023-03-29 12:57:37 -03:00
Giegue
acc22bc9ef Fix BSP reader crashing the server. 2023-03-29 12:54:54 -03:00
Giegue
79d4b3b21d Read entities within the BSP itself.
NOT YET COMPLETE, HIGHLY UNSTABLE!

Disabled by default, prone to crashing under Windows.
Set CVar "monster_entity_config" to 0 (or 2) to enable reading from BSP.
2023-03-29 02:48:18 -03:00
Giegue
074635bf8d Derp. Fixed an inverted check. 2023-03-25 21:52:57 -03:00
Giegue
a3086aaaa4 Print number of entities found in BSP file.
Add 'ambient_music' entity.
2023-03-25 21:48:27 -03:00
Giegue
c813f6e76a Fix entvars keyvalues not working.
Fix monstermaker classname.
2023-03-25 21:46:22 -03:00
Giegue
b757c65345 Forgotten header update for windows compilation. 2023-03-16 16:06:45 -03:00
Giegue
ecf3bd9a3d Fixed tons of monsters not working/crashing when attacking HL monsters. 2023-03-16 15:58:09 -03:00
Giegue
bc7633bf9c Update readme. 2023-03-15 14:23:44 -03:00
Giegue
3b1c99d2cc [#11] Add basic death message on PvP kills. 2023-03-15 14:09:06 -03:00
Giegue
5478860f27 Merge branch 'tier4' of https://github.com/JulianR0/monstermod-redo into tier4 2023-03-15 14:07:20 -03:00
Giegue
76d4c3b4bd Compile under modern Visual Studio versions. 2023-03-15 14:06:02 -03:00
Giegue
9849c5296b Add link to wiki. 2023-03-08 19:17:38 -03:00
Giegue
b364915799 [#10] Fix linux compilation. 2023-03-07 13:47:03 -03:00
Giegue
bd9fe1f487 Handle entvar keyvalues. 2023-03-06 20:02:04 -03:00
Giegue
73f240ddb1 Fixed monster turn rate being too slow.
Fixed heavy weapons grunt AI being complete nonsense.
Small improvements to stukabat.
2023-03-06 02:08:37 -03:00
Giegue
750b916666 *screams in AI* 2023-03-04 17:24:23 -03:00
Giegue
bd02a95260 Fix broken shock roach death.
Fix hwgrunt not spinning down the minigun.
Other misc. fixes.
2023-03-04 17:24:01 -03:00
Giegue
62063e34da Scrap scaling idea, not possible. 2023-03-03 01:33:37 -03:00
Giegue
55dfee7d74 Fixed human grunts refusing to attack and refusing to reload.
This also fixes male assassins and shock troopers behaving erraticaly.
Probably the heavy weapons grunt becomes better, too.
2023-03-03 01:18:38 -03:00
Giegue
2140e3413d [#4] Fix compiler warnings. 2023-03-02 14:09:49 -03:00
Giegue
e1bd51b220 [#4] Fix wrong angles on shocktroopers beams and roaches. 2023-03-02 14:09:15 -03:00
Giegue
4b087efde8 I keep forgetting to update this... 2023-02-28 13:46:44 -03:00
Giegue
08846e8dee Merge pull request #6 from JulianR0/tier4
Fix 'git clone' not working on Lubuntu 22.10
2023-02-28 13:19:28 -03:00
Giegue
7075efe7d9 Fixed git clone not working because some distros REALLY dislike the "aux" name! 2023-02-28 13:14:04 -03:00
Giegue
b265a65fe1 Fixed damageBits not being catched for death messages.
Removed DeathMsg manipulation, it never worked correctly.
2023-02-27 10:27:21 -03:00
89 changed files with 4490 additions and 1687 deletions

136
README.md
View File

@@ -23,13 +23,13 @@ A small light is seen at the distance...
MonsterMod is a MetaMod plugin. Its purpose was to allow multiplayer games to add monsters, where it wasn't possible to do so by normal means. The updates of the project became incredibly obscure: Getting the "up-to-date" versions containing the new additions (opposing force monsters, for example) were very difficult. And the only one who managed to bring the plugin even futher kept the progress of the plugin private.
After 20 years (and a half) since botman's original plugin was released, the future of the project became nothing but a forgotten, ancient relic of the past.
After 21 years since botman's original plugin was released, the future of the project became nothing but a forgotten, ancient relic of the past.
Not anymore...
The first goal of this project aims towards the recreation of the new features of the "obscured and updated" Monster Mod plugin. Taking botman's original 2002 plugin and working from the ground up, the mission is to rebuild it with the new features and monsters that only few were able to see.
The source code is completely free for everyone to use: In the event that the development of this project falls and becomes stagnant again, the plugin will live on, as the project's second goal is its preservation. The original botman's page where you can download the 2002 plugin will not stay up forever.
The source code is completely free for everyone to use: In the event that the development of this project falls and becomes stagnant again, the plugin will live on, as the project's second goal is its preservation. ~~The original botman's page where you can download the 2002 plugin will not stay up forever.~~ **April 2023 update**: The page is gone, the original 2002 plugin can no longer be found.
Under no circumstances shall we allow this project to fade away and become lost amidst the gears of time.
@@ -43,11 +43,13 @@ The plugin -should- be able to be used out-of-the-box by simply downloading the
**Linux:**
`linux addons/monstermod/monster_mm_i386.so`
Additional configuration files are included in the release files, each explaining it's usage and installation instructions.
To start adding monsters onto your maps, additional configuration files are included in the release files, each explaining its usage and installation instructions. Nevertheless, if you are felling lost, the [wiki](https://github.com/JulianR0/monstermod-redo/wiki) contains usage instructions, and how to configure MonsterMod to your liking.
Extra MonsterMod features can be unlocked with additional AMX Mod X plugins which are located in the `extra` folder. All these plugins are optional, and only required based on your use-case.
## Build Instructions
*TODO: Add build instructions.*
The [Building](https://github.com/JulianR0/monstermod-redo/wiki) section of the wiki contains instructions on how to compile MonsterMod by yourself.
## MonsterMod and ReHLDS
@@ -55,122 +57,21 @@ Usage of ReHLDS is highly recommended, as you can use the command `rescount` whi
Keeping track of the number of precached content will allow you to maximize the number of monsters you can use without risking going over the limits.
## Using MonsterMod on Counter-Strike
Counter-Strike precaches the sounds of all weapons. This means that sounds such as "clip-ins", "clip-outs" are added to the list, taking quite a bit of space in the precache count. Let it be a reminder that our good old Half-Life can only store a maximum of 512 precached resources. Most of these sounds are handled client-side by the models themselves, there is no need for all of them to be kept precached on the server. Only the weapons fire sounds are needed.
MonsterMod does not have an integrated "Unprecacher" to remove those sounds, but you can remove them manually with AMX Mod X, using Fakemeta. Register forward **FM_PrecacheSound** and return **FMRES_SUPERCEDE** on the following sounds:
```
"weapons/ak47_boltpull.wav"
"weapons/ak47_clipin.wav"
"weapons/ak47_clipout.wav"
"weapons/aug_boltpull.wav"
"weapons/aug_boltslap.wav"
"weapons/aug_clipin.wav"
"weapons/aug_clipout.wav"
"weapons/aug_forearm.wav"
"weapons/awp_clipin.wav"
"weapons/awp_clipout.wav"
"weapons/awp_deploy.wav"
"weapons/boltdown.wav"
"weapons/boltpull1.wav"
"weapons/boltup.wav"
"weapons/clipin1.wav"
"weapons/clipout1.wav"
"weapons/de_clipin.wav"
"weapons/de_clipout.wav"
"weapons/de_deploy.wav"
"weapons/elite_clipout.wav"
"weapons/elite_deploy.wav"
"weapons/elite_leftclipin.wav"
"weapons/elite_reloadstart.wav"
"weapons/elite_rightclipin.wav"
"weapons/elite_sliderelease.wav"
"weapons/elite_twirl.wav"
"weapons/famas_boltpull.wav"
"weapons/famas_boltslap.wav"
"weapons/famas_clipin.wav"
"weapons/famas_clipout.wav"
"weapons/famas_forearm.wav"
"weapons/fiveseven_clipin.wav"
"weapons/fiveseven_clipout.wav"
"weapons/fiveseven_slidepull.wav"
"weapons/fiveseven_sliderelease.wav"
"weapons/g3sg1_clipin.wav"
"weapons/g3sg1_clipout.wav"
"weapons/g3sg1_slide.wav"
"weapons/galil_boltpull.wav"
"weapons/galil_clipin.wav"
"weapons/galil_clipout.wav"
"weapons/m4a1_boltpull.wav"
"weapons/m4a1_clipin.wav"
"weapons/m4a1_clipout.wav"
"weapons/m4a1_deploy.wav"
"weapons/m4a1_silencer_off.wav"
"weapons/m4a1_silencer_on.wav"
"weapons/m249_boxin.wav"
"weapons/m249_boxout.wav"
"weapons/m249_chain.wav"
"weapons/m249_coverdown.wav"
"weapons/m249_coverup.wav"
"weapons/mac10_boltpull.wav"
"weapons/mac10_clipin.wav"
"weapons/mac10_clipout.wav"
"weapons/mp5_clipin.wav"
"weapons/mp5_clipout.wav"
"weapons/mp5_slideback.wav"
"weapons/p90_boltpull.wav"
"weapons/p90_clipin.wav"
"weapons/p90_clipout.wav"
"weapons/p90_cliprelease.wav"
"weapons/p228_clipin.wav"
"weapons/p228_clipout.wav"
"weapons/p228_slidepull.wav"
"weapons/p228_sliderelease.wav"
"weapons/scout_bolt.wav"
"weapons/scout_clipin.wav"
"weapons/scout_clipout.wav"
"weapons/sg550_boltpull.wav"
"weapons/sg550_clipin.wav"
"weapons/sg550_clipout.wav"
"weapons/sg552_boltpull.wav"
"weapons/sg552_clipin.wav"
"weapons/sg552_clipout.wav"
"weapons/slideback1.wav"
"weapons/sliderelease1.wav"
"weapons/ump45_boltslap.wav"
"weapons/ump45_clipin.wav"
"weapons/ump45_clipout.wav"
"weapons/usp_clipin.wav"
"weapons/usp_clipout.wav"
"weapons/usp_silencer_off.wav"
"weapons/usp_silencer_on.wav"
"weapons/usp_slideback.wav"
"weapons/usp_sliderelease.wav"
```
Doing this will free **85** sounds from the precache list that you can now use for additional monsters.
## Known Bugs
## Known Bugs and Issues
I'm aware that the plugin is far from perfect, and there are a few things that need polishing *-especially the AI-*. I'll try to fix/will be fixing as the project evolves:
- Human Grunts are unable to reload their weapons. As a workaround, infinite ammo has been given to them.
- Rarely, Stukabats will become unable to fly towards their target, standing in air doing seemingly nothing.
- Male Assassins share the same AI as HGrunts, so their ammo problem is still a thing, and the same workaround is used.
- Monsters are very prone to gibbing when hurt during death animations.
- Shock Troopers seems to be broken despite sharing HGrunts AI code. Despite having infinite ammo, they eventually stop firing. Worse, taking cover is absolutely broken, and they remain completely frozen in place when it happens.
- If a Heavy Weapons Grunt is to lose their target while his minigun is still spinning, the next time it targets an enemy it will instantly fire instead of spinning up the minigun again.
There are probably more issues that aren't listed here, I'll attempt to fix them as I find them. Of course, any bug report is welcome. If reporting a bug, try to explain step by step how the bug ocurred. The easier it is to replicate a bug, the easier it is to locate it and fix it.
## Milestones
Attempting to recreate everything in one go is a daunting task.
Let it be known that the original 2002 source code will NOT compile on today's compilers, and does NOT contain all the necessary files for compilation. The preliminary was to rewrite and provide as many files or lines of code to ensure it can compile again, and be usable on an actual HLDS installation.
The original Visual C++ 6.0 DSP file exists in the repository but neither the file nor the code has been updated to newer formats. Don't expect it to compile on modern Visual Studio versions.
Current milestones are separated by "Tiers", which are as follows:
### Tier 0
@@ -200,16 +101,23 @@ Current milestones are separated by "Tiers", which are as follows:
### Tier 4
- Implement reading entities within the BSP itself.
- Model scaling. *-If possible.-*
- Custom sound support, along with sentences.
- Fix all pending bugs.
- Implement reading entities within the BSP itself. **[DONE]**
- Add build instructions. **[DONE]**
- Global Model Replacement. **[DONE]**
- Global Sound Replacement. **[DONE]**
- Miscellaneous customization options, such as blood color. **[DONE]**
- Individual sound replacement: "soundlist" keyvalue for monsters. **[DONE]**
- Sentences support for speakable monsters. **[DONE]**
- Attempt to fix bugs as they appear. **[DONE]**
### Tier 5
- Enhance the AI.
- Add configurations to change AI behaviour.
- Optimize code and enhance the AI.
- Create "tool" entities for easier map customization.
- Optimize and clean the code.
- Add a wiki with full documentation.
- Fix **ALL** bugs, specially those not covered in Tier 4.
What will the future hold after all Tiers has been completed?

View File

@@ -1,19 +0,0 @@
## 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.

Binary file not shown.

View File

@@ -2,34 +2,13 @@
// Make a copy of this file and rename it to "<mapname>_monster.cfg".
// Send this new file to your maps folder.
//
// To add entries to this file, just pretend it's ripent.
//
// You may also be interesed in these other keyvalues:
//
// "displayname" to change the monster's name, shown in HUD when you point at it.
// "model" to change the monster's default model. If using monstermaker, use "new_model".
// "classify" to change the monster's default classification, use one of these values:
// Adding entities to this file is done in the same way as ripenting a map.
//
// CLASS_NONE -1
// CLASS_MACHINE 1
// CLASS_PLAYER 2
// CLASS_HUMAN_PASSIVE 3
// CLASS_HUMAN_MILITARY 4
// CLASS_ALIEN_MILITARY 5
// CLASS_ALIEN_PASSIVE 6
// CLASS_ALIEN_MONSTER 7
// CLASS_ALIEN_PREY 8
// CLASS_ALIEN_PREDATOR 9
// CLASS_INSECT 10
// CLASS_PLAYER_ALLY 11
// CLASS_PLAYER_BIOWEAPON 12
// CLASS_ALIEN_BIOWEAPON 13
// CLASS_RACEX_PITDRONE 14
// CLASS_RACEX_SHOCK 15
// For more detailed instructions, check the wiki at
// https://github.com/JulianR0/monstermod-redo/wiki
{
"origin" "90 -180 150"
"delay" "30"
"displayname" "Example Custom Name"
"orientation" "1"
"spawnflags" "32"
@@ -37,7 +16,6 @@
}
{
"origin" "123 456 789"
"delay" "5"
"classify" "7"
"angles" "0 45 0"
"classname" "monster_houndeye"

View File

@@ -1,9 +1,9 @@
// This file constains the monsters that you always want to precache for dynamic spawning.
//
// MONSTERS - monsters that you always want to precache (for dynamic spawning)
// Dynamic spawning means - Monsters that you want to invoke at any time, on any map.
//
// Install this file to your mod's base directory.
//
// Just remove the comment characters at the beginning of the line for the
// Then, remove the comment characters at the beginning of the line for the
// monsters that you always want to precache.
//
// Be wary if you precache too many monsters, it may easily crash your
@@ -13,7 +13,7 @@
//monster_apache
//monster_barney
//monster_bigmomma
//monster_bullsquid
//monster_bullchicken
//monster_gargantua
//monster_human_assassin
//monster_headcrab

View File

@@ -4,4 +4,6 @@ This folder contains auxiliary tools used to enhance the compatibility and/or in
As these are auxiliary, they aren't needed to enjoy MonsterMod. If you want an extra boost, feel free to install these.
Plugins from the `base` folder should come first, then the ones from the appropiate mod folder.
Once all milestones are completed, the possibility of removing the need for external plugins will be considered. Until then, this has to stay.

29
extra/base/README.md Normal file
View File

@@ -0,0 +1,29 @@
## Base Plugins (All Mods)
Auxiliary Tools to use MonsterMod in any GoldSrc game.
These are base plugins that should be installed first before adding any mod-specific plugin.
### AMX Mod X Plugins
#### -A note about AMXX plugins-
All plugins in this section require AMXX 1.9.0 or greater, they will not work on 1.8.2 or older.
Compiled plugins are provided in the `bin` folder for your convenience. However, if you prefer to build the plugins yourself, the source code of all AMXX plugins are located in the `src` folder for compilation.
#### Use Dispatcher
Because MonsterMod entities are, -quite literally-, just a func_wall with its own logic, trying to trigger any MonsterMod entity from the outside will fail, as it will attempt to use the logic of game's "func_wall" instead of our own.
In normal circunstances, you do not need this plugin. But let's say you have a turret monster, disabled by default, and you gave it a targetname. Even with a name, triggering this turret regardless of the method used will not activate it.
The same problem occurs from the other side, a MonsterMod entity trying to trigger something will expect said entity to be part of MonsterMod as well.
This plugin redirects the game's func_wall Use() function to MonsterMod, as well as bridging Use() calls from MonsterMod back to the game, connecting the missing pieces and allowing you to trigger MonsterMod entities from the game, and game entities from MonsterMod.
#### External TakeDamage
When a MonsterMod entity tries to inflict damage to something, it expects said entity to be either a player or a MonsterMod monster. If something else is to be found, it will deal no damage to it, as it doesn't know how to manage it.
This plugin allows MonsterMod entities to inflict damage to normal game entities, such as breakables.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,57 @@
#pragma semicolon 1
#include <amxmodx>
#include <engine>
#include <hamsandwich>
public plugin_init()
{
register_plugin( "GAME-MONSTER: Use Dispatcher", "1.1", "Giegue" );
register_cvar( "_glb_use", "1" );
// Game --> MonsterMod
RegisterHam( Ham_Use, "func_wall", "DispatchUse" );
// MonsterMod --> Game
register_srvcmd( "_trigger", "FireTargets" );
}
public DispatchUse( entity, caller, activator, useType, Float:value )
{
// all monstermod entities have this set
if ( entity_get_edict( entity, EV_ENT_euser4 ) )
{
server_cmd( "_use %i %i %i %i %f", entity, caller, activator, useType, value );
return HAM_SUPERCEDE;
}
return HAM_IGNORED;
}
public FireTargets()
{
if ( read_argc() == 6 )
{
new entity, caller, activator;
new Float:value;
new useType;
entity = read_argv_int( 1 );
caller = read_argv_int( 2 );
activator = read_argv_int( 3 );
value = read_argv_float( 4 );
useType = read_argv_int( 5 );
// caller and activator can be null, but never allow entity to be null
if ( !is_valid_ent( entity ) )
return;
if ( !is_valid_ent( caller ) )
caller = 0;
if ( !is_valid_ent( activator ) )
activator = 0;
ExecuteHamB( Ham_Use, entity, caller, activator, useType, value );
}
}

View File

@@ -0,0 +1,42 @@
#pragma semicolon 1
#include <amxmodx>
#include <engine>
#include <hamsandwich>
public plugin_init()
{
register_plugin( "GAME-MONSTER: External TakeDamage", "1.0", "Giegue" );
register_cvar( "_glb_takedamage", "1" );
// MonsterMod --> Game
register_srvcmd( "_takedamage", "TakeDamage" );
}
public TakeDamage()
{
if ( read_argc() == 6 )
{
new victim, inflictor, attacker;
new Float:damage;
new damageBits;
victim = read_argv_int( 1 );
inflictor = read_argv_int( 2 );
attacker = read_argv_int( 3 );
damage = read_argv_float( 4 );
damageBits = read_argv_int( 5 );
// attacker and inflictor can be null, but never allow victim to be null
if ( !is_valid_ent( victim ) )
return;
if ( !is_valid_ent( inflictor ) )
inflictor = 0;
if ( !is_valid_ent( attacker ) )
attacker = 0;
ExecuteHamB( Ham_TakeDamage, victim, inflictor, attacker, damage, damageBits );
}
}

17
extra/cstrike/README.md Normal file
View File

@@ -0,0 +1,17 @@
## Counter-Strike (cstrike)
Auxiliary Tools to use MonsterMod in Counter-Strike.
### AMX Mod X Plugins
#### -A note about AMXX plugins-
All plugins in this section require AMXX 1.9.0 or greater, they will not work on 1.8.2 or older.
Compiled plugins are provided in the `bin` folder for your convenience. However, if you prefer to build the plugins yourself, the source code of all AMXX plugins are located in the `src` folder for compilation.
#### Unprecacher
Counter-Strike precaches the sounds of all weapons. This means that sounds such as "clip-ins", "clip-outs" are added to the list, taking quite a bit of space in the precache count. Let it be a reminder that our good old GoldSrc can only store a maximum of 512 precached resources. Most of these sounds are handled client-side by the models themselves, so there is no need for them to be kept precached on the server. Only the weapons fire sounds are needed.
This plugin removes 85 sounds from the precache list, adding extra space for additional monsters to fit in the map.

Binary file not shown.

View File

@@ -0,0 +1,126 @@
#pragma semicolon 1
#include <amxmodx>
#include <fakemeta>
// List of sounds that must NOT be precached
new g_SoundList[][64] =
{
"weapons/ak47_boltpull.wav",
"weapons/ak47_clipin.wav",
"weapons/ak47_clipout.wav",
"weapons/aug_boltpull.wav",
"weapons/aug_boltslap.wav",
"weapons/aug_clipin.wav",
"weapons/aug_clipout.wav",
"weapons/aug_forearm.wav",
"weapons/awp_clipin.wav",
"weapons/awp_clipout.wav",
"weapons/awp_deploy.wav",
"weapons/boltdown.wav",
"weapons/boltpull1.wav",
"weapons/boltup.wav",
"weapons/clipin1.wav",
"weapons/clipout1.wav",
"weapons/de_clipin.wav",
"weapons/de_clipout.wav",
"weapons/de_deploy.wav",
"weapons/elite_clipout.wav",
"weapons/elite_deploy.wav",
"weapons/elite_leftclipin.wav",
"weapons/elite_reloadstart.wav",
"weapons/elite_rightclipin.wav",
"weapons/elite_sliderelease.wav",
"weapons/elite_twirl.wav",
"weapons/famas_boltpull.wav",
"weapons/famas_boltslap.wav",
"weapons/famas_clipin.wav",
"weapons/famas_clipout.wav",
"weapons/famas_forearm.wav",
"weapons/fiveseven_clipin.wav",
"weapons/fiveseven_clipout.wav",
"weapons/fiveseven_slidepull.wav",
"weapons/fiveseven_sliderelease.wav",
"weapons/g3sg1_clipin.wav",
"weapons/g3sg1_clipout.wav",
"weapons/g3sg1_slide.wav",
"weapons/galil_boltpull.wav",
"weapons/galil_clipin.wav",
"weapons/galil_clipout.wav",
"weapons/m4a1_boltpull.wav",
"weapons/m4a1_clipin.wav",
"weapons/m4a1_clipout.wav",
"weapons/m4a1_deploy.wav",
"weapons/m4a1_silencer_off.wav",
"weapons/m4a1_silencer_on.wav",
"weapons/m249_boxin.wav",
"weapons/m249_boxout.wav",
"weapons/m249_chain.wav",
"weapons/m249_coverdown.wav",
"weapons/m249_coverup.wav",
"weapons/mac10_boltpull.wav",
"weapons/mac10_clipin.wav",
"weapons/mac10_clipout.wav",
"weapons/mp5_clipin.wav",
"weapons/mp5_clipout.wav",
"weapons/mp5_slideback.wav",
"weapons/p90_boltpull.wav",
"weapons/p90_clipin.wav",
"weapons/p90_clipout.wav",
"weapons/p90_cliprelease.wav",
"weapons/p228_clipin.wav",
"weapons/p228_clipout.wav",
"weapons/p228_slidepull.wav",
"weapons/p228_sliderelease.wav",
"weapons/scout_bolt.wav",
"weapons/scout_clipin.wav",
"weapons/scout_clipout.wav",
"weapons/sg550_boltpull.wav",
"weapons/sg550_clipin.wav",
"weapons/sg550_clipout.wav",
"weapons/sg552_boltpull.wav",
"weapons/sg552_clipin.wav",
"weapons/sg552_clipout.wav",
"weapons/slideback1.wav",
"weapons/sliderelease1.wav",
"weapons/ump45_boltslap.wav",
"weapons/ump45_clipin.wav",
"weapons/ump45_clipout.wav",
"weapons/usp_clipin.wav",
"weapons/usp_clipout.wav",
"weapons/usp_silencer_off.wav",
"weapons/usp_silencer_on.wav",
"weapons/usp_slideback.wav",
"weapons/usp_sliderelease.wav"
};
public plugin_init()
{
register_plugin( "CS-MONSTER: Unprecacher", "1.0", "Giegue" );
}
public plugin_precache()
{
register_forward( FM_PrecacheSound, "fw_PrecacheSound" );
}
public fw_PrecacheSound( const sound[] )
{
static bool:bBlock, i;
bBlock = false;
i = 0;
for ( i = 0; i < sizeof( g_SoundList ); i++ )
{
if (contain( sound, g_SoundList[ i ] ) != -1 )
{
bBlock = true;
break;
}
}
if ( bBlock )
return FMRES_SUPERCEDE;
return FMRES_IGNORED;
}

40
extra/valve/README.md Normal file
View File

@@ -0,0 +1,40 @@
## Half-Life (valve)
Auxiliary Tools to use MonsterMod in the original Half-Life.
### AMX Mod X Plugins
#### -A note about AMXX plugins-
All plugins in this section require AMXX 1.9.0 or greater, they will not work on 1.8.2 or older.
Compiled plugins are provided in the `bin` folder for your convenience. However, if you prefer to build the plugins yourself, the source code of all AMXX plugins are located in the `src` folder for compilation.
#### Bridge Plugin
MonsterMod monsters are hacked "func_wall"'s with simulated AI. Because of this, MonsterMod cannot interact with the Half-Life monsters. This issue also happens on the other side: The Half-Life monsters cannot interact with the MonsterMod monsters.
In simple terms, this plugin acts as a "bridge" to help Half-Life and MonsterMod communicate with each other. With this plugin, HL and MM monsters can "see" and interact with each other, and will react accordingly.
Without this plugin, HL and MM monsters will be "invisible" to each other.
#### Soundlist
This plugin allows you to use the "soundlist" keyvalue in HL monsters to individually replace monster sounds. Path starts from `sound/MAPNAME`. Use `../` to go to the previous directory if needed.
The plugin can work standalone, meaning it can be used without MonsterMod.
#### Extra Keyvalues
**"Bridge Plugin" is REQUIRED for this add-on to work**
This plugin allows you use the following keyvalues on HL monsters:
- classify
- is_player_ally *(non-monstermaker entities)*
- bloodcolor
- respawn_as_playerally *(monstermaker entity)*
The plugin also adds a 5th keyvalue, **"use_monstermod"**. When reading entities from the BSP file, if MonsterMod finds an entity that already exists in the game, it will stick to the game entity and ignore it. By setting this keyvalue to "1", it will explicity use MonsterMod for this entity.
This is useful when, for example, you are trying to spawn a Pit Drone from a monstermaker. HL does not recognize monster_pitdrone, but MonsterMod does. By redirecting the entity to MonsterMod, Pit Drones will spawn from this monstermaker.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,232 @@
#pragma semicolon 1
#include <amxmodx>
#include <engine>
#include <fakemeta>
#include <hamsandwich>
const bits_MEMORY_SPAWN = ( 1 << 1 );
const BLOOD_COLOR_BLUE = 211;
const BLOOD_COLOR_PINK = 147;
const BLOOD_COLOR_WHITE = 11;
const BLOOD_COLOR_ORANGE = 231;
const BLOOD_COLOR_BLACK = 49; // not 100% black but close enough
const BLOOD_COLOR_DARKGREEN = 181; // GREEN is aliased to YELLOW, use custom name
public plugin_init()
{
register_plugin( "HL-MONSTER Extra Keyvalues", "1.0", "Giegue" );
/* CLASSIFY */
// HACK: since Ham_Spawn won't work, this should do as an alternative
RegisterHam( Ham_SetObjectCollisionBox, "monster_headcrab", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_babycrab", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_bullchicken", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_barnacle", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_bigmomma", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_houndeye", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_slave", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_controller", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_grunt", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_zombie", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_ichthyosaur", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_human_grunt", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_human_assassin", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_barney", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_gman", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_scientist", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_sentry", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_snark", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_miniturret", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_turret", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_apache", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_osprey", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_gargantua", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_nihilanth", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_tentacle", "MonsterSpawn_Post", 1 );
/* BLOODCOLOR */
RegisterHam( Ham_BloodColor, "monster_headcrab", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_babycrab", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_bullchicken", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_barnacle", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_bigmomma", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_houndeye", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_alien_slave", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_alien_controller", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_alien_grunt", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_zombie", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_ichthyosaur", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_human_grunt", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_human_assassin", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_barney", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_gman", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_scientist", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_sentry", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_snark", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_miniturret", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_turret", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_apache", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_osprey", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_gargantua", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_nihilanth", "MonsterBlood" );
RegisterHam( Ham_BloodColor, "monster_tentacle", "MonsterBlood" );
// "use_monstermod" keyvalue
register_cvar( "_hl_explicit", "1" );
}
public plugin_precache()
{
register_forward( FM_KeyValue, "ScanKeys" );
}
public ScanKeys( entid, kvd_handle )
{
if (is_valid_ent(entid))
{
static classname[ 33 ], keyname[ 33 ], value[ 128 ];
get_kvd( kvd_handle, KV_ClassName, classname, charsmax( classname ) );
// Monsters
if ( equal( classname, "monster_", 8 ) )
{
get_kvd( kvd_handle, KV_KeyName, keyname, charsmax( keyname ) );
get_kvd( kvd_handle, KV_Value, value, charsmax( value ) );
// Classification override
if ( equal( keyname, "classify" ) )
entity_set_int( entid, EV_INT_iuser4, str_to_num( value ) );
// Allied monster
if ( equal( keyname, "is_player_ally" ) )
{
if ( str_to_num( value ) )
entity_set_int( entid, EV_INT_iuser4, 11 ); // CLASS_PLAYER_ALLY
}
// Custom blood color
if ( equal( keyname, "bloodcolor" ) )
{
switch ( str_to_num( value ) )
{
case -1: entity_set_int( entid, EV_INT_iuser3, DONT_BLEED );
// 0 = Monster Default
case 1: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_RED );
case 2: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_YELLOW );
case 3: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_BLUE );
case 4: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_PINK );
case 5: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_WHITE );
case 6: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_ORANGE );
case 7: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_BLACK );
case 8: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_DARKGREEN );
}
}
// Redirect entity to MonsterMod
if ( equal( keyname, "use_monstermod" ) )
{
if ( str_to_num( value ) )
{
// MonsterMod will inherit this entity, remove it from here
remove_entity( entid );
return FMRES_SUPERCEDE;
}
}
return FMRES_IGNORED;
}
// Monster Makers
else if ( equal( classname, "monstermaker" ) )
{
get_kvd( kvd_handle, KV_KeyName, keyname, charsmax( keyname ) );
get_kvd( kvd_handle, KV_Value, value, charsmax( value ) );
// Classification override
if ( equal( keyname, "classify" ) )
entity_set_int( entid, EV_INT_iuser4, str_to_num( value ) );
// Allied monster
if ( equal( keyname, "respawn_as_playerally" ) )
{
if ( str_to_num( value ) )
entity_set_int( entid, EV_INT_iuser4, 11 ); // CLASS_PLAYER_ALLY
}
// Custom blood color
if ( equal( keyname, "bloodcolor" ) )
{
switch ( str_to_num( value ) )
{
case -1: entity_set_int( entid, EV_INT_iuser3, DONT_BLEED );
// 0 = Monster Default
case 1: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_RED );
case 2: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_YELLOW );
case 3: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_BLUE );
case 4: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_PINK );
case 5: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_WHITE );
case 6: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_ORANGE );
case 7: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_BLACK );
case 8: entity_set_int( entid, EV_INT_iuser3, BLOOD_COLOR_DARKGREEN );
}
}
// Redirect entity to MonsterMod
if ( equal( keyname, "use_monstermod" ) )
{
if ( str_to_num( value ) )
{
// MonsterMod will inherit this entity, remove it from here
remove_entity( entid );
return FMRES_IGNORED; // not a typo, must not supercede or it will crash
}
}
return FMRES_IGNORED;
}
}
return FMRES_IGNORED;
}
public MonsterSpawn_Post( entity )
{
// Why is it called 3 times? Restrict this to only once
if ( !( entity_get_int( entity, EV_INT_impulse ) & bits_MEMORY_SPAWN ) )
{
// monstermaker sets owner after monster spawn, wait next frame
set_task( 0.000001, "MakerSpawn_Post", entity );
entity_set_int( entity, EV_INT_impulse, entity_get_int( entity, EV_INT_impulse ) | bits_MEMORY_SPAWN );
}
}
public MakerSpawn_Post( entity )
{
if ( is_valid_ent( entity ) )
{
static owner;
owner = entity_get_edict( entity, EV_ENT_owner );
if ( owner )
{
// pass parent configurations to child entity
entity_set_int( entity, EV_INT_iuser4, entity_get_int( owner, EV_INT_iuser4 ) ); // classify
entity_set_int( entity, EV_INT_iuser3, entity_get_int( owner, EV_INT_iuser3 ) ); // bloodcolor
}
}
}
public MonsterBlood( entity )
{
static newBlood;
newBlood = entity_get_int( entity, EV_INT_iuser3 );
if ( newBlood )
{
SetHamReturnInteger( newBlood );
return HAM_OVERRIDE;
}
return HAM_IGNORED;
}

View File

@@ -14,9 +14,11 @@ const R_HT = 2; // (HATE) will attack this character instead of any visible DISL
new Trie:g_HLDefaultNames;
const bits_MEMORY_NAMED = ( 1 << 2 );
public plugin_init()
{
register_plugin( "HL-MONSTER Bridge", "1.0", "Giegue" );
register_plugin( "HL-MONSTER Bridge", "1.2", "Giegue" );
RegisterHam( Ham_IRelationship, "monster_alien_controller", "mmIRelationship" );
RegisterHam( Ham_IRelationship, "monster_alien_grunt", "mmIRelationship" );
@@ -67,10 +69,36 @@ public plugin_init()
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" );
TrieSetString( g_HLDefaultNames, "monster_tentacle", "Tentacle" );
set_task( 0.3, "hlScan", 0, "", 0, "b" );
register_srvcmd( "monster_hurt_entity", "hlTakeDamage" );
// HACK: since Ham_Spawn won't work, this should do as an alternative
RegisterHam( Ham_SetObjectCollisionBox, "monster_headcrab", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_babycrab", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_bullchicken", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_barnacle", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_bigmomma", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_houndeye", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_slave", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_controller", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_grunt", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_zombie", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_ichthyosaur", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_human_grunt", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_human_assassin", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_barney", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_gman", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_scientist", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_sentry", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_snark", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_miniturret", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_turret", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_apache", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_osprey", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_gargantua", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_nihilanth", "hlSpawn", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_tentacle", "hlSpawn", 1 );
RegisterHam( Ham_Killed, "player", "PlayerKilled", 1 );
}
public plugin_end()
{
@@ -92,43 +120,40 @@ public mmIRelationship( entity, other )
return HAM_OVERRIDE;
}
public hlScan()
public hlSpawn( entity )
{
new entity, szClassname[ 33 ], szDisplayname[ 129 ], bool:found;
for ( entity = 0; entity < get_global_int( GL_maxEntities ); entity++ )
// Why is it called 3 times? Restrict this to only once
if ( !( entity_get_int( entity, EV_INT_impulse ) & bits_MEMORY_NAMED ) )
{
// Nothing deleted me?
if ( is_valid_ent( entity ) )
// Classify not overriden?
if ( !entity_get_int( entity, EV_INT_iuser4 ) )
{
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" ) );
}
}
// Set default
entity_set_int( entity, EV_INT_iuser4, ExecuteHam( Ham_Classify, entity ) );
}
// Blood color not overriden?
if ( !entity_get_int( entity, EV_INT_iuser3 ) )
{
// Set default
entity_set_int( entity, EV_INT_iuser3, ExecuteHam( Ham_BloodColor, entity ) );
}
// No name set?
new szDisplayname[ 129 ];
entity_get_string( entity, EV_SZ_netname, szDisplayname, charsmax( szDisplayname ) );
if ( !strlen( szDisplayname ) )
{
// Find a default name
new szClassname[ 33 ], bool:found;
entity_get_string( entity, EV_SZ_classname, szClassname, charsmax( szClassname ) );
found = TrieGetString( g_HLDefaultNames, szClassname, szDisplayname, charsmax( szDisplayname ) );
// Use this name
entity_set_string( entity, EV_SZ_netname, ( found ? szDisplayname : "Monster" ) );
}
entity_set_int( entity, EV_INT_impulse, entity_get_int( entity, EV_INT_impulse ) | bits_MEMORY_NAMED );
}
}
@@ -160,29 +185,16 @@ stock IRelationshipByClass( classEntity, classOther )
return iEnemy[ classEntity ][ classOther ];
}
public hlTakeDamage()
public PlayerKilled( victim, attacker, shouldgib )
{
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 );
}
// don't obstruct monstermod
if ( victim == attacker )
return HAM_IGNORED;
// fix monster score
if ( entity_get_int( attacker, EV_INT_flags ) & FL_MONSTER )
entity_set_float( attacker, EV_FL_frags, entity_get_float( attacker, EV_FL_frags ) + 2 );
entity_set_edict( victim, EV_ENT_dmg_inflictor, attacker );
return HAM_IGNORED;
}

View File

@@ -0,0 +1,204 @@
#pragma semicolon 1
#include <amxmodx>
#include <engine>
#include <fakemeta>
#include <hamsandwich>
const bits_MEMORY_SOUNDLIST = ( 1 << 3 );
new Trie:m_Sounds;
public plugin_init()
{
register_plugin( "HL-MONSTER Soundlist", "1.0", "Giegue" );
/* STOP DUPLICATING CODE FFS */
RegisterHam( Ham_SetObjectCollisionBox, "monster_headcrab", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_babycrab", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_bullchicken", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_barnacle", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_bigmomma", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_houndeye", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_slave", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_controller", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_alien_grunt", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_zombie", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_ichthyosaur", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_human_grunt", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_human_assassin", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_barney", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_gman", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_scientist", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_sentry", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_snark", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_miniturret", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_turret", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_apache", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_osprey", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_gargantua", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_nihilanth", "MonsterSpawn_Post", 1 );
RegisterHam( Ham_SetObjectCollisionBox, "monster_tentacle", "MonsterSpawn_Post", 1 );
}
public plugin_end()
{
if ( m_Sounds )
TrieDestroy( m_Sounds );
}
// has to be in precache or it won't work
public plugin_precache()
{
// check individual monster soundlists
register_forward( FM_KeyValue, "ScanSL" );
}
public ScanSL( entid, kvd_handle )
{
if (is_valid_ent(entid))
{
static classname[ 33 ], keyname[ 33 ], value[ 128 ];
get_kvd( kvd_handle, KV_ClassName, classname, charsmax( classname ) );
// Monsters
if ( equal( classname, "monster_", 8 ) )
{
get_kvd( kvd_handle, KV_KeyName, keyname, charsmax( keyname ) );
get_kvd( kvd_handle, KV_Value, value, charsmax( value ) );
// Individual sound replacement
if ( equal( keyname, "soundlist" ) )
{
ProcessSoundList( entid, value );
}
return FMRES_IGNORED;
}
// Monster Makers
else if ( equal( classname, "monstermaker" ) )
{
get_kvd( kvd_handle, KV_KeyName, keyname, charsmax( keyname ) );
get_kvd( kvd_handle, KV_Value, value, charsmax( value ) );
// Children sound list
if ( equal( keyname, "soundlist" ) )
{
ProcessSoundList( entid, value );
}
return FMRES_IGNORED;
}
}
return FMRES_IGNORED;
}
public ProcessSoundList( entity, const filename[] )
{
// First time?
if ( !m_Sounds )
m_Sounds = TrieCreate();
new fullPath[ 129 ];
new mapName[ 33 ], pFile;
get_mapname( mapName, charsmax( mapName ) );
// path always starts from sound/[MAPNAME] (SC behaviour)
formatex( fullPath, charsmax( fullPath ), "sound/%s/%s", mapName, filename );
pFile = fopen( fullPath, "r" );
if ( pFile )
{
new line[ 258 ], soundSrc[ 129 ], soundDest[ 129 ];
while ( fgets( pFile, line, charsmax( line ) ) )
{
// Replace newlines
replace_all( line, charsmax( line ), "^n", "" );
// Ignore blank lines
if ( !line[ 0 ] ) continue;
// source --> destination
parse( line, soundSrc, charsmax( soundSrc ), soundDest, charsmax( soundDest ) );
// Precache destination sound
// HACK: precache_sound outside of plugin_precache
engfunc( EngFunc_PrecacheSound, soundDest );
// HACK: prepend the entityID at the beginning of the soundSrc for later identification
format( soundSrc, charsmax( soundSrc ), "%i#%s", entity, soundSrc );
TrieSetString( m_Sounds, soundSrc, soundDest );
entity_set_int( entity, EV_INT_impulse, entity_get_int( entity, EV_INT_impulse ) | bits_MEMORY_SOUNDLIST );
}
fclose( pFile );
// file could be empty
if ( TrieGetSize( m_Sounds ) )
{
register_forward( FM_EmitSound, "ReplaceSound" );
}
}
}
public ReplaceSound( entity, channel, const sample[], Float:volume, Float:attn, flags, pitch )
{
static newSound[ 129 ];
// replace monster sound?
if ( entity_get_int( entity, EV_INT_impulse ) & bits_MEMORY_SOUNDLIST )
{
// get entityID
static owner, entid;
owner = entity_get_edict( entity, EV_ENT_owner );
if ( owner )
entid = owner;
else
entid = entity;
// get sound
static searchSound[ 129 ];
formatex( searchSound, charsmax( searchSound ), "%i#%s", entid, sample );
// if found, stick to that one
if ( TrieGetString( m_Sounds, searchSound, newSound, charsmax( newSound ) ) )
{
// emit new sound and supercede this one
emit_sound( entity, channel, newSound, volume, attn, flags, pitch );
return FMRES_SUPERCEDE;
}
}
return FMRES_IGNORED;
}
/* extra_keyvalues.sma duplication */
public MonsterSpawn_Post( entity )
{
// monstermaker sets owner after monster spawn, wait next frame
set_task( 0.000001, "MakerSpawn_Post", entity );
}
public MakerSpawn_Post( entity )
{
if ( is_valid_ent( entity ) )
{
static owner;
owner = entity_get_edict( entity, EV_ENT_owner );
if ( owner )
{
// monstermaker has soundlist defined?
if ( entity_get_int( owner, EV_INT_impulse ) & bits_MEMORY_SOUNDLIST )
{
// 3 time call
if ( !( entity_get_int( entity, EV_INT_impulse ) & bits_MEMORY_SOUNDLIST ) )
{
// this monster is to use sound replacements
entity_set_int( entity, EV_INT_impulse, entity_get_int( entity, EV_INT_impulse ) | bits_MEMORY_SOUNDLIST );
}
}
}
}
}

6
src/dlls/.gitignore vendored
View File

@@ -1,5 +1,9 @@
Release/
Debug/
msgs/
opt.*/
debug.*/
*.o
*.so
*.so
*.suo
*.sdf

View File

@@ -1085,7 +1085,7 @@ jlb*/
{
m_movementActivity = ACT_FLY;
}
if ( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE )
else if ( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE )
{
m_movementActivity = ACT_WALK;
}

View File

@@ -1,5 +1,5 @@
CPP = g++
BASEFLAGS = -Dstricmp=strcasecmp -Dstrcmpi=strcasecmp -m32
BASEFLAGS = -Dstricmp=strcasecmp -Dstrcmpi=strcasecmp -m32 -fPIC
OPTFLAGS = -O2
CPPFLAGS = ${BASEFLAGS} ${OPTFLAGS} -w -I. -I../engine -I../common -I../pm_shared -I../metamod
@@ -22,11 +22,12 @@ OBJ = \
flyingmonster.o \
gargantua.o \
ggrenade.o \
globalreplace.o \
gonome.o \
h_ai.o \
h_export.o \
hassassin.o \
headcrab.o \
h_export.o \
hgrunt.o \
hornet.o \
houndeye.o \
@@ -35,12 +36,15 @@ OBJ = \
massn.o \
monster_api.o \
monster_config.o \
monstermaker.o \
monsters.o \
monsterstate.o \
music.o \
nodes.o \
otis.o \
pitdrone.o \
rgrunt.o \
ripent.o \
scientist.o \
shock.o \
shockroach.o \

View File

@@ -19,12 +19,12 @@
#include "extdll.h"
#include "util.h"
#include "cmbase.h"
#include "cmbasemonster.h"
#include "cmbasemonster.h"
#include "monsters.h"
#include "schedule.h"
#include "weapons.h"
#include "hornet.h"
#include "skill.h"
#include "skill.h"
//=========================================================
@@ -87,6 +87,13 @@ const char *CMAGrunt::pAttackSounds[] =
"agrunt/ag_attack3.wav",
};
const char *CMAGrunt::pFireSounds[] =
{
"agrunt/ag_fire1.wav",
"agrunt/ag_fire2.wav",
"agrunt/ag_fire3.wav",
};
const char *CMAGrunt::pDieSounds[] =
{
"agrunt/ag_die1.wav",
@@ -184,13 +191,8 @@ void CMAGrunt :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vec
if (flDamage <= 0)
flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated
}
else
{
SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood.
TraceBleed( flDamage, vecDir, ptr, bitsDamageType );
}
AddMultiDamage( pevAttacker, this->edict(), flDamage, bitsDamageType );
CMBaseMonster::TraceAttack(pevAttacker, flDamage, vecDir, ptr, bitsDamageType);
}
//=========================================================
@@ -418,6 +420,8 @@ void CMAGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent )
UTIL_MakeVectors ( pHornet->pev->angles );
pHornet->pev->velocity = gpGlobals->v_forward * 300;
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, pFireSounds[RANDOM_LONG(0, ARRAYSIZE(pFireSounds) - 1)], 1.0, ATTN_NORM, 0, 100);
CMBaseMonster *pHornetMonster = pHornet->MyMonsterPointer();
if ( pHornetMonster )
@@ -532,12 +536,12 @@ void CMAGrunt :: Spawn()
{
Precache( );
SET_MODEL(ENT(pev), "models/agrunt.mdl");
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/agrunt.mdl"));
UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64));
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0;
pev->health = gSkillData.agruntHealth;
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
@@ -563,40 +567,23 @@ void CMAGrunt :: Spawn()
//=========================================================
void CMAGrunt :: Precache()
{
int i;
PRECACHE_MODEL("models/agrunt.mdl");
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
PRECACHE_SOUND((char *)pAttackHitSounds[i]);
PRECACHE_SOUND_ARRAY( pAttackHitSounds );
PRECACHE_SOUND_ARRAY( pAttackHitSounds );
PRECACHE_SOUND_ARRAY( pAttackMissSounds );
PRECACHE_SOUND_ARRAY( pIdleSounds );
PRECACHE_SOUND_ARRAY( pDieSounds );
PRECACHE_SOUND_ARRAY( pPainSounds );
PRECACHE_SOUND_ARRAY( pAttackSounds );
PRECACHE_SOUND_ARRAY( pAlertSounds );
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
PRECACHE_SOUND((char *)pAttackMissSounds[i]);
iAgruntMuzzleFlash = PRECACHE_MODELINDEX("sprites/muz4.spr");
for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ )
PRECACHE_SOUND((char *)pIdleSounds[i]);
for ( i = 0; i < ARRAYSIZE( pDieSounds ); i++ )
PRECACHE_SOUND((char *)pDieSounds[i]);
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
PRECACHE_SOUND((char *)pPainSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ )
PRECACHE_SOUND((char *)pAttackSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ )
PRECACHE_SOUND((char *)pAlertSounds[i]);
PRECACHE_SOUND( "hassault/hw_shoot1.wav" );
iAgruntMuzzleFlash = PRECACHE_MODEL( "sprites/muz4.spr" );
CMHornet hornet;
hornet.Precache();
CMHornet hornet;
hornet.Precache();
}
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
@@ -1030,7 +1017,7 @@ Schedule_t *CMAGrunt :: GetSchedule ( void )
// zap player!
if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) )
{
AttackSound();// this is a total hack. Should be parto f the schedule
AttackSound();// this is a total hack. Should be part of the schedule
return GetScheduleOfType ( SCHED_MELEE_ATTACK1 );
}

View File

@@ -163,7 +163,11 @@ int LookupSequence( void *pmodel, const char *label )
for (int i = 0; i < pstudiohdr->numseq; i++)
{
#if defined (_WIN32)
if (_stricmp( pseqdesc[i].label, label ) == 0)
#else
if (stricmp( pseqdesc[i].label, label ) == 0)
#endif
return i;
}
@@ -209,7 +213,7 @@ void SequencePrecache( void *pmodel, const char *pSequenceName )
ALERT( at_error, "Bad sound event %d in sequence %s :: %s (sound is \"%s\")\n", pevent[i].event, pstudiohdr->name, pSequenceName, pevent[i].options );
}
PRECACHE_SOUND( (char *)(gpGlobals->pStringBase + ALLOC_STRING(pevent[i].options) ) );
PRECACHE_SOUND2( (char *)(gpGlobals->pStringBase + ALLOC_STRING(pevent[i].options) ) );
}
}
}

View File

@@ -105,14 +105,14 @@ void CMApache::Precache( void )
PRECACHE_SOUND("weapons/mortarhit.wav");
m_iSpriteTexture = PRECACHE_MODEL( "sprites/white.spr" );
m_iSpriteTexture = PRECACHE_MODELINDEX( "sprites/white.spr" );
PRECACHE_SOUND("turret/tu_fire1.wav");
PRECACHE_MODEL("sprites/lgtning.spr");
m_iExplode = PRECACHE_MODEL( "sprites/fexplo.spr" );
m_iBodyGibs = PRECACHE_MODEL( "models/metalplategibs_green.mdl" );
m_iExplode = PRECACHE_MODELINDEX( "sprites/fexplo.spr" );
m_iBodyGibs = PRECACHE_MODELINDEX( "models/metalplategibs_green.mdl" );
CMApacheHVR apache_rocket;
apache_rocket.Precache();
@@ -156,6 +156,11 @@ void CMApache :: Killed( entvars_t *pevAttacker, int iGib )
pev->nextthink = gpGlobals->time + 0.1;
pev->health = 0;
pev->takedamage = DAMAGE_NO;
pev->deadflag = DEAD_DYING;
FCheckAITrigger(); // trigger death condition
if ( UTIL_IsPlayer( ENT( pevAttacker ) ) ) // If a player killed this monster, add score
pevAttacker->frags += 1.0;
if (pev->spawnflags & SF_NOWRECKAGE)
{
@@ -178,7 +183,7 @@ void CMApache :: DyingThink( void )
if (m_flNextRocket > gpGlobals->time )
{
if (g_sModelIndexFireball == 0)
g_sModelIndexFireball = PRECACHE_MODEL ("sprites/zerogxplode.spr"); // fireball
g_sModelIndexFireball = PRECACHE_MODELINDEX("sprites/zerogxplode.spr"); // fireball
// random explosions
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
@@ -193,7 +198,7 @@ void CMApache :: DyingThink( void )
MESSAGE_END();
if (g_sModelIndexSmoke == 0)
g_sModelIndexSmoke = PRECACHE_MODEL ("sprites/steam1.spr"); // smoke
g_sModelIndexSmoke = PRECACHE_MODELINDEX("sprites/steam1.spr"); // smoke
// lots of smoke
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
@@ -419,7 +424,7 @@ void CMApache :: HuntThink( void )
// if (m_hEnemy == NULL)
{
Look( 4092 );
Look( 4096 );
m_hEnemy = BestVisibleEnemy( );
}
@@ -930,7 +935,7 @@ void CMApacheHVR :: Spawn( void )
void CMApacheHVR :: Precache( void )
{
PRECACHE_MODEL("models/HVR.mdl");
m_iTrail = PRECACHE_MODEL("sprites/smoke.spr");
m_iTrail = PRECACHE_MODELINDEX("sprites/smoke.spr");
PRECACHE_SOUND ("weapons/rocket1.wav");
}

View File

@@ -350,7 +350,7 @@ void CMBarney :: Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
pev->health = gSkillData.barneyHealth;
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_FULL;

View File

@@ -609,7 +609,7 @@ void CMBigMomma :: Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->health = 150 * gSkillData.bigmommaHealthFactor;
pev->view_ofs = Vector ( 0, 0, 128 );// position of the eyes relative to monster's origin.
m_flFieldOfView = 0.3;// indicates the width of this monster's forward view cone ( as a dotproduct result )
@@ -648,8 +648,8 @@ void CMBigMomma :: Precache()
// TEMP: Squid
PRECACHE_MODEL("sprites/mommaspit.spr");// spit projectile.
gSpitSprite = PRECACHE_MODEL("sprites/mommaspout.spr");// client side spittle.
gSpitDebrisSprite = PRECACHE_MODEL("sprites/mommablob.spr" );
gSpitSprite = PRECACHE_MODELINDEX("sprites/mommaspout.spr");// client side spittle.
gSpitDebrisSprite = PRECACHE_MODELINDEX("sprites/mommablob.spr" );
PRECACHE_SOUND( "bullchicken/bc_acid1.wav" );
PRECACHE_SOUND( "bullchicken/bc_spithit1.wav" );
@@ -1147,7 +1147,7 @@ CMBMortar *CMBMortar::Shoot( edict_t *pOwner, Vector vecStart, Vector vecVelocit
{
CMBMortar *pSpit = CreateClassPtr( (CMBMortar *)NULL );
if (pSpit)
{
{
pSpit->Spawn();
UTIL_SetOrigin( pSpit->pev, vecStart );

View File

@@ -113,7 +113,7 @@ void CSquidSpit::Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity
pSpit->SetThink ( &CSquidSpit::Animate );
pSpit->pev->nextthink = gpGlobals->time + 0.1;
pSpit->SetTouch ( &CSquidSpit::SpitTouch );
pSpit->SetTouch ( &CSquidSpit::SpitTouch );
}
void CSquidSpit :: SpitTouch ( edict_t *pOther )
@@ -166,6 +166,8 @@ void CSquidSpit :: SpitTouch ( edict_t *pOther )
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
pMonster->TakeDamage ( pev, pev, gSkillData.bullsquidDmgSpit, DMG_GENERIC );
}
else
UTIL_TakeDamageExternal( pOther, pev, pev, gSkillData.bullsquidDmgSpit, DMG_GENERIC );
}
SetThink ( &CSquidSpit::SUB_Remove );
@@ -613,7 +615,7 @@ void CMBullsquid :: Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0;
pev->health = gSkillData.bullsquidHealth;
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
@@ -640,7 +642,7 @@ void CMBullsquid :: Precache()
PRECACHE_MODEL("sprites/bigspit.spr");// spit projectile.
iSquidSpitSprite = PRECACHE_MODEL("sprites/tinyspit.spr");// client side spittle.
iSquidSpitSprite = PRECACHE_MODELINDEX("sprites/tinyspit.spr");// client side spittle.
PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event

View File

@@ -17,6 +17,8 @@
#include "cmbase.h"
#include "decals.h"
void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd );
extern Vector VecBModelOrigin( entvars_t* pevBModel );
extern DLL_GLOBAL Vector g_vecAttackDir;
@@ -103,6 +105,15 @@ edict_t *CMBaseEntity::CreateEntity(char *classname)
return pent;
}
// process entvar keyvalue
void CMBaseEntity :: KeyValue( KeyValueData* pkvd )
{
if ( !pev || !pkvd )
return;
EntvarsKeyvalue( pev, pkvd );
}
// give health
int CMBaseEntity :: TakeHealth( float flHealth, int bitsDamageType )
{

View File

@@ -134,7 +134,7 @@ public:
// initialization functions
virtual void Spawn( void ) { return; }
virtual void Precache( void ) { return; }
virtual void KeyValue( KeyValueData* pkvd) { pkvd->fHandled = FALSE; }
virtual void KeyValue( KeyValueData* pkvd );
virtual int ObjectCaps( void ) { return FCAP_ACROSS_TRANSITION; }
virtual void Activate( void ) {}
@@ -222,7 +222,7 @@ public:
pent = ENT(0);
if ( pent->v.euser4 == NULL )
return (CMBaseEntity *)NULL;
CMBaseEntity *pEnt = GetClassPtr((CMBaseEntity *)VARS(pent));
CMBaseEntity *pEnt = GetClassPtr((CMBaseEntity *)VARS(pent));
return pEnt;
}
@@ -608,3 +608,7 @@ template <class T> T * CreateClassPtr( T *a )
return a;
}
#ifndef GLOBALREPLACE_H
#include "globalreplace.h"
#endif

View File

@@ -21,6 +21,7 @@ public:
int m_iMonsterIndex;// index of the monster(s) that will be created.
string_t m_iszCustomModel;// custom model that the monster will use.
int m_iMonsterBlood;//blood color of spawned monsters.
int m_cNumMonsters;// max number of monsters this ent can create
int m_iMaxLiveChildren;// max number of monsters that this maker may have out at one time.
@@ -33,4 +34,18 @@ public:
BOOL m_fFadeChildren;// should we make the children fadeout?
};
//=========================================================
// Ambient Music - Plays an mp3 music file to players.
//=========================================================
class CMAmbientMusic : public CMBaseMonster
{
public:
void Spawn(void);
//void Precache(void); // accessed before entvars are valid, manual precache in monster_config.cpp
void KeyValue(KeyValueData* pkvd);
void EXPORT MusicUse(edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value);
BOOL m_fPlaying; // music is active
};
#endif // BASEEXTRA_H

View File

@@ -105,6 +105,11 @@ public:
string_t m_szMonsterName; // Monster name to display on HUD
int m_iClassifyOverride; // Overriden classification for this monster
REPLACER::REPLACER *m_srSoundList; // individual sound replacements for this monster
int m_isrSounds; // number of replaced sounds
float m_flLastYawTime;
void KeyValue( KeyValueData *pkvd );
// monster use function
@@ -729,6 +734,7 @@ public:
static const char *pAttackHitSounds[];
static const char *pAttackMissSounds[];
static const char *pAttackSounds[];
static const char *pFireSounds[];
static const char *pDieSounds[];
static const char *pPainSounds[];
static const char *pIdleSounds[];
@@ -1332,6 +1338,11 @@ public:
void DeathSound(void);
void PainSound(void);
void IdleSound(void);
void SetActivity(Activity NewActivity);
Schedule_t *GetScheduleOfType( int Type );
CUSTOM_SCHEDULES;
};
//=========================================================
@@ -1371,6 +1382,8 @@ public:
void EXPORT SpikeTouch(edict_t *pOther);
void EXPORT StartTrail();
static edict_t *Shoot(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, Vector vecAngles);
EHANDLE m_hOwner;
};
//=========================================================
@@ -1434,6 +1447,7 @@ public:
void AlertSound(void);
void MonsterThink(void);
void StartTask(Task_t* pTask);
void HandleAnimEvent(MonsterEvent_t *pEvent);
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
static const char *pIdleSounds[];
@@ -1546,6 +1560,7 @@ public:
Schedule_t *GetScheduleOfType(int Type);
virtual int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType);
virtual void Killed(entvars_t *pevAttacker, int iGib);
void UpdateOnRemove();
CUSTOM_SCHEDULES
@@ -1667,8 +1682,6 @@ public:
void Minigun(void);
CUSTOM_SCHEDULES
float m_flMinigunSpinTime;
};
//=========================================================
@@ -1679,14 +1692,11 @@ class CMRGrunt : public CMHGrunt
public:
int Classify(void);
BOOL FOkToSpeak(void);
void Spawn( void );
void Precache( void );
void DeathSound(void);
void PainSound(void);
void IdleSound(void);
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
@@ -1704,6 +1714,8 @@ public:
float m_flActiveDischarge;
int m_iBodyGibs;
static const char *pRobotSentences[];
};
//=========================================================

View File

@@ -130,7 +130,7 @@ public:
int FIdleStare( void );
int FIdleHello( void );
void IdleHeadTurn( Vector &vecFriend );
int FOkToSpeak( void );
virtual int FOkToSpeak( void );
void TrySmellTalk( void );
edict_t *EnumFriends( edict_t *pentPrevious, int listNumber, BOOL bTrace );
void AlertFriends( void );

View File

@@ -30,8 +30,7 @@
#include "weapons.h"
#include "func_break.h"
const Vector g_vecZero = Vector(0,0,0);
Vector g_vecAttackDir;
extern DLL_GLOBAL Vector g_vecAttackDir;
entvars_t *g_pevLastInflictor;
#define HUMAN_GIB_COUNT 6
@@ -831,7 +830,7 @@ int CMBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker
{
float flTake;
Vector vecDir;
if (!pev->takedamage)
return 0;
@@ -1322,33 +1321,33 @@ void CMBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vecto
if ( pev->takedamage )
{
m_LastHitGroup = ptr->iHitgroup;
/*jlb
// do we need the hitboxes to be customizable? use vanilla HL skill.cfg for now
switch ( ptr->iHitgroup )
{
case HITGROUP_GENERIC:
break;
case HITGROUP_HEAD:
flDamage *= gSkillData.monHead;
flDamage *= 3; //gSkillData.monHead;
break;
case HITGROUP_CHEST:
flDamage *= gSkillData.monChest;
flDamage *= 1; //gSkillData.monChest;
break;
case HITGROUP_STOMACH:
flDamage *= gSkillData.monStomach;
flDamage *= 1; //gSkillData.monStomach;
break;
case HITGROUP_LEFTARM:
case HITGROUP_RIGHTARM:
flDamage *= gSkillData.monArm;
flDamage *= 1; //gSkillData.monArm;
break;
case HITGROUP_LEFTLEG:
case HITGROUP_RIGHTLEG:
flDamage *= gSkillData.monLeg;
flDamage *= 1; //gSkillData.monLeg;
break;
default:
break;
}
jlb*/
SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood.
TraceBleed( flDamage, vecDir, ptr, bitsDamageType );
AddMultiDamage( pevAttacker, this->edict(), flDamage, bitsDamageType );

View File

@@ -308,7 +308,7 @@ void CMController :: Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_FLY;
pev->flags |= FL_FLY;
m_bloodColor = BLOOD_COLOR_GREEN;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->health = gSkillData.controllerHealth;
pev->view_ofs = Vector( 0, 0, -2 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_FULL;// indicates the width of this monster's forward view cone ( as a dotproduct result )
@@ -1185,6 +1185,8 @@ void CMControllerHeadBall :: HuntThink( void )
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit));
pMonster->TraceAttack( VARS(m_hOwner), gSkillData.controllerDmgZap, pev->velocity, &tr, DMG_SHOCK );
}
else
UTIL_TraceAttack( tr.pHit, VARS(m_hOwner), gSkillData.controllerDmgZap, pev->velocity, &tr, DMG_SHOCK );
ApplyMultiDamage( pev, VARS(m_hOwner) );
}
@@ -1361,6 +1363,8 @@ void CMControllerZapBall::ExplodeTouch( edict_t *pOther )
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
pMonster->TraceAttack(pevOwner, gSkillData.controllerDmgBall, pev->velocity.Normalize(), &tr, DMG_ENERGYBEAM );
}
else
UTIL_TraceAttack(pOther, pevOwner, gSkillData.controllerDmgBall, pev->velocity.Normalize(), &tr, DMG_ENERGYBEAM );
ApplyMultiDamage( pevOwner, pevOwner );
UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.3, ATTN_NORM, 0, RANDOM_LONG( 90, 99 ) );

View File

@@ -62,18 +62,16 @@ extern cvar_t *monster_spawn;
extern cvar_t *monster_show_deaths;
extern cvar_t *monster_show_info;
// compiler does not like util.h being included here so i'll just extern the function
extern void SENTENCEG_Init();
// Player TakeDamage and Killed
int g_DamageMsg;
bool g_DamageActive;
int g_DamageVictim;
edict_t *g_DamageAttacker[33];
int g_DamageBits[33];
bool g_PlayerKilled[33];
// DeathMsg
int g_DeathMsg;
bool g_DeathActive;
// TE_TEXTMESSAGE
float g_NextMessage[33];
@@ -138,7 +136,7 @@ monster_type_t monster_types[]=
"monster_apache", FALSE,
"monster_barney", FALSE,
"monster_bigmomma", FALSE,
"monster_bullsquid", FALSE,
"monster_bullchicken", FALSE,
"monster_alien_controller", FALSE,
"monster_human_assassin", FALSE,
"monster_headcrab", FALSE,
@@ -167,6 +165,8 @@ monster_type_t monster_types[]=
"info_node", FALSE, // Nodes
"info_node_air", FALSE,
"monstermaker", FALSE, // Extra entities
"ambient_music", FALSE,
"squadmaker", FALSE, // Aliases
"", FALSE
};
@@ -302,7 +302,7 @@ void check_monster_hurt(edict_t *pAttacker)
vecSpot = vecSrc + gpGlobals->v_forward * distance;
// trace a line ignoring enemies body...
UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, pent, &tr );
UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, pAttacker, &tr );
damage = pent->v.fuser4 - pent->v.health;
@@ -310,7 +310,7 @@ void check_monster_hurt(edict_t *pAttacker)
pent->v.health = pent->v.fuser4;
ClearMultiDamage( );
monsters[index].pMonster->TraceAttack( VARS(pAttacker), damage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, DMG_BULLET );
monsters[index].pMonster->TraceAttack( VARS(pAttacker), damage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, DMG_BULLET|DMG_NEVERGIB );
ApplyMultiDamage( VARS(pAttacker), VARS(pAttacker) );
}
@@ -404,12 +404,12 @@ void check_player_dead( edict_t *pPlayer )
}
else
{
// SOMETHING that is a monster
// Does this monster have a name?
if ( !FStringNull( pAttacker->v.netname ) )
strcpy(szName, STRING( pAttacker->v.netname ));
else
{
// No netname, use classname
// No name, use class
strcpy(szName, STRING( pAttacker->v.classname ));
}
}
@@ -429,24 +429,45 @@ void check_player_dead( edict_t *pPlayer )
// Suicide?
if ( pAttacker == pPlayer )
sprintf( szMessage, "* %s commited suicide.\n", szPlayerName );
// Player killed by another player
else if ( UTIL_IsPlayer( pAttacker ) )
{
// Get attacker name
char szAttackerName[33];
strcpy(szAttackerName, STRING(pAttacker->v.netname));
// Print a very basic death message until we can detect teamkills
sprintf( szMessage, "* %s was killed by %s.\n", szPlayerName, szAttackerName );
}
// An entity killed this player.
else if ( ENTINDEX( pAttacker ) > 0 )
{
// HLSDK: "int visibleDamageBits = m_bitsDamageType & DMG_SHOWNHUD;"
// When the game sends a "Damage" NetworkMessage, the damageBits
// gets filtered so only damages that can be shown on HUD will pass
// through, otherwise it gets neutered to DMG_GENERIC.
// This means that players will only see a few death messages
// instead of all possibilities that are written here.
// If you want to make use of all possible death messages, you
// will have to override the NetworkMessage. -Giegue
// Gather damage type and format death message
if ( g_DamageBits[ iPlayerIndex ] == DMG_GENERIC )
sprintf( szMessage, "* %s died mysteriously.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_CRUSH )
sprintf( szMessage, "* %s was smashed.\n", szPlayerName );
sprintf( szMessage, "* %s was crushed.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_BULLET )
sprintf( szMessage, "* %s was shot.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_SLASH )
sprintf( szMessage, "* %s lost its jelly.\n", szPlayerName );
sprintf( szMessage, "* %s has been chopped.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_BURN )
sprintf( szMessage, "* %s burned to death.\n", szPlayerName );
sprintf( szMessage, "* %s burned down.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_FREEZE )
sprintf( szMessage, "* %s froze to death.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_FALL )
sprintf( szMessage, "* %s broke its bones.\n", szPlayerName );
sprintf( szMessage, "* %s fell.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_BLAST )
sprintf( szMessage, "* %s blew up.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_CLUB )
@@ -456,31 +477,29 @@ void check_player_dead( edict_t *pPlayer )
else if ( g_DamageBits[ iPlayerIndex ] & DMG_SONIC )
sprintf( szMessage, "* %s ears popped.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_ENERGYBEAM )
sprintf( szMessage, "* %s saw the pretty lights.\n", szPlayerName );
sprintf( szMessage, "* %s was cut by a laser.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] == DMG_NEVERGIB )
sprintf( szMessage, "* %s had a painful death.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] == DMG_ALWAYSGIB )
sprintf( szMessage, "* %s was gibbed.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_DROWN )
sprintf( szMessage, "* %s became too drunk.\n", szPlayerName );
sprintf( szMessage, "* %s drowned.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_PARALYZE )
sprintf( szMessage, "* %s was paralyzed.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_NERVEGAS )
sprintf( szMessage, "* %s lost its brain.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_POISON )
sprintf( szMessage, "* %s had a slow death.\n", szPlayerName );
sprintf( szMessage, "* %s has been poisoned.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_RADIATION )
sprintf( szMessage, "* %s went nuclear.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_DROWNRECOVER )
sprintf( szMessage, "* %s used too much flex tape.\n", szPlayerName ); // is this type of death even possible?
else if ( g_DamageBits[ iPlayerIndex ] & DMG_ACID )
sprintf( szMessage, "* %s was melted.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_SLOWBURN )
sprintf( szMessage, "* %s became a cake.\n", szPlayerName );
sprintf( szMessage, "* %s was baked like a cake.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_SLOWFREEZE )
sprintf( szMessage, "* %s died of hypothermia.\n", szPlayerName );
else if ( g_DamageBits[ iPlayerIndex ] & DMG_MORTAR )
sprintf( szMessage, "* %s blew its missile pet.\n", szPlayerName );
sprintf( szMessage, "* %s was killed by a Mortar Shell.\n", szPlayerName );
else // other mods could have more DMG_ variants that aren't registered here.
sprintf( szMessage, "* %s deadly died.\n", szPlayerName );
}
@@ -533,8 +552,8 @@ void check_monster_info( edict_t *pPlayer )
// It should be alive
if ( UTIL_IsAlive( tr.pHit ) )
{
// Must be a monster
if (tr.pHit->v.flags & FL_MONSTER)
// Must be a monster (and strictly a monster!)
if (strncmp( STRING( tr.pHit->v.classname ), "monster_", 8 ) == 0 && tr.pHit->v.flags & FL_MONSTER)
{
char szName[129];
float monsterHealth, monsterFrags;
@@ -691,6 +710,7 @@ edict_t* spawn_monster(int monster_type, Vector origin, Vector angles, int spawn
case 29: monsters[monster_index].pMonster = CreateClassPtr((CMStukabat *)NULL); break;
// Extra entities
case 32: monsters[monster_index].pMonster = CreateClassPtr((CMMonsterMaker *)NULL); break;
case 33: monsters[monster_index].pMonster = CreateClassPtr((CMAmbientMusic *)NULL); break;
}
if (monsters[monster_index].pMonster == NULL)
@@ -708,6 +728,9 @@ edict_t* spawn_monster(int monster_type, Vector origin, Vector angles, int spawn
monster_pent->v.origin = origin;
monster_pent->v.angles = angles;
// Pass spawnflags first if no keyvalue data exists for it
monster_pent->v.spawnflags = spawnflags;
// Keyvalue data
if (keyvalue != NULL)
{
@@ -722,8 +745,6 @@ edict_t* spawn_monster(int monster_type, Vector origin, Vector angles, int spawn
}
}
monster_pent->v.spawnflags = spawnflags;
monsters[monster_index].pMonster->Spawn();
// Only modify starting spawnflags for monsters, not for entities!
@@ -772,13 +793,12 @@ void check_respawn(void)
if (spawn_monster(monster_type, origin, angles, spawnflags, keyvalue) == NULL)
{
// spawn_monster failed
ALERT( at_error, "Failed to spawn %s at origin %f %f %f\n", monster_types[monster_type].name, origin.x, origin.y, origin.z );
ALERT( at_error, "[MONSTER] Failed to spawn %s at origin %f %f %f\n", monster_types[monster_type].name, origin.x, origin.y, origin.z );
}
}
}
}
DLL_GLOBAL short g_sModelIndexFireball;// holds the index for the fireball
DLL_GLOBAL short g_sModelIndexSmoke;// holds the index for the smoke cloud
DLL_GLOBAL short g_sModelIndexTinySpit;// holds the index for the spore grenade explosion
@@ -790,20 +810,25 @@ DLL_GLOBAL short g_sModelIndexLaser;// holds the index for the laser beam
DLL_GLOBAL const char *g_pModelNameLaser = "sprites/laserbeam.spr";
DLL_GLOBAL short g_sModelIndexLaserDot;// holds the index for the laser beam dot
// globals.cpp
DLL_GLOBAL const Vector g_vecZero = Vector(0, 0, 0); // null vector
DLL_GLOBAL Vector g_vecAttackDir; // attack direction
void world_precache(void)
{
g_sModelIndexFireball = PRECACHE_MODEL ("sprites/zerogxplode.spr");// fireball
g_sModelIndexSmoke = PRECACHE_MODEL ("sprites/steam1.spr");// smoke
g_sModelIndexTinySpit = PRECACHE_MODEL ("sprites/tinyspit.spr");// spore
g_sModelIndexWExplosion = PRECACHE_MODEL ("sprites/WXplo1.spr");// underwater fireball
g_sModelIndexBubbles = PRECACHE_MODEL ("sprites/bubble.spr");//bubbles
g_sModelIndexBloodSpray = PRECACHE_MODEL ("sprites/bloodspray.spr"); // initial blood
g_sModelIndexBloodDrop = PRECACHE_MODEL ("sprites/blood.spr"); // splattered blood
g_sModelIndexFireball = PRECACHE_MODELINDEX("sprites/zerogxplode.spr");// fireball
g_sModelIndexSmoke = PRECACHE_MODELINDEX("sprites/steam1.spr");// smoke
g_sModelIndexTinySpit = PRECACHE_MODELINDEX("sprites/tinyspit.spr");// spore
g_sModelIndexWExplosion = PRECACHE_MODELINDEX("sprites/WXplo1.spr");// underwater fireball
g_sModelIndexBubbles = PRECACHE_MODELINDEX("sprites/bubble.spr");//bubbles
g_sModelIndexBloodSpray = PRECACHE_MODELINDEX("sprites/bloodspray.spr"); // initial blood
g_sModelIndexBloodDrop = PRECACHE_MODELINDEX("sprites/blood.spr"); // splattered blood
g_sModelIndexLaser = PRECACHE_MODEL( (char *)g_pModelNameLaser );
g_sModelIndexLaserDot = PRECACHE_MODEL("sprites/laserdot.spr");
g_sModelIndexLaser = PRECACHE_MODELINDEX( (char *)g_pModelNameLaser );
g_sModelIndexLaserDot = PRECACHE_MODELINDEX("sprites/laserdot.spr");
PRECACHE_MODEL ("models/w_grenade.mdl");
PRECACHE_MODEL("models/w_grenade.mdl");
}
void MonsterCommand(void)
@@ -1237,10 +1262,11 @@ int mmDispatchSpawn( edict_t *pent )
}
// free any allocated keyvalue memory
for (index = 0; index < monster_spawn_count; index++)
for (index = 0; index < MAX_MONSTERS; index++)
{
if (monster_spawnpoint[index].keyvalue)
if (monster_spawnpoint[index].keyvalue != NULL)
free(monster_spawnpoint[index].keyvalue);
monster_spawnpoint[index].keyvalue = NULL;
}
// do level initialization stuff here...
@@ -1248,7 +1274,9 @@ int mmDispatchSpawn( edict_t *pent )
for (index = 0; monster_types[index].name[0]; index++)
monster_types[index].need_to_precache = FALSE;
world_precache();
CVAR_SET_STRING("monster_gmr", "");
CVAR_SET_STRING("monster_gsr", "");
REPLACER::Init();
monster_spawn_count = 0;
node_spawn_count = 0;
@@ -1259,6 +1287,10 @@ int mmDispatchSpawn( edict_t *pent )
process_monster_cfg();
// precache last in the event of a GMR being present
world_precache();
SENTENCEG_Init();
// node support. -Giegue
// init the WorldGraph.
WorldGraph.InitGraph();
@@ -1323,6 +1355,46 @@ void mmDispatchTouch( edict_t *pentTouched, edict_t *pentOther )
RETURN_META(MRES_IGNORED);
}
// pfnUse has been deprecated so the only way to trigger a monstermod
// entity from the outside is to do it manually. ARRGHH! -Giegue
void mmDispatchUse( void )
{
if ( CMD_ARGC() >= 6 ) // the command itself is an argument, we need 5. so argc == 6
{
edict_t *entity = INDEXENT( atoi( CMD_ARGV( 1 ) ) );
edict_t *caller = INDEXENT( atoi( CMD_ARGV( 2 ) ) );
edict_t *activator = INDEXENT( atoi( CMD_ARGV( 3 ) ) );
USE_TYPE useType = USE_TYPE( atoi( CMD_ARGV( 4 ) ) );
float flValue = atof( CMD_ARGV( 5 ) );
// nevermind the unoptimization that this brings... >C
for (int index=0; index < monster_ents_used; index++)
{
if ((entity != NULL) && (entity == monsters[index].monster_pent))
{
if ( FNullEnt( caller ) ) caller = NULL;
if ( FNullEnt( activator ) ) activator = NULL;
monsters[index].pMonster->Use( activator, caller, useType, flValue );
return;
}
}
}
}
void mmDispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd )
{
for (int index=0; index < monster_ents_used; index++)
{
if ((pentKeyvalue != NULL) && (pentKeyvalue == monsters[index].monster_pent))
{
monsters[index].pMonster->KeyValue( pkvd );
RETURN_META(MRES_SUPERCEDE);
}
}
RETURN_META(MRES_IGNORED);
}
void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
{
@@ -1362,11 +1434,13 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
// Extra entities
CMMonsterMaker monstermaker; // 32
CMAmbientMusic ambientmusic;
g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" );
(g_engfuncs.pfnAddServerCommand)("monster", MonsterCommand);
(g_engfuncs.pfnAddServerCommand)("node_viewer", SpawnViewerCommand);
(g_engfuncs.pfnAddServerCommand)("_use", mmDispatchUse);
for (index = 0; monster_types[index].name[0]; index++)
{
@@ -1410,6 +1484,7 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
case 28: rgrunt.Precache(); break;
case 29: stukabat.Precache(); break;
case 32: monstermaker.Precache(); break;
//case 33: ambientmusic.Precache(); break;
}
}
}
@@ -1424,7 +1499,6 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
for (index = 0; index < 33; index++)
{
g_DamageAttacker[index] = NULL;
g_DamageBits[index] = 0;
g_PlayerKilled[index] = false;
g_NextMessage[index] = 0.0;
@@ -1514,22 +1588,34 @@ void mmStartFrame( void )
RETURN_META(MRES_IGNORED);
}
void mmClientKill( edict_t *pPlayer )
void mmClientKill_Post( edict_t *pPlayer )
{
// Just to let the system know the player commited suicide
// Show "commited suicide" message
pPlayer->v.dmg_inflictor = pPlayer;
check_player_dead( pPlayer );
RETURN_META(MRES_IGNORED);
}
BOOL mmClientConnect( edict_t *pPlayer, const char *pszName, const char *pszAddress, char *szRejectReason )
{
// stop any ambient_music that is playing
MESSAGE_BEGIN(MSG_ONE, SVC_STUFFTEXT, NULL, pPlayer);
WRITE_STRING("mp3 stop\n");
MESSAGE_END();
RETURN_META_VALUE( MRES_IGNORED, TRUE );
}
static DLL_FUNCTIONS gFunctionTable =
{
mmGameDLLInit, //! pfnGameInit() Initialize the game (one-time call after loading of game .dll)
mmDispatchSpawn, //! pfnSpawn()
mmDispatchThink, //! pfnThink
NULL, // pfnUse
NULL, // pfnUse [DEPRECATED]
mmDispatchTouch, //! pfnTouch
NULL, // pfnBlocked
NULL, // pfnKeyValue
mmDispatchKeyValue, //! pfnKeyValue
NULL, // pfnSave
NULL, // pfnRestore
NULL, // pfnSetAbsBox
@@ -1541,9 +1627,9 @@ static DLL_FUNCTIONS gFunctionTable =
NULL, // pfnRestoreGlobalState
NULL, // pfnResetGlobalState
NULL, // pfnClientConnect
mmClientConnect, //! pfnClientConnect
NULL, // pfnClientDisconnect
mmClientKill, //! pfnClientKill
NULL, // pfnClientKill
NULL, // pfnClientPutInServer
NULL, // pfnClientCommand
NULL, // pfnClientUserInfoChanged
@@ -1615,7 +1701,7 @@ void mmPlayerPostThink_Post( edict_t *pEntity )
{
check_monster_hurt(pEntity);
check_monster_dead(pEntity);
check_player_dead(pEntity);
//check_player_dead(pEntity); // too early for damageBits
check_monster_info(pEntity);
RETURN_META(MRES_IGNORED);
@@ -1626,7 +1712,7 @@ static DLL_FUNCTIONS gFunctionTable_Post =
NULL, // pfnGameInit() Initialize the game (one-time call after loading of game .dll)
NULL, // pfnSpawn()
mmDispatchThink_Post, //! pfnThink
NULL, // pfnUse
NULL, // pfnUse [DEPRECATED]
NULL, // pfnTouch
NULL, // pfnBlocked
NULL, // pfnKeyValue
@@ -1643,7 +1729,7 @@ static DLL_FUNCTIONS gFunctionTable_Post =
NULL, // pfnClientConnect
NULL, // pfnClientDisconnect
NULL, // pfnClientKill
mmClientKill_Post, //! pfnClientKill
NULL, // pfnClientPutInServer
NULL, // pfnClientCommand
NULL, // pfnClientUserInfoChanged
@@ -1720,8 +1806,6 @@ int mmRegUserMsg_Post( const char *pName, int iSize )
if ( strcmp( pName, "Damage" ) == 0 )
g_DamageMsg = META_RESULT_ORIG_RET( int ) - cs_server;
else if ( strcmp( pName, "DeathMsg" ) == 0 )
g_DeathMsg = META_RESULT_ORIG_RET( int );// - cs_server;
RETURN_META_VALUE( MRES_IGNORED, 0 );
}
@@ -1735,14 +1819,8 @@ void mmMessageBegin_Post( int msg_dest, int msg_type, const float *pOrigin, edic
{
g_DamageActive = true;
g_DamageVictim = ENTINDEX( ed );
g_DamageAttacker[ g_DamageVictim ] = ed->v.dmg_inflictor;
}
}
else if ( msg_type == g_DeathMsg )
{
// Prepare to update deathmsg
g_DeathActive = true;
}
RETURN_META( MRES_IGNORED );
}
@@ -1755,35 +1833,17 @@ void mmWriteLong_Post( int iValue )
RETURN_META( MRES_IGNORED );
}
// This cannot be done on post!
void mmWriteString( const char *szValue )
{
if ( g_DeathActive )
{
// Prevent recursion
g_DeathActive = false;
// Ensure whatever killed the player is a valid entity
if (g_DamageAttacker[ g_DamageVictim ] != NULL)
{
// Send a new WriteString with the killer's classname
WRITE_STRING( STRING( g_DamageAttacker[ g_DamageVictim ]->v.classname ) );
// Supercede the old message
RETURN_META( MRES_SUPERCEDE );
}
}
RETURN_META( MRES_IGNORED );
}
void mmMessageEnd_Post( void )
{
if ( g_DamageActive )
{
check_player_dead( INDEXENT( g_DamageVictim ) );
}
g_DamageActive = false;
RETURN_META( MRES_IGNORED );
}
/*
enginefuncs_t meta_engfuncs =
{
NULL, // pfnPrecacheModel()
@@ -1853,7 +1913,7 @@ enginefuncs_t meta_engfuncs =
NULL, // pfnWriteLong()
NULL, // pfnWriteAngle()
NULL, // pfnWriteCoord()
mmWriteString, //! pfnWriteString()
NULL, // pfnWriteString()
NULL, // pfnWriteEntity()
NULL, // pfnCVarRegister()
@@ -2007,7 +2067,7 @@ C_DLLEXPORT int GetEngineFunctions(enginefuncs_t *pengfuncsFromEngine, int *inte
memcpy(pengfuncsFromEngine, &meta_engfuncs, sizeof(enginefuncs_t));
return TRUE;
}
*/
enginefuncs_t meta_engfuncs_post =
{
NULL, // pfnPrecacheModel()

View File

@@ -114,7 +114,7 @@ void CMBeam::BeamInit( const char *pSpriteName, int width )
SetFrame( 0 );
SetScrollRate( 0 );
pev->model = MAKE_STRING( pSpriteName );
SetTexture( PRECACHE_MODEL( (char *)pSpriteName ) );
SetTexture( PRECACHE_MODELINDEX( (char *)pSpriteName ) );
SetWidth( width );
pev->skin = 0;
pev->sequence = 0;

View File

@@ -23,10 +23,10 @@ extern enginefuncs_t g_engfuncs;
// The actual engine callbacks
#define GETPLAYERUSERID (*g_engfuncs.pfnGetPlayerUserId)
#define PRECACHE_MODEL (*g_engfuncs.pfnPrecacheModel)
#define PRECACHE_SOUND (*g_engfuncs.pfnPrecacheSound)
#define PRECACHE_MODEL2 (*g_engfuncs.pfnPrecacheModel)
#define PRECACHE_SOUND2 (*g_engfuncs.pfnPrecacheSound)
#define PRECACHE_GENERIC (*g_engfuncs.pfnPrecacheGeneric)
#define SET_MODEL (*g_engfuncs.pfnSetModel)
#define SET_MODEL2 (*g_engfuncs.pfnSetModel)
#define MODEL_INDEX (*g_engfuncs.pfnModelIndex)
#define MODEL_FRAMES (*g_engfuncs.pfnModelFrames)
#define SET_SIZE (*g_engfuncs.pfnSetSize)

View File

@@ -54,7 +54,7 @@ void CMShower::Spawn( void )
pev->speed = RANDOM_FLOAT( 0.5, 1.5 );
pev->angles = g_vecZero;
pev->classname = MAKE_STRING( "_spark_shower" );
pev->classname = MAKE_STRING( "spark_shower" );
}
@@ -172,7 +172,7 @@ void CMEnvExplosion::Spawn( void )
}
m_spriteScale = (int)flSpriteScale;
pev->classname = MAKE_STRING( "_env_explosion" );
pev->classname = MAKE_STRING( "env_explosion" );
}
void CMEnvExplosion::DelayUse( void )

View File

@@ -26,12 +26,15 @@
#endif
// Silence certain warnings
// PS: All warnings to be silenced until T5 milestone. -Giegue
#pragma warning(disable : 4244) // int or float down-conversion
#pragma warning(disable : 4305) // int or float data truncation
#pragma warning(disable : 4201) // nameless struct/union
#pragma warning(disable : 4514) // unreferenced inline function removed
#pragma warning(disable : 4100) // unreferenced formal parameter
#pragma warning(disable : 4390) // empty controlled statement (seems to work fine? monster_api.cpp[101/115])
#pragma warning(disable : 4091) // nameless typedef
#pragma warning(disable : 4996) // unsafe string operations
// Prevent tons of unused windows definitions
#ifdef _WIN32

View File

@@ -130,13 +130,23 @@ void CStomp::Think( void )
if ( tr.pHit && tr.pHit != pev->owner )
{
CMBaseEntity *pEntity = CMBaseEntity::Instance( tr.pHit );
edict_t *pEntity = tr.pHit;
entvars_t *pevOwner = pev;
if ( pev->owner )
pevOwner = VARS(pev->owner);
if ( pEntity )
pEntity->TakeDamage( pev, pevOwner, pev->dmg, DMG_SONIC );
if (pEntity->v.takedamage)
{
if (UTIL_IsPlayer(pEntity))
UTIL_TakeDamage(pEntity, pev, pevOwner, pev->dmg, DMG_SONIC);
else if (pEntity->v.euser4 != NULL)
{
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
pMonster->TakeDamage(pev, pevOwner, pev->dmg, DMG_SONIC);
}
else
UTIL_TakeDamageExternal(pEntity, pev, pevOwner, pev->dmg, DMG_SONIC);
}
}
// Accelerate the effect
@@ -564,6 +574,8 @@ void CMGargantua :: FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevI
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
pMonster->TraceAttack( pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize(), &tr, bitsDamageType );
}
else
UTIL_TraceAttack( pEntity, pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize(), &tr, bitsDamageType );
ApplyMultiDamage( pevInflictor, pevAttacker );
}
else
@@ -575,6 +587,8 @@ void CMGargantua :: FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevI
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
pMonster->TakeDamage( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType );
}
else
UTIL_TakeDamageExternal( pEntity, pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType );
}
}
}
@@ -669,7 +683,7 @@ void CMGargantua :: Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->health = gSkillData.gargantuaHealth;
//pev->view_ofs = Vector ( 0, 0, 96 );// taken from mdl file
m_flFieldOfView = -0.2;// width of forward view cone ( as a dotproduct result )
@@ -698,48 +712,25 @@ void CMGargantua :: Spawn()
//=========================================================
void CMGargantua :: Precache()
{
int i;
PRECACHE_MODEL("models/garg.mdl");
PRECACHE_MODEL( GARG_EYE_SPRITE_NAME );
PRECACHE_MODEL( GARG_BEAM_SPRITE_NAME );
PRECACHE_MODEL( GARG_BEAM_SPRITE2 );
gStompSprite = PRECACHE_MODEL( GARG_STOMP_SPRITE_NAME );
gGargGibModel = PRECACHE_MODEL( GARG_GIB_MODEL );
gStompSprite = PRECACHE_MODELINDEX( GARG_STOMP_SPRITE_NAME );
gGargGibModel = PRECACHE_MODELINDEX( GARG_GIB_MODEL );
PRECACHE_SOUND( GARG_STOMP_BUZZ_SOUND );
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
PRECACHE_SOUND((char *)pAttackHitSounds[i]);
for ( i = 0; i < ARRAYSIZE( pBeamAttackSounds ); i++ )
PRECACHE_SOUND((char *)pBeamAttackSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
PRECACHE_SOUND((char *)pAttackMissSounds[i]);
for ( i = 0; i < ARRAYSIZE( pRicSounds ); i++ )
PRECACHE_SOUND((char *)pRicSounds[i]);
for ( i = 0; i < ARRAYSIZE( pFootSounds ); i++ )
PRECACHE_SOUND((char *)pFootSounds[i]);
for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ )
PRECACHE_SOUND((char *)pIdleSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ )
PRECACHE_SOUND((char *)pAlertSounds[i]);
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
PRECACHE_SOUND((char *)pPainSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ )
PRECACHE_SOUND((char *)pAttackSounds[i]);
for ( i = 0; i < ARRAYSIZE( pStompSounds ); i++ )
PRECACHE_SOUND((char *)pStompSounds[i]);
for ( i = 0; i < ARRAYSIZE( pBreatheSounds ); i++ )
PRECACHE_SOUND((char *)pBreatheSounds[i]);
PRECACHE_SOUND_ARRAY(pAttackHitSounds);
PRECACHE_SOUND_ARRAY(pBeamAttackSounds);
PRECACHE_SOUND_ARRAY(pAttackMissSounds);
PRECACHE_SOUND_ARRAY(pRicSounds);
PRECACHE_SOUND_ARRAY(pFootSounds);
PRECACHE_SOUND_ARRAY(pIdleSounds);
PRECACHE_SOUND_ARRAY(pAlertSounds);
PRECACHE_SOUND_ARRAY(pPainSounds);
PRECACHE_SOUND_ARRAY(pAttackSounds);
PRECACHE_SOUND_ARRAY(pStompSounds);
PRECACHE_SOUND_ARRAY(pBreatheSounds);
}
@@ -824,9 +815,12 @@ void CMGargantua::DeathEffect( void )
void CMGargantua::Killed( entvars_t *pevAttacker, int iGib )
{
EyeOff();
UTIL_Remove( m_pEyeGlow->edict() );
m_pEyeGlow = NULL;
if ( m_pEyeGlow )
{
EyeOff();
UTIL_Remove( m_pEyeGlow->edict() );
m_pEyeGlow = NULL;
}
CMBaseMonster::Killed( pevAttacker, GIB_NEVER );
}
@@ -976,6 +970,8 @@ edict_t *CMGargantua::GargantuaCheckTraceHullAttack(float flDist, int iDamage, i
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit));
pMonster->TakeDamage( pev, pev, iDamage, iDmgType );
}
else
UTIL_TakeDamageExternal( tr.pHit, pev, pev, iDamage, iDmgType );
}
return tr.pHit;
@@ -1332,7 +1328,7 @@ void CMBabyGargantua::Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->health = gSkillData.babygargHealth;
//pev->view_ofs = Vector ( 0, 0, 96 );// taken from mdl file
m_flFieldOfView = -0.2;// width of forward view cone ( as a dotproduct result )
@@ -1363,51 +1359,26 @@ void CMBabyGargantua::Spawn()
//=========================================================
void CMBabyGargantua::Precache()
{
int i;
PRECACHE_MODEL("models/babygarg.mdl");
PRECACHE_MODEL( GARG_EYE_SPRITE_NAME );
PRECACHE_MODEL( GARG_BEAM_SPRITE_NAME );
PRECACHE_MODEL( GARG_BEAM_SPRITE2 );
gStompSprite = PRECACHE_MODEL( GARG_STOMP_SPRITE_NAME );
gGargGibModel = PRECACHE_MODEL( GARG_GIB_MODEL );
gStompSprite = PRECACHE_MODELINDEX( GARG_STOMP_SPRITE_NAME );
gGargGibModel = PRECACHE_MODELINDEX( GARG_GIB_MODEL );
PRECACHE_SOUND( GARG_STOMP_BUZZ_SOUND );
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
PRECACHE_SOUND((char *)pAttackHitSounds[i]);
for ( i = 0; i < ARRAYSIZE( pBeamAttackSounds ); i++ )
PRECACHE_SOUND((char *)pBeamAttackSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
PRECACHE_SOUND((char *)pAttackMissSounds[i]);
for ( i = 0; i < ARRAYSIZE( pRicSounds ); i++ )
PRECACHE_SOUND((char *)pRicSounds[i]);
for ( i = 0; i < ARRAYSIZE( pFootSounds ); i++ )
PRECACHE_SOUND((char *)pFootSounds[i]);
for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ )
PRECACHE_SOUND((char *)pIdleSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ )
PRECACHE_SOUND((char *)pAlertSounds[i]);
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
PRECACHE_SOUND((char *)pPainSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ )
PRECACHE_SOUND((char *)pAttackSounds[i]);
for ( i = 0; i < ARRAYSIZE( pStompSounds ); i++ )
PRECACHE_SOUND((char *)pStompSounds[i]);
for ( i = 0; i < ARRAYSIZE( pBreatheSounds ); i++ )
PRECACHE_SOUND((char *)pBreatheSounds[i]);
for ( i = 0; i < ARRAYSIZE( pDieSounds ); i++ )
PRECACHE_SOUND((char *)pDieSounds[i]);
PRECACHE_SOUND_ARRAY(pAttackHitSounds);
PRECACHE_SOUND_ARRAY(pBeamAttackSounds);
PRECACHE_SOUND_ARRAY(pAttackMissSounds);
PRECACHE_SOUND_ARRAY(pRicSounds);
PRECACHE_SOUND_ARRAY(pFootSounds);
PRECACHE_SOUND_ARRAY(pIdleSounds);
PRECACHE_SOUND_ARRAY(pAlertSounds);
PRECACHE_SOUND_ARRAY(pPainSounds);
PRECACHE_SOUND_ARRAY(pAttackSounds);
PRECACHE_SOUND_ARRAY(pStompSounds);
PRECACHE_SOUND_ARRAY(pBreatheSounds);
PRECACHE_SOUND_ARRAY(pDieSounds);
}
void CMBabyGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
@@ -1791,6 +1762,8 @@ edict_t *CMBabyGargantua::BabyGargCheckTraceHullAttack(float flDist, int iDamage
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(tr.pHit));
pMonster->TakeDamage( pev, pev, iDamage, iDmgType );
}
else
UTIL_TakeDamageExternal( tr.pHit, pev, pev, iDamage, iDmgType );
}
return tr.pHit;

View File

@@ -48,6 +48,10 @@ void CMGrenade::Explode( Vector vecSrc, Vector vecAim )
// UNDONE: temporary scorching for PreAlpha - find a less sleazy permenant solution.
void CMGrenade::Explode( TraceResult *pTrace, int bitsDamageType )
{
// CRITICAL - always ensure owner of grenade is valid
if (m_hOwner == NULL)
pev->owner = NULL;
float flRndSound;// sound randomizer
pev->model = iStringNull;//invisible
@@ -227,13 +231,15 @@ void CMGrenade::BounceTouch( edict_t *pOther )
TraceResult tr = UTIL_GetGlobalTrace( );
ClearMultiDamage( );
if (UTIL_IsPlayer(pOther))
UTIL_TraceAttack(pOther, pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB );
else if (pOther->v.euser4 != NULL)
{
if (UTIL_IsPlayer(pOther))
UTIL_TraceAttack(pOther, pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB );
else if (pOther->v.euser4 != NULL)
{
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
pMonster->TraceAttack(pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB );
}
pMonster->TraceAttack(pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB );
}
else
UTIL_TraceAttack(pOther, pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB); // lmao
ApplyMultiDamage( pev, pevOwner);
}
@@ -277,7 +283,6 @@ void CMGrenade::BounceTouch( edict_t *pOther )
pev->framerate = 1;
else if (pev->framerate < 0.5)
pev->framerate = 0;
}
@@ -308,6 +313,10 @@ void CMGrenade::SlideTouch( edict_t *pOther )
void CMGrenade :: BounceSound( void )
{
// CRITICAL - always ensure owner of grenade is valid
if (m_hOwner == NULL)
pev->owner = NULL;
switch ( RANDOM_LONG( 0, 2 ) )
{
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/grenade_hit1.wav", 0.25, ATTN_NORM); break;
@@ -368,7 +377,8 @@ CMGrenade *CMGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector
pGrenade->pev->velocity = vecVelocity;
pGrenade->pev->angles = UTIL_VecToAngles (pGrenade->pev->velocity);
pGrenade->pev->owner = ENT(pevOwner);
pGrenade->m_hOwner = ENT(pevOwner);
// make monsters afaid of it while in the air
pGrenade->SetThink( &CMGrenade::DangerSoundThink );
pGrenade->pev->nextthink = gpGlobals->time;
@@ -397,7 +407,8 @@ CMGrenade * CMGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector
pGrenade->pev->velocity = vecVelocity;
pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity);
pGrenade->pev->owner = ENT(pevOwner);
pGrenade->m_hOwner = ENT(pevOwner);
pGrenade->SetTouch( &CMGrenade::BounceTouch ); // Bounce if touched
// Take one second off of the desired detonation time and set the think to PreDetonate. PreDetonate
@@ -450,7 +461,8 @@ CMGrenade * CMGrenade :: ShootSatchelCharge( entvars_t *pevOwner, Vector vecStar
pGrenade->pev->velocity = vecVelocity;
pGrenade->pev->angles = g_vecZero;
pGrenade->pev->owner = ENT(pevOwner);
pGrenade->m_hOwner = ENT(pevOwner);
// Detonate in "time" seconds
pGrenade->SetThink( &CMGrenade::SUB_DoNothing );
pGrenade->SetUse( &CMGrenade::DetonateUse );

164
src/dlls/globalreplace.cpp Normal file
View File

@@ -0,0 +1,164 @@
//=========================================================
// Global Replacement:
// Tool to replace all default models/sounds with a
// customized list.
//=========================================================
#include "extdll.h"
#include "dllapi.h"
#include "meta_api.h"
#include "cmbase.h"
#include "cmbasemonster.h"
namespace REPLACER
{
REPLACER *GMR;
REPLACER *GSR;
int numModels;
int numSounds;
void Init(void)
{
if ( GMR != NULL )
{
free( GMR );
GMR = NULL;
}
if ( GSR != NULL )
{
free( GSR );
GSR = NULL;
}
numModels = 0;
numSounds = 0;
}
bool AddGlobalModel(const char *from, const char *to)
{
if (numModels < MAX_REPLACEMENTS)
{
// allocate for the first time
if (!numModels)
GMR = (REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*GMR));
strcpy(GMR[numModels].source, from);
strcpy(GMR[numModels].destination, to);
numModels++;
return true;
}
LOG_MESSAGE(PLID, "Can't replace model '%s', too many models in GMR.", from);
return false;
}
bool AddGlobalSound(const char *from, const char *to)
{
if (numSounds < MAX_REPLACEMENTS)
{
// allocate for the first time
if (!numSounds)
GSR = (REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*GSR));
strcpy(GSR[numSounds].source, from);
strcpy(GSR[numSounds].destination, to);
numSounds++;
return true;
}
LOG_MESSAGE(PLID, "Can't replace sound '%s', too many sounds in GSR.", from);
return false;
}
bool AddIndividualSound(edict_t *pMonster, const char *from, const char *to)
{
CMBaseMonster *castMonster = GetClassPtr((CMBaseMonster *)VARS(pMonster));
if ( castMonster == NULL )
return false;
int m_iSounds = castMonster->m_isrSounds;
if (m_iSounds < MAX_REPLACEMENTS)
{
// allocate for the first time
if (!m_iSounds)
castMonster->m_srSoundList = (REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*castMonster->m_srSoundList));
strcpy(castMonster->m_srSoundList[m_iSounds].source, from);
strcpy(castMonster->m_srSoundList[m_iSounds].destination, to);
castMonster->m_isrSounds++;
return true;
}
LOG_MESSAGE(PLID, "Can't replace sound '%s', too many sounds in list.", from);
return false;
}
const char* FindModelReplacement( edict_t *pMonster, const char *from )
{
// Individually set models takes priority!
if (UTIL_IsValidEntity(pMonster) && !FStringNull(pMonster->v.model))
return STRING(pMonster->v.model);
// Find the model
for (int model = 0; model < numModels; model++)
{
if (strcmp(GMR[model].source, from) == 0)
{
// If found, use that model instead
return GMR[model].destination;
}
}
// Nothing found, stick with default
return from;
}
const char* FindSoundReplacement( edict_t *pMonster, const char *from )
{
// Individually set sounds takes priority!
if (UTIL_IsValidEntity(pMonster))
{
CMBaseMonster *castMonster = NULL;
// Check if this is really a monster or not
if (pMonster->v.flags & FL_MONSTER)
castMonster = GetClassPtr((CMBaseMonster *)VARS(pMonster));
else
{
// This is probably a monster-owned projectile of sorts
if (UTIL_IsValidEntity(pMonster->v.owner))
castMonster = GetClassPtr((CMBaseMonster *)VARS(pMonster->v.owner));
}
// If still no valid BaseMonster pointer, full stop, use GSR.
if (castMonster != NULL && castMonster->m_srSoundList != NULL && castMonster->m_isrSounds > 0)
{
for (int sound = 0; sound < castMonster->m_isrSounds; sound++)
{
if (strcmp(castMonster->m_srSoundList[sound].source, from) == 0)
{
// If found, use it
return castMonster->m_srSoundList[sound].destination;
}
}
// If nothing is found stick to GSR if available
}
}
for (int sound = 0; sound < numSounds; sound++)
{
if (strcmp(GSR[sound].source, from) == 0)
{
// If found, use that sound instead
return GSR[sound].destination;
}
}
// Nothing found, stick with default
return from;
}
}

26
src/dlls/globalreplace.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef GLOBALREPLACE_H
#define GLOBALREPLACE_H
#define MAX_REPLACEMENTS 255
namespace REPLACER
{
typedef struct
{
char source[128];
char destination[128];
} REPLACER;
void Init(void);
bool AddGlobalModel(const char *from, const char *to);
bool AddGlobalSound(const char *from, const char *to);
bool AddIndividualSound(edict_t *pMonster, const char *from, const char *to);
const char* FindModelReplacement( edict_t *pMonster, const char *from );
inline const char* FindModelReplacement( const char *from ) { return FindModelReplacement( NULL, from ); }
const char* FindSoundReplacement( edict_t *pMonster, const char *from );
inline const char* FindSoundReplacement( const char *from ) { return FindSoundReplacement( NULL, from ); }
}
#endif

View File

@@ -134,12 +134,14 @@ void CGonomeGuts :: GutsTouch( edict_t *pOther )
else
{
if (UTIL_IsPlayer(pOther))
UTIL_TakeDamage( pOther, pev, pev, gSkillData.gonomeDmgGuts, DMG_GENERIC );
UTIL_TakeDamage( pOther, pev, VARS(pev->owner), gSkillData.gonomeDmgGuts, DMG_GENERIC );
else if (pOther->v.euser4 != NULL)
{
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
pMonster->TakeDamage ( pev, pev, gSkillData.gonomeDmgGuts, DMG_GENERIC );
pMonster->TakeDamage ( pev, VARS(pev->owner), gSkillData.gonomeDmgGuts, DMG_GENERIC );
}
else
UTIL_TakeDamageExternal( pOther, pev, VARS(pev->owner), gSkillData.gonomeDmgGuts, DMG_GENERIC );
}
SetThink( &CGonomeGuts::SUB_Remove );
@@ -349,16 +351,6 @@ int CMGonome::Classify(void)
//=========================================================
int CMGonome::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType)
{
// Take 15% damage from bullets
if( bitsDamageType == DMG_BULLET )
{
Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5;
vecDir = vecDir.Normalize();
float flForce = DamageForce( flDamage );
pev->velocity = pev->velocity + vecDir * flForce;
flDamage *= 0.15;
}
// HACK HACK -- until we fix this.
if( IsAlive() )
PainSound();
@@ -621,7 +613,7 @@ void CMGonome::Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0;
pev->health = gSkillData.gonomeHealth;
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )

View File

@@ -220,7 +220,7 @@ void CMHAssassin :: Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
pev->effects = 0;
pev->health = gSkillData.hassassinHealth;
m_flFieldOfView = VIEW_FIELD_WIDE; // indicates the width of this monster's forward view cone ( as a dotproduct result )
@@ -256,7 +256,7 @@ void CMHAssassin :: Precache()
PRECACHE_SOUND("debris/beamstart1.wav");
m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell
m_iShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell
}

View File

@@ -252,7 +252,7 @@ void CMHeadCrab :: Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0;
pev->health = gSkillData.headcrabHealth;
pev->view_ofs = Vector ( 0, 0, 20 );// position of the eyes relative to monster's origin.

View File

@@ -163,7 +163,7 @@ void CMHGrunt :: SpeakSentence( void )
if (FOkToSpeak())
{
SENTENCEG_PlayRndSz( ENT(pev), pGruntSentences[ m_iSentence ], HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
SENTENCEG_PlayRndSz( ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? pGruntSentences[ m_iSentence ] : CMRGrunt::pRobotSentences[ m_iSentence ], HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
JustSpoke();
}
}
@@ -546,21 +546,22 @@ void CMHGrunt :: IdleSound( void )
{
if (FOkToSpeak() && (g_fGruntQuestion || RANDOM_LONG(0,1)))
{
// there has to be a better way than spamming ternary operators... -Giegue
if (!g_fGruntQuestion)
{
// ask question or make statement
switch (RANDOM_LONG(0,2))
{
case 0: // check in
SENTENCEG_PlayRndSz(ENT(pev), "HG_CHECK", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
SENTENCEG_PlayRndSz(ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_CHECK" : "RB_CHECK", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
g_fGruntQuestion = 1;
break;
case 1: // question
SENTENCEG_PlayRndSz(ENT(pev), "HG_QUEST", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
SENTENCEG_PlayRndSz(ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_QUEST" : "RB_QUEST", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
g_fGruntQuestion = 2;
break;
case 2: // statement
SENTENCEG_PlayRndSz(ENT(pev), "HG_IDLE", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
SENTENCEG_PlayRndSz(ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_IDLE" : "RB_IDLE", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
break;
}
}
@@ -569,10 +570,10 @@ void CMHGrunt :: IdleSound( void )
switch (g_fGruntQuestion)
{
case 1: // check in
SENTENCEG_PlayRndSz(ENT(pev), "HG_CLEAR", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
SENTENCEG_PlayRndSz(ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_CLEAR" : "RB_CLEAR", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
break;
case 2: // question
SENTENCEG_PlayRndSz(ENT(pev), "HG_ANSWER", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
SENTENCEG_PlayRndSz(ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_ANSWER" : "RB_ANSWER", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
break;
}
g_fGruntQuestion = 0;
@@ -663,9 +664,7 @@ void CMHGrunt :: Shoot ( void )
pev->effects |= EF_MUZZLEFLASH;
// BUG - For some reason that still eludes me, grunts are completely unable to reload their weapons.
// As a temporary fix, give them infinite ammo. It will look bad I know... I gotta find a solution. -Giegue
//m_cAmmoLoaded--;// take away a bullet!
m_cAmmoLoaded--;// take away a bullet!
Vector angDir = UTIL_VecToAngles( vecShootDir );
SetBlending( 0, angDir.x );
@@ -692,9 +691,7 @@ void CMHGrunt :: Shotgun ( void )
pev->effects |= EF_MUZZLEFLASH;
// BUG - For some reason that still eludes me, grunts are completely unable to reload their weapons.
// As a temporary fix, give them infinite ammo. It will look bad I know... I gotta find a solution. -Giegue
//m_cAmmoLoaded--;// take away a bullet!
m_cAmmoLoaded--;// take away a bullet!
Vector angDir = UTIL_VecToAngles( vecShootDir );
SetBlending( 0, angDir.x );
@@ -802,8 +799,10 @@ void CMHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent )
else if (pHurt->v.euser4 != NULL)
{
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pHurt));
pMonster->TakeDamage( pev, pev, gSkillData.hgruntDmgKick, DMG_CLUB );
pMonster->TakeDamage(pev, pev, gSkillData.hgruntDmgKick, DMG_CLUB);
}
else
UTIL_TakeDamageExternal(pHurt, pev, pev, gSkillData.hgruntDmgKick, DMG_CLUB);
}
}
break;
@@ -812,8 +811,8 @@ void CMHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
if ( FOkToSpeak() )
{
SENTENCEG_PlayRndSz(ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
JustSpoke();
SENTENCEG_PlayRndSz(ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_ALERT" : "RB_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
JustSpoke();
}
}
@@ -836,7 +835,7 @@ void CMHGrunt :: Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
pev->effects = 0;
pev->health = gSkillData.hgruntHealth;
m_flFieldOfView = VIEW_FIELD_FULL; // indicates the width of this monster's forward view cone ( as a dotproduct result )
@@ -941,8 +940,8 @@ void CMHGrunt :: Precache()
else
m_voicePitch = 100;
m_iBrassShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell
m_iShotgunShell = PRECACHE_MODEL ("models/shotgunshell.mdl");
m_iBrassShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell
m_iShotgunShell = PRECACHE_MODELINDEX("models/shotgunshell.mdl");
}
//=========================================================
@@ -1677,6 +1676,37 @@ Schedule_t slGruntRepelLand[] =
},
};
//=========================================================
// Chase enemy failure schedule
//=========================================================
Task_t tlGruntChaseEnemyFailed[] =
{
{ TASK_STOP_MOVING, (float)0 },
{ TASK_WAIT, (float)0.2 },
{ TASK_FIND_COVER_FROM_ENEMY, (float)0 },
{ TASK_RUN_PATH, (float)0 },
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
{ TASK_REMEMBER, (float)bits_MEMORY_INCOVER },
// { TASK_TURN_LEFT, (float)179 },
{ TASK_FACE_ENEMY, (float)0 },
{ TASK_WAIT, (float)1 },
};
Schedule_t slGruntChaseEnemyFailed[] =
{
{
tlGruntChaseEnemyFailed,
ARRAYSIZE ( tlGruntChaseEnemyFailed ),
bits_COND_NEW_ENEMY |
bits_COND_CAN_RANGE_ATTACK1 |
bits_COND_CAN_MELEE_ATTACK1 |
bits_COND_CAN_RANGE_ATTACK2 |
bits_COND_CAN_MELEE_ATTACK2 |
bits_COND_HEAR_SOUND,
0,
"GruntChaseEnemyFailed"
},
};
DEFINE_CUSTOM_SCHEDULES( CMHGrunt )
{
@@ -1701,6 +1731,7 @@ DEFINE_CUSTOM_SCHEDULES( CMHGrunt )
slGruntRepel,
slGruntRepelAttack,
slGruntRepelLand,
slGruntChaseEnemyFailed,
};
IMPLEMENT_CUSTOM_SCHEDULES( CMHGrunt, CMBaseMonster );
@@ -1856,6 +1887,8 @@ Schedule_t *CMHGrunt :: GetSchedule( void )
// new enemy
if ( HasConditions(bits_COND_NEW_ENEMY) )
{
// none of this should take place as CSquadMonster functions were completely stripped. -Giegue
/*
{
{
//!!!KELLY - the leader of a squad of grunts has just seen the player or a
@@ -1871,14 +1904,14 @@ Schedule_t *CMHGrunt :: GetSchedule( void )
if ((m_hEnemy != NULL) && UTIL_IsPlayer(m_hEnemy))
// player
SENTENCEG_PlayRndSz( ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
/*jlb
else if ((m_hEnemy != NULL) &&
(m_hEnemy->Classify() != CLASS_PLAYER_ALLY) &&
(m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE) &&
(m_hEnemy->Classify() != CLASS_MACHINE))
// monster
SENTENCEG_PlayRndSz( ENT(pev), "HG_MONST", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
jlb*/
JustSpoke();
}
@@ -1892,6 +1925,7 @@ jlb*/
}
}
}
*/
}
// no ammo
else if ( HasConditions ( bits_COND_NO_AMMO_LOADED ) )
@@ -1917,9 +1951,9 @@ jlb*/
//!!!KELLY - this grunt was hit and is going to run to cover.
if (FOkToSpeak()) // && RANDOM_LONG(0,1))
{
//SENTENCEG_PlayRndSz( ENT(pev), "HG_COVER", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
SENTENCEG_PlayRndSz( ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_COVER" : "RB_COVER", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
m_iSentence = HGRUNT_SENT_COVER;
//JustSpoke();
JustSpoke();
}
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
}
@@ -1943,6 +1977,10 @@ jlb*/
// can shoot
else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
{
// lack of CSquadMonster functionality makes hgrunt behave erraticaly as is removes
// core conditions to make them attack (OccupySlot). -Giegue
// check if a grenade can be thrown, otherwise force weapon fire.
if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) )
{
// throw a grenade if can and no engage slots are available
@@ -1950,24 +1988,34 @@ jlb*/
}
else
{
return GetScheduleOfType( SCHED_RANGE_ATTACK1 );
// hide!
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
//return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
}
}
// can't see enemy
else if ( HasConditions( bits_COND_ENEMY_OCCLUDED ) )
{
// missing CSquadMonster functions means that the monster will stand still if its enemy is out of sight
// AND if it is impossible to throw a grenade. force it to chase the enemy if attack isn't possible
// -Giegue
if ( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) )
{
//!!!KELLY - this grunt is about to throw or fire a grenade at the player. Great place for "fire in the hole" "frag out" etc
if (FOkToSpeak())
{
SENTENCEG_PlayRndSz( ENT(pev), "HG_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
SENTENCEG_PlayRndSz( ENT(pev), !FClassnameIs(pev, "monster_robogrunt") ? "HG_THROW" : "RB_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
JustSpoke();
}
return GetScheduleOfType( SCHED_RANGE_ATTACK2 );
}
else
{
return GetScheduleOfType( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE );
}
/*
else
{
//!!!KELLY - grunt is going to stay put for a couple seconds to see if
// the enemy wanders back out into the open, or approaches the
@@ -1979,6 +2027,7 @@ jlb*/
}
return GetScheduleOfType( SCHED_STANDOFF );
}
*/
}
if ( HasConditions( bits_COND_SEE_ENEMY ) && !HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
@@ -2113,6 +2162,11 @@ Schedule_t* CMHGrunt :: GetScheduleOfType ( int Type )
{
return &slGruntRepelLand[ 0 ];
}
case SCHED_CHASE_ENEMY_FAILED:
{
// add missing schedule from squadmonster.cpp
return &slGruntChaseEnemyFailed[ 0 ];
}
default:
{
return CMBaseMonster :: GetScheduleOfType ( Type );

View File

@@ -104,8 +104,8 @@ void CMHornet :: Precache()
PRECACHE_SOUND( "hornet/ag_hornethit2.wav" );
PRECACHE_SOUND( "hornet/ag_hornethit3.wav" );
iHornetPuff = PRECACHE_MODEL( "sprites/muz1.spr" );
iHornetTrail = PRECACHE_MODEL("sprites/laserbeam.spr");
iHornetPuff = PRECACHE_MODELINDEX( "sprites/muz1.spr" );
iHornetTrail = PRECACHE_MODELINDEX("sprites/laserbeam.spr");
}
//=========================================================
@@ -126,23 +126,14 @@ int CMHornet::IRelationship ( CMBaseEntity *pTarget )
//=========================================================
int CMHornet::Classify ( void )
{
/*
if ( pev->owner && pev->owner->v.flags & FL_CLIENT)
{
return CLASS_PLAYER_BIOWEAPON;
}
return CLASS_ALIEN_BIOWEAPON;
*/
// Ensure classify is consistent with the owner, in the event
// it's classification was overriden.
if ( pev->owner == NULL )
return CLASS_ALIEN_BIOWEAPON;
// Ain't this going to make the hornets code "slow"?
CMBaseMonster *pOwner = GetClassPtr((CMBaseMonster *)VARS(pev->owner));
return pOwner->Classify();
if (UTIL_IsValidEntity(pev->owner))
{
CMBaseMonster *pOwner = GetClassPtr((CMBaseMonster *)VARS(pev->owner));
return pOwner->Classify();
}
return CLASS_ALIEN_BIOWEAPON;
}
//=========================================================
@@ -372,6 +363,8 @@ void CMHornet::DieTouch ( edict_t *pOther )
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
pMonster->TakeDamage( pev, VARS( pev->owner ), pev->dmg, DMG_BULLET );
}
else
UTIL_TakeDamageExternal( pOther, pev, VARS( pev->owner ), pev->dmg, DMG_BULLET );
}
pev->modelindex = 0;// so will disappear for the 0.1 secs we wait until NEXTTHINK gets rid

View File

@@ -272,7 +272,7 @@ void CMHoundeye :: Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_YELLOW;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0;
pev->health = gSkillData.houndeyeHealth;
pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim?
@@ -326,7 +326,7 @@ void CMHoundeye :: Precache()
PRECACHE_SOUND("houndeye/he_blast2.wav");
PRECACHE_SOUND("houndeye/he_blast3.wav");
m_iSpriteTexture = PRECACHE_MODEL( "sprites/shockwave.spr" );
m_iSpriteTexture = PRECACHE_MODELINDEX( "sprites/shockwave.spr" );
}
//=========================================================
@@ -524,7 +524,8 @@ void CMHoundeye :: SonicAttack ( void )
{
if ( pEntity->v.takedamage != DAMAGE_NO )
{
if ( strcmp(STRING(pEntity->v.model), "models/houndeye.mdl") != 0 )
// don't compare by model because a mapper might change it
if ( strcmp(STRING(pEntity->v.classname), "monster_houndeye") != 0 )
{// houndeyes don't hurt other houndeyes with their attack
// houndeyes do FULL damage if the ent in question is visible. Half damage otherwise.
@@ -565,6 +566,8 @@ void CMHoundeye :: SonicAttack ( void )
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
pMonster->TakeDamage( pev, pev, flAdjustedDamage, DMG_SONIC | DMG_ALWAYSGIB );
}
else
UTIL_TakeDamageExternal( pEntity, pev, pev, flAdjustedDamage, DMG_SONIC | DMG_ALWAYSGIB );
}
}
}

View File

@@ -32,46 +32,38 @@
//=========================================================
// monster-specific DEFINE's
//=========================================================
#define HWGRUNT_9MM_CLIP_SIZE 17 // clip ammo per gun
#define HWGRUNT_DGL_CLIP_SIZE 7
#define HWGRUNT_357_CLIP_SIZE 6
// Weapon flags
#define HWGRUNT_MINIGUN 0
#define HWGRUNT_PISTOL_9MM 1
#define HWGRUNT_PISTOL_DGL 2
#define HWGRUNT_PISTOL_357 3
#define GUN_GROUP 1
// Gun values
#define GUN_MINIGUN 0
#define GUN_PISTOL_9MM 1
#define GUN_PISTOL_357 2
#define GUN_PISTOL_DGL 3
#define GUN_NONE 4
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
#define HWGRUNT_AE_DEATH ( 11 )
#define HWGRUNT_AE_MINIGUN ( 5001 )
//=========================================================
// monster-specific schedule types
//=========================================================
enum
{
SCHED_HWGRUNT_SUPPRESS = LAST_COMMON_SCHEDULE + 1,
SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE,// move to a location to set up an attack against the enemy. (usually when a friendly is in the way).
SCHED_HWGRUNT_SWEEP,
SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE = LAST_COMMON_SCHEDULE + 1,// move to a location to set up an attack against the enemy.
SCHED_HWGRUNT_REPEL,
SCHED_HWGRUNT_REPEL_ATTACK,
SCHED_HWGRUNT_REPEL_LAND,
SCHED_HWGRUNT_WAIT_FACE_ENEMY,
SCHED_HWGRUNT_TAKECOVER_FAILED,// force analysis of conditions and pick the best possible schedule to recover from failure.
SCHED_HWGRUNT_ELOF_FAIL,
};
//=========================================================
// monster-specific conditions
//=========================================================
#define bits_MEMORY_HWGRUNT_SPINUP ( bits_MEMORY_CUSTOM1 )
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
#define HWGRUNT_AE_DEATH ( 11 )
#define HWGRUNT_AE_MINIGUN ( 5001 )
//=========================================================
// Classify - indicates this monster's place in the
// relationship table.
@@ -207,14 +199,14 @@ void CMHWGrunt::Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
pev->effects = 0;
pev->health = gSkillData.hwgruntHealth;
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE;
//m_flNextGrenadeCheck = gpGlobals->time + 1;
m_flNextPainTime = gpGlobals->time;
m_flMinigunSpinTime = 0; // be able to spin up/down minigun right away
//m_flMinigunSpinTime = 0; // be able to spin up/down minigun right away
m_iSentence = -1;
m_fStanding = TRUE;
@@ -259,14 +251,12 @@ void CMHWGrunt::Precache()
PRECACHE_SOUND("hassault/hw_shoot1.wav");
PRECACHE_SOUND("hassault/hw_spinup.wav");
PRECACHE_SOUND("hassault/hw_spindown.wav");
PRECACHE_SOUND("common/null.wav");
// get voice pitch
if (RANDOM_LONG(0, 1))
m_voicePitch = 102 + RANDOM_LONG(0, 7);
else
m_voicePitch = 93; // slight voice change for hwgrunt
m_voicePitch = 95 + RANDOM_LONG(0, 3); // slighly lower than normal grunt
CMHGrunt hgrunt;
hgrunt.Precache();
}
//=========================================================
@@ -274,7 +264,7 @@ void CMHWGrunt::Precache()
//=========================================================
//=========================================================
// GruntFail
// Fail
//=========================================================
Task_t tlHWGruntFail[] =
{
@@ -296,7 +286,7 @@ Schedule_t slHWGruntFail[] =
};
//=========================================================
// Grunt Combat Fail
// Combat Fail
//=========================================================
Task_t tlHWGruntCombatFail[] =
{
@@ -318,7 +308,7 @@ Schedule_t slHWGruntCombatFail[] =
};
//=========================================================
// Victory dance!
// Not really victory dance
//=========================================================
Task_t tlHWGruntVictoryDance[] =
{
@@ -328,7 +318,8 @@ Task_t tlHWGruntVictoryDance[] =
{ TASK_GET_PATH_TO_ENEMY_CORPSE, (float)0 },
{ TASK_WALK_PATH, (float)0 },
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
{ TASK_FACE_ENEMY, (float)0 }
{ TASK_FACE_ENEMY, (float)0 },
// { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE },
};
Schedule_t slHWGruntVictoryDance[] =
@@ -336,35 +327,11 @@ Schedule_t slHWGruntVictoryDance[] =
{
tlHWGruntVictoryDance,
ARRAYSIZE ( tlHWGruntVictoryDance ),
bits_COND_NEW_ENEMY,
bits_COND_NEW_ENEMY |
bits_COND_LIGHT_DAMAGE |
bits_COND_HEAVY_DAMAGE,
0,
"HWGruntVictoryDance"
},
};
//=========================================================
// ELOF fail, just wait and try again
//=========================================================
Task_t tlHWGruntELOFFail[] =
{
{ TASK_STOP_MOVING, (float)0 },
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
{ TASK_FACE_ENEMY, (float)0 },
{ TASK_WAIT, (float)1.5 },
{ TASK_SET_SCHEDULE, (float)SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE },
};
Schedule_t slHWGruntELOFFail[] =
{
{
tlHWGruntELOFFail,
ARRAYSIZE ( tlHWGruntELOFFail ),
bits_COND_NEW_ENEMY |
bits_COND_ENEMY_DEAD |
bits_COND_CAN_RANGE_ATTACK1,
0,
"HWGrunt Failed ELOF"
"HWGrunt Victory Dance"
},
};
@@ -376,6 +343,7 @@ Task_t tlHWGruntEstablishLineOfFire[] =
{
{ TASK_SET_FAIL_SCHEDULE, (float)SCHED_HWGRUNT_ELOF_FAIL },
{ TASK_GET_PATH_TO_ENEMY, (float)0 },
// { TASK_GRUNT_SPEAK_SENTENCE,(float)0 },
{ TASK_RUN_PATH, (float)0 },
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
};
@@ -390,66 +358,14 @@ Schedule_t slHWGruntEstablishLineOfFire[] =
bits_COND_CAN_RANGE_ATTACK1 |
bits_COND_HEAR_SOUND,
0,
"HWGruntEstablishLineOfFire"
"HWGrunt Establish Line Of Fire"
},
};
//=========================================================
// GruntCombatFace Schedule
//=========================================================
Task_t tlHWGruntCombatFace1[] =
{
{ TASK_STOP_MOVING, 0 },
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
{ TASK_FACE_ENEMY, (float)0 },
{ TASK_WAIT, (float)1.5 },
{ TASK_SET_SCHEDULE, (float)SCHED_HWGRUNT_SWEEP },
};
Schedule_t slHWGruntCombatFace[] =
{
{
tlHWGruntCombatFace1,
ARRAYSIZE ( tlHWGruntCombatFace1 ),
bits_COND_NEW_ENEMY |
bits_COND_ENEMY_DEAD |
bits_COND_CAN_RANGE_ATTACK1,
0,
"HWCombat Face"
},
};
Task_t tlHWGruntSuppress[] =
{
{ TASK_STOP_MOVING, 0 },
{ TASK_FACE_ENEMY, (float)0 },
{ TASK_RANGE_ATTACK1, (float)0 },
{ TASK_FACE_ENEMY, (float)0 },
{ TASK_RANGE_ATTACK1, (float)0 },
{ TASK_FACE_ENEMY, (float)0 },
{ TASK_RANGE_ATTACK1, (float)0 },
{ TASK_FACE_ENEMY, (float)0 },
{ TASK_RANGE_ATTACK1, (float)0 },
{ TASK_FACE_ENEMY, (float)0 },
{ TASK_RANGE_ATTACK1, (float)0 },
};
Schedule_t slHWGruntSuppress[] =
{
{
tlHWGruntSuppress,
ARRAYSIZE ( tlHWGruntSuppress ),
0,
0,
"HWSuppress"
},
};
//=========================================================
// grunt wait in cover - we don't allow danger or the ability
// to attack to break a grunt's run to cover schedule, but
// when a grunt is in cover, we do want them to attack if they can.
// wait in cover - we don't allow danger or the ability to
// attack to break a grunt's run to cover schedule, but when
// a grunt is in cover, we do want them to attack if they can.
//=========================================================
Task_t tlHWGruntWaitInCover[] =
{
@@ -467,73 +383,90 @@ Schedule_t slHWGruntWaitInCover[] =
bits_COND_HEAR_SOUND |
bits_COND_CAN_RANGE_ATTACK1,
0,
"HWGruntWaitInCover"
"HWGrunt Wait In Cover"
},
};
//=========================================================
// Do a turning sweep of the area
// run to cover.
//=========================================================
Task_t tlHWGruntSweep[] =
Task_t tlHWGruntTakeCover[] =
{
{ TASK_TURN_LEFT, (float)179 },
{ TASK_WAIT, (float)1 },
{ TASK_TURN_LEFT, (float)179 },
{ TASK_WAIT, (float)1 },
{ TASK_STOP_MOVING, (float)0 },
{ TASK_SET_FAIL_SCHEDULE, (float)SCHED_HWGRUNT_TAKECOVER_FAILED },
{ TASK_WAIT, (float)0.2 },
{ TASK_FIND_COVER_FROM_ENEMY, (float)0 },
// { TASK_GRUNT_SPEAK_SENTENCE, (float)0 },
{ TASK_RUN_PATH, (float)0 },
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
{ TASK_REMEMBER, (float)bits_MEMORY_INCOVER },
{ TASK_SET_SCHEDULE, (float)SCHED_HWGRUNT_WAIT_FACE_ENEMY },
};
Schedule_t slHWGruntSweep[] =
Schedule_t slHWGruntTakeCover[] =
{
{
tlHWGruntSweep,
ARRAYSIZE ( tlHWGruntSweep ),
bits_COND_NEW_ENEMY |
bits_COND_CAN_RANGE_ATTACK1,
tlHWGruntTakeCover,
ARRAYSIZE ( tlHWGruntTakeCover ),
0,
"HWGrunt Sweep"
0,
"HWGrunt Take Cover"
},
};
//=========================================================
// primary range attack. Overriden because base class stops attacking when the enemy is occluded.
// grunt's grenade toss requires the enemy be occluded.
// minigun spinup
//=========================================================
Task_t tlHWGruntRangeAttack1B[] =
Task_t tlHWGruntMinigunSpinUp[] =
{
{ TASK_STOP_MOVING, (float)0 },
{ TASK_PLAY_SEQUENCE_FACE_ENEMY,(float)ACT_IDLE_ANGRY },
{ TASK_RANGE_ATTACK1, (float)0 },
{ TASK_FACE_ENEMY, (float)0 },
{ TASK_RANGE_ATTACK1, (float)0 },
{ TASK_FACE_ENEMY, (float)0 },
{ TASK_RANGE_ATTACK1, (float)0 },
{ TASK_FACE_ENEMY, (float)0 },
{ TASK_RANGE_ATTACK1, (float)0 },
{ TASK_STOP_MOVING, (float)0 },
{ TASK_SET_ACTIVITY, (float)ACT_THREAT_DISPLAY },
{ TASK_WAIT_FACE_ENEMY, (float)1 },
{ TASK_REMEMBER, (float)bits_MEMORY_HWGRUNT_SPINUP },
};
Schedule_t slHWGruntRangeAttack1B[] =
Schedule_t slHWGruntMinigunSpinUp[] =
{
{
tlHWGruntRangeAttack1B,
ARRAYSIZE ( tlHWGruntRangeAttack1B ),
tlHWGruntMinigunSpinUp,
ARRAYSIZE ( tlHWGruntMinigunSpinUp ),
0, // nothing should interrupt this
0,
"HWGrunt Minigun Spin Up"
},
};
//=========================================================
// minigun attack
//=========================================================
Task_t tlHWGruntMinigunAttack[] =
{
{ TASK_STOP_MOVING, (float)0 },
{ TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_RANGE_ATTACK1 },
{ TASK_RANGE_ATTACK1, (float)0 },
};
Schedule_t slHWGruntMinigunAttack[] =
{
{
tlHWGruntMinigunAttack,
ARRAYSIZE ( tlHWGruntMinigunAttack ),
bits_COND_NEW_ENEMY |
bits_COND_ENEMY_DEAD |
bits_COND_ENEMY_OCCLUDED,
bits_COND_ENEMY_OCCLUDED |
bits_COND_HEAR_SOUND,
0,
"HWRange Attack1B"
"HWGrunt Minigun Attack"
},
};
//=========================================================
// repel
//=========================================================
Task_t tlHWGruntRepel[] =
{
{ TASK_STOP_MOVING, (float)0 },
{ TASK_FACE_IDEAL, (float)0 },
{ TASK_STOP_MOVING, (float)0 },
{ TASK_FACE_IDEAL, (float)0 },
{ TASK_PLAY_SEQUENCE, (float)ACT_GLIDE },
};
@@ -543,31 +476,12 @@ Schedule_t slHWGruntRepel[] =
tlHWGruntRepel,
ARRAYSIZE ( tlHWGruntRepel ),
bits_COND_SEE_ENEMY |
bits_COND_NEW_ENEMY,
bits_COND_NEW_ENEMY |
bits_COND_LIGHT_DAMAGE |
bits_COND_HEAVY_DAMAGE |
bits_COND_HEAR_SOUND,
0,
"HWRepel"
},
};
//=========================================================
// repel
//=========================================================
Task_t tlHWGruntRepelAttack[] =
{
{ TASK_STOP_MOVING, (float)0 },
{ TASK_FACE_ENEMY, (float)0 },
{ TASK_PLAY_SEQUENCE, (float)ACT_FLY },
};
Schedule_t slHWGruntRepelAttack[] =
{
{
tlHWGruntRepelAttack,
ARRAYSIZE ( tlHWGruntRepelAttack ),
bits_COND_ENEMY_OCCLUDED,
0,
"HWRepel Attack"
"HWGrunt Repel"
},
};
@@ -576,12 +490,12 @@ Schedule_t slHWGruntRepelAttack[] =
//=========================================================
Task_t tlHWGruntRepelLand[] =
{
{ TASK_STOP_MOVING, (float)0 },
{ TASK_PLAY_SEQUENCE, (float)ACT_LAND },
{ TASK_GET_PATH_TO_LASTPOSITION,(float)0 },
{ TASK_RUN_PATH, (float)0 },
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
{ TASK_CLEAR_LASTPOSITION, (float)0 },
{ TASK_STOP_MOVING, (float)0 },
{ TASK_PLAY_SEQUENCE, (float)ACT_LAND },
{ TASK_GET_PATH_TO_LASTPOSITION, (float)0 },
{ TASK_RUN_PATH, (float)0 },
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
{ TASK_CLEAR_LASTPOSITION, (float)0 },
};
Schedule_t slHWGruntRepelLand[] =
@@ -590,9 +504,41 @@ Schedule_t slHWGruntRepelLand[] =
tlHWGruntRepelLand,
ARRAYSIZE ( tlHWGruntRepelLand ),
bits_COND_SEE_ENEMY |
bits_COND_NEW_ENEMY,
bits_COND_NEW_ENEMY |
bits_COND_LIGHT_DAMAGE |
bits_COND_HEAVY_DAMAGE |
bits_COND_HEAR_SOUND,
0,
"HWRepel Land"
"HWGrunt Repel Land"
},
};
//=========================================================
// Chase enemy failure
//=========================================================
Task_t tlHWGruntChaseEnemyFailed[] =
{
{ TASK_STOP_MOVING, (float)0 },
{ TASK_WAIT, (float)0.2 },
{ TASK_FIND_COVER_FROM_ENEMY, (float)0 },
{ TASK_RUN_PATH, (float)0 },
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
{ TASK_REMEMBER, (float)bits_MEMORY_INCOVER },
// { TASK_TURN_LEFT, (float)179 },
{ TASK_FACE_ENEMY, (float)0 },
{ TASK_WAIT, (float)1 },
};
Schedule_t slHWGruntChaseEnemyFailed[] =
{
{
tlHWGruntChaseEnemyFailed,
ARRAYSIZE ( tlHWGruntChaseEnemyFailed ),
bits_COND_NEW_ENEMY |
bits_COND_CAN_RANGE_ATTACK1 |
bits_COND_HEAR_SOUND,
0,
"HWGrunt Chase Enemy Failed"
},
};
@@ -602,110 +548,43 @@ DEFINE_CUSTOM_SCHEDULES( CMHWGrunt )
slHWGruntFail,
slHWGruntCombatFail,
slHWGruntVictoryDance,
slHWGruntELOFFail,
slHWGruntEstablishLineOfFire,
slHWGruntCombatFace,
slHWGruntSuppress,
slHWGruntWaitInCover,
slHWGruntSweep,
slHWGruntRangeAttack1B,
slHWGruntTakeCover,
slHWGruntMinigunSpinUp,
slHWGruntMinigunAttack,
slHWGruntRepel,
slHWGruntRepelAttack,
slHWGruntRepelLand,
slHWGruntChaseEnemyFailed,
};
IMPLEMENT_CUSTOM_SCHEDULES( CMHWGrunt, CMBaseMonster );
//=========================================================
// SetActivity - different set than normal hgrunt, adapt
// SetActivity
//=========================================================
void CMHWGrunt :: SetActivity ( Activity NewActivity )
{
int iSequence = ACTIVITY_NOT_AVAILABLE;
void *pmodel = GET_MODEL_PTR( ENT(pev) );
bool refreshActivity = TRUE;
switch ( NewActivity )
{
case ACT_RANGE_ATTACK1:
iSequence = LookupSequence( "attack" );
break;
case ACT_RUN:
iSequence = LookupSequence( "run" );
break;
case ACT_WALK:
iSequence = LookupSequence( "creeping_walk" );
break;
default:
iSequence = LookupActivity( NewActivity );
break;
}
// PS: This is terrible code. -Giegue
// Time to die?
if ( NewActivity < ACT_DIESIMPLE )
{
if ( pev->sequence == LookupSequence( "attack" ) )
{
// I won't do anything else if I'm attacking!
refreshActivity = FALSE;
// Unless the enemy has gone out of my sight
if ( m_hEnemy == 0 || !UTIL_IsAlive( m_hEnemy ) || !UTIL_FVisible( m_hEnemy, ENT(pev) ) )
{
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "hassault/hw_spindown.wav", 0.8, ATTN_NORM);
m_flMinigunSpinTime = gpGlobals->time + 1.40;
iSequence = LookupSequence( "spindown" ); // time to relax
}
}
else if ( pev->sequence == LookupSequence( "spindown" ) )
{
// Not yet!
refreshActivity = FALSE;
// Wait until the minigun is no longer spinning before doing something else
if ( gpGlobals->time > m_flMinigunSpinTime )
{
refreshActivity = TRUE;
m_flMinigunSpinTime = 0; // do spin up again when required
}
}
}
if (refreshActivity)
{
switch (NewActivity)
{
case ACT_RANGE_ATTACK1:
// if carring a gun, either standing or crouched.
// always standing when firing minigun
if (pev->weapons > 0) // any pistol
{
// same animation regardless of pistol
if ( m_fStanding )
{
// get aimable sequence
iSequence = LookupSequence( "pistol_shoot" );
}
else
{
// get crouching shoot
iSequence = LookupSequence( "pistol_crouchshoot" );
}
}
else // minigun
{
if ( m_flMinigunSpinTime == 0 ) // starting to spin up the minigun
{
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "hassault/hw_spinup.wav", 0.8, ATTN_NORM);
m_flMinigunSpinTime = gpGlobals->time + 1.15;
iSequence = LookupSequence( "spinup" );
}
else if ( gpGlobals->time > m_flMinigunSpinTime ) // spun up, ready to fire
iSequence = LookupSequence( "attack" );
}
break;
case ACT_IDLE:
if ( m_MonsterState == MONSTERSTATE_COMBAT )
{
NewActivity = ACT_IDLE_ANGRY;
}
iSequence = LookupActivity ( NewActivity );
break;
case ACT_RUN:
case ACT_WALK:
default:
iSequence = LookupActivity ( NewActivity );
break;
}
m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present
}
m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present
// Set to the desired anim, or default anim if the desired is not present
if ( iSequence > ACTIVITY_NOT_AVAILABLE )
@@ -719,7 +598,7 @@ void CMHWGrunt :: SetActivity ( Activity NewActivity )
ResetSequenceInfo( );
SetYawSpeed();
}
else if (refreshActivity)
else
{
// Not available try to get default anim
ALERT ( at_console, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity );
@@ -732,6 +611,9 @@ void CMHWGrunt :: SetActivity ( Activity NewActivity )
//=========================================================
Schedule_t *CMHWGrunt :: GetSchedule( void )
{
// clear old sentence
m_iSentence = -1; // we don't care about sounds for now.
// flying? If PRONE, barnacle has me. IF not, it's assumed I am rapelling.
if ( pev->movetype == MOVETYPE_FLY && m_MonsterState != MONSTERSTATE_PRONE )
{
@@ -743,11 +625,8 @@ Schedule_t *CMHWGrunt :: GetSchedule( void )
}
else
{
// repel down a rope,
if ( m_MonsterState == MONSTERSTATE_COMBAT )
return GetScheduleOfType ( SCHED_HWGRUNT_REPEL_ATTACK );
else
return GetScheduleOfType ( SCHED_HWGRUNT_REPEL );
// can not attack while holding a minigun in rapel
return GetScheduleOfType ( SCHED_HWGRUNT_REPEL );
}
}
@@ -758,6 +637,13 @@ Schedule_t *CMHWGrunt :: GetSchedule( void )
// dead enemy
if ( HasConditions( bits_COND_ENEMY_DEAD ) )
{
// was attacking, spin down
if ( HasMemory( bits_MEMORY_HWGRUNT_SPINUP ) )
{
Forget( bits_MEMORY_HWGRUNT_SPINUP );
EMIT_SOUND(ENT(pev), CHAN_ITEM, "hassault/hw_spindown.wav", 0.8, ATTN_NORM);
}
// call base class, all code to handle dead enemies is centralized there.
return CMBaseMonster :: GetSchedule();
}
@@ -765,40 +651,76 @@ Schedule_t *CMHWGrunt :: GetSchedule( void )
// new enemy
if ( HasConditions(bits_COND_NEW_ENEMY) )
{
if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
// none of this should take place as CSquadMonster functions were completely stripped. -Giegue
/*
{
return GetScheduleOfType ( SCHED_HWGRUNT_SUPPRESS );
}
else
{
return GetScheduleOfType ( SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE );
{
//!!!KELLY - the leader of a squad of grunts has just seen the player or a
// monster and has made it the squad's enemy. You
// can check pev->flags for FL_CLIENT to determine whether this is the player
// or a monster. He's going to immediately start
// firing, though. If you'd like, we can make an alternate "first sight"
// schedule where the leader plays a handsign anim
// that gives us enough time to hear a short sentence or spoken command
// before he starts pluggin away.
if (FOkToSpeak())// && RANDOM_LONG(0,1))
{
if ((m_hEnemy != NULL) && UTIL_IsPlayer(m_hEnemy))
// player
SENTENCEG_PlayRndSz( ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
else if ((m_hEnemy != NULL) &&
(m_hEnemy->Classify() != CLASS_PLAYER_ALLY) &&
(m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE) &&
(m_hEnemy->Classify() != CLASS_MACHINE))
// monster
SENTENCEG_PlayRndSz( ENT(pev), "HG_MONST", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
JustSpoke();
}
if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
{
return GetScheduleOfType ( SCHED_GRUNT_SUPPRESS );
}
else
{
return GetScheduleOfType ( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE );
}
}
}
*/
}
// no ammo
else if ( HasConditions ( bits_COND_NO_AMMO_LOADED ) )
// damaged just a little
else if ( HasConditions( bits_COND_LIGHT_DAMAGE ) )
{
// Stop believing you have no ammo! -Giegue
ClearConditions( bits_COND_NO_AMMO_LOADED );
if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
{
return GetScheduleOfType ( SCHED_HWGRUNT_SUPPRESS );
}
else
{
return GetScheduleOfType ( SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE );
}
// we don't want the monster to take cover when hurt while attacking, clear this
ClearConditions( bits_COND_LIGHT_DAMAGE );
}
// can shoot
else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
{
// Force attack!
return GetScheduleOfType ( SCHED_HWGRUNT_SUPPRESS );
// can fire? shoot. destroy without a care
return GetScheduleOfType( SCHED_RANGE_ATTACK1 );
}
// can't see enemy
else if ( HasConditions( bits_COND_ENEMY_OCCLUDED ) )
{
// do sound
if ( HasMemory( bits_MEMORY_HWGRUNT_SPINUP ) )
{
Forget( bits_MEMORY_HWGRUNT_SPINUP );
EMIT_SOUND(ENT(pev), CHAN_ITEM, "hassault/hw_spindown.wav", 0.8, ATTN_NORM);
}
// then go kamikaze and chase the enemy
return GetScheduleOfType( SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE );
}
if ( HasConditions( bits_COND_SEE_ENEMY ) && !HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
{
return GetScheduleOfType ( SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE );
return GetScheduleOfType( SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE );
}
}
}
@@ -813,10 +735,24 @@ Schedule_t* CMHWGrunt :: GetScheduleOfType ( int Type )
{
switch ( Type )
{
case SCHED_TAKE_COVER_FROM_ENEMY:
{
return &slHWGruntTakeCover[ 0 ];
}
case SCHED_HWGRUNT_TAKECOVER_FAILED:
{
if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) )
{
return GetScheduleOfType( SCHED_RANGE_ATTACK1 );
}
return GetScheduleOfType ( SCHED_FAIL );
}
break;
case SCHED_HWGRUNT_ELOF_FAIL:
{
// human grunt is unable to move to a position that allows him to attack the enemy.
return &slHWGruntELOFFail[ 0 ];
// unable to move to a position that allows attacking the enemy.
return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY );
}
break;
case SCHED_HWGRUNT_ESTABLISH_LINE_OF_FIRE:
@@ -826,34 +762,28 @@ Schedule_t* CMHWGrunt :: GetScheduleOfType ( int Type )
break;
case SCHED_RANGE_ATTACK1:
{
// no pistols yet, always do standing attack
return &slHWGruntRangeAttack1B[ 0 ];
}
case SCHED_COMBAT_FACE:
{
return &slHWGruntCombatFace[ 0 ];
// minigun should spin up first
if ( !HasMemory( bits_MEMORY_HWGRUNT_SPINUP ) )
{
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "hassault/hw_spinup.wav", 0.8, ATTN_NORM);
return &slHWGruntMinigunSpinUp[ 0 ];
}
else
return &slHWGruntMinigunAttack[ 0 ];
}
case SCHED_HWGRUNT_WAIT_FACE_ENEMY:
{
return &slHWGruntWaitInCover[ 0 ];
}
case SCHED_HWGRUNT_SWEEP:
{
return &slHWGruntSweep[ 0 ];
}
case SCHED_VICTORY_DANCE:
{
return &slHWGruntVictoryDance[ 0 ];
}
case SCHED_HWGRUNT_SUPPRESS:
{
return &slHWGruntSuppress[ 0 ];
}
case SCHED_FAIL:
{
if ( m_hEnemy != NULL )
{
// grunt has an enemy, so pick a different default fail schedule most likely to help recover.
// has an enemy, so pick a different default fail schedule most likely to help recover.
return &slHWGruntCombatFail[ 0 ];
}
@@ -865,19 +795,19 @@ Schedule_t* CMHWGrunt :: GetScheduleOfType ( int Type )
pev->velocity.z -= 32;
return &slHWGruntRepel[ 0 ];
}
case SCHED_HWGRUNT_REPEL_ATTACK:
{
if (pev->velocity.z > -128)
pev->velocity.z -= 32;
return &slHWGruntRepelAttack[ 0 ];
}
case SCHED_HWGRUNT_REPEL_LAND:
{
return &slHWGruntRepelLand[ 0 ];
}
case SCHED_CHASE_ENEMY_FAILED:
{
// add missing schedule from squadmonster.cpp
return &slHWGruntChaseEnemyFailed[ 0 ];
}
default:
{
return CMBaseMonster :: GetScheduleOfType ( Type );
}
}
}

View File

@@ -421,7 +421,7 @@ void CMISlave :: Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0;
pev->health = gSkillData.slaveHealth;
pev->view_ofs = Vector ( 0, 0, 64 );// position of the eyes relative to monster's origin.
@@ -451,8 +451,6 @@ void CMISlave :: Spawn()
//=========================================================
void CMISlave :: Precache()
{
int i;
PRECACHE_MODEL("models/islave.mdl");
PRECACHE_MODEL("sprites/lgtning.spr");
PRECACHE_SOUND("debris/zap1.wav");
@@ -463,17 +461,10 @@ void CMISlave :: Precache()
PRECACHE_SOUND("headcrab/hc_headbite.wav");
PRECACHE_SOUND("weapons/cbar_miss1.wav");
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
PRECACHE_SOUND((char *)pAttackHitSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
PRECACHE_SOUND((char *)pAttackMissSounds[i]);
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
PRECACHE_SOUND((char *)pPainSounds[i]);
for ( i = 0; i < ARRAYSIZE( pDeathSounds ); i++ )
PRECACHE_SOUND((char *)pDeathSounds[i]);
PRECACHE_SOUND_ARRAY(pAttackHitSounds);
PRECACHE_SOUND_ARRAY(pAttackMissSounds);
PRECACHE_SOUND_ARRAY(pPainSounds);
PRECACHE_SOUND_ARRAY(pDeathSounds);
}
@@ -737,6 +728,8 @@ void CMISlave :: ZapBeam( int side )
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
pMonster->TraceAttack( pev, gSkillData.slaveDmgZap, vecAim, &tr, DMG_SHOCK );
}
else
UTIL_TraceAttack( pEntity, pev, gSkillData.slaveDmgZap, vecAim, &tr, DMG_SHOCK );
}
UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) );

View File

@@ -31,6 +31,8 @@
#include "effects.h"
#include "customentity.h"
extern cvar_t *monster_default_maxrange;
//=========================================================
// monster-specific DEFINE's
//=========================================================
@@ -61,6 +63,8 @@
//=========================================================
#define MASSN_AE_KICK ( 3 )
#define MASSN_AE_BURST1 ( 4 )
#define MASSN_AE_BURST2 ( 5 )
#define MASSN_AE_BURST3 ( 6 )
#define MASSN_AE_CAUGHT_ENEMY ( 10 ) // grunt established sight with an enemy (player only) that had previously eluded the squad.
#define MASSN_AE_DROP_GUN ( 11 ) // grunt (probably dead) is dropping his mp5.
@@ -120,9 +124,7 @@ void CMMassn::Sniperrifle(void)
pev->effects |= EF_MUZZLEFLASH;
// BUG - For some reason that still eludes me, grunts are completely unable to reload their weapons.
// As a temporary fix, give them infinite ammo. It will look bad I know... I gotta find a solution. -Giegue
//m_cAmmoLoaded--;// take away a bullet!
m_cAmmoLoaded--;// take away a bullet!
Vector angDir = UTIL_VecToAngles(vecShootDir);
SetBlending(0, angDir.x);
@@ -178,6 +180,11 @@ void CMMassn::HandleAnimEvent(MonsterEvent_t *pEvent)
}
break;
case MASSN_AE_BURST2:
case MASSN_AE_BURST3:
Shoot();
break;
case MASSN_AE_KICK:
{
edict_t *pHurt = Kick();
@@ -195,6 +202,8 @@ void CMMassn::HandleAnimEvent(MonsterEvent_t *pEvent)
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pHurt));
pMonster->TakeDamage( pev, pev, gSkillData.massnDmgKick, DMG_CLUB );
}
else
UTIL_TakeDamageExternal( pHurt, pev, pev, gSkillData.massnDmgKick, DMG_CLUB );
}
}
break;
@@ -220,7 +229,7 @@ void CMMassn::Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
pev->effects = 0;
pev->health = gSkillData.massnHealth;
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
@@ -258,6 +267,10 @@ void CMMassn::Spawn()
{
SetBodygroup(GUN_GROUP, GUN_SNIPERRIFLE);
m_cClipSize = 5;
// if no attack range set, set 2x default
if (!m_flDistLook)
m_flDistLook = monster_default_maxrange->value * 2;
}
else
{
@@ -273,7 +286,12 @@ void CMMassn::Spawn()
CMTalkMonster::g_talkWaitTime = 0;
MonsterInit();
if (FBitSet(pev->weapons, MASSN_SNIPERRIFLE))
{
// override for snipers
m_flDistTooFar = m_flDistLook / 1.33;
}
pev->classname = MAKE_STRING( "monster_male_assassin" );
if ( strlen( STRING( m_szMonsterName ) ) == 0 )
{
@@ -307,5 +325,118 @@ void CMMassn::Precache()
else
m_voicePitch = 100;
m_iBrassShell = PRECACHE_MODEL("models/shell.mdl");// brass shell
m_iBrassShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell
}
//=========================================================
// Chase enemy failure schedule
//=========================================================
Task_t tlMassnSniperAttack[] =
{
{ TASK_STOP_MOVING, (float)0 },
{ TASK_SET_ACTIVITY, (float)ACT_IDLE_ANGRY },
{ TASK_WAIT_FACE_ENEMY , (float)1 },
{ TASK_SET_ACTIVITY, (float)ACT_RANGE_ATTACK1 },
{ TASK_WAIT_FACE_ENEMY, (float)1 },
};
Schedule_t slMassnSniperAttack[] =
{
{
tlMassnSniperAttack,
ARRAYSIZE ( tlMassnSniperAttack ),
bits_COND_HEAR_SOUND,
0,
"MassnSniperAttack"
},
};
DEFINE_CUSTOM_SCHEDULES( CMMassn )
{
slMassnSniperAttack,
};
IMPLEMENT_CUSTOM_SCHEDULES( CMMassn, CMHGrunt );
//=========================================================
// SetActivity
//=========================================================
void CMMassn :: SetActivity ( Activity NewActivity )
{
int iSequence = ACTIVITY_NOT_AVAILABLE;
void *pmodel = GET_MODEL_PTR( ENT(pev) );
switch ( NewActivity )
{
case ACT_RANGE_ATTACK1:
// shooting standing or shooting crouched
if (FBitSet( pev->weapons, MASSN_SNIPERRIFLE))
{
// Always standing
iSequence = LookupSequence( "standing_m40a1" );
}
else
{
if ( m_fStanding )
{
// get aimable sequence
iSequence = LookupSequence( "standing_mp5" );
}
else
{
// get crouching shoot
iSequence = LookupSequence( "crouching_mp5" );
}
}
break;
default:
CMHGrunt::SetActivity(NewActivity);
return;
}
m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present
// Set to the desired anim, or default anim if the desired is not present
if ( iSequence > ACTIVITY_NOT_AVAILABLE )
{
if ( pev->sequence != iSequence || !m_fSequenceLoops )
{
pev->frame = 0;
}
pev->sequence = iSequence; // Set to the reset anim (if it's there)
ResetSequenceInfo( );
SetYawSpeed();
}
else
{
// Not available try to get default anim
ALERT ( at_console, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity );
pev->sequence = 0; // Set to the reset anim (if it's there)
}
}
//=========================================================
// GetScheduleOfType - Override schedule for sniper attack
//=========================================================
Schedule_t* CMMassn :: GetScheduleOfType ( int Type )
{
switch ( Type )
{
case SCHED_RANGE_ATTACK1:
{
if (FBitSet(pev->weapons, MASSN_SNIPERRIFLE))
{
// sniper attack is always standing
m_fStanding = TRUE;
return &slMassnSniperAttack[ 0 ];
}
return CMHGrunt :: GetScheduleOfType ( Type );
}
default:
{
return CMHGrunt :: GetScheduleOfType ( Type );
}
}
}

View File

@@ -48,7 +48,7 @@ static META_FUNCTIONS gMetaFunctionTable =
GetEntityAPI2_Post, // pfnGetEntityAPI2_Post META; called after game DLL
NULL, // pfnGetNewDLLFunctions HL SDK2; called before game DLL
NULL, // pfnGetNewDLLFunctions_Post META; called after game DLL
GetEngineFunctions, // pfnGetEngineFunctions META; called before HL engine
NULL, // pfnGetEngineFunctions META; called before HL engine
GetEngineFunctions_Post, // pfnGetEngineFunctions_Post META; called after HL engine
};
@@ -56,8 +56,8 @@ static META_FUNCTIONS gMetaFunctionTable =
plugin_info_t Plugin_info = {
META_INTERFACE_VERSION, // interface version
"MonsterMod", // name
"3.0", // version
"24/02/2023", // date in DD/MM/YYYY format
"4.0", // version
"14/07/2023", // date in DD/MM/YYYY format
"botman, Rick90, Giegue", // original authors + recreation by...
"https://github.com/JulianR0/monstermod-redo", // url
"MONSTER", // logtag
@@ -87,6 +87,16 @@ cvar_t init_monster_show_deaths = {"monster_show_deaths", "1", FCVAR_EXTDLL, 0,
cvar_t *monster_show_deaths = NULL;
cvar_t init_monster_show_info = {"monster_show_info", "1", FCVAR_EXTDLL, 0, NULL};
cvar_t *monster_show_info = NULL;
cvar_t init_monster_turn_coeficient = {"monster_turn_coeficient", "1.75", FCVAR_EXTDLL, 0, NULL};
cvar_t *monster_turn_coeficient = NULL;
cvar_t init_monster_entity_config = {"monster_entity_config", "1", FCVAR_EXTDLL, 0, NULL};
cvar_t *monster_entity_config = NULL;
cvar_t init_globalmodellist = {"monster_gmr", "", FCVAR_EXTDLL, 0, NULL};
cvar_t *globalmodellist = NULL;
cvar_t init_globalsoundlist = {"monster_gsr", "", FCVAR_EXTDLL, 0, NULL};
cvar_t *globalsoundlist = NULL;
cvar_t init_monster_default_maxrange = {"monster_default_maxrange", "2048", FCVAR_EXTDLL, 0, NULL};
cvar_t *monster_default_maxrange = NULL;
// Metamod requesting info about this plugin:
@@ -146,6 +156,20 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m
CVAR_REGISTER(&init_monster_show_info);
monster_show_info = CVAR_GET_POINTER("monster_show_info");
CVAR_REGISTER(&init_monster_turn_coeficient);
monster_turn_coeficient = CVAR_GET_POINTER("monster_turn_coeficient");
CVAR_REGISTER(&init_monster_entity_config);
monster_entity_config = CVAR_GET_POINTER("monster_entity_config");
CVAR_REGISTER(&init_globalmodellist);
globalmodellist = CVAR_GET_POINTER("monster_gmr");
CVAR_REGISTER(&init_globalsoundlist);
globalsoundlist = CVAR_GET_POINTER("monster_gsr");
CVAR_REGISTER(&init_monster_default_maxrange);
monster_default_maxrange = CVAR_GET_POINTER("monster_default_maxrange");
return(TRUE);
}

View File

@@ -13,8 +13,14 @@
#include "meta_api.h"
#include "monster_plugin.h"
#include "ripent.h"
#include "globalreplace.h"
extern cvar_t *dllapi_log;
extern cvar_t *monster_entity_config;
extern cvar_t *globalmodellist;
extern cvar_t *globalsoundlist;
extern monster_type_t monster_types[];
extern int monster_spawn_count;
@@ -62,6 +68,84 @@ bool get_input(FILE *fp, char *input)
return FALSE; // no input found
}
void scan_monster_sound(FILE *fp, edict_t *pMonster )
{
char input[1024];
while (get_input(fp, input))
{
// might slip through
if (strlen(input) == 0)
continue;
char *source = strtok(input, " \t");
char *destination = strtok(NULL, " \t");
// Remove all quotes
char parse[128] = {0};
int skip;
// source
skip = 0;
for (unsigned i = 0; i < strlen(source); i++)
{
if (source[i] == '"')
{
skip++;
continue;
}
parse[i-skip] = source[i];
}
parse[strlen(parse)] = '\0';
strcpy(source, parse);
// destination
memset(parse, 0, sizeof(parse));
skip = 0;
for (unsigned i = 0; i < strlen(destination); i++)
{
if (destination[i] == '"')
{
skip++;
continue;
}
parse[i-skip] = destination[i];
}
parse[strlen(parse)] = '\0';
strcpy(destination, parse);
if ( pMonster )
REPLACER::AddIndividualSound( pMonster, source, destination );
else
PRECACHE_SOUND2(destination);
}
}
void process_monster_sound(edict_t *pMonster, char *fileName)
{
char game_dir[256];
FILE *fp = NULL;
// find the directory name of the currently running MOD...
(*g_engfuncs.pfnGetGameDir)(game_dir);
char srPath[192];
// SC soundlist path starts from sound/MAPNAME
sprintf(srPath, "%s/sound/%s/%s", game_dir, STRING(gpGlobals->mapname), fileName);
if (access(srPath, 0) == 0)
{
if ((fp = fopen(srPath, "r")) != NULL)
{
scan_monster_sound(fp, pMonster);
fclose(fp);
}
}
return;
}
void scan_monster_cfg(FILE *fp)
{
// Let's make a full rework of this. -Giegue
@@ -110,7 +194,7 @@ void scan_monster_cfg(FILE *fp)
monster = TRUE;
}
}
else if (strcmp(monster_types[mIndex].name, "monstermaker") == 0)
else if (strcmp(monster_types[mIndex].name, "monstermaker") == 0 || strcmp(monster_types[mIndex].name, "squadmaker") == 0)
{
// A monster spawner, add it to the list
if (monster_spawn_count == MAX_MONSTERS)
@@ -120,6 +204,21 @@ void scan_monster_cfg(FILE *fp)
badent = TRUE;
}
else
{
monster_spawnpoint[monster_spawn_count].monster = 32; // monstermaker index is fixed at 32
monster_types[32].need_to_precache = TRUE;
monster = TRUE;
}
}
else if (strcmp(monster_types[mIndex].name, "ambient_music") == 0)
{
// TODO - Extra entities should go towards a separate counter like nodes
if (monster_spawn_count == MAX_MONSTERS)
{
LOG_MESSAGE(PLID, "ERROR: can't add ambient_music, reached MAX_MONSTERS!");
badent = TRUE;
}
else
{
monster_spawnpoint[monster_spawn_count].monster = mIndex;
monster_types[mIndex].need_to_precache = TRUE;
@@ -245,7 +344,7 @@ void scan_monster_cfg(FILE *fp)
if (monster)
{
// only applicable for normal monsters
if (strcmp(data[kvd_index-1].value, "monstermaker") != 0)
if (strcmp(data[kvd_index-1].value, "monstermaker") != 0 && strcmp(data[kvd_index-1].value, "squadmaker") != 0)
{
// precache the custom model here
PRECACHE_MODEL( data[i].value );
@@ -256,12 +355,28 @@ void scan_monster_cfg(FILE *fp)
}
}
}
else if (strcmp(data[i].key, "soundlist") == 0)
{
if (monster)
{
// file handling, string must not be empty
if (strlen(data[i].value))
{
// process and precache the replacement sounds
process_monster_sound( NULL, data[i].value );
// the entity will need the keyvalue
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
}
}
}
else if (strcmp(data[i].key, "new_model") == 0)
{
if (monster)
{
// only applicable for monstermaket entity
if (strcmp(data[kvd_index-1].value, "monstermaker") == 0)
// only applicable for monstermaker entity
if (strcmp(data[kvd_index-1].value, "monstermaker") == 0 || strcmp(data[kvd_index-1].value, "squadmaker") == 0)
{
// precache the custom model
PRECACHE_MODEL( data[i].value );
@@ -277,7 +392,7 @@ void scan_monster_cfg(FILE *fp)
if (monster)
{
// this keyvalue is only valid for monstermaker entity
if (strcmp(data[kvd_index-1].value, "monstermaker") == 0)
if (strcmp(data[kvd_index-1].value, "monstermaker") == 0 || strcmp(data[kvd_index-1].value, "squadmaker") == 0)
{
// process the entity precache here
int mIndex;
@@ -296,6 +411,22 @@ void scan_monster_cfg(FILE *fp)
}
}
}
else if (strcmp(data[i].key, "message") == 0)
{
if (monster)
{
// only applicable for ambient_music
if (strcmp(data[kvd_index - 1].value, "ambient_music") == 0)
{
// precache the sound here
PRECACHE_GENERIC(data[i].value);
// the entity will need the keyvalue
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
}
}
}
else
{
// We do not know this keyvalue, but an specific entity might use it.
@@ -371,51 +502,564 @@ void scan_monster_cfg(FILE *fp)
}
}
void scan_monster_bsp(void)
{
// TODO: code duplication galore! optimize this for T5 milestone. -Giegue
epair_t *kv_pair;
pKVD data[MAX_KEYVALUES];
int kvd_index;
bool use_monstermod_explicit;
bool use_monstermod;
int classname_kvdI, mIndex;
float x, y, z;
bool badent, monster, node;
// go through all entities
for (int ent = 1; ent < num_entities; ent++)
{
kv_pair = entities[ent].epairs;
kvd_index = 0;
use_monstermod_explicit = false;
use_monstermod = true;
classname_kvdI = 0;
badent = monster = node = false;
// examine all keys
while (kv_pair != NULL)
{
// entities cannot be this big!
if (kvd_index >= MAX_KEYVALUES)
{
LOG_MESSAGE(PLID, "WARNING: can't process entity #%i - too many keyvalues", ent);
use_monstermod = false;
use_monstermod_explicit = false;
break;
}
if (strcmp(kv_pair->key, "classname") == 0)
{
// the entity we are trying to spawn could already exist within the game
// use the engine's CREATE_NAMED_ENTITY to see if it's valid or not
edict_t *existsGAME = CREATE_NAMED_ENTITY( MAKE_STRING( kv_pair->value ) );
if ( !FNullEnt( existsGAME ) )
{
// this entity already exists and we should ignore it
// use REMOVE_ENTITY instead of UTIL_Remove!
// UTIL_Remove sets FL_KILLME to remove the entity on the next frame, that won't do.
// REMOVE_ENTITY instead removes it instantly, which is needed to prevent server crashes
// due to "ED_Alloc: no free edicts" error.
REMOVE_ENTITY( existsGAME ); // get rid of the temporary entity
use_monstermod = false; // stick with game entity
}
}
else if (strcmp(kv_pair->key, "use_monstermod") == 0)
{
if (atoi(kv_pair->value) == 1)
{
// The extra plugin must be available to handle the old entity!
if (CVAR_GET_FLOAT("_hl_explicit"))
{
// EXPLICITY requested to use monstermod for this entity
use_monstermod_explicit = true;
}
else
LOG_MESSAGE(PLID, "WARNING: can't explicity add entity #%i - add-on plugin unavailable", ent);
}
}
strcpy(data[kvd_index].key, kv_pair->key);
strcpy(data[kvd_index].value, kv_pair->value);
kvd_index++;
kv_pair = kv_pair->next;
}
// spawn a monstermod entity?
if (use_monstermod_explicit || use_monstermod)
{
// find classname keyvalue
for (int i = 0; i < kvd_index; i++)
{
if (strcmp(data[i].key, "classname") == 0)
{
for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
{
if (strcmp(data[i].value, monster_types[mIndex].name) == 0)
{
// Match found, check if it's a node
if (strcmp(monster_types[mIndex].name, "info_node") == 0)
{
// Normal node
if (node_spawn_count == MAX_NODES)
{
LOG_MESSAGE(PLID, "ERROR: can't add node, reached MAX_NODES!");
badent = true;
}
else
node = true;
}
else if (strcmp(monster_types[mIndex].name, "info_node_air") == 0)
{
// Aerial node
if (node_spawn_count == MAX_NODES)
{
LOG_MESSAGE(PLID, "ERROR: can't add node, reached MAX_NODES!");
badent = true;
}
else
{
node_spawnpoint[node_spawn_count].is_air_node = true;
node = true;
}
}
else
{
// Assume it's a monster and add it to the list
// (Extra entities are built as CMBaseMonster)
if (monster_spawn_count == MAX_MONSTERS)
{
LOG_MESSAGE(PLID, "ERROR: can't add entity, reached MAX_MONSTERS!");
badent = true;
}
else
{
// Aliases
if (strcmp(monster_types[mIndex].name, "squadmaker") == 0)
mIndex = 32; // monstermaker
monster_spawnpoint[monster_spawn_count].monster = mIndex;
monster_types[mIndex].need_to_precache = true;
monster = true;
}
}
classname_kvdI = i;
break;
}
}
if (monster_types[mIndex].name[0] == 0)
{
LOG_MESSAGE(PLID, "unknown classname: %s", data[i].value);
badent = true;
}
}
}
if (!badent)
{
// Make room for entity-specific keyvalues.
if (monster)
{
// Can I use malloc/calloc again or you are going to crash cuz you feel like it? >.>
monster_spawnpoint[monster_spawn_count].keyvalue = (pKVD*)calloc(MAX_KEYVALUES, sizeof(*monster_spawnpoint[monster_spawn_count].keyvalue));
}
// process entity keyvalues
for (int i = 0; i < kvd_index; i++)
{
// duplicates are overwritten
if (strcmp(data[i].key, "origin") == 0)
{
if (sscanf(data[i].value, "%f %f %f", &x, &y, &z) != 3)
{
LOG_MESSAGE(PLID, "ERROR: invalid origin: %s", data[i].value); // print conflictive line
// reset origin to g_vecZero
LOG_MESSAGE(PLID, "ERROR: entity will spawn at 0 0 0");
x = y = z = 0;
}
if (monster)
{
monster_spawnpoint[monster_spawn_count].origin[0] = x;
monster_spawnpoint[monster_spawn_count].origin[1] = y;
monster_spawnpoint[monster_spawn_count].origin[2] = z;
}
else if (node)
{
node_spawnpoint[node_spawn_count].origin[0] = x;
node_spawnpoint[node_spawn_count].origin[1] = y;
node_spawnpoint[node_spawn_count].origin[2] = z;
}
}
else if (strcmp(data[i].key, "angles") == 0)
{
if (monster)
{
if (sscanf(data[i].value, "%f %f %f", &x, &y, &z) != 3)
{
LOG_MESSAGE(PLID, "ERROR: invalid angles: %s", data[i].value); // print conflictive line
// reset angles to g_vecZero
LOG_MESSAGE(PLID, "ERROR: entity angles will be set to 0 0 0");
x = y = z = 0;
}
monster_spawnpoint[monster_spawn_count].angles[0] = x;
monster_spawnpoint[monster_spawn_count].angles[1] = y;
monster_spawnpoint[monster_spawn_count].angles[2] = z;
}
}
else if (strcmp(data[i].key, "spawnflags") == 0)
{
if (monster)
{
if (sscanf(data[i].value, "%f", &x) != 1)
{
LOG_MESSAGE(PLID, "ERROR: invalid spawnflags: %s", data[i].value); // print conflictive line
// default to no spawnflags
LOG_MESSAGE(PLID, "ERROR: entity spawnflags will be set to none (0)");
x = 0;
}
monster_spawnpoint[monster_spawn_count].spawnflags = x;
}
}
else if (strcmp(data[i].key, "model") == 0)
{
if (monster)
{
// only applicable for normal monsters
if (strcmp(data[classname_kvdI].value, "monstermaker") != 0 && strcmp(data[classname_kvdI].value, "squadmaker") != 0)
{
// precache the custom model here
PRECACHE_MODEL( data[i].value );
// the entity will need the keyvalue
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
}
}
}
else if (strcmp(data[i].key, "soundlist") == 0)
{
if (monster)
{
// file handling, string must not be empty
if (strlen(data[i].value))
{
// process and precache the replacement sounds
process_monster_sound( NULL, data[i].value );
// the entity will need the keyvalue
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
}
}
}
else if (strcmp(data[i].key, "new_model") == 0)
{
if (monster)
{
// only applicable for monstermaker entity
if (strcmp(data[classname_kvdI].value, "monstermaker") == 0 || strcmp(data[classname_kvdI].value, "squadmaker") == 0)
{
// precache the custom model
PRECACHE_MODEL( data[i].value );
// the entity will need the keyvalue as well
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
}
}
}
else if (strcmp(data[i].key, "monstertype") == 0)
{
if (monster)
{
// this keyvalue is only valid for monstermaker entity
if (strcmp(data[classname_kvdI].value, "monstermaker") == 0 || strcmp(data[classname_kvdI].value, "squadmaker") == 0)
{
// process the entity precache here
for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++)
{
if (strcmp(data[i].value, monster_types[mIndex].name) == 0)
{
monster_types[mIndex].need_to_precache = TRUE;
break; // only one monster at a time
}
}
// pass the keyvalue to the entity
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
}
}
}
else if (strcmp(data[i].key, "message") == 0)
{
if (monster)
{
// only applicable for ambient_music
if (strcmp(data[classname_kvdI].value, "ambient_music") == 0)
{
// precache the sound here
PRECACHE_GENERIC(data[i].value);
// the entity will need the keyvalue
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
}
}
}
else
{
// We do not know this keyvalue, but an specific entity might use it.
// Save it for later
if (monster)
{
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key);
strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value);
}
}
}
if (monster)
{
// Spawn right away
monster_spawnpoint[monster_spawn_count].need_to_respawn = TRUE;
monster_spawn_count++;
}
else if (node)
{
// Increase node count
node_spawn_count++;
}
// Log on? Print all the entities that were added
if (dllapi_log->value)
{
// Classname only, or we will flood the server!
LOG_CONSOLE(PLID, "[DEBUG] Added entity: %s", data[classname_kvdI].value);
}
}
}
}
}
void scan_extra_cfg(FILE *fp)
{
char input[1024];
while (get_input(fp, input))
{
char *cmd = strtok(input, " ");
char *value = strtok(NULL, " ");
if (value == NULL)
continue; // command with no value, skip
// Remove all quotes from "value"
char parse[128] = {0};
int skip = 0;
for (unsigned i = 0; i < strlen(value); i++)
{
if (value[i] == '"')
{
skip++;
continue;
}
parse[i-skip] = value[i];
}
parse[strlen(parse)] = '\0';
strcpy(value, parse);
if (strcmp(cmd, "globalmodellist") == 0)
{
// ugh...
//globalmodellist->string = value;
CVAR_SET_STRING( "monster_gmr", value );
// Verbose if logging is enabled
if (dllapi_log->value)
LOG_CONSOLE(PLID, "[DEBUG] Using global model replacement file: %s", value);
}
if (strcmp(cmd, "globalsoundlist") == 0)
{
//globalsoundlist->string = value;
CVAR_SET_STRING( "monster_gsr", value );
// Verbose if logging is enabled
if (dllapi_log->value)
LOG_CONSOLE(PLID, "[DEBUG] Using global sound replacement file: %s", value);
}
}
}
void scan_monster_replace(FILE *fp, bool toGSR )
{
char input[1024];
while (get_input(fp, input))
{
// might slip through
if (strlen(input) == 0)
continue;
char *source = strtok(input, " \t");
char *destination = strtok(NULL, " \t");
// Remove all quotes
char parse[128] = {0};
int skip;
// source
skip = 0;
for (unsigned i = 0; i < strlen(source); i++)
{
if (source[i] == '"')
{
skip++;
continue;
}
parse[i-skip] = source[i];
}
parse[strlen(parse)] = '\0';
strcpy(source, parse);
// destination
memset(parse, 0, sizeof(parse));
skip = 0;
for (unsigned i = 0; i < strlen(destination); i++)
{
if (destination[i] == '"')
{
skip++;
continue;
}
parse[i-skip] = destination[i];
}
parse[strlen(parse)] = '\0';
strcpy(destination, parse);
if ( toGSR )
REPLACER::AddGlobalSound( source, destination );
else
REPLACER::AddGlobalModel( source, destination );
}
}
bool process_monster_cfg(void)
{
char game_dir[256];
char filename[256];
char BSPfilename[256]; // to read ents directly from BSP
char CFGfilename[256]; // read ents from MAPNAME_monster.cfg file
char EXTfilename[256]; // extra map configs from MAPNAME.cfg
FILE *fp = NULL;
monster_spawn_count = 0;
node_spawn_count = 0;
// find the directory name of the currently running MOD...
(*g_engfuncs.pfnGetGameDir)(game_dir);
strcpy(filename, game_dir);
#ifdef __linux__
strcat(filename, "/maps/");
#else
strcat(filename, "\\maps\\");
#endif
strcat(filename, STRING(gpGlobals->mapname));
strcat(filename, "_monster.cfg");
// build route...
strcpy(CFGfilename, game_dir);
strcat(CFGfilename, "/maps/");
strcat(CFGfilename, STRING(gpGlobals->mapname));
strcpy(BSPfilename, CFGfilename);
strcpy(EXTfilename, CFGfilename);
// check if the map specific filename exists...
if (access(filename, 0) == 0)
strcat(BSPfilename, ".bsp");
strcat(CFGfilename, "_monster.cfg");
strcat(EXTfilename, ".cfg");
// process config files?
// -1 = don't process monster config, dynamic spawns only
// 0 = read entities from BSP file
// 1 = read entities from CFG file
// 2 = read entities from both, BSP first, then CFG file
if (monster_entity_config->value >= 0)
{
if (dllapi_log->value)
// read from bsp? (mode 0 or 2)
if (monster_entity_config->value != 1)
{
//META_CONS("[MONSTER] Processing config file=%s", filename);
LOG_MESSAGE(PLID, "Processing config file=%s", filename);
LoadBSPFile(BSPfilename);
ParseEntities();
scan_monster_bsp();
}
if ((fp = fopen(filename, "r")) == NULL)
// read from cfg? (mode 1 or 2)
if (monster_entity_config->value > 0)
{
//META_CONS("[MONSTER] ERROR: Could not open \"%s\"!", filename);
LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\" file!", filename);
return TRUE; // error
// check if the map specific filename exists...
if (access(CFGfilename, 0) == 0)
{
if (dllapi_log->value)
{
//META_CONS("[MONSTER] Processing config file=%s", filename);
LOG_MESSAGE(PLID, "Processing config file '%s'", CFGfilename);
}
if ((fp = fopen(CFGfilename, "r")) == NULL)
{
//META_CONS("[MONSTER] ERROR: Could not open \"%s\"!", filename);
LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\" file!", CFGfilename);
return TRUE; // error
}
scan_monster_cfg(fp);
fclose(fp);
}
}
}
/* The code is only getting worse from here, I have to finish T4 quickly
* so I can move into making actual clean and optimized code for the final tier...
* -Giegue */
scan_monster_cfg(fp);
// extra map configs
if (access(EXTfilename, 0) == 0)
{
// first read configs
if ((fp = fopen(EXTfilename, "r")) != NULL)
{
scan_extra_cfg(fp);
fclose(fp);
}
// then process them here
if (strlen(globalmodellist->string))
{
char gmrPath[192];
fclose(fp);
// SC globalmodellist path starts from models/MAPNAME
sprintf(gmrPath, "%s/models/%s/%s", game_dir, STRING(gpGlobals->mapname), globalmodellist->string);
if (access(gmrPath, 0) == 0)
{
if ((fp = fopen(gmrPath, "r")) != NULL)
{
scan_monster_replace(fp, false);
fclose(fp);
}
}
}
if (strlen(globalsoundlist->string))
{
char gsrPath[192];
// SC globalsoundlist path starts from sound/MAPNAME
sprintf(gsrPath, "%s/sound/%s/%s", game_dir, STRING(gpGlobals->mapname), globalsoundlist->string);
if (access(gsrPath, 0) == 0)
{
if ((fp = fopen(gsrPath, "r")) != NULL)
{
scan_monster_replace(fp, true);
fclose(fp);
}
}
}
}
return FALSE; // all ok
}
bool scan_monster_precache_cfg(FILE *fp)
{
char input[1024];

View File

@@ -1,437 +0,0 @@
# Microsoft Developer Studio Project File - Name="monster_mm" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=monster_mm - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "monster_mm.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "monster_mm.mak" CFG="monster_mm - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "monster_mm - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "monster_mm - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "monster_mm - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "monster_mm_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\dlls" /I "..\common" /I "..\engine" /I "..\pm_shared" /I "..\metamod" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "monster_mm_EXPORTS" /D strcasecmp=stricmp /D strncasecmp=_strnicmp /FD /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /def:".\monster_mm.def"
!ELSEIF "$(CFG)" == "monster_mm - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "monster_mm_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\dlls" /I "..\common" /I "..\engine" /I "..\pm_shared" /I "..\metamod" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "monster_mm_EXPORTS" /D strcasecmp=stricmp /D strncasecmp=_strnicmp /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /def:".\monster_mm.def" /pdbtype:sept
!ENDIF
# Begin Target
# Name "monster_mm - Win32 Release"
# Name "monster_mm - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\agrunt.cpp
# End Source File
# Begin Source File
SOURCE=.\AI_BaseNPC_Schedule.cpp
# End Source File
# Begin Source File
SOURCE=.\animating.cpp
# End Source File
# Begin Source File
SOURCE=.\animation.cpp
# End Source File
# Begin Source File
SOURCE=.\apache.cpp
# End Source File
# Begin Source File
SOURCE=.\barney.cpp
# End Source File
# Begin Source File
SOURCE=.\bigmomma.cpp
# End Source File
# Begin Source File
SOURCE=.\bullsquid.cpp
# End Source File
# Begin Source File
SOURCE=.\cmbase.cpp
# End Source File
# Begin Source File
SOURCE=.\combat.cpp
# End Source File
# Begin Source File
SOURCE=.\controller.cpp
# End Source File
# Begin Source File
SOURCE=.\defaultai.cpp
# End Source File
# Begin Source File
SOURCE=.\dllapi.cpp
# End Source File
# Begin Source File
SOURCE=.\effects.cpp
# End Source File
# Begin Source File
SOURCE=.\explode.cpp
# End Source File
# Begin Source File
SOURCE=.\flyingmonster.cpp
# End Source File
# Begin Source File
SOURCE=.\gargantua.cpp
# End Source File
# Begin Source File
SOURCE=.\ggrenade.cpp
# End Source File
# Begin Source File
SOURCE=.\gonome.cpp
# End Source File
# Begin Source File
SOURCE=.\h_ai.cpp
# End Source File
# Begin Source File
SOURCE=.\h_export.cpp
# End Source File
# Begin Source File
SOURCE=.\hassassin.cpp
# End Source File
# Begin Source File
SOURCE=.\headcrab.cpp
# End Source File
# Begin Source File
SOURCE=.\hgrunt.cpp
# End Source File
# Begin Source File
SOURCE=.\hornet.cpp
# End Source File
# Begin Source File
SOURCE=.\houndeye.cpp
# End Source File
# Begin Source File
SOURCE=.\hwgrunt.cpp
# End Source File
# Begin Source File
SOURCE=.\islave.cpp
# End Source File
# Begin Source File
SOURCE=.\massn.cpp
# End Source File
# Begin Source File
SOURCE=.\monster_api.cpp
# End Source File
# Begin Source File
SOURCE=.\monster_config.cpp
# End Source File
# Begin Source File
SOURCE=.\monstermaker.cpp
# End Source File
# Begin Source File
SOURCE=.\monsters.cpp
# End Source File
# Begin Source File
SOURCE=.\monsterstate.cpp
# End Source File
# Begin Source File
SOURCE=.\nodes.cpp
# End Source File
# Begin Source File
SOURCE=.\otis.cpp
# End Source File
# Begin Source File
SOURCE=.\pitdrone.cpp
# End Source File
# Begin Source File
SOURCE=.\rgrunt.cpp
# End Source File
# Begin Source File
SOURCE=.\scientist.cpp
# End Source File
# Begin Source File
SOURCE=.\shock.cpp
# End Source File
# Begin Source File
SOURCE=.\shockroach.cpp
# End Source File
# Begin Source File
SOURCE=.\skill.cpp
# End Source File
# Begin Source File
SOURCE=.\sound.cpp
# End Source File
# Begin Source File
SOURCE=.\sporegrenade.cpp
# End Source File
# Begin Source File
SOURCE=.\squeakgrenade.cpp
# End Source File
# Begin Source File
SOURCE=.\strooper.cpp
# End Source File
# Begin Source File
SOURCE=.\stukabat.cpp
# End Source File
# Begin Source File
SOURCE=.\subs.cpp
# End Source File
# Begin Source File
SOURCE=.\talkmonster.cpp
# End Source File
# Begin Source File
SOURCE=.\turret.cpp
# End Source File
# Begin Source File
SOURCE=.\util.cpp
# End Source File
# Begin Source File
SOURCE=.\voltigore.cpp
# End Source File
# Begin Source File
SOURCE=.\weapons.cpp
# End Source File
# Begin Source File
SOURCE=.\zombie.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\activity.h
# End Source File
# Begin Source File
SOURCE=.\activitymap.h
# End Source File
# Begin Source File
SOURCE=.\animation.h
# End Source File
# Begin Source File
SOURCE=.\cdll_dll.h
# End Source File
# Begin Source File
SOURCE=.\cmbase.h
# End Source File
# Begin Source File
SOURCE=.\cmbaseextra.h
# End Source File
# Begin Source File
SOURCE=.\cmbasemonster.h
# End Source File
# Begin Source File
SOURCE=.\cmflyingmonster.h
# End Source File
# Begin Source File
SOURCE=.\cmtalkmonster.h
# End Source File
# Begin Source File
SOURCE=.\decals.h
# End Source File
# Begin Source File
SOURCE=.\defaultai.h
# End Source File
# Begin Source File
SOURCE=.\doors.h
# End Source File
# Begin Source File
SOURCE=.\effects.h
# End Source File
# Begin Source File
SOURCE=.\enginecallback.h
# End Source File
# Begin Source File
SOURCE=.\explode.h
# End Source File
# Begin Source File
SOURCE=.\extdll.h
# End Source File
# Begin Source File
SOURCE=.\func_break.h
# End Source File
# Begin Source File
SOURCE=.\hornet.h
# End Source File
# Begin Source File
SOURCE=.\monster_plugin.h
# End Source File
# Begin Source File
SOURCE=.\monsterevent.h
# End Source File
# Begin Source File
SOURCE=.\monsters.h
# End Source File
# Begin Source File
SOURCE=.\nodes.h
# End Source File
# Begin Source File
SOURCE=.\plane.h
# End Source File
# Begin Source File
SOURCE=.\schedule.h
# End Source File
# Begin Source File
SOURCE=.\shock.h
# End Source File
# Begin Source File
SOURCE=.\skill.h
# End Source File
# Begin Source File
SOURCE=.\util.h
# End Source File
# Begin Source File
SOURCE=.\vector.h
# End Source File
# Begin Source File
SOURCE=.\weapons.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

25
src/dlls/monster_mm.sln Normal file
View File

@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.1433
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "monster_mm", "monster_mm.vcxproj", "{E4F36B30-6406-4D6E-90F6-DE34744D2434}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E4F36B30-6406-4D6E-90F6-DE34744D2434}.Debug|x86.ActiveCfg = Debug|Win32
{E4F36B30-6406-4D6E-90F6-DE34744D2434}.Debug|x86.Build.0 = Debug|Win32
{E4F36B30-6406-4D6E-90F6-DE34744D2434}.Release|x86.ActiveCfg = Release|Win32
{E4F36B30-6406-4D6E-90F6-DE34744D2434}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {32C2F544-BCE4-4787-9C16-F85467CD69DA}
EndGlobalSection
EndGlobal

227
src/dlls/monster_mm.vcxproj Normal file
View File

@@ -0,0 +1,227 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{E4F36B30-6406-4D6E-90F6-DE34744D2434}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v141_xp</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v141_xp</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
<PostBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</PostBuildEventUseInBuild>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Midl>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>.\Debug/monster_mm.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\dlls;..\common;..\engine;..\pm_shared;..\metamod;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;monster_mm_EXPORTS;strcasecmp=stricmp;strncasecmp=_strnicmp;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\Debug/monster_mm.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>.\Debug/</AssemblerListingLocation>
<ObjectFileName>.\Debug/</ObjectFileName>
<ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<CompileAs>Default</CompileAs>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>.\Debug/monster_mm.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ModuleDefinitionFile>.\monster_mm.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/monster_mm.pdb</ProgramDatabaseFile>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>.\Debug/monster_mm.lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Midl>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MkTypLibCompatible>true</MkTypLibCompatible>
<SuppressStartupBanner>true</SuppressStartupBanner>
<TargetEnvironment>Win32</TargetEnvironment>
<TypeLibraryName>.\Release/monster_mm.tlb</TypeLibraryName>
</Midl>
<ClCompile>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\dlls;..\common;..\engine;..\pm_shared;..\metamod;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;monster_mm_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\Release/monster_mm.pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>.\Release/</AssemblerListingLocation>
<ObjectFileName>.\Release/</ObjectFileName>
<ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<CompileAs>Default</CompileAs>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>.\Release/monster_mm.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<ModuleDefinitionFile>.\monster_mm.def</ModuleDefinitionFile>
<ProgramDatabaseFile>.\Release/monster_mm.pdb</ProgramDatabaseFile>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention>
</DataExecutionPrevention>
<ImportLibrary>.\Release/monster_mm.lib</ImportLibrary>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="agrunt.cpp" />
<ClCompile Include="AI_BaseNPC_Schedule.cpp" />
<ClCompile Include="animating.cpp" />
<ClCompile Include="animation.cpp" />
<ClCompile Include="apache.cpp" />
<ClCompile Include="barney.cpp" />
<ClCompile Include="bigmomma.cpp" />
<ClCompile Include="bullsquid.cpp" />
<ClCompile Include="cmbase.cpp" />
<ClCompile Include="combat.cpp" />
<ClCompile Include="controller.cpp" />
<ClCompile Include="defaultai.cpp" />
<ClCompile Include="dllapi.cpp" />
<ClCompile Include="effects.cpp" />
<ClCompile Include="explode.cpp" />
<ClCompile Include="flyingmonster.cpp" />
<ClCompile Include="gargantua.cpp" />
<ClCompile Include="ggrenade.cpp" />
<ClCompile Include="globalreplace.cpp" />
<ClCompile Include="gonome.cpp" />
<ClCompile Include="h_ai.cpp" />
<ClCompile Include="h_export.cpp" />
<ClCompile Include="hassassin.cpp" />
<ClCompile Include="headcrab.cpp" />
<ClCompile Include="hgrunt.cpp" />
<ClCompile Include="hornet.cpp" />
<ClCompile Include="houndeye.cpp" />
<ClCompile Include="hwgrunt.cpp" />
<ClCompile Include="islave.cpp" />
<ClCompile Include="massn.cpp" />
<ClCompile Include="monster_api.cpp" />
<ClCompile Include="monster_config.cpp" />
<ClCompile Include="monstermaker.cpp" />
<ClCompile Include="monsters.cpp" />
<ClCompile Include="monsterstate.cpp" />
<ClCompile Include="music.cpp" />
<ClCompile Include="nodes.cpp" />
<ClCompile Include="otis.cpp" />
<ClCompile Include="pitdrone.cpp" />
<ClCompile Include="rgrunt.cpp" />
<ClCompile Include="ripent.cpp" />
<ClCompile Include="scientist.cpp" />
<ClCompile Include="shock.cpp" />
<ClCompile Include="shockroach.cpp" />
<ClCompile Include="skill.cpp" />
<ClCompile Include="sound.cpp" />
<ClCompile Include="sporegrenade.cpp" />
<ClCompile Include="squeakgrenade.cpp" />
<ClCompile Include="strooper.cpp" />
<ClCompile Include="stukabat.cpp" />
<ClCompile Include="subs.cpp" />
<ClCompile Include="talkmonster.cpp" />
<ClCompile Include="turret.cpp" />
<ClCompile Include="util.cpp" />
<ClCompile Include="voltigore.cpp" />
<ClCompile Include="weapons.cpp" />
<ClCompile Include="zombie.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="activity.h" />
<ClInclude Include="activitymap.h" />
<ClInclude Include="animation.h" />
<ClInclude Include="cdll_dll.h" />
<ClInclude Include="cmbase.h" />
<ClInclude Include="cmbaseextra.h" />
<ClInclude Include="cmbasemonster.h" />
<ClInclude Include="cmflyingmonster.h" />
<ClInclude Include="cmtalkmonster.h" />
<ClInclude Include="decals.h" />
<ClInclude Include="defaultai.h" />
<ClInclude Include="doors.h" />
<ClInclude Include="effects.h" />
<ClInclude Include="enginecallback.h" />
<ClInclude Include="explode.h" />
<ClInclude Include="extdll.h" />
<ClInclude Include="func_break.h" />
<ClInclude Include="globalreplace.h" />
<ClInclude Include="hornet.h" />
<ClInclude Include="monster_plugin.h" />
<ClInclude Include="monsterevent.h" />
<ClInclude Include="monsters.h" />
<ClInclude Include="nodes.h" />
<ClInclude Include="plane.h" />
<ClInclude Include="ripent.h" />
<ClInclude Include="schedule.h" />
<ClInclude Include="shock.h" />
<ClInclude Include="skill.h" />
<ClInclude Include="util.h" />
<ClInclude Include="vector.h" />
<ClInclude Include="weapons.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,285 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{c6c9a5d3-53c7-4dda-a7f7-a278343d08f6}</UniqueIdentifier>
<Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{7a512719-d6e9-4695-acde-c7239717ece9}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{af74e8b8-3ee2-4d62-b8cb-fa3952c4afed}</UniqueIdentifier>
<Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="agrunt.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AI_BaseNPC_Schedule.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="animating.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="animation.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="apache.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="barney.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="bigmomma.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="bullsquid.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="cmbase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="combat.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="controller.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="defaultai.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="dllapi.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="effects.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="explode.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="flyingmonster.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gargantua.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ggrenade.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gonome.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="h_ai.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="h_export.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hassassin.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="headcrab.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hgrunt.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hornet.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="houndeye.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hwgrunt.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="islave.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="massn.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="monster_api.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="monster_config.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="monstermaker.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="monsters.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="monsterstate.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="nodes.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="otis.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pitdrone.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="rgrunt.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="scientist.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="shock.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="shockroach.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="skill.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="sound.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="sporegrenade.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="squeakgrenade.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="strooper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="stukabat.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="subs.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="talkmonster.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="turret.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="voltigore.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="weapons.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="zombie.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ripent.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="music.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="globalreplace.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="activity.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="activitymap.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="animation.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cdll_dll.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cmbase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cmbaseextra.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cmbasemonster.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cmflyingmonster.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cmtalkmonster.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="decals.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="defaultai.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="doors.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="effects.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="enginecallback.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="explode.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="extdll.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="func_break.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="hornet.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="monster_plugin.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="monsterevent.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="monsters.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="nodes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="plane.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="schedule.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="shock.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="skill.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="util.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vector.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="weapons.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ripent.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="globalreplace.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -8,7 +8,7 @@
typedef struct
{
char key[33];
char value[33];
char value[481];
} pKVD;
#define MAX_KEYVALUES 32
@@ -30,7 +30,7 @@ typedef struct
CMBaseMonster *pMonster;
} monster_t;
#define MAX_MONSTER_ENTS 400 // increased from 200 so it can hold non-monster entities
#define MAX_MONSTER_ENTS 400
extern monster_t monsters[MAX_MONSTER_ENTS];
@@ -43,7 +43,7 @@ typedef struct {
bool need_to_respawn;
} monster_spawnpoint_t;
#define MAX_MONSTERS 100
#define MAX_MONSTERS 200
extern monster_spawnpoint_t monster_spawnpoint[MAX_MONSTERS];
// this is here to store if a node we want to spawn is an ordinary one, or a flying one

View File

@@ -58,6 +58,11 @@ void CMMonsterMaker :: KeyValue( KeyValueData *pkvd )
break; // grab the first entry we find
}
}
if (monster_types[mIndex].name[0] == 0)
{
ALERT ( at_logged, "[MONSTER] MonsterMaker - %s is not a valid monster type!\n", pkvd->szValue );
m_iMonsterIndex = -1;
}
pkvd->fHandled = TRUE;
}
else if ( FStrEq(pkvd->szKeyName, "new_model") )
@@ -65,6 +70,30 @@ void CMMonsterMaker :: KeyValue( KeyValueData *pkvd )
m_iszCustomModel = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if ( FStrEq(pkvd->szKeyName, "bloodcolor") )
{
m_iMonsterBlood = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if ( FStrEq(pkvd->szKeyName, "respawn_as_playerally") )
{
if (atoi(pkvd->szValue))
m_iClassifyOverride = CLASS_PLAYER_ALLY;
pkvd->fHandled = TRUE;
}
// These are to keep consistency with Sven Co-op's squadmaker entity.
// CMBaseMonster::KeyValue will process TriggerCondition/TriggerTarget
// keyvalues in the same way.
else if ( FStrEq(pkvd->szKeyName, "trigger_condition") )
{
m_iTriggerCondition = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if ( FStrEq(pkvd->szKeyName, "trigger_target") )
{
m_iszTriggerTarget = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CMBaseMonster::KeyValue( pkvd );
}
@@ -72,6 +101,17 @@ void CMMonsterMaker :: KeyValue( KeyValueData *pkvd )
void CMMonsterMaker :: Spawn( )
{
// likely omitted keyvalue, but it could truly be an alien grunt spawn
if ( m_iMonsterIndex == 0 )
{
if ( !monster_types[0].need_to_precache )
{
// monstertype was not defined
ALERT ( at_logged, "[MONSTER] Spawned a monstermaker entity without a monstertype! targetname: \"%s\"\n", STRING(pev->targetname) );
m_iMonsterIndex = -1;
}
}
pev->solid = SOLID_NOT;
m_cLiveChildren = 0;
@@ -109,6 +149,7 @@ void CMMonsterMaker :: Spawn( )
m_fFadeChildren = TRUE;
m_flGround = 0;
pev->classname = MAKE_STRING("monstermaker");
}
void CMMonsterMaker :: Precache( void )
@@ -122,8 +163,15 @@ void CMMonsterMaker :: Precache( void )
//=========================================================
void CMMonsterMaker::MakeMonster( void )
{
// monstermaker incorrectly setup or intentionally empty
if ( m_iMonsterIndex == -1 )
{
ALERT ( at_console, "[MONSTER] NULL Ent in MonsterMaker!\n" );
return;
}
edict_t *pent;
pKVD keyvalue[1]; // sometimes, i don't know what am i doing. -Giegue
pKVD keyvalue[MAX_KEYVALUES]; // sometimes, i don't know what am i doing. -Giegue
int createSF = SF_MONSTER_FALL_TO_GROUND;
if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren )
@@ -157,6 +205,7 @@ void CMMonsterMaker::MakeMonster( void )
if ( pev->spawnflags & SF_MONSTERMAKER_MONSTERCLIP )
createSF |= SF_MONSTER_HITMONSTERCLIP;
/* KEYVALUES */
// Monster is to have a custom model?
if ( !FStringNull( m_iszCustomModel ) )
{
@@ -164,12 +213,46 @@ void CMMonsterMaker::MakeMonster( void )
strcpy(keyvalue[0].key, "model");
strcpy(keyvalue[0].value, STRING( m_iszCustomModel ));
}
// Override monster blood color?
if ( m_iMonsterBlood )
{
// setup blood keyvalue
strcpy(keyvalue[1].key, "bloodcolor");
sprintf(keyvalue[1].value, "%i", m_iMonsterBlood);
}
// Trigger conditions set?
if ( !FStringNull( m_iszTriggerTarget ) )
{
// setup trigger keyvalues
strcpy(keyvalue[2].key, "TriggerCondition");
sprintf(keyvalue[2].value, "%i", m_iTriggerCondition);
strcpy(keyvalue[3].key, "TriggerTarget");
strcpy(keyvalue[3].value, STRING( m_iszTriggerTarget ));
}
// Weapons (For hgrunt/massn/rgrunt/etc...)
if ( pev->weapons )
{
strcpy(keyvalue[4].key, "weapons");
sprintf(keyvalue[4].value, "%i", pev->weapons);
}
// Monster's Name
if ( !FStringNull( m_szMonsterName ) )
{
strcpy(keyvalue[5].key, "displayname");
strcpy(keyvalue[5].value, STRING( m_szMonsterName ));
}
// Classify override
if ( m_iClassifyOverride )
{
strcpy(keyvalue[6].key, "classify");
sprintf(keyvalue[6].value, "%i", m_iClassifyOverride);
}
// Attempt to spawn monster
pent = spawn_monster(m_iMonsterIndex, pev->origin, pev->angles, createSF, keyvalue);
if ( pent == NULL )
{
ALERT ( at_console, "NULL Ent in MonsterMaker!\n" );
ALERT ( at_console, "[MONSTER] MonsterMaker - failed to spawn monster! targetname: \"%s\"\n", STRING(pev->targetname) );
return;
}
@@ -188,6 +271,23 @@ void CMMonsterMaker::MakeMonster( void )
pent->v.targetname = pev->netname;
}
// Pass parent's rendering effects to child
pent->v.rendermode = pev->rendermode;
pent->v.renderfx = pev->renderfx;
pent->v.renderamt = pev->renderamt;
pent->v.rendercolor = pev->rendercolor;
// Soundlist isn't "exactly" a keyvalue so pass it here
if ( m_srSoundList != NULL )
{
// it needs to be allocated first
CMBaseMonster *pChild = GetClassPtr((CMBaseMonster *)VARS(pent));
pChild->m_srSoundList = (REPLACER::REPLACER*)calloc(MAX_REPLACEMENTS, sizeof(*pChild->m_srSoundList));
memcpy(pChild->m_srSoundList, m_srSoundList, sizeof(REPLACER::REPLACER));
pChild->m_isrSounds = m_isrSounds;
}
m_cLiveChildren++;// count this monster
m_cNumMonsters--;

View File

@@ -39,7 +39,10 @@ extern DLL_GLOBAL BOOL g_fDrawLines;
extern CGraph WorldGraph;// the world node graph
extern cvar_t *monster_turn_coeficient;
extern cvar_t *monster_default_maxrange;
extern void process_monster_sound(edict_t *pMonster, char *fileName);
//=========================================================
// Eat - makes a monster full for a little while.
@@ -169,7 +172,7 @@ void CMBaseMonster :: Look ( int iDistance )
{
/* MonsterMod monster looking at another MonsterMod monster */
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pSightEnt));
// the looker will want to consider this entity
// don't check anything else about an entity that can't be seen, or an entity that you don't care about.
if ( IRelationship( pMonster ) != R_NO && UTIL_FInViewCone( pSightEnt, ENT(pev), m_flFieldOfView ) && !FBitSet( pSightEnt->v.flags, FL_NOTARGET ) && UTIL_FVisible( pSightEnt, ENT(pev) ) )
@@ -1552,7 +1555,7 @@ void CMBaseMonster :: Move ( float flInterval )
}
else
{
//jlb TaskFail();
TaskFail();
ALERT( at_aiconsole, "%s Failed to move (%d)!\n", STRING(pev->classname), HasMemory( bits_MEMORY_MOVE_FAILED ) );
//ALERT( at_aiconsole, "%f, %f, %f\n", pev->origin.z, (pev->origin + (vecDir * flCheckDist)).z, m_Route[m_iRouteIndex].vecLocation.z );
}
@@ -1661,8 +1664,9 @@ void CMBaseMonster :: MonsterInit ( void )
for (int i=0; i < MAX_OLD_ENEMIES; i++)
m_hOldEnemy[ i ] = NULL;
m_flDistTooFar = 1024.0;
m_flDistLook = 2048.0;
if (!m_flDistLook)
m_flDistLook = monster_default_maxrange->value;
m_flDistTooFar = m_flDistLook / 2; // always 50%
// set eye position
SetEyePosition();
@@ -2234,7 +2238,22 @@ float CMBaseMonster::ChangeYaw ( int yawSpeed )
ideal = pev->ideal_yaw;
if (current != ideal)
{
speed = (float)yawSpeed * gpGlobals->frametime * 10;
// -SamVanheer
if ( m_flLastYawTime == 0 )
{
m_flLastYawTime = gpGlobals->time - gpGlobals->frametime;
}
float delta = gpGlobals->time - m_flLastYawTime;
if ( delta > 0.25 )
delta = 0.25;
// let server operators modify the multiplier coeficient -Giegue
float multiplier = monster_turn_coeficient->value;
if ( multiplier < 0.1 || multiplier > 10.0 )
multiplier = 1.75;
speed = (float)yawSpeed * delta * multiplier;
move = ideal - current;
if (ideal > current)
@@ -2609,9 +2628,34 @@ void CMBaseMonster :: KeyValue( KeyValueData *pkvd )
m_iClassifyOverride = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "model"))
else if (FStrEq(pkvd->szKeyName, "bloodcolor"))
{
pev->model = ALLOC_STRING( pkvd->szValue );
switch ( atoi( pkvd->szValue ) )
{
case -1: m_bloodColor = DONT_BLEED; break;
case 1: m_bloodColor = BLOOD_COLOR_RED; break;
case 2: m_bloodColor = BLOOD_COLOR_YELLOW; break;
case 3: m_bloodColor = BLOOD_COLOR_BLUE; break;
case 4: m_bloodColor = BLOOD_COLOR_PINK; break;
case 5: m_bloodColor = BLOOD_COLOR_WHITE; break;
case 6: m_bloodColor = BLOOD_COLOR_ORANGE; break;
case 7: m_bloodColor = BLOOD_COLOR_BLACK; break;
case 8: m_bloodColor = BLOOD_COLOR_GREEN; break;
default: m_bloodColor = 0; break; // Invalid, set default
}
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "soundlist"))
{
if (strlen( pkvd->szValue ))
{
process_monster_sound(edict(), pkvd->szValue);
}
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "attackrange"))
{
m_flDistLook = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else

61
src/dlls/music.cpp Normal file
View File

@@ -0,0 +1,61 @@
//=========================================================
// Ambient Music - when triggered, it will play an mp3
// music file locally to players, looped or once.
//=========================================================
#include "extdll.h"
#include "util.h"
#include "cmbase.h"
#include "cmbasemonster.h"
#include "cmbaseextra.h"
// spawnflags
#define SF_MUSIC_LOOP 2 // music will loop instead of playing once.
#define SF_MUSIC_ACTIVATOR_ONLY 4 // only play to the one that activates this entity.
void CMAmbientMusic::KeyValue(KeyValueData *pkvd)
{
CMBaseMonster::KeyValue(pkvd);
}
void CMAmbientMusic::Spawn()
{
pev->solid = SOLID_NOT;
SetUse(&CMAmbientMusic::MusicUse);
pev->classname = MAKE_STRING("ambient_music");
}
void CMAmbientMusic::MusicUse(edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value)
{
// no music
if (FStringNull(pev->message))
return;
// not a player (if not to everyone)
if (pev->spawnflags & SF_MUSIC_ACTIVATOR_ONLY && !UTIL_IsPlayer(pActivator))
return;
if (pev->spawnflags & SF_MUSIC_ACTIVATOR_ONLY)
MESSAGE_BEGIN(MSG_ONE, SVC_STUFFTEXT, NULL, pActivator);
else
MESSAGE_BEGIN(MSG_ALL, SVC_STUFFTEXT);
// triggering off
if (useType == USE_OFF || m_fPlaying && useType != USE_ON)
{
WRITE_STRING("mp3 stop\n");
m_fPlaying = FALSE;
}
else // USE_ON / USE_TOGGLE
{
char szPath[256];
if (pev->spawnflags & SF_MUSIC_LOOP)
sprintf(szPath, "mp3 loop %s\n", STRING(pev->message));
else
sprintf(szPath, "mp3 play %s\n", STRING(pev->message));
WRITE_STRING(szPath);
m_fPlaying = TRUE;
}
MESSAGE_END();
}

View File

@@ -212,6 +212,10 @@ entvars_t* CGraph :: LinkEntForLink ( CLink *pLink, CNode *pNode )
//=========================================================
int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, NODEQUERY queryType )
{
// NULL pointers are becoming a nightmare... -Giegue
return FALSE;
#if 0
edict_t *pentWorld;
CMBaseEntity *pDoor;
TraceResult tr;
@@ -282,6 +286,7 @@ int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, N
}
return FALSE;
#endif
}
#if 0
@@ -1278,7 +1283,7 @@ int CGraph :: LinkVisibleNodes ( CLink *pLinkPool, FILE *file, int *piBadNode )
fprintf ( file, " Entity on connection: %s, name: %s Model: %s", STRING( VARS( pTraceEnt )->classname ), STRING ( VARS( pTraceEnt )->targetname ), STRING ( VARS(tr.pHit)->model ) );
}
fprintf ( file, "\n", j );
fprintf ( file, "\n" );
}
pLinkPool [ cTotalLinks ].m_iDestNode = j;
@@ -1889,17 +1894,17 @@ void CTestHull :: BuildNodeGraph( void )
switch ( hull )
{
case NODE_SMALL_HULL: // if this hull can't fit, nothing can, so drop the connection
fprintf ( file, "NODE_SMALL_HULL step %f\n", step );
fprintf ( file, "NODE_SMALL_HULL step %i\n", step );
pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~(bits_LINK_SMALL_HULL | bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL);
fSkipRemainingHulls = TRUE;// don't bother checking larger hulls
break;
case NODE_HUMAN_HULL:
fprintf ( file, "NODE_HUMAN_HULL step %f\n", step );
fprintf ( file, "NODE_HUMAN_HULL step %i\n", step );
pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~(bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL);
fSkipRemainingHulls = TRUE;// don't bother checking larger hulls
break;
case NODE_LARGE_HULL:
fprintf ( file, "NODE_LARGE_HULL step %f\n", step );
fprintf ( file, "NODE_LARGE_HULL step %i\n", step );
pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~bits_LINK_LARGE_HULL;
break;
}
@@ -3437,7 +3442,7 @@ void CGraph :: TestRoutingTables( void )
#endif
ALERT(at_aiconsole, "Routing is inconsistent!!!\n");
ALERT(at_aiconsole, "(%d to %d |%d/%d)1:", iFrom, iTo, iHull, iCap);
for (int i = 0; i < cPathSize1; i++)
for (i = 0; i < cPathSize1; i++)
{
ALERT(at_aiconsole, "%d ", pMyPath[i]);
}

View File

@@ -142,7 +142,7 @@ void CMOtis::Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
pev->health = gSkillData.otisHealth;
pev->view_ofs = Vector(0, 0, 50);// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello

View File

@@ -60,6 +60,9 @@ void CPitdroneSpike::Spawn(void)
void CPitdroneSpike::SpikeTouch(edict_t *pOther)
{
if (m_hOwner == NULL)
pev->owner = NULL;
int iPitch;
// splat sound
@@ -89,7 +92,9 @@ void CPitdroneSpike::SpikeTouch(edict_t *pOther)
else
{
entvars_t *pevOwner = VARS(pev->owner);
if (pevOwner == NULL)
pevOwner = pev;
if ( UTIL_IsPlayer( pOther ) )
UTIL_TakeDamage( pOther, pev, pevOwner, gSkillData.pitdroneDmgSpit, DMG_GENERIC | DMG_NEVERGIB );
else if ( pOther->v.euser4 != NULL )
@@ -97,7 +102,9 @@ void CPitdroneSpike::SpikeTouch(edict_t *pOther)
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
pMonster->TakeDamage( pev, pevOwner, gSkillData.pitdroneDmgSpit, DMG_GENERIC | DMG_NEVERGIB );
}
else
UTIL_TakeDamageExternal( pOther, pev, pevOwner, gSkillData.pitdroneDmgSpit, DMG_GENERIC | DMG_NEVERGIB );
if (RANDOM_LONG(0,1))
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM, 0, iPitch);
else
@@ -139,6 +146,7 @@ edict_t *CPitdroneSpike::Shoot(entvars_t *pevOwner, Vector vecStart, Vector vecV
pSpit->pev->velocity = vecVelocity;
pSpit->pev->angles = vecAngles;
pSpit->pev->owner = ENT( pevOwner );
pSpit->m_hOwner = ENT( pevOwner );
pSpit->SetThink(&CPitdroneSpike::StartTrail);
pSpit->pev->nextthink = gpGlobals->time + 0.1;
@@ -568,7 +576,7 @@ void CMPitdrone::Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0;
pev->health = gSkillData.pitdroneHealth;
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
@@ -603,7 +611,7 @@ void CMPitdrone::Precache()
{
PRECACHE_MODEL("models/pit_drone.mdl");
PRECACHE_MODEL("models/pit_drone_gibs.mdl");
iPitdroneSpitSprite = PRECACHE_MODEL("sprites/tinyspit.spr");// client side spittle.
iPitdroneSpitSprite = PRECACHE_MODELINDEX("sprites/tinyspit.spr");// client side spittle.
PRECACHE_SOUND_ARRAY(pAttackMissSounds);
PRECACHE_SOUND_ARRAY(pIdleSounds);
@@ -640,7 +648,7 @@ void CMPitdrone::Precache()
PRECACHE_SOUND("weapons/xbow_hitbod2.wav");
PRECACHE_SOUND("weapons/xbow_hit1.wav");
#if FEATURE_PITDRONE_SPIKE_TRAIL
iSpikeTrail = PRECACHE_MODEL("sprites/spike_trail.spr");
iSpikeTrail = PRECACHE_MODELINDEX("sprites/spike_trail.spr");
#endif
}

View File

@@ -53,21 +53,26 @@
#define RGRUNT_MAX_SPARKS 5
//=========================================================
// These sounds are muted for Robo Grunts
// This sound is muted for Robo Grunts
//=========================================================
BOOL CMRGrunt::FOkToSpeak(void)
{
return FALSE;
}
void CMRGrunt::IdleSound(void)
{
}
void CMRGrunt::PainSound(void)
{
}
// This is a gross hack: RGRUNT inherits from HGRUNT, so...
// to avoid duplicating code, I'm going to define it here
// then use it in hgrunt whenever speech is needed. -Giegue
const char *CMRGrunt::pRobotSentences[] =
{
"RB_GREN", // Sven Co-op uses "RB_" for rgrunt sentences
"RB_ALERT",
"RB_MONSTER",
"RB_COVER",
"RB_THROW",
"RB_CHARGE",
"RB_TAUNT",
};
//=========================================================
// DeathSound
//=========================================================
@@ -387,7 +392,7 @@ void CMRGrunt::Precache()
{
PRECACHE_MODEL("models/rgrunt.mdl");
m_iBodyGibs = PRECACHE_MODEL( "models/metalplategibs_green.mdl" );
m_iBodyGibs = PRECACHE_MODELINDEX( "models/metalplategibs_green.mdl" );
PRECACHE_SOUND("hgrunt/gr_mgun1.wav");
PRECACHE_SOUND("hgrunt/gr_mgun2.wav");
@@ -411,13 +416,8 @@ void CMRGrunt::Precache()
PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event
/*
// get voice pitch
if (RANDOM_LONG(0, 1))
m_voicePitch = 109 + RANDOM_LONG(0, 7);
else
m_voicePitch = 100;
*/
m_voicePitch = 115; // always the same
m_iBrassShell = PRECACHE_MODEL("models/shell.mdl");// brass shell
m_iBrassShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell
}

456
src/dlls/ripent.cpp Normal file
View File

@@ -0,0 +1,456 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
****/
// this is a stripped down "bspfile.c" file containing only entity data similar
// to using a ripent tool to read ents from a bsp, hence the name.
// -Giegue
#include "extdll.h"
#include "ripent.h"
#include "meta_api.h"
#if defined linux
#include <sys/stat.h>
#endif
//=============================================================================
int entdatasize;
char dentdata[MAX_MAP_ENTSTRING];
int num_entities;
entity_t entities[MAX_MAP_ENTITIES];
//=============================================================================
dheader_t *header;
int CopyLump(int lump, void *dest, int size)
{
int length, ofs;
length = header->lumps[lump].filelen;
ofs = header->lumps[lump].fileofs;
if (length % size)
{
LOG_MESSAGE(PLID, "LoadBSPFile: odd lump size");
return 0;
}
memcpy(dest, (byte *)header + ofs, length);
return length / size;
}
/*
=============
LoadBSPFile
=============
*/
void LoadBSPFile(char *filename)
{
//int i;
// reset these values
entdatasize = 0;
num_entities = 0;
memset(dentdata, 0, sizeof(dentdata));
memset(entities, 0, sizeof(entities));
//
// load the file header
//
if (LoadFile(filename, (void **)&header) == -1)
return;
// UNDONE: there is no need to swap it...? -Giegue
// swap the header
/*for (i = 0; i < sizeof(dheader_t) / 4; i++)
((int *)header)[i] = LittleLong(((int *)header)[i]);*/
// game will not load the BSP if it's invalid.
// so if this is called, it means something went really wrong loading it
if (header->version != BSPVERSION)
{
LOG_MESSAGE(PLID, "%s is version %i, not %i", filename, header->version, BSPVERSION);
return;
}
entdatasize = CopyLump(LUMP_ENTITIES, dentdata, 1);
free(header); // everything has been copied out
}
//============================================================================
/*
=================
ParseEpair
=================
*/
epair_t *ParseEpair(void)
{
epair_t *e;
e = (epair_t*)malloc(sizeof(epair_t));
memset(e, 0, sizeof(epair_t));
if (strlen(token) >= MAX_KEY - 1)
{
LOG_MESSAGE(PLID, "ParseEpar: token key too long");
return NULL;
}
e->key = copystring(token);
GetToken(false);
if (strlen(token) >= MAX_VALUE - 1)
{
LOG_MESSAGE(PLID, "ParseEpar: token value too long");
return NULL;
}
e->value = copystring(token);
return e;
}
/*
================
ParseEntity
================
*/
bool ParseEntity(void)
{
epair_t *e;
entity_t *mapent;
if (!GetToken(true))
return false;
if (strcmp(token, "{"))
{
LOG_MESSAGE(PLID, "ParseEntity: { not found");
return false;
}
if (num_entities == MAX_MAP_ENTITIES)
{
LOG_MESSAGE(PLID, "num_entities == MAX_MAP_ENTITIES");
return false;
}
mapent = &entities[num_entities];
num_entities++;
do
{
if (!GetToken(true))
{
LOG_MESSAGE(PLID, "ParseEntity: EOF without closing brace");
return false;
}
if (!strcmp(token, "}"))
break;
e = ParseEpair();
e->next = mapent->epairs;
mapent->epairs = e;
} while (1);
return true;
}
/*
================
ParseEntities
Parses the dentdata string into entities
================
*/
void ParseEntities(void)
{
num_entities = 0;
ParseFromMemory(dentdata, entdatasize);
while (ParseEntity())
{
}
}
// --
/* MERGE cmdlib.c AND scriplib.c INTO ripent.cpp */
/* Only add needed functions. */
// --
// -- cmdlib.c --
char qdir[1024] = { '\0' };
int LoadFile(char *filename, void **bufferptr)
{
FILE *f;
int length;
void *buffer;
f = SafeOpenRead(filename);
if (f == NULL)
return -1; // error
#if defined (_WIN32)
length = filelength(fileno(f));
#else
struct stat st; stat(filename, &st);
length = st.st_size;
#endif
buffer = malloc(length + 1);
((char *)buffer)[length] = 0;
SafeRead(f, buffer, length);
fclose(f);
*bufferptr = buffer;
return length;
}
int LittleLong(int l)
{
byte b1, b2, b3, b4;
b1 = l & 255;
b2 = (l >> 8) & 255;
b3 = (l >> 16) & 255;
b4 = (l >> 24) & 255;
return ((int)b1 << 24) + ((int)b2 << 16) + ((int)b3 << 8) + b4;
}
char *copystring(char *s)
{
char *b;
b = (char*)malloc(strlen(s) + 1);
strcpy(b, s);
return b;
}
FILE *SafeOpenRead(char *filename)
{
FILE *f;
f = fopen(filename, "rb");
if (!f)
{
LOG_MESSAGE(PLID, "Error opening %s: %s", filename, strerror(errno));
return NULL;
}
return f;
}
void SafeRead(FILE *f, void *buffer, int count)
{
if (fread(buffer, 1, count, f) != (size_t)count)
{
LOG_MESSAGE(PLID, "File read failure");
return;
}
}
char *ExpandPath(char *path)
{
char *psz;
static char full[1024];
if (!qdir)
{
LOG_MESSAGE(PLID, "ExpandPath called without qdir set");
return NULL;
}
if (path[0] == '/' || path[0] == '\\' || path[1] == ':')
return path;
psz = strstr(path, qdir);
if (psz)
strcpy(full, path);
else
sprintf(full, "%s%s", qdir, path);
return full;
}
// -- scriplib.c --
typedef struct
{
char filename[1024];
char *buffer, *script_p, *end_p;
int line;
} script_t;
#define MAX_INCLUDES 8
script_t scriptstack[MAX_INCLUDES];
script_t *script;
int scriptline;
char token[MAXTOKEN];
bool endofscript;
bool tokenready; // only true if UnGetToken was just called
void ParseFromMemory(char *buffer, int size)
{
script = scriptstack;
script++;
if (script == &scriptstack[MAX_INCLUDES])
{
LOG_MESSAGE(PLID, "script file exceeded MAX_INCLUDES");
return;
}
strcpy(script->filename, "memory buffer");
script->buffer = buffer;
script->line = 1;
script->script_p = script->buffer;
script->end_p = script->buffer + size;
endofscript = false;
tokenready = false;
}
bool EndOfScript(bool crossline)
{
if (!crossline)
{
LOG_MESSAGE(PLID, "Line %i is incomplete", scriptline);
return false;
}
if (!strcmp(script->filename, "memory buffer"))
{
endofscript = true;
return false;
}
free(script->buffer);
if (script == scriptstack + 1)
{
endofscript = true;
return false;
}
script--;
scriptline = script->line;
//printf("returning to %s\n", script->filename);
return GetToken(crossline);
}
void AddScriptToStack(char *filename)
{
int size;
script++;
if (script == &scriptstack[MAX_INCLUDES])
{
LOG_MESSAGE(PLID, "script file exceeded MAX_INCLUDES");
return;
}
strcpy(script->filename, ExpandPath(filename));
size = LoadFile(script->filename, (void **)&script->buffer);
//printf("entering %s\n", script->filename);
script->line = 1;
script->script_p = script->buffer;
script->end_p = script->buffer + size;
}
bool GetToken(bool crossline)
{
char *token_p;
if (tokenready) // is a token allready waiting?
{
tokenready = false;
return true;
}
if (script->script_p >= script->end_p)
return EndOfScript(crossline);
//
// skip space
//
skipspace:
while (*script->script_p <= 32)
{
if (script->script_p >= script->end_p)
return EndOfScript(crossline);
if (*script->script_p++ == '\n')
{
if (!crossline)
{
LOG_MESSAGE(PLID, "Line %i is incomplete", scriptline);
return false;
}
scriptline = script->line++;
}
}
if (script->script_p >= script->end_p)
return EndOfScript(crossline);
if (*script->script_p == ';' || *script->script_p == '#' || // semicolon and # is comment field
(*script->script_p == '/' && *((script->script_p) + 1) == '/')) // also make // a comment field
{
if (!crossline)
{
LOG_MESSAGE(PLID, "Line %i is incomplete", scriptline);
return false;
}
while (*script->script_p++ != '\n')
if (script->script_p >= script->end_p)
return EndOfScript(crossline);
goto skipspace;
}
//
// copy token
//
token_p = token;
if (*script->script_p == '"')
{
// quoted token
script->script_p++;
while (*script->script_p != '"')
{
*token_p++ = *script->script_p++;
if (script->script_p == script->end_p)
break;
if (token_p == &token[MAXTOKEN])
{
// if the server does not crash before this happens, then monstermod will.
// simulate a fatal error and be verbose on why it happens.
ALERT(at_logged, "FATAL ERROR (shutting down): ReadEntsFromBSP: Line %i is too long (length > %i).", scriptline, MAXTOKEN);
}
}
script->script_p++;
}
else // regular token
while (*script->script_p > 32 && *script->script_p != ';')
{
*token_p++ = *script->script_p++;
if (script->script_p == script->end_p)
break;
if (token_p == &token[MAXTOKEN])
{
// ditto
ALERT(at_logged, "FATAL ERROR (shutting down): ReadEntsFromBSP: Line %i is too long (length > %i).", scriptline, MAXTOKEN);
}
}
*token_p = 0;
if (!strcmp(token, "$include"))
{
GetToken(false);
AddScriptToStack(token);
return GetToken(crossline);
}
return true;
}

97
src/dlls/ripent.h Normal file
View File

@@ -0,0 +1,97 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
****/
// this is a stripped down "bspfile.h". contains only entity data similar
// to using a ripent tool to read ents from a bsp, hence the name.
// -Giegue
#include "extdll.h"
// upper design bounds
// some ents are info holders for compiler tools (also -num_edicts is customizable)
#define MAX_MAP_ENTITIES 2048
#define MAX_MAP_ENTSTRING (128*2048)
// key / value pair sizes
#define MAX_KEY 32
#define MAX_VALUE 1024
//=============================================================================
#define BSPVERSION 30
typedef struct
{
int fileofs, filelen;
} lump_t;
#define LUMP_ENTITIES 0
#define HEADER_LUMPS 15
typedef struct
{
int version;
lump_t lumps[HEADER_LUMPS];
} dheader_t;
//============================================================================
// the utilities get to be lazy and just use large static arrays
extern int entdatasize;
extern char dentdata[MAX_MAP_ENTSTRING];
void LoadBSPFile(char *filename);
//===============
typedef struct epair_s
{
struct epair_s *next;
char *key;
char *value;
} epair_t;
typedef struct
{
vec3_t origin;
int firstbrush;
int numbrushes;
epair_t *epairs;
} entity_t;
extern int num_entities;
extern entity_t entities[MAX_MAP_ENTITIES];
void ParseEntities(void);
epair_t *ParseEpair(void);
// --
/* MERGE cmdlib.h AND scriplib.h INTO ripent.h */
/* Only add needed functions. */
// --
// -- cmdlib.h --
int LoadFile(char *filename, void **bufferptr);
int LittleLong(int l);
char *copystring(char *s);
FILE *SafeOpenRead(char *filename);
void SafeRead(FILE *f, void *buffer, int count);
char *ExpandPath(char *path); // from scripts
// -- scriplib.h --
#define MAXTOKEN 4096
extern char token[MAXTOKEN];
bool GetToken(bool crossline);
void ParseFromMemory(char *buffer, int size);

View File

@@ -601,7 +601,7 @@ void CMScientist :: Spawn( void )
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_RED : m_bloodColor;
pev->health = gSkillData.scientistHealth;
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so scientists will notice player and say hello

View File

@@ -142,7 +142,9 @@ void CMShock::Touch(edict_t *pOther)
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
pMonster->TraceAttack( pevAttacker, pev->dmg, pev->velocity.Normalize(), &tr, damageType );
}
else
UTIL_TraceAttack( pOther, pevAttacker, pev->dmg, pev->velocity.Normalize(), &tr, damageType );
ApplyMultiDamage(pev, pevAttacker);
}

View File

@@ -26,6 +26,8 @@
#include "schedule.h"
#include "weapons.h"
#define SR_AE_JUMPATTACK ( 2 )
const char *CMShockRoach::pIdleSounds[] =
{
"shockroach/shock_idle1.wav",
@@ -69,7 +71,7 @@ void CMShockRoach::Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_FLY;
m_bloodColor = BLOOD_COLOR_GREEN;
m_bloodColor = BLOOD_COLOR_YELLOW;
pev->effects = 0;
pev->health = gSkillData.roachHealth;
@@ -131,6 +133,8 @@ void CMShockRoach::LeapTouch(edict_t *pOther)
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
pMonster->TakeDamage( pev, pev, GetDamageAmount(), DMG_SLASH );
}
else
UTIL_TakeDamageExternal( pOther, pev, pev, GetDamageAmount(), DMG_SLASH );
}
SetTouch(NULL);
@@ -153,7 +157,7 @@ void CMShockRoach::MonsterThink(void)
{
pev->health = -1;
Killed(pev, 0);
return;
//return; // it still needs to think
}
CMHeadCrab::MonsterThink();
@@ -217,7 +221,26 @@ int CMShockRoach::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, f
return CMBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
}
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//=========================================================
void CMShockRoach::HandleAnimEvent(MonsterEvent_t *pEvent)
{
CMHeadCrab::HandleAnimEvent(pEvent);
switch (pEvent->event)
{
case SR_AE_JUMPATTACK:
{
// Overwrite attack noise
AttackSound();
}
break;
}
}
void CMShockRoach::AttackSound()
{
EMIT_SOUND_DYN(edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch());
EMIT_SOUND_DYN(edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAttackSounds), GetSoundVolume(), ATTN_IDLE, 0, GetVoicePitch());
}

View File

@@ -540,19 +540,18 @@ int SENTENCEG_Lookup(const char *sample, char *sentencenum)
return -1;
}
void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation,
int flags, int pitch)
void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch)
{
if (sample && *sample == '!')
{
char name[32];
if (SENTENCEG_Lookup(sample, name) >= 0)
EMIT_SOUND_DYN2(entity, channel, name, volume, attenuation, flags, pitch);
EMIT_SOUND_DYN2(entity, channel, name, volume, attenuation, flags, pitch);
else
ALERT( at_aiconsole, "Unable to find %s in sentences.txt\n", sample );
}
else
EMIT_SOUND_DYN2(entity, channel, sample, volume, attenuation, flags, pitch);
EMIT_SOUND_DYN2(entity, channel, REPLACER::FindSoundReplacement( entity, sample ), volume, attenuation, flags, pitch);
}
// play a specific sentence over the HEV suit speaker - just pass player entity, and !sentencename

View File

@@ -31,15 +31,18 @@ void CMSporeGrenade::Precache()
{
PRECACHE_MODEL("models/spore.mdl");
PRECACHE_MODEL("sprites/glow02.spr");
g_sModelIndexTinySpit = PRECACHE_MODEL("sprites/tinyspit.spr");
gSporeExplode = PRECACHE_MODEL("sprites/spore_exp_01.spr");
gSporeExplodeC = PRECACHE_MODEL("sprites/spore_exp_c_01.spr");
g_sModelIndexTinySpit = PRECACHE_MODELINDEX("sprites/tinyspit.spr");
gSporeExplode = PRECACHE_MODELINDEX("sprites/spore_exp_01.spr");
gSporeExplodeC = PRECACHE_MODELINDEX("sprites/spore_exp_c_01.spr");
PRECACHE_SOUND("weapons/splauncher_bounce.wav");
PRECACHE_SOUND("weapons/splauncher_impact.wav");
}
void CMSporeGrenade::Explode(TraceResult *pTrace)
{
if (m_hOwner == NULL)
pev->owner = NULL;
pev->solid = SOLID_NOT;// intangible
pev->takedamage = DAMAGE_NO;
@@ -125,6 +128,9 @@ void CMSporeGrenade::Detonate()
void CMSporeGrenade::BounceSound()
{
if (m_hOwner == NULL)
pev->owner = NULL;
EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/splauncher_bounce.wav", 0.25, ATTN_NORM);
}
@@ -252,6 +258,7 @@ CMSporeGrenade* CMSporeGrenade::ShootTimed(entvars_t *pevOwner, Vector vecStart,
pGrenade->pev->velocity = vecVelocity;
pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity);
pGrenade->pev->owner = ENT(pevOwner);
pGrenade->m_hOwner = ENT(pevOwner);
pGrenade->SetTouch(&CMSporeGrenade::BounceTouch); // Bounce if touched
@@ -286,6 +293,7 @@ CMSporeGrenade *CMSporeGrenade::ShootContact(entvars_t *pevOwner, Vector vecStar
pGrenade->pev->velocity = vecVelocity;
pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity);
pGrenade->pev->owner = ENT(pevOwner);
pGrenade->m_hOwner = ENT(pevOwner);
// make monsters afraid of it while in the air
pGrenade->SetThink(&CMSporeGrenade::DangerSoundThink);

View File

@@ -295,13 +295,15 @@ void CMSqueakGrenade::SuperBounceTouch( edict_t *pOther )
// ALERT( at_console, "hit enemy\n");
ClearMultiDamage( );
if (UTIL_IsPlayer(pOther))
if (UTIL_IsPlayer(pOther))
UTIL_TraceAttack(pOther, pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH );
else if (pOther->v.euser4 != NULL)
{
else if (pOther->v.euser4 != NULL)
{
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
pMonster->TraceAttack(pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH );
}
}
else
UTIL_TraceAttack(pOther, pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH );
ApplyMultiDamage( pev, pev );

View File

@@ -216,7 +216,7 @@ int CMStrooper::Classify()
BOOL CMStrooper::CheckRangeAttack1(float flDot, float flDist)
{
return m_cAmmoLoaded >= 1;// && CMHGrunt::CheckRangeAttack1(flDot, flDist);
return (m_cAmmoLoaded >= 1) && CMHGrunt::CheckRangeAttack1(flDot, flDist);
}
BOOL CMStrooper::CheckRangeAttack2( float flDot, float flDist )
@@ -288,34 +288,24 @@ void CMStrooper::HandleAnimEvent(MonsterEvent_t *pEvent)
UTIL_MakeVectors(pev->angles);
Vector vecShootOrigin = vecGunPos + gpGlobals->v_forward * 32;
Vector vecShootDir = ShootAtEnemy( vecShootOrigin );
vecGunAngles = UTIL_VecToAngles(vecShootDir);
//CBaseEntity *pShock = CBaseEntity::Create("shock_beam", vecShootOrigin, vecGunAngles, edict());
CMShock *pShock = CreateClassPtr((CMShock *)NULL);
vecGunAngles = UTIL_VecToAngles( vecShootDir );
vecGunAngles.z += RANDOM_FLOAT( -0.05, 0 );
Vector vecVelocity = vecShootDir * 2000;
edict_t *pShock = CMShock::Shoot( pev, vecGunAngles, vecShootOrigin, vecVelocity );
if (pShock != NULL)
{
pShock->pev->origin = vecShootOrigin;
m_cAmmoLoaded--;
SetBlending( 0, vecGunAngles.x );
vecGunAngles.z += RANDOM_FLOAT( -0.05, 0 );
pShock->pev->angles = UTIL_VecToAngles( vecGunAngles );
pShock->pev->owner = edict();
// Initialize these for entities who don't link to the world
pShock->pev->absmin = pShock->pev->origin - Vector(1,1,1);
pShock->pev->absmax = pShock->pev->origin + Vector(1,1,1);
pShock->Spawn();
pShock->pev->velocity = vecShootDir * 2000;
pShock->pev->nextthink = gpGlobals->time;
// Play fire sound.
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/shock_fire.wav", 1, ATTN_NORM);
}
else
{
ALERT( at_console, "Cannot create shock_beam!\n" );
}
m_cAmmoLoaded--;
SetBlending( 0, vecGunAngles.x );
// Play fire sound.
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/shock_fire.wav", 1, ATTN_NORM);
}
}
break;
@@ -340,6 +330,8 @@ void CMStrooper::HandleAnimEvent(MonsterEvent_t *pEvent)
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pHurt));
pMonster->TakeDamage( pev, pev, gSkillData.strooperDmgKick, DMG_CLUB );
}
else
UTIL_TakeDamageExternal( pHurt, pev, pev, gSkillData.strooperDmgKick, DMG_CLUB );
}
m_fRightClaw = !m_fRightClaw;
@@ -375,7 +367,7 @@ void CMStrooper::Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0;
pev->health = gSkillData.strooperHealth;
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
@@ -451,7 +443,7 @@ void CMStrooper::Precache()
{
PRECACHE_MODEL("models/strooper.mdl");
PRECACHE_MODEL("models/strooper_gibs.mdl");
iStrooperMuzzleFlash = PRECACHE_MODEL(STROOPER_MUZZLEFLASH);
iStrooperMuzzleFlash = PRECACHE_MODELINDEX(STROOPER_MUZZLEFLASH);
PRECACHE_SOUND("shocktrooper/shock_trooper_attack.wav");
PRECACHE_SOUND("shocktrooper/shock_trooper_die1.wav");
@@ -488,7 +480,7 @@ void CMStrooper::Precache()
else
m_voicePitch = 100;
m_iBrassShell = PRECACHE_MODEL("models/shell.mdl");// brass shell
m_iBrassShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell
}
@@ -590,12 +582,8 @@ void CMStrooper::DropShockRoach(bool gibbed)
CMShockRoach *roach = CreateClassPtr((CMShockRoach *)NULL);
if (roach != NULL)
{
roach->pev->origin = vecPos;
roach->pev->angles = UTIL_VecToAngles( vecDropAngles );
// Initialize these for entities who don't link to the world
roach->pev->absmin = roach->pev->origin - Vector(1,1,1);
roach->pev->absmax = roach->pev->origin + Vector(1,1,1);
UTIL_SetOrigin(roach->pev, vecPos);
roach->pev->angles = vecDropAngles;
roach->Spawn();
@@ -744,6 +732,8 @@ Schedule_t *CMStrooper::GetSchedule(void)
// new enemy
if (HasConditions(bits_COND_NEW_ENEMY))
{
// pretty much a copypaste of hgrunt and so the same issues. -Giegue
/*
//!!!KELLY - the leader of a squad of grunts has just seen the player or a
// monster and has made it the squad's enemy. You
// can check pev->flags for FL_CLIENT to determine whether this is the player
@@ -757,14 +747,14 @@ Schedule_t *CMStrooper::GetSchedule(void)
if ((m_hEnemy != 0) && UTIL_IsPlayer( m_hEnemy ))
// player
SENTENCEG_PlayRndSz(ENT(pev), "ST_ALERT", STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch);
/*
else if ((m_hEnemy != 0) &&
(m_hEnemy->Classify() != CLASS_PLAYER_ALLY) &&
(m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE) &&
(m_hEnemy->Classify() != CLASS_MACHINE))
// monster
SENTENCEG_PlayRndSz(ENT(pev), "ST_MONST", STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch);
*/
JustSpoke();
}
@@ -776,6 +766,7 @@ Schedule_t *CMStrooper::GetSchedule(void)
{
return GetScheduleOfType(SCHED_STROOPER_ESTABLISH_LINE_OF_FIRE);
}
*/
}
// no ammo
else if (HasConditions(bits_COND_NO_AMMO_LOADED))
@@ -801,9 +792,9 @@ Schedule_t *CMStrooper::GetSchedule(void)
//!!!KELLY - this grunt was hit and is going to run to cover.
if (FOkToSpeak()) // && RANDOM_LONG(0,1))
{
//SENTENCEG_PlayRndSz( ENT(pev), "HG_COVER", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
SENTENCEG_PlayRndSz( ENT(pev), "ST_COVER", STROOPER_SENTENCE_VOLUME, STROOPER_ATTN, 0, m_voicePitch);
m_iSentence = STROOPER_SENT_COVER;
//JustSpoke();
JustSpoke();
}
return GetScheduleOfType(SCHED_TAKE_COVER_FROM_ENEMY);
}
@@ -828,8 +819,10 @@ Schedule_t *CMStrooper::GetSchedule(void)
}
else
{
return GetScheduleOfType(SCHED_RANGE_ATTACK1);
// hide!
return GetScheduleOfType(SCHED_TAKE_COVER_FROM_ENEMY);
//return GetScheduleOfType(SCHED_TAKE_COVER_FROM_ENEMY);
}
}
// can't see enemy
@@ -846,6 +839,11 @@ Schedule_t *CMStrooper::GetSchedule(void)
return GetScheduleOfType(SCHED_RANGE_ATTACK2);
}
else
{
return GetScheduleOfType(SCHED_STROOPER_ESTABLISH_LINE_OF_FIRE);
}
/*
else
{
//!!!KELLY - grunt is going to stay put for a couple seconds to see if
// the enemy wanders back out into the open, or approaches the
@@ -857,6 +855,7 @@ Schedule_t *CMStrooper::GetSchedule(void)
}
return GetScheduleOfType(SCHED_STANDOFF);
}
*/
}
if (HasConditions(bits_COND_SEE_ENEMY) && !HasConditions(bits_COND_CAN_RANGE_ATTACK1))

View File

@@ -105,13 +105,13 @@ void CMStukabat :: Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_FLY;
pev->flags |= FL_FLY;
m_bloodColor = BLOOD_COLOR_YELLOW;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->health = gSkillData.stukabatHealth;
pev->view_ofs = Vector ( 0, 0, 22 );// position of the eyes relative to monster's origin.
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE;
m_pFlapSound = "stukabat/stukabat_flap1.wav";
m_pFlapSound = REPLACER::FindSoundReplacement( "stukabat/stukabat_flap1.wav" );
MonsterInit();
@@ -130,7 +130,7 @@ void CMStukabat :: Precache()
{
PRECACHE_MODEL("models/stukabat.mdl");
PRECACHE_SOUND("stukabat/stukabat_flap1.wav"); // flying sound
PRECACHE_SOUND("stukabat/stukabat_flap1.wav" ); // flying sound
PRECACHE_SOUND("headcrab/hc_headbite.wav"); // bite sound
}
@@ -138,42 +138,72 @@ void CMStukabat :: Precache()
// AI Schedules Specific to this monster
//=========================================================
/* Chase */
// Chase enemy
Task_t tlStukabatChaseEnemy[] =
{
{ TASK_GET_PATH_TO_ENEMY, (float)128 }, // is the 128 number really used?
{ TASK_SET_ACTIVITY, (float)ACT_FLY },
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
{ TASK_SET_FAIL_SCHEDULE, (float)SCHED_CHASE_ENEMY_FAILED },
{ TASK_GET_PATH_TO_ENEMY, (float)0 },
{ TASK_WALK_PATH, (float)0 }, // flying monster, use walk
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
};
Schedule_t slStukabatChaseEnemy[] =
{
{
tlStukabatChaseEnemy,
ARRAYSIZE ( tlStukabatChaseEnemy ),
bits_COND_NEW_ENEMY |
bits_COND_CAN_RANGE_ATTACK1 |
bits_COND_TASK_FAILED,
0,
"StukabatChaseEnemy"
0,
"Stukabat Chase Enemy"
},
};
/* Fail */
// Chase failed
Task_t tlStukabatChaseEnemyFailed[] =
{
{ TASK_STOP_MOVING, (float)0 },
{ TASK_WAIT, (float)0.2 },
{ TASK_FIND_COVER_FROM_ENEMY, (float)0 },
{ TASK_WALK_PATH, (float)0 },
{ TASK_WAIT_FOR_MOVEMENT, (float)0 },
{ TASK_REMEMBER, (float)bits_MEMORY_INCOVER },
// { TASK_TURN_LEFT, (float)179 },
{ TASK_FACE_ENEMY, (float)0 },
{ TASK_WAIT, (float)1 },
};
Schedule_t slStukabatChaseEnemyFailed[] =
{
{
tlStukabatChaseEnemyFailed,
ARRAYSIZE ( tlStukabatChaseEnemyFailed ),
bits_COND_NEW_ENEMY |
bits_COND_CAN_RANGE_ATTACK1,
0,
"Stukabat Chase Failed"
},
};
// Fail
Task_t tlStukabatFail[] =
{
{ TASK_STOP_MOVING, 0 },
{ TASK_STOP_MOVING, (float)0 },
{ TASK_SET_ACTIVITY, (float)ACT_HOVER },
{ TASK_WAIT, (float)2 },
{ TASK_WAIT_PVS, (float)0 },
};
Schedule_t slStukabatFail[] =
{
{
tlStukabatFail,
ARRAYSIZE ( tlStukabatFail ),
bits_COND_CAN_ATTACK,
0,
0,
"StukabatFail"
"Stukabat Fail"
},
};
@@ -181,6 +211,7 @@ Schedule_t slStukabatFail[] =
DEFINE_CUSTOM_SCHEDULES( CMStukabat )
{
slStukabatChaseEnemy,
slStukabatChaseEnemyFailed,
slStukabatFail,
};
@@ -198,9 +229,8 @@ void CMStukabat :: SetActivity ( Activity NewActivity )
{
case ACT_IDLE:
return; // refuse
case ACT_HOVER:
case ACT_FLY:
iSequence = LookupActivity ( NewActivity );
break;
default:
iSequence = LookupActivity ( NewActivity );
break;
@@ -238,6 +268,8 @@ Schedule_t* CMStukabat :: GetScheduleOfType ( int Type )
{
case SCHED_CHASE_ENEMY:
return slStukabatChaseEnemy;
case SCHED_CHASE_ENEMY_FAILED:
return slStukabatChaseEnemyFailed;
case SCHED_FAIL:
return slStukabatFail;
}

View File

@@ -145,12 +145,25 @@ void FireTargets( const char *targetName, edict_t *pActivator, edict_t *pCaller,
if (FNullEnt(pentTarget))
break;
// MonsterMod entity
CMBaseEntity *pTarget = CMBaseEntity::Instance( pentTarget );
if ( pTarget && !(pTarget->pev->flags & FL_KILLME) ) // Don't use dying ents
if ( pTarget && !(pTarget->pev->flags & FL_KILLME) )
{
ALERT( at_aiconsole, "Found: %s, firing (%s)\n", STRING(pTarget->pev->classname), targetName );
pTarget->Use( pActivator, pCaller, useType, value );
}
// Valid entity but not recognized by monstermod, must be a normal entity
else if (!(pentTarget->v.flags & FL_KILLME))
{
if (CVAR_GET_FLOAT("_glb_use")) // avoid "unknown command" spam
{
ALERT( at_aiconsole, "Found: %s, firing (%s)\n", STRING(pentTarget->v.classname), targetName );
char extCmd[64];
sprintf( extCmd, "_trigger %i %i %i %i %f\n", ENTINDEX( pentTarget ), ENTINDEX( ENT( pActivator ) ), ENTINDEX( ENT( pCaller ) ), useType, value );
SERVER_COMMAND( extCmd );
}
}
}
}

View File

@@ -92,6 +92,9 @@ void CMBaseTurret::Spawn()
m_iAutoStart = TRUE;
}
if (!m_flDistLook)
m_flDistLook = TURRET_RANGE;
ResetSequenceInfo( );
SetBoneController( 0, 0 );
SetBoneController( 1, 0 );
@@ -348,7 +351,7 @@ void CMBaseTurret::ActiveThink(void)
Vector vec = UTIL_VecToAngles(vecMidEnemy - vecMid);
// Current enemy is not visible.
if (!fEnemyVisible || (flDistToEnemy > TURRET_RANGE))
if (!fEnemyVisible || (flDistToEnemy > m_flDistLook))
{
if (!m_flLastSight)
m_flLastSight = gpGlobals->time + 0.5;
@@ -459,7 +462,7 @@ void CMBaseTurret::ActiveThink(void)
void CMTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy)
{
FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, TURRET_RANGE, BULLET_MONSTER_12MM, 1 );
FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, m_flDistLook, BULLET_MONSTER_12MM, 1 );
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "turret/tu_fire1.wav", 1, 0.6);
pev->effects = pev->effects | EF_MUZZLEFLASH;
}
@@ -467,7 +470,7 @@ void CMTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy)
void CMMiniTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy)
{
FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, TURRET_RANGE, BULLET_MONSTER_9MM, 1 );
FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, m_flDistLook, BULLET_MONSTER_9MM, 1 );
switch(RANDOM_LONG(0,2))
{
@@ -721,7 +724,7 @@ void CMBaseTurret::SearchThink(void)
// Acquire Target
if (m_hEnemy == NULL)
{
Look(TURRET_RANGE);
Look(m_flDistLook);
m_hEnemy = BestVisibleEnemy();
}
@@ -779,7 +782,7 @@ void CMBaseTurret::AutoSearchThink(void)
if (m_hEnemy == NULL)
{
Look( TURRET_RANGE );
Look( m_flDistLook );
m_hEnemy = BestVisibleEnemy();
}
@@ -801,6 +804,7 @@ void CMBaseTurret :: TurretDeath( void )
if (pev->deadflag != DEAD_DEAD)
{
pev->deadflag = DEAD_DEAD;
FCheckAITrigger(); // trigger death condition
float flRndSound = RANDOM_FLOAT ( 0 , 1 );
@@ -1041,7 +1045,7 @@ void CMSentry::Spawn()
void CMSentry::Shoot(Vector &vecSrc, Vector &vecDirToEnemy)
{
FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, TURRET_RANGE, BULLET_MONSTER_MP5, 1 );
FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, m_flDistLook, BULLET_MONSTER_MP5, 1 );
switch(RANDOM_LONG(0,2))
{
@@ -1105,6 +1109,7 @@ void CMSentry::SentryDeath( void )
if (pev->deadflag != DEAD_DEAD)
{
pev->deadflag = DEAD_DEAD;
FCheckAITrigger(); // trigger death condition
float flRndSound = RANDOM_FLOAT ( 0 , 1 );

View File

@@ -39,7 +39,7 @@ typedef struct {
} gamedll_funcs_t;
extern gamedll_funcs_t *gpGamedllFuncs;
extern void check_player_dead( edict_t *pPlayer );
// Print to console.
void META_CONS(char *fmt, ...) {
@@ -226,6 +226,120 @@ UTIL_GroupTrace::~UTIL_GroupTrace( void )
}
TYPEDESCRIPTION gEntvarsDescription[] =
{
DEFINE_ENTITY_FIELD( classname, FIELD_STRING ),
DEFINE_ENTITY_GLOBAL_FIELD( globalname, FIELD_STRING ),
DEFINE_ENTITY_FIELD( origin, FIELD_POSITION_VECTOR ),
DEFINE_ENTITY_FIELD( oldorigin, FIELD_POSITION_VECTOR ),
DEFINE_ENTITY_FIELD( velocity, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( basevelocity, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( movedir, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( angles, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( avelocity, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( punchangle, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( v_angle, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( fixangle, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( idealpitch, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( pitch_speed, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( ideal_yaw, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( yaw_speed, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( modelindex, FIELD_INTEGER ),
DEFINE_ENTITY_GLOBAL_FIELD( model, FIELD_MODELNAME ),
DEFINE_ENTITY_FIELD( viewmodel, FIELD_MODELNAME ),
DEFINE_ENTITY_FIELD( weaponmodel, FIELD_MODELNAME ),
DEFINE_ENTITY_FIELD( absmin, FIELD_POSITION_VECTOR ),
DEFINE_ENTITY_FIELD( absmax, FIELD_POSITION_VECTOR ),
DEFINE_ENTITY_GLOBAL_FIELD( mins, FIELD_VECTOR ),
DEFINE_ENTITY_GLOBAL_FIELD( maxs, FIELD_VECTOR ),
DEFINE_ENTITY_GLOBAL_FIELD( size, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( ltime, FIELD_TIME ),
DEFINE_ENTITY_FIELD( nextthink, FIELD_TIME ),
DEFINE_ENTITY_FIELD( solid, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( movetype, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( skin, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( body, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( effects, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( gravity, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( friction, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( light_level, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( frame, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( scale, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( sequence, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( animtime, FIELD_TIME ),
DEFINE_ENTITY_FIELD( framerate, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( controller, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( blending, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( rendermode, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( renderamt, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( rendercolor, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( renderfx, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( health, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( frags, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( weapons, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( takedamage, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( deadflag, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( view_ofs, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( button, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( impulse, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( chain, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( dmg_inflictor, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( enemy, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( aiment, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( owner, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( groundentity, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( spawnflags, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( flags, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( colormap, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( team, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( max_health, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( teleport_time, FIELD_TIME ),
DEFINE_ENTITY_FIELD( armortype, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( armorvalue, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( waterlevel, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( watertype, FIELD_INTEGER ),
// Having these fields be local to the individual levels makes it easier to test those levels individually.
DEFINE_ENTITY_GLOBAL_FIELD( target, FIELD_STRING ),
DEFINE_ENTITY_GLOBAL_FIELD( targetname, FIELD_STRING ),
DEFINE_ENTITY_FIELD( netname, FIELD_STRING ),
DEFINE_ENTITY_FIELD( message, FIELD_STRING ),
DEFINE_ENTITY_FIELD( dmg_take, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( dmg_save, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( dmg, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( dmgtime, FIELD_TIME ),
DEFINE_ENTITY_FIELD( noise, FIELD_SOUNDNAME ),
DEFINE_ENTITY_FIELD( noise1, FIELD_SOUNDNAME ),
DEFINE_ENTITY_FIELD( noise2, FIELD_SOUNDNAME ),
DEFINE_ENTITY_FIELD( noise3, FIELD_SOUNDNAME ),
DEFINE_ENTITY_FIELD( speed, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( air_finished, FIELD_TIME ),
DEFINE_ENTITY_FIELD( pain_finished, FIELD_TIME ),
DEFINE_ENTITY_FIELD( radsuit_finished, FIELD_TIME ),
};
#define ENTVARS_COUNT (sizeof(gEntvarsDescription)/sizeof(gEntvarsDescription[0]))
#ifdef DEBUG
edict_t *DBG_EntOfVars( const entvars_t *pev )
{
@@ -1512,6 +1626,55 @@ void UTIL_StripToken( const char *pKey, char *pDest )
}
void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd )
{
int i;
TYPEDESCRIPTION *pField;
for ( i = 0; i < ENTVARS_COUNT; i++ )
{
pField = &gEntvarsDescription[i];
if ( !stricmp( pField->fieldName, pkvd->szKeyName ) )
{
switch( pField->fieldType )
{
case FIELD_MODELNAME:
case FIELD_SOUNDNAME:
case FIELD_STRING:
(*(int *)((char *)pev + pField->fieldOffset)) = ALLOC_STRING( pkvd->szValue );
break;
case FIELD_TIME:
case FIELD_FLOAT:
(*(float *)((char *)pev + pField->fieldOffset)) = atof( pkvd->szValue );
break;
case FIELD_INTEGER:
(*(int *)((char *)pev + pField->fieldOffset)) = atoi( pkvd->szValue );
break;
case FIELD_POSITION_VECTOR:
case FIELD_VECTOR:
UTIL_StringToVector( (float *)((char *)pev + pField->fieldOffset), pkvd->szValue );
break;
default:
case FIELD_EVARS:
case FIELD_CLASSPTR:
case FIELD_EDICT:
case FIELD_ENTITY:
case FIELD_POINTER:
ALERT( at_error, "Bad field in entity!!\n" );
break;
}
pkvd->fHandled = TRUE;
return;
}
}
}
Vector VecBModelOrigin( entvars_t* pevBModel )
{
return pevBModel->absmin + ( pevBModel->size * 0.5 );
@@ -1760,7 +1923,8 @@ int UTIL_TakeDamage( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAtt
{
pEdict->v.health = 1; // can't suicide if already dead!
gpGamedllFuncs->dllapi_table->pfnClientKill(pEdict);
check_player_dead(pEdict); // will you just fucking work?
// Add 1 score to the monster that killed this player
if ( pevAttacker->flags & FL_MONSTER )
pevAttacker->frags += 1.0;
@@ -1977,8 +2141,11 @@ bool UTIL_IsBSPModel( edict_t *pent )
void UTIL_TakeDamageExternal( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
{
// Tell AMXX to call TakeDamage for us.
char extCmd[64];
sprintf( extCmd, "monster_hurt_entity %i %i %i %f %i\n", ENTINDEX( pEdict ), ENTINDEX( ENT( pevInflictor ) ), ENTINDEX( ENT( pevAttacker ) ), flDamage, bitsDamageType );
SERVER_COMMAND( extCmd );
// Tell AMXX to call TakeDamage for us if it can.
if (CVAR_GET_FLOAT("_glb_takedamage"))
{
char extCmd[64];
sprintf( extCmd, "_takedamage %i %i %i %f %i\n", ENTINDEX( pEdict ), ENTINDEX( ENT( pevInflictor ) ), ENTINDEX( ENT( pevAttacker ) ), flDamage, bitsDamageType );
SERVER_COMMAND( extCmd );
}
}

View File

@@ -149,7 +149,12 @@ inline BOOL FStringNull(int iString) { return iString == iStringNull; }
#define DONT_BLEED -1
#define BLOOD_COLOR_RED (BYTE)247
#define BLOOD_COLOR_YELLOW (BYTE)195
#define BLOOD_COLOR_GREEN BLOOD_COLOR_YELLOW
#define BLOOD_COLOR_BLUE (BYTE)211 // custom colors
#define BLOOD_COLOR_PINK (BYTE)147
#define BLOOD_COLOR_WHITE (BYTE)11
#define BLOOD_COLOR_ORANGE (BYTE)231
#define BLOOD_COLOR_BLACK (BYTE)49 // not 100% accurate but close enough
#define BLOOD_COLOR_GREEN (BYTE)181 // ^
typedef enum
{
@@ -400,6 +405,9 @@ extern DLL_GLOBAL const Vector g_vecZero;
#define SVC_ROOMTYPE 37
#define SVC_HLTV 50
// Added to stuff text to the clients
#define SVC_STUFFTEXT 9 // [string] stuffed into client's console buffer
// prxoy director stuff
#define DRC_EVENT 3 // informs the dircetor about ann important game event
@@ -433,6 +441,18 @@ extern DLL_GLOBAL const Vector g_vecZero;
#define SF_TRIG_PUSH_ONCE 1
// Override a few engine callbacks for model replacements
#include "globalreplace.h"
#define SET_MODEL( entity, model ) \
{ SET_MODEL2( entity, REPLACER::FindModelReplacement( entity, model ) ); }
#define PRECACHE_MODEL( model ) \
{ PRECACHE_MODEL2( (char*)REPLACER::FindModelReplacement( model ) ); }
#define PRECACHE_SOUND( sound ) \
{ PRECACHE_SOUND2( (char*)REPLACER::FindSoundReplacement( sound ) ); }
inline int PRECACHE_MODELINDEX( char* model )
{
return PRECACHE_MODEL2( (char*)REPLACER::FindModelReplacement( model ) );
}
// Sound Utilities
@@ -466,9 +486,7 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int
// EMIT_SOUND_DYN with pitch != 100 should be used sparingly, as it's not quite as
// fast as EMIT_SOUND (the pitchshift mixer is not native coded).
void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation,
int flags, int pitch);
void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch);
inline void EMIT_SOUND(edict_t *entity, int channel, const char *sample, float volume, float attenuation)
{
@@ -485,7 +503,7 @@ void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg);
void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname);
#define PRECACHE_SOUND_ARRAY( a ) \
{ for (int i = 0; i < ARRAYSIZE( a ); i++ ) PRECACHE_SOUND((char *) a [i]); }
{ for (int i = 0; i < ARRAYSIZE( a ); i++ ) PRECACHE_SOUND2((char *) REPLACER::FindSoundReplacement(a[i])); }
#define EMIT_SOUND_ARRAY_DYN( chan, array ) \
EMIT_SOUND_DYN ( ENT(pev), chan , array [ RANDOM_LONG(0,ARRAYSIZE( array )-1) ], 1.0, ATTN_NORM, 0, RANDOM_LONG(95,105) );
@@ -538,4 +556,4 @@ Vector UTIL_Center(edict_t *pEdict);
edict_t *UTIL_GetNextTarget( edict_t *pEntity );
edict_t *UTIL_FindNearestPlayer(edict_t *pEdict, float m_flFieldOfView);
bool UTIL_IsBSPModel( edict_t *pent );
void UTIL_TakeDamageExternal( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
void UTIL_TakeDamageExternal( edict_t *pEdict, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );

View File

@@ -127,6 +127,8 @@ void CMVoltigoreEnergyBall::BallTouch(edict_t *pOther)
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pOther));
pMonster->TakeDamage( pev, VARS( pev->owner ), gSkillData.voltigoreDmgBeam, DMG_SHOCK|DMG_ALWAYSGIB );
}
else
UTIL_TakeDamageExternal( pOther, pev, VARS(pev->owner), gSkillData.voltigoreDmgBeam, DMG_SHOCK | DMG_ALWAYSGIB );
}
pev->velocity = Vector(0,0,0);
@@ -154,6 +156,8 @@ void CMVoltigoreEnergyBall::FlyThink(void)
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
pMonster->TakeDamage( pev, pev, gSkillData.voltigoreDmgBeam/5, DMG_SHOCK );
}
else
UTIL_TakeDamageExternal( pEntity, pev, pev, gSkillData.voltigoreDmgBeam / 5, DMG_SHOCK );
}
}
@@ -387,15 +391,15 @@ BOOL CMVoltigore::CheckRangeAttack1(float flDot, float flDist)
{
if (IsMoving() && flDist >= 512)
{
// voltigore will far too far behind if he stops running to spit at this distance from the enemy.
// voltigore will far too far behind if he stops running to spit at this distance from the enemy.
return FALSE;
}
if (flDist > 64 && flDist <= 784 && flDot >= 0.5 && gpGlobals->time >= m_flNextZapTime)
if (flDist > 64 && flDist <= m_flDistTooFar && flDot >= 0.5 && gpGlobals->time >= m_flNextZapTime)
{
if (m_hEnemy != 0)
{
if (fabs(pev->origin.z - m_hEnemy->v.origin.z) > 256)
if (fabs(pev->origin.z - m_hEnemy->v.origin.z) > 512)
{
// don't try to spit at someone up really high or down really low.
return FALSE;
@@ -445,6 +449,13 @@ void CMVoltigore::GibMonster()
pev->nextthink = gpGlobals->time;
}
void CMVoltigore::UpdateOnRemove()
{
CMBaseMonster::UpdateOnRemove();
DestroyBeams();
DestroyGlow();
}
//=========================================================
// CheckMeleeAttack1 - voltigore is a big guy, so has a longer
// melee range than most monsters. This is the tailwhip attack
@@ -631,7 +642,7 @@ void CMVoltigore::Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0;
pev->health = gSkillData.voltigoreHealth;
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
@@ -688,7 +699,7 @@ void CMVoltigore::PrecacheImpl(char *modelName)
PRECACHE_SOUND("debris/beamstart1.wav");
m_beamTexture = PRECACHE_MODEL(VOLTIGORE_ZAP_BEAM);
m_beamTexture = PRECACHE_MODELINDEX(VOLTIGORE_ZAP_BEAM);
PRECACHE_MODEL(VOLTIGORE_GLOW_SPRITE);
PRECACHE_MODEL("sprites/lgtning.spr");
@@ -1020,6 +1031,8 @@ void CMVoltigore::GibBeamDamage()
CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pEntity));
pMonster->TakeDamage( pev, pev, flAdjustedDamage, DMG_SHOCK );
}
else
UTIL_TakeDamageExternal( pEntity, pev, pev, flAdjustedDamage, DMG_SHOCK );
}
}
}
@@ -1137,7 +1150,7 @@ void CMBabyVoltigore::Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->effects = 0;
pev->health = gSkillData.babyVoltigoreHealth;
m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )

View File

@@ -47,6 +47,7 @@ public:
virtual void Killed( entvars_t *pevAttacker, int iGib );
BOOL m_fRegisteredSound;// whether or not this grenade has issued its DANGER sound to the world sound list yet.
EHANDLE m_hOwner;
};
// Contact/Timed spore grenade
@@ -75,6 +76,7 @@ public:
void UpdateOnRemove();
CMSprite* m_pSporeGlow;
EHANDLE m_hOwner;
};
// constant items

View File

@@ -111,16 +111,6 @@ void CMZombie :: SetYawSpeed ( void )
int CMZombie :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
{
// Take 30% damage from bullets
if ( bitsDamageType == DMG_BULLET )
{
Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5;
vecDir = vecDir.Normalize();
float flForce = DamageForce( flDamage );
pev->velocity = pev->velocity + vecDir * flForce;
flDamage *= 0.3;
}
// HACK HACK -- until we fix this.
if ( IsAlive() )
PainSound();
@@ -245,13 +235,13 @@ void CMZombie :: HandleAnimEvent( MonsterEvent_t *pEvent )
void CMZombie :: Spawn()
{
Precache( );
SET_MODEL(ENT(pev), (!FStringNull( pev->model ) ? STRING( pev->model ) : "models/zombie.mdl"));
UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX );
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
m_bloodColor = !m_bloodColor ? BLOOD_COLOR_YELLOW : m_bloodColor;
pev->health = gSkillData.zombieHealth;
pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin.
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
@@ -273,27 +263,14 @@ void CMZombie :: Spawn()
//=========================================================
void CMZombie :: Precache()
{
int i;
PRECACHE_MODEL("models/zombie.mdl");
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
PRECACHE_SOUND((char *)pAttackHitSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
PRECACHE_SOUND((char *)pAttackMissSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ )
PRECACHE_SOUND((char *)pAttackSounds[i]);
for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ )
PRECACHE_SOUND((char *)pIdleSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ )
PRECACHE_SOUND((char *)pAlertSounds[i]);
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
PRECACHE_SOUND((char *)pPainSounds[i]);
PRECACHE_SOUND_ARRAY(pAttackHitSounds);
PRECACHE_SOUND_ARRAY(pAttackMissSounds);
PRECACHE_SOUND_ARRAY(pAttackSounds);
PRECACHE_SOUND_ARRAY(pIdleSounds);
PRECACHE_SOUND_ARRAY(pAlertSounds);
PRECACHE_SOUND_ARRAY(pPainSounds);
}
//=========================================================

View File

@@ -420,11 +420,10 @@ typedef enum _fieldtypes
FIELD_TYPECOUNT, // MUST BE LAST
} FIELDTYPE;
#ifndef linux
#ifndef offsetof
#if !defined(offsetof) && !defined(GNUC)
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#endif
#endif
#define _FIELD(type,name,fieldtype,count,flags) { fieldtype, #name, offsetof(type, name), count, flags }
#define DEFINE_FIELD(type,name,fieldtype) _FIELD(type, name, fieldtype, 1, 0)

View File

@@ -74,14 +74,17 @@
#endif //defined WIN32
#endif
#if defined (_WIN32) && defined (_MSC_VER)
// VS2015 and newer already has va_copy defined
#if defined (_WIN32) && defined (_MSC_VER) && _MSC_VER < 1900
// On x86 va_list is just a pointer.
#define va_copy(dst,src) ((dst)=(src))
#else
// Some systems that do not supply va_copy have __va_copy instead, since
// that was the name used in the draft proposal.
#if !defined(__GNUC__) || __GNUC__ < 3
#define va_copy __va_copy
#if (linux)
// Some systems that do not supply va_copy have __va_copy instead, since
// that was the name used in the draft proposal.
#if !defined(__GNUC__) || __GNUC__ < 3
#define va_copy __va_copy
#endif
#endif
#endif

View File

@@ -1,63 +1,89 @@
/**
* This file has no copyright assigned and is placed in the Public Domain.
* This file was originally part of the w64 mingw-runtime package.
*/
/* ISO C9x 7.18 Integer types <stdint.h>
* Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794)
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* Contributor: Danny Smith <danny_r_smith_2001@yahoo.co.nz>
*
* This source code is offered for use in the public domain. You may
* use, modify or distribute it freely.
*
* This code is distributed in the hope that it will be useful but
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
* DISCLAIMED. This includes but is not limited to warranties of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* Date: 2000-12-02
*
* mwb: This was modified in the following ways:
*
* - make it compatible with Visual C++ 6 (which uses
* non-standard keywords and suffixes for 64-bit types)
* - some environments need stddef.h included (for wchar stuff?)
* - handle the fact that Microsoft's limits.h header defines
* SIZE_MAX
* - make corrections for SIZE_MAX, INTPTR_MIN, INTPTR_MAX, UINTPTR_MAX,
* PTRDIFF_MIN, PTRDIFF_MAX, SIG_ATOMIC_MIN, and SIG_ATOMIC_MAX
* to be 64-bit aware.
*/
* Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794)
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* Contributor: Danny Smith <danny_r_smith_2001@yahoo.co.nz>
* Modified for libusb/MSVC: Pete Batard <pbatard@gmail.com>
*
* This source code is offered for use in the public domain. You may
* use, modify or distribute it freely.
*
* This code is distributed in the hope that it will be useful but
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
* DISCLAIMED. This includes but is not limited to warranties of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* Date: 2010-04-02
*/
#ifndef _MSC_VER
#error This header should only be used with Microsoft compilers
#endif
#ifndef _STDINT_H
#define _STDINT_H
#define __need_wint_t
#define __need_wchar_t
#include <wchar.h>
#include <stddef.h>
#if _MSC_VER && (_MSC_VER < 1300)
/* using MSVC 6 or earlier - no "long long" type, but might have _int64 type */
#define __STDINT_LONGLONG __int64
#define __STDINT_LONGLONG_SUFFIX i64
#ifndef _INTPTR_T_DEFINED
#define _INTPTR_T_DEFINED
#ifndef __intptr_t_defined
#define __intptr_t_defined
#undef intptr_t
#ifdef _WIN64
typedef __int64 intptr_t;
#else
#define __STDINT_LONGLONG long long
#define __STDINT_LONGLONG_SUFFIX LL
#endif
#if !defined( PASTE)
#define PASTE2( x, y) x##y
#define PASTE( x, y) PASTE2( x, y)
#endif /* PASTE */
typedef int intptr_t;
#endif /* _WIN64 */
#endif /* __intptr_t_defined */
#endif /* _INTPTR_T_DEFINED */
#ifndef _UINTPTR_T_DEFINED
#define _UINTPTR_T_DEFINED
#ifndef __uintptr_t_defined
#define __uintptr_t_defined
#undef uintptr_t
#ifdef _WIN64
typedef unsigned __int64 uintptr_t;
#else
typedef unsigned int uintptr_t;
#endif /* _WIN64 */
#endif /* __uintptr_t_defined */
#endif /* _UINTPTR_T_DEFINED */
#ifndef _PTRDIFF_T_DEFINED
#define _PTRDIFF_T_DEFINED
#ifndef _PTRDIFF_T_
#define _PTRDIFF_T_
#undef ptrdiff_t
#ifdef _WIN64
typedef __int64 ptrdiff_t;
#else
typedef int ptrdiff_t;
#endif /* _WIN64 */
#endif /* _PTRDIFF_T_ */
#endif /* _PTRDIFF_T_DEFINED */
#ifndef _WCHAR_T_DEFINED
#define _WCHAR_T_DEFINED
#ifndef __cplusplus
typedef unsigned short wchar_t;
#endif /* C++ */
#endif /* _WCHAR_T_DEFINED */
#ifndef _WCTYPE_T_DEFINED
#define _WCTYPE_T_DEFINED
#ifndef _WINT_T
#define _WINT_T
typedef unsigned short wint_t;
typedef unsigned short wctype_t;
#endif /* _WINT_T */
#endif /* _WCTYPE_T_DEFINED */
/* 7.18.1.1 Exact-width integer types */
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned uint32_t;
typedef __STDINT_LONGLONG int64_t;
typedef unsigned __STDINT_LONGLONG uint64_t;
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
/* 7.18.1.2 Minimum-width integer types */
typedef signed char int_least8_t;
typedef unsigned char uint_least8_t;
@@ -65,97 +91,65 @@ typedef short int_least16_t;
typedef unsigned short uint_least16_t;
typedef int int_least32_t;
typedef unsigned uint_least32_t;
typedef __STDINT_LONGLONG int_least64_t;
typedef unsigned __STDINT_LONGLONG uint_least64_t;
/* 7.18.1.3 Fastest minimum-width integer types
* Not actually guaranteed to be fastest for all purposes
* Here we use the exact-width types for 8 and 16-bit ints.
*/
typedef char int_fast8_t;
typedef unsigned char uint_fast8_t;
typedef short int_fast16_t;
typedef unsigned short uint_fast16_t;
typedef int int_fast32_t;
typedef unsigned int uint_fast32_t;
typedef __STDINT_LONGLONG int_fast64_t;
typedef unsigned __STDINT_LONGLONG uint_fast64_t;
/* 7.18.1.4 Integer types capable of holding object pointers */
#ifndef _INTPTR_T_DEFINED
#define _INTPTR_T_DEFINED
#ifdef _WIN64
typedef __STDINT_LONGLONG intptr_t
#else
typedef int intptr_t;
#endif /* _WIN64 */
#endif /* _INTPTR_T_DEFINED */
#ifndef _UINTPTR_T_DEFINED
#define _UINTPTR_T_DEFINED
#ifdef _WIN64
typedef unsigned __STDINT_LONGLONG uintptr_t
#else
typedef unsigned int uintptr_t;
#endif /* _WIN64 */
#endif /* _UINTPTR_T_DEFINED */
typedef __int64 int_least64_t;
typedef unsigned __int64 uint_least64_t;
/* 7.18.1.3 Fastest minimum-width integer types
* Not actually guaranteed to be fastest for all purposes
* Here we use the exact-width types for 8 and 16-bit ints.
*/
typedef __int8 int_fast8_t;
typedef unsigned __int8 uint_fast8_t;
typedef __int16 int_fast16_t;
typedef unsigned __int16 uint_fast16_t;
typedef __int32 int_fast32_t;
typedef unsigned __int32 uint_fast32_t;
typedef __int64 int_fast64_t;
typedef unsigned __int64 uint_fast64_t;
/* 7.18.1.5 Greatest-width integer types */
typedef __STDINT_LONGLONG intmax_t;
typedef unsigned __STDINT_LONGLONG uintmax_t;
typedef __int64 intmax_t;
typedef unsigned __int64 uintmax_t;
/* 7.18.2 Limits of specified-width integer types */
#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS)
/* 7.18.2.1 Limits of exact-width integer types */
#define INT8_MIN (-128)
#define INT8_MIN (-128)
#define INT16_MIN (-32768)
#define INT32_MIN (-2147483647 - 1)
#define INT64_MIN (PASTE( -9223372036854775807, __STDINT_LONGLONG_SUFFIX) - 1)
#define INT64_MIN (-9223372036854775807LL - 1)
#define INT8_MAX 127
#define INT16_MAX 32767
#define INT32_MAX 2147483647
#define INT64_MAX (PASTE( 9223372036854775807, __STDINT_LONGLONG_SUFFIX))
#define UINT8_MAX 0xff /* 255U */
#define UINT16_MAX 0xffff /* 65535U */
#define UINT32_MAX 0xffffffff /* 4294967295U */
#define UINT64_MAX (PASTE( 0xffffffffffffffffU, __STDINT_LONGLONG_SUFFIX)) /* 18446744073709551615ULL */
#define INT64_MAX 9223372036854775807LL
#define UINT8_MAX 255
#define UINT16_MAX 65535
#define UINT32_MAX 0xffffffffU /* 4294967295U */
#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */
/* 7.18.2.2 Limits of minimum-width integer types */
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX
/* 7.18.2.3 Limits of fastest minimum-width integer types */
#define INT_FAST8_MIN INT8_MIN
#define INT_FAST16_MIN INT16_MIN
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST64_MIN INT64_MIN
#define INT_FAST8_MAX INT8_MAX
#define INT_FAST16_MAX INT16_MAX
#define INT_FAST32_MAX INT32_MAX
#define INT_FAST64_MAX INT64_MAX
#define UINT_FAST8_MAX UINT8_MAX
#define UINT_FAST16_MAX UINT16_MAX
#define UINT_FAST32_MAX UINT32_MAX
#define UINT_FAST64_MAX UINT64_MAX
/* 7.18.2.4 Limits of integer types capable of holding object pointers */
/* 7.18.2.4 Limits of integer types capable of holding
object pointers */
#ifdef _WIN64
#define INTPTR_MIN INT64_MIN
#define INTPTR_MAX INT64_MAX
@@ -164,42 +158,40 @@ typedef unsigned __STDINT_LONGLONG uintmax_t;
#define INTPTR_MIN INT32_MIN
#define INTPTR_MAX INT32_MAX
#define UINTPTR_MAX UINT32_MAX
#endif /* _WIN64 */
#endif
/* 7.18.2.5 Limits of greatest-width integer types */
#define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX
/* 7.18.3 Limits of other integer types */
#define PTRDIFF_MIN INTPTR_MIN
#define PTRDIFF_MAX INTPTR_MAX
#define SIG_ATOMIC_MIN INTPTR_MIN
#define SIG_ATOMIC_MAX INTPTR_MAX
/* we need to check for SIZE_MAX already defined because MS defines it in limits.h */
#ifdef _WIN64
#define PTRDIFF_MIN INT64_MIN
#define PTRDIFF_MAX INT64_MAX
#else
#define PTRDIFF_MIN INT32_MIN
#define PTRDIFF_MAX INT32_MAX
#endif
#define SIG_ATOMIC_MIN INT32_MIN
#define SIG_ATOMIC_MAX INT32_MAX
#ifndef SIZE_MAX
#define SIZE_MAX UINTPTR_MAX
#ifdef _WIN64
#define SIZE_MAX UINT64_MAX
#else
#define SIZE_MAX UINT32_MAX
#endif
#ifndef WCHAR_MIN /* also in wchar.h */
#define WCHAR_MIN 0
#define WCHAR_MAX ((wchar_t)-1) /* UINT16_MAX */
#endif
/* wint_t is unsigned short for compatibility with MS runtime */
#define WINT_MIN 0
#define WINT_MAX ((wint_t)-1) /* UINT16_MAX */
#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */
#ifndef WCHAR_MIN /* also in wchar.h */
#define WCHAR_MIN 0U
#define WCHAR_MAX 0xffffU
#endif
/*
* wint_t is unsigned short for compatibility with MS runtime
*/
#define WINT_MIN 0U
#define WINT_MAX 0xffffU
/* 7.18.4 Macros for integer constants */
#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS)
/* 7.18.4.1 Macros for minimum-width integer constants
Accoding to Douglas Gwyn <gwyn@arl.mil>:
Accoding to Douglas Gwyn <gwyn@arl.mil>:
"This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC
9899:1999 as initially published, the expansion was required
to be an integer constant of precisely matching type, which
@@ -208,22 +200,19 @@ typedef unsigned __STDINT_LONGLONG uintmax_t;
an integer constant with width less than that of type int.
TC1 changed this to require just an integer constant
*expression* with *promoted* type."
The trick used here is from Clive D W Feather.
*/
#define INT8_C(val) ((int8_t) + (val))
#define UINT8_C(val) ((uint8_t) + (val##U))
#define INT16_C(val) ((int16_t) + (val))
#define UINT16_C(val) ((uint16_t) + (val##U))
#define INT32_C(val) val##L
#define UINT32_C(val) val##UL
#define INT64_C(val) (PASTE( val, __STDINT_LONGLONG_SUFFIX))
#define UINT64_C(val)(PASTE( PASTE( val, U), __STDINT_LONGLONG_SUFFIX))
#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val))
#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val))
#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val))
/* The 'trick' doesn't work in C89 for long long because, without
suffix, (val) will be evaluated as int, not intmax_t */
#define INT64_C(val) val##i64
#define UINT8_C(val) (val)
#define UINT16_C(val) (val)
#define UINT32_C(val) (val##i32)
#define UINT64_C(val) val##ui64
/* 7.18.4.2 Macros for greatest-width integer constants */
#define INTMAX_C(val) INT64_C(val)
#define UINTMAX_C(val) UINT64_C(val)
#endif /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */
#endif
#define INTMAX_C(val) val##i64
#define UINTMAX_C(val) val##ui64
#endif