diff --git a/README.md b/README.md index 27602d2..6ffedc0 100644 --- a/README.md +++ b/README.md @@ -57,103 +57,6 @@ 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 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: diff --git a/extra/base/README.md b/extra/base/README.md index 4e3384d..e6df5c1 100644 --- a/extra/base/README.md +++ b/extra/base/README.md @@ -12,14 +12,18 @@ All plugins in this section require AMXX 1.9.0 or greater, they will not work on 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. -#### GoldSrc --> MonsterMod Use Dispatcher +#### 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. -To add salt to injury, Metamod is incapable of hooking use functions, as the pfnUse/DispatchUse methods provided by the API has been deprecated, and no longer work. Leaving AMXX's HamSandwich as the only module that can hook an entity's Use() function. - 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. -This plugin redirects the game's func_wall Use() function to MonsterMod, connecting the missing piece and allowing you to trigger MonsterMod entities with your shiny func_button. +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. -I can't believe I've done this. *incomprehensible screams* +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. diff --git a/extra/base/bin/glb_takedamage.amxx b/extra/base/bin/glb_takedamage.amxx new file mode 100644 index 0000000..1f9807d Binary files /dev/null and b/extra/base/bin/glb_takedamage.amxx differ diff --git a/extra/base/src/glb_dispatchuse.sma b/extra/base/src/glb_dispatchuse.sma index ab5066e..94b3196 100644 --- a/extra/base/src/glb_dispatchuse.sma +++ b/extra/base/src/glb_dispatchuse.sma @@ -6,9 +6,15 @@ public plugin_init() { - register_plugin( "GAME-MONSTER: Use Dispatcher", "1.0", "Giegue" ); + 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 ) @@ -22,3 +28,30 @@ public DispatchUse( entity, caller, activator, useType, Float:value ) 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 ); + } +} diff --git a/extra/base/src/glb_takedamage.sma b/extra/base/src/glb_takedamage.sma new file mode 100644 index 0000000..2a60294 --- /dev/null +++ b/extra/base/src/glb_takedamage.sma @@ -0,0 +1,42 @@ +#pragma semicolon 1 + +#include +#include +#include + +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 ); + } +} diff --git a/extra/cstrike/README.md b/extra/cstrike/README.md new file mode 100644 index 0000000..de3fcbf --- /dev/null +++ b/extra/cstrike/README.md @@ -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. diff --git a/extra/cstrike/bin/cs_unprecacher.amxx b/extra/cstrike/bin/cs_unprecacher.amxx new file mode 100644 index 0000000..f4af338 Binary files /dev/null and b/extra/cstrike/bin/cs_unprecacher.amxx differ diff --git a/extra/cstrike/src/cs_unprecacher.sma b/extra/cstrike/src/cs_unprecacher.sma new file mode 100644 index 0000000..056e93c --- /dev/null +++ b/extra/cstrike/src/cs_unprecacher.sma @@ -0,0 +1,126 @@ +#pragma semicolon 1 + +#include +#include + +// 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; +} diff --git a/extra/valve/README.md b/extra/valve/README.md index 0010cdf..1b063f8 100644 --- a/extra/valve/README.md +++ b/extra/valve/README.md @@ -10,7 +10,7 @@ All plugins in this section require AMXX 1.9.0 or greater, they will not work on 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 +#### 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. diff --git a/extra/valve/bin/hl_monsterbridge.amxx b/extra/valve/bin/hl_monsterbridge.amxx index ada2c3e..cb05ae8 100644 Binary files a/extra/valve/bin/hl_monsterbridge.amxx and b/extra/valve/bin/hl_monsterbridge.amxx differ diff --git a/extra/valve/src/hl_monsterbridge.sma b/extra/valve/src/hl_monsterbridge.sma index cb4b933..57b8fe6 100644 --- a/extra/valve/src/hl_monsterbridge.sma +++ b/extra/valve/src/hl_monsterbridge.sma @@ -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.1", "Giegue" ); + register_plugin( "HL-MONSTER Bridge", "1.2", "Giegue" ); RegisterHam( Ham_IRelationship, "monster_alien_controller", "mmIRelationship" ); RegisterHam( Ham_IRelationship, "monster_alien_grunt", "mmIRelationship" ); @@ -69,8 +71,32 @@ public plugin_init() TrieSetString( g_HLDefaultNames, "monster_nihilanth", "Nihilanth" ); TrieSetString( g_HLDefaultNames, "monster_tentacle", "Tentacle" ); - set_task( 0.3, "hlScan", 0, "", 0, "b" ); - register_srvcmd( "monster_hurt_entity", "hlTakeDamage" ); + // 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 ); } @@ -94,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 ); } } @@ -162,33 +185,6 @@ stock IRelationshipByClass( classEntity, classOther ) return iEnemy[ classEntity ][ classOther ]; } -public hlTakeDamage() -{ - if ( read_argc() == 6 ) - { - new victim, inflictor, attacker; - new Float:damage; - new damageBits; - - victim = read_argv_int( 1 ); - inflictor = read_argv_int( 2 ); - attacker = read_argv_int( 3 ); - damage = read_argv_float( 4 ); - damageBits = read_argv_int( 5 ); - - // attacker and inflictor can be null, but never allow victim to be null - if ( !is_valid_ent( victim ) ) - return; - - if ( !is_valid_ent( inflictor ) ) - inflictor = 0; - if ( !is_valid_ent( attacker ) ) - attacker = 0; - - ExecuteHamB( Ham_TakeDamage, victim, inflictor, attacker, damage, damageBits ); - } -} - public PlayerKilled( victim, attacker, shouldgib ) { // don't obstruct monstermod