From 4b087efde8548a63ef5ebb488c10c938f871d18e Mon Sep 17 00:00:00 2001 From: Giegue Date: Tue, 28 Feb 2023 13:46:44 -0300 Subject: [PATCH 01/45] I keep forgetting to update this... --- src/dlls/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dlls/Makefile b/src/dlls/Makefile index 3113bc1..a5c6afc 100644 --- a/src/dlls/Makefile +++ b/src/dlls/Makefile @@ -35,6 +35,7 @@ OBJ = \ massn.o \ monster_api.o \ monster_config.o \ + monstermaker.o \ monsters.o \ monsterstate.o \ nodes.o \ From e1bd51b220536c05829866a47467aa921355df4e Mon Sep 17 00:00:00 2001 From: Giegue Date: Thu, 2 Mar 2023 14:09:15 -0300 Subject: [PATCH 02/45] [#4] Fix wrong angles on shocktroopers beams and roaches. --- src/dlls/strooper.cpp | 46 +++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/src/dlls/strooper.cpp b/src/dlls/strooper.cpp index fc5a709..4bf7f10 100644 --- a/src/dlls/strooper.cpp +++ b/src/dlls/strooper.cpp @@ -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; @@ -590,12 +580,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(); From 2140e3413d88c7f793ba64f120c2eb2514d87f21 Mon Sep 17 00:00:00 2001 From: Giegue Date: Thu, 2 Mar 2023 14:09:49 -0300 Subject: [PATCH 03/45] [#4] Fix compiler warnings. --- src/dlls/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dlls/Makefile b/src/dlls/Makefile index a5c6afc..a87d2d4 100644 --- a/src/dlls/Makefile +++ b/src/dlls/Makefile @@ -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 From 55dfee7d740b7e002b4e4362820fccaa5bf30728 Mon Sep 17 00:00:00 2001 From: Giegue Date: Fri, 3 Mar 2023 01:18:38 -0300 Subject: [PATCH 04/45] 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. --- src/dlls/hgrunt.cpp | 69 +++++++++++++++++++++++++++++++++++++------ src/dlls/massn.cpp | 4 +-- src/dlls/strooper.cpp | 19 +++++++++--- 3 files changed, 76 insertions(+), 16 deletions(-) diff --git a/src/dlls/hgrunt.cpp b/src/dlls/hgrunt.cpp index 1f97329..6f6bcfa 100644 --- a/src/dlls/hgrunt.cpp +++ b/src/dlls/hgrunt.cpp @@ -663,9 +663,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 +690,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 ); @@ -1677,6 +1673,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 +1728,7 @@ DEFINE_CUSTOM_SCHEDULES( CMHGrunt ) slGruntRepel, slGruntRepelAttack, slGruntRepelLand, + slGruntChaseEnemyFailed, }; IMPLEMENT_CUSTOM_SCHEDULES( CMHGrunt, CMBaseMonster ); @@ -1856,6 +1884,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 +1901,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 +1922,7 @@ jlb*/ } } } + */ } // no ammo else if ( HasConditions ( bits_COND_NO_AMMO_LOADED ) ) @@ -1943,6 +1974,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,13 +1985,18 @@ 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 @@ -1968,6 +2008,11 @@ jlb*/ 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 +2024,7 @@ jlb*/ } return GetScheduleOfType( SCHED_STANDOFF ); } + */ } if ( HasConditions( bits_COND_SEE_ENEMY ) && !HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) @@ -2113,6 +2159,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 ); diff --git a/src/dlls/massn.cpp b/src/dlls/massn.cpp index aa08dc9..1cc2b81 100644 --- a/src/dlls/massn.cpp +++ b/src/dlls/massn.cpp @@ -120,9 +120,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); diff --git a/src/dlls/strooper.cpp b/src/dlls/strooper.cpp index 4bf7f10..09dc91d 100644 --- a/src/dlls/strooper.cpp +++ b/src/dlls/strooper.cpp @@ -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 ) @@ -730,6 +730,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 @@ -743,14 +745,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(); } @@ -762,6 +764,7 @@ Schedule_t *CMStrooper::GetSchedule(void) { return GetScheduleOfType(SCHED_STROOPER_ESTABLISH_LINE_OF_FIRE); } + */ } // no ammo else if (HasConditions(bits_COND_NO_AMMO_LOADED)) @@ -814,8 +817,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 @@ -832,6 +837,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 @@ -843,6 +853,7 @@ Schedule_t *CMStrooper::GetSchedule(void) } return GetScheduleOfType(SCHED_STANDOFF); } + */ } if (HasConditions(bits_COND_SEE_ENEMY) && !HasConditions(bits_COND_CAN_RANGE_ATTACK1)) From 62063e34dadbd9f57cebda51daeccaf2593cd950 Mon Sep 17 00:00:00 2001 From: Giegue Date: Fri, 3 Mar 2023 01:33:37 -0300 Subject: [PATCH 05/45] Scrap scaling idea, not possible. --- README.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7994667..d388d9a 100644 --- a/README.md +++ b/README.md @@ -156,14 +156,12 @@ Doing this will free **85** sounds from the precache list that you can now use f I'm aware that the plugin is far from perfect, and there are a few things that need polishing *-especially the AI-*. I'll try to fix/will be fixing as the project evolves: -- Human Grunts are unable to reload their weapons. As a workaround, infinite ammo has been given to them. - -- Male Assassins share the same AI as HGrunts, so their ammo problem is still a thing, and the same workaround is used. - -- Shock Troopers seems to be broken despite sharing HGrunts AI code. Despite having infinite ammo, they eventually stop firing. Worse, taking cover is absolutely broken, and they remain completely frozen in place when it happens. - - If a Heavy Weapons Grunt is to lose their target while his minigun is still spinning, the next time it targets an enemy it will instantly fire instead of spinning up the minigun again. +- Monster "turning speed" (yaw speed) is too slow. While this doesn't cause any breaks, it degrades the quality of the AI, making them really easy to cheese. + +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. + ## Milestones Attempting to recreate everything in one go is a daunting task. @@ -201,7 +199,7 @@ Current milestones are separated by "Tiers", which are as follows: ### Tier 4 - Implement reading entities within the BSP itself. -- Model scaling. *-If possible.-* +- Add build instructions. - Custom sound support, along with sentences. - Fix all pending bugs. From bd02a9526002f7b7aa7934e77586945e17854833 Mon Sep 17 00:00:00 2001 From: Giegue Date: Sat, 4 Mar 2023 17:24:01 -0300 Subject: [PATCH 06/45] Fix broken shock roach death. Fix hwgrunt not spinning down the minigun. Other misc. fixes. --- extra/valve/bin/hl_monsterbridge.amxx | Bin 4049 -> 4426 bytes extra/valve/src/hl_monsterbridge.sma | 20 ++++++++++++++++++-- src/dlls/dllapi.cpp | 8 ++++---- src/dlls/hornet.cpp | 2 ++ src/dlls/hwgrunt.cpp | 13 ++++++++++++- src/dlls/shockroach.cpp | 2 +- src/dlls/util.cpp | 5 +++-- 7 files changed, 40 insertions(+), 10 deletions(-) diff --git a/extra/valve/bin/hl_monsterbridge.amxx b/extra/valve/bin/hl_monsterbridge.amxx index 59a174c47e5cbe21a648e691db50611021fb9058..ada2c3eb826b26a78c41e0c717ec36ede769cdaa 100644 GIT binary patch literal 4426 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 Q{N^JnH@4UR11Ob1d3T58V*mgE literal 4049 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 DP8=bR diff --git a/extra/valve/src/hl_monsterbridge.sma b/extra/valve/src/hl_monsterbridge.sma index 199c817..cb4b933 100644 --- a/extra/valve/src/hl_monsterbridge.sma +++ b/extra/valve/src/hl_monsterbridge.sma @@ -16,7 +16,7 @@ new Trie:g_HLDefaultNames; public plugin_init() { - register_plugin( "HL-MONSTER Bridge", "1.0", "Giegue" ); + register_plugin( "HL-MONSTER Bridge", "1.1", "Giegue" ); RegisterHam( Ham_IRelationship, "monster_alien_controller", "mmIRelationship" ); RegisterHam( Ham_IRelationship, "monster_alien_grunt", "mmIRelationship" ); @@ -67,10 +67,12 @@ 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" ); + + RegisterHam( Ham_Killed, "player", "PlayerKilled", 1 ); } public plugin_end() { @@ -186,3 +188,17 @@ public hlTakeDamage() ExecuteHamB( Ham_TakeDamage, victim, inflictor, attacker, damage, damageBits ); } } + +public PlayerKilled( victim, attacker, shouldgib ) +{ + // don't obstruct monstermod + if ( victim == attacker ) + return HAM_IGNORED; + + // fix monster score + if ( entity_get_int( attacker, EV_INT_flags ) & FL_MONSTER ) + entity_set_float( attacker, EV_FL_frags, entity_get_float( attacker, EV_FL_frags ) + 2 ); + + entity_set_edict( victim, EV_ENT_dmg_inflictor, attacker ); + return HAM_IGNORED; +} diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index 21be0f7..e81a07f 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -399,12 +399,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 )); } } @@ -537,8 +537,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; diff --git a/src/dlls/hornet.cpp b/src/dlls/hornet.cpp index b41edc0..e4966e7 100644 --- a/src/dlls/hornet.cpp +++ b/src/dlls/hornet.cpp @@ -372,6 +372,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 diff --git a/src/dlls/hwgrunt.cpp b/src/dlls/hwgrunt.cpp index 09888bd..a768b6d 100644 --- a/src/dlls/hwgrunt.cpp +++ b/src/dlls/hwgrunt.cpp @@ -700,7 +700,18 @@ void CMHWGrunt :: SetActivity ( Activity NewActivity ) case ACT_RUN: case ACT_WALK: default: - iSequence = LookupActivity ( NewActivity ); + if ( m_flMinigunSpinTime != 0 ) + { + // if the hwgrunt used his minigun but became unable to attack + // then spin it down before doing anything else + refreshActivity = FALSE; + + EMIT_SOUND(ENT(pev), CHAN_WEAPON, "hassault/hw_spindown.wav", 0.8, ATTN_NORM); + m_flMinigunSpinTime = gpGlobals->time + 1.40; + iSequence = LookupSequence( "spindown" ); + } + else + iSequence = LookupActivity ( NewActivity ); break; } diff --git a/src/dlls/shockroach.cpp b/src/dlls/shockroach.cpp index baf7125..34d074d 100644 --- a/src/dlls/shockroach.cpp +++ b/src/dlls/shockroach.cpp @@ -153,7 +153,7 @@ void CMShockRoach::MonsterThink(void) { pev->health = -1; Killed(pev, 0); - return; + //return; // it still needs to think } CMHeadCrab::MonsterThink(); diff --git a/src/dlls/util.cpp b/src/dlls/util.cpp index fc65ad3..c6382ab 100644 --- a/src/dlls/util.cpp +++ b/src/dlls/util.cpp @@ -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, ...) { @@ -1760,7 +1760,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; From 750b9166666c21843089a08ac19a0c9bf6f876e5 Mon Sep 17 00:00:00 2001 From: Giegue Date: Sat, 4 Mar 2023 17:24:23 -0300 Subject: [PATCH 07/45] *screams in AI* --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d388d9a..d3d77ab 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ Doing this will free **85** sounds from the precache list that you can now use f 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: -- 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. +- The Heavy Weapons Grunt AI is borked, they "run" with their miniguns like if they have pistols. - Monster "turning speed" (yaw speed) is too slow. While this doesn't cause any breaks, it degrades the quality of the AI, making them really easy to cheese. From 73f240ddb1c06548da1b3688c06f6f9674459784 Mon Sep 17 00:00:00 2001 From: Giegue Date: Mon, 6 Mar 2023 02:08:37 -0300 Subject: [PATCH 08/45] Fixed monster turn rate being too slow. Fixed heavy weapons grunt AI being complete nonsense. Small improvements to stukabat. --- README.md | 6 +- src/dlls/AI_BaseNPC_Schedule.cpp | 2 +- src/dlls/cmbasemonster.h | 5 +- src/dlls/hwgrunt.cpp | 580 +++++++++++++------------------ src/dlls/monster_api.cpp | 5 + src/dlls/monsters.cpp | 19 +- src/dlls/stukabat.cpp | 58 +++- 7 files changed, 325 insertions(+), 350 deletions(-) diff --git a/README.md b/README.md index d3d77ab..d93b501 100644 --- a/README.md +++ b/README.md @@ -156,11 +156,11 @@ Doing this will free **85** sounds from the precache list that you can now use f 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: -- The Heavy Weapons Grunt AI is borked, they "run" with their miniguns like if they have pistols. +- Rarely, Stukabats will become unable to fly towards their target, standing in air doing seemingly nothing. Cause of bug unknown. -- Monster "turning speed" (yaw speed) is too slow. While this doesn't cause any breaks, it degrades the quality of the AI, making them really easy to cheese. +- Entvars are not recognized, so anything that is a pevfield that is not used by monstermod is unusable. -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. +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 diff --git a/src/dlls/AI_BaseNPC_Schedule.cpp b/src/dlls/AI_BaseNPC_Schedule.cpp index de53898..0825a6e 100644 --- a/src/dlls/AI_BaseNPC_Schedule.cpp +++ b/src/dlls/AI_BaseNPC_Schedule.cpp @@ -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; } diff --git a/src/dlls/cmbasemonster.h b/src/dlls/cmbasemonster.h index 446a984..26439b1 100644 --- a/src/dlls/cmbasemonster.h +++ b/src/dlls/cmbasemonster.h @@ -104,7 +104,8 @@ public: string_t m_szMonsterName; // Monster name to display on HUD int m_iClassifyOverride; // Overriden classification for this monster - + float m_flLastYawTime; + void KeyValue( KeyValueData *pkvd ); // monster use function @@ -1667,8 +1668,6 @@ public: void Minigun(void); CUSTOM_SCHEDULES - - float m_flMinigunSpinTime; }; //========================================================= diff --git a/src/dlls/hwgrunt.cpp b/src/dlls/hwgrunt.cpp index a768b6d..8d85d4a 100644 --- a/src/dlls/hwgrunt.cpp +++ b/src/dlls/hwgrunt.cpp @@ -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. @@ -214,7 +206,7 @@ void CMHWGrunt::Spawn() 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,15 @@ 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 + + CMHGrunt hgrunt; + hgrunt.Precache(); } //========================================================= @@ -274,7 +267,7 @@ void CMHWGrunt::Precache() //========================================================= //========================================================= -// GruntFail +// Fail //========================================================= Task_t tlHWGruntFail[] = { @@ -296,7 +289,7 @@ Schedule_t slHWGruntFail[] = }; //========================================================= -// Grunt Combat Fail +// Combat Fail //========================================================= Task_t tlHWGruntCombatFail[] = { @@ -318,7 +311,7 @@ Schedule_t slHWGruntCombatFail[] = }; //========================================================= -// Victory dance! +// Not really victory dance //========================================================= Task_t tlHWGruntVictoryDance[] = { @@ -328,7 +321,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 +330,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 +346,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 +361,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 +386,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 +479,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 +493,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 +507,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,121 +551,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: - if ( m_flMinigunSpinTime != 0 ) - { - // if the hwgrunt used his minigun but became unable to attack - // then spin it down before doing anything else - refreshActivity = FALSE; - - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "hassault/hw_spindown.wav", 0.8, ATTN_NORM); - m_flMinigunSpinTime = gpGlobals->time + 1.40; - iSequence = LookupSequence( "spindown" ); - } - else - 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 ) @@ -730,7 +601,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 ); @@ -743,6 +614,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 ) { @@ -754,11 +628,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 ); } } @@ -769,6 +640,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(); } @@ -776,40 +654,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 ); } } } @@ -824,10 +738,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: @@ -837,34 +765,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 ]; } @@ -876,19 +798,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 ); } } } + diff --git a/src/dlls/monster_api.cpp b/src/dlls/monster_api.cpp index 1beda0a..7f5361f 100644 --- a/src/dlls/monster_api.cpp +++ b/src/dlls/monster_api.cpp @@ -87,6 +87,8 @@ 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; // Metamod requesting info about this plugin: @@ -146,6 +148,9 @@ 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"); + return(TRUE); } diff --git a/src/dlls/monsters.cpp b/src/dlls/monsters.cpp index 56759a4..19d8284 100644 --- a/src/dlls/monsters.cpp +++ b/src/dlls/monsters.cpp @@ -39,6 +39,8 @@ extern DLL_GLOBAL BOOL g_fDrawLines; extern CGraph WorldGraph;// the world node graph +extern cvar_t *monster_turn_coeficient; + //========================================================= @@ -2234,7 +2236,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) diff --git a/src/dlls/stukabat.cpp b/src/dlls/stukabat.cpp index 9f841c1..3490097 100644 --- a/src/dlls/stukabat.cpp +++ b/src/dlls/stukabat.cpp @@ -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; } From bd9fe1f487d9a0d52a4a6ae6fef38e131945e0ba Mon Sep 17 00:00:00 2001 From: Giegue Date: Mon, 6 Mar 2023 20:02:04 -0300 Subject: [PATCH 09/45] Handle entvar keyvalues. --- README.md | 2 - extra/README.md | 2 + extra/base/README.md | 25 +++++ extra/base/bin/glb_dispatchuse.amxx | Bin 0 -> 1547 bytes extra/base/src/glb_dispatchuse.sma | 24 ++++ src/dlls/cmbase.cpp | 15 +++ src/dlls/cmbase.h | 2 +- src/dlls/dllapi.cpp | 47 +++++++- src/dlls/util.cpp | 163 ++++++++++++++++++++++++++++ 9 files changed, 274 insertions(+), 6 deletions(-) create mode 100644 extra/base/README.md create mode 100644 extra/base/bin/glb_dispatchuse.amxx create mode 100644 extra/base/src/glb_dispatchuse.sma diff --git a/README.md b/README.md index d93b501..c8da562 100644 --- a/README.md +++ b/README.md @@ -158,8 +158,6 @@ I'm aware that the plugin is far from perfect, and there are a few things that n - Rarely, Stukabats will become unable to fly towards their target, standing in air doing seemingly nothing. Cause of bug unknown. -- Entvars are not recognized, so anything that is a pevfield that is not used by monstermod is unusable. - 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 diff --git a/extra/README.md b/extra/README.md index 5df6f0e..aa681a4 100644 --- a/extra/README.md +++ b/extra/README.md @@ -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. diff --git a/extra/base/README.md b/extra/base/README.md new file mode 100644 index 0000000..4e3384d --- /dev/null +++ b/extra/base/README.md @@ -0,0 +1,25 @@ +## 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. + +#### GoldSrc --> MonsterMod 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. + +I can't believe I've done this. *incomprehensible screams* diff --git a/extra/base/bin/glb_dispatchuse.amxx b/extra/base/bin/glb_dispatchuse.amxx new file mode 100644 index 0000000000000000000000000000000000000000..4d912151f45f71dfacc2b807711c721ccc8a8554 GIT binary patch literal 1547 zcmV+m2K4z@SWQ6y0|5l{1pol24FCXeMgRa90001ZoSj!oY#c=pt+AbCLmV)~1Ooxg z*BD~2oy2i~h+yyf2exC`4u5IX-tFBTGN0A-jN?@}aEU|^2OtvS2oebK5dy&>2M#&p zfDl*2B~l{J5fLYHKnky?Yu4j+6bK`|ecjd7RsE^%>aA}jy7Xr**G4&_HloWNM0LpO zlSJ3>9U`Iy;A6&F;1W=T?(bmqqCbEiE&OQU>tya>?q`06d5-y2W{0`Ke2V!)=1;&F z7JY3Qe`mq%M9-ZE525}uco_UEcm#YAd=PvEe1wXQs*9*pJEkPrc11+OwQIt&Wf%q_ z)!n%2__pIa5mjYmS7N_pJ7p>f*GpETkqSMFo>%Y#t+cV?K>YikKdzrIiPsjHW*2in2`CI10%$;m&E8FO58GDvHEW;PL{v>lZ+t|i7dTua|TUz!a zUAuG+oxCm=+DxBQz#irv=5FRL=G4{!9$ydJ+|D-lu>T#rc0-xE#r5lb(|`axV3POE z)q4g=AY{EMU<{Z8CV&Ah9|h)tC19D`7J;XMUf>v@*p{vr*@u?Z*|+vp0%|Qjhk0$& zu}^Vdty2YJF6*ztb)Rk7zzMeRGUz|}&yJVaPTVqwN7=^Blq+m+6ajPv`9`0*UD(}2 z$?oXL$kzf-=HG~2NBH@oR3#Bsg~|(W%?rwF1H*$)4Gs-dooHm==bIQ7EnPV}HklzWOZ8JXK0^b4t1-y&Q zk=RYT`vZDffKDaJZE4O%Q;c+z2#g;+&ko2#DOBL|nrlb|=@lp<$UL`be(o7!}Sl*aeQ29p94(RzbE z+}ZR^&3Pu>z?tmWv7xaY&DnfO%{Xh{tiyTK+{(EPi>ZgO`PGoTc9P#B4>S9Y(5J?t zl^}2t*9#VZl%}GB-&=%D5f#WYFkDFb(cP$J~6rE6F z`w@EG5b4HPjf;@(MC~Oh>VaQyg;I&>-P%zc1>ULZFZqm*xr! zBE$oap3vn*sbV)mnnigciLJdfGe5&B15{WQ;kb?$g;Y>Nr4|IoDNj?vlZC*qI8~&F z%+qf;^Z46G`f<5m{~FT=bWtx?vYaEEUWW%;--n~R!?gC8ejPX%Ll@uASU{R;69hDTUI%4Z3j)-&MqR-XrtY)89wGUHt2{)b_Jy xZs +#include +#include + +public plugin_init() +{ + register_plugin( "GAME-MONSTER: Use Dispatcher", "1.0", "Giegue" ); + + RegisterHam( Ham_Use, "func_wall", "DispatchUse" ); +} + +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; +} diff --git a/src/dlls/cmbase.cpp b/src/dlls/cmbase.cpp index 644a062..e97cc96 100644 --- a/src/dlls/cmbase.cpp +++ b/src/dlls/cmbase.cpp @@ -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,19 @@ edict_t *CMBaseEntity::CreateEntity(char *classname) return pent; } +// process entvar keyvalue +void CMBaseEntity :: KeyValue( KeyValueData* pkvd ) +{ + if ( !pev || !pkvd ) + return; + + if ( pkvd->fHandled ) + { + // only handled data contain readable strings + EntvarsKeyvalue( pev, pkvd ); + } +} + // give health int CMBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) { diff --git a/src/dlls/cmbase.h b/src/dlls/cmbase.h index 6f5d1f0..824ae1c 100644 --- a/src/dlls/cmbase.h +++ b/src/dlls/cmbase.h @@ -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 ) {} diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index e81a07f..572a000 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -1327,6 +1327,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( caller, activator, 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 ) { @@ -1371,6 +1411,7 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) (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++) { @@ -1531,10 +1572,10 @@ 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 @@ -1631,7 +1672,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 diff --git a/src/dlls/util.cpp b/src/dlls/util.cpp index c6382ab..c1a0d18 100644 --- a/src/dlls/util.cpp +++ b/src/dlls/util.cpp @@ -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 ); From b36491579930edc274f8a2ac31470f00f455fd2c Mon Sep 17 00:00:00 2001 From: Giegue Date: Tue, 7 Mar 2023 13:44:14 -0300 Subject: [PATCH 10/45] [#10] Fix linux compilation. --- src/engine/eiface.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/engine/eiface.h b/src/engine/eiface.h index 596aa9b..6994273 100644 --- a/src/engine/eiface.h +++ b/src/engine/eiface.h @@ -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) From 9849c5296bf71eb4967eea49f9171ea10a37d632 Mon Sep 17 00:00:00 2001 From: Giegue <48396052+JulianR0@users.noreply.github.com> Date: Wed, 8 Mar 2023 19:17:38 -0300 Subject: [PATCH 11/45] Add link to wiki. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c8da562..7861a30 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ Additional configuration files are included in the release files, each explainin ## Build Instructions -*TODO: Add build instructions.* +The [wiki](https://github.com/JulianR0/monstermod-redo/wiki) contains instructions on how to compile MonsterMod by yourself. ## MonsterMod and ReHLDS From 76d4c3b4bd0c5662531e11fc30f45ae00c317748 Mon Sep 17 00:00:00 2001 From: Giegue Date: Wed, 15 Mar 2023 14:06:02 -0300 Subject: [PATCH 12/45] Compile under modern Visual Studio versions. --- src/dlls/animation.cpp | 4 + src/dlls/extdll.h | 3 + src/dlls/monster_mm.dsp | 437 ---------------------------- src/dlls/monster_mm.sln | 25 ++ src/dlls/monster_mm.vcxproj | 222 ++++++++++++++ src/dlls/monster_mm.vcxproj.filters | 270 +++++++++++++++++ src/dlls/nodes.cpp | 10 +- 7 files changed, 529 insertions(+), 442 deletions(-) delete mode 100644 src/dlls/monster_mm.dsp create mode 100644 src/dlls/monster_mm.sln create mode 100644 src/dlls/monster_mm.vcxproj create mode 100644 src/dlls/monster_mm.vcxproj.filters diff --git a/src/dlls/animation.cpp b/src/dlls/animation.cpp index 273d3e0..56d8d4d 100644 --- a/src/dlls/animation.cpp +++ b/src/dlls/animation.cpp @@ -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; } diff --git a/src/dlls/extdll.h b/src/dlls/extdll.h index a6d3ca2..6fb13c9 100644 --- a/src/dlls/extdll.h +++ b/src/dlls/extdll.h @@ -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 diff --git a/src/dlls/monster_mm.dsp b/src/dlls/monster_mm.dsp deleted file mode 100644 index 1432f8f..0000000 --- a/src/dlls/monster_mm.dsp +++ /dev/null @@ -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 diff --git a/src/dlls/monster_mm.sln b/src/dlls/monster_mm.sln new file mode 100644 index 0000000..a739e5e --- /dev/null +++ b/src/dlls/monster_mm.sln @@ -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 diff --git a/src/dlls/monster_mm.vcxproj b/src/dlls/monster_mm.vcxproj new file mode 100644 index 0000000..53658f6 --- /dev/null +++ b/src/dlls/monster_mm.vcxproj @@ -0,0 +1,222 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {E4F36B30-6406-4D6E-90F6-DE34744D2434} + + + + DynamicLibrary + false + MultiByte + v141_xp + + + DynamicLibrary + false + MultiByte + v141_xp + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Debug\ + .\Debug\ + true + .\Release\ + .\Release\ + false + false + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/monster_mm.tlb + + + Disabled + ..\dlls;..\common;..\engine;..\pm_shared;..\metamod;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;monster_mm_EXPORTS;strcasecmp=stricmp;strncasecmp=_strnicmp;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + .\Debug/monster_mm.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level3 + true + EditAndContinue + Default + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + /MACHINE:I386 %(AdditionalOptions) + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + .\Debug/monster_mm.dll + true + .\monster_mm.def + true + .\Debug/monster_mm.pdb + false + + + .\Debug/monster_mm.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/monster_mm.tlb + + + OnlyExplicitInline + ..\dlls;..\common;..\engine;..\pm_shared;..\metamod;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;monster_mm_EXPORTS;%(PreprocessorDefinitions) + true + MultiThreaded + true + .\Release/monster_mm.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + Default + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + /MACHINE:I386 %(AdditionalOptions) + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + .\Release/monster_mm.dll + true + .\monster_mm.def + .\Release/monster_mm.pdb + false + + + .\Release/monster_mm.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/dlls/monster_mm.vcxproj.filters b/src/dlls/monster_mm.vcxproj.filters new file mode 100644 index 0000000..7d2721f --- /dev/null +++ b/src/dlls/monster_mm.vcxproj.filters @@ -0,0 +1,270 @@ + + + + + {c6c9a5d3-53c7-4dda-a7f7-a278343d08f6} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {7a512719-d6e9-4695-acde-c7239717ece9} + h;hpp;hxx;hm;inl + + + {af74e8b8-3ee2-4d62-b8cb-fa3952c4afed} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/src/dlls/nodes.cpp b/src/dlls/nodes.cpp index 85b9320..a4d7eb0 100644 --- a/src/dlls/nodes.cpp +++ b/src/dlls/nodes.cpp @@ -1278,7 +1278,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 +1889,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 +3437,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]); } From 3b1c99d2cc84ad8a064206c3ba2321a0207ccf24 Mon Sep 17 00:00:00 2001 From: Giegue Date: Wed, 15 Mar 2023 14:09:06 -0300 Subject: [PATCH 13/45] [#11] Add basic death message on PvP kills. --- src/dlls/dllapi.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index 572a000..23678d9 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -424,6 +424,16 @@ 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 ) { From bc7633bf9c36adad4d2f43cf32f5da7bdcd3860e Mon Sep 17 00:00:00 2001 From: Giegue Date: Wed, 15 Mar 2023 14:23:44 -0300 Subject: [PATCH 14/45] Update readme. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7861a30..69afc20 100644 --- a/README.md +++ b/README.md @@ -197,7 +197,7 @@ Current milestones are separated by "Tiers", which are as follows: ### Tier 4 - Implement reading entities within the BSP itself. -- Add build instructions. +- Add build instructions. **[DONE]** - Custom sound support, along with sentences. - Fix all pending bugs. From ecf3bd9a3da78b6aaf8fdb77bc9b91b26233ff8b Mon Sep 17 00:00:00 2001 From: Giegue Date: Thu, 16 Mar 2023 15:58:09 -0300 Subject: [PATCH 15/45] Fixed tons of monsters not working/crashing when attacking HL monsters. --- src/dlls/bullsquid.cpp | 4 +++- src/dlls/controller.cpp | 4 ++++ src/dlls/gargantua.cpp | 24 +++++++++++++++++++++--- src/dlls/ggrenade.cpp | 15 ++++++++------- src/dlls/gonome.cpp | 6 ++++-- src/dlls/houndeye.cpp | 5 ++++- src/dlls/islave.cpp | 2 ++ src/dlls/pitdrone.cpp | 4 +++- src/dlls/shock.cpp | 4 +++- src/dlls/shockroach.cpp | 2 ++ src/dlls/squeakgrenade.cpp | 10 ++++++---- src/dlls/strooper.cpp | 2 ++ src/dlls/voltigore.cpp | 8 +++++++- 13 files changed, 69 insertions(+), 21 deletions(-) diff --git a/src/dlls/bullsquid.cpp b/src/dlls/bullsquid.cpp index 9064814..bbaaf94 100644 --- a/src/dlls/bullsquid.cpp +++ b/src/dlls/bullsquid.cpp @@ -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 ); diff --git a/src/dlls/controller.cpp b/src/dlls/controller.cpp index 60f5fe9..fd424f4 100644 --- a/src/dlls/controller.cpp +++ b/src/dlls/controller.cpp @@ -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 ) ); diff --git a/src/dlls/gargantua.cpp b/src/dlls/gargantua.cpp index 8f79e7b..4e66181 100644 --- a/src/dlls/gargantua.cpp +++ b/src/dlls/gargantua.cpp @@ -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 ); } } } @@ -976,6 +990,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; @@ -1791,6 +1807,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; diff --git a/src/dlls/ggrenade.cpp b/src/dlls/ggrenade.cpp index f0dc470..aa2f3d2 100644 --- a/src/dlls/ggrenade.cpp +++ b/src/dlls/ggrenade.cpp @@ -227,13 +227,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 +279,6 @@ void CMGrenade::BounceTouch( edict_t *pOther ) pev->framerate = 1; else if (pev->framerate < 0.5) pev->framerate = 0; - } diff --git a/src/dlls/gonome.cpp b/src/dlls/gonome.cpp index f534bdd..87a306c 100644 --- a/src/dlls/gonome.cpp +++ b/src/dlls/gonome.cpp @@ -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 ); diff --git a/src/dlls/houndeye.cpp b/src/dlls/houndeye.cpp index cf0ef2b..de64661 100644 --- a/src/dlls/houndeye.cpp +++ b/src/dlls/houndeye.cpp @@ -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 ); } } } diff --git a/src/dlls/islave.cpp b/src/dlls/islave.cpp index 7230429..f3ae9fd 100644 --- a/src/dlls/islave.cpp +++ b/src/dlls/islave.cpp @@ -737,6 +737,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 ) ); diff --git a/src/dlls/pitdrone.cpp b/src/dlls/pitdrone.cpp index 7474803..a1c3955 100644 --- a/src/dlls/pitdrone.cpp +++ b/src/dlls/pitdrone.cpp @@ -97,7 +97,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 diff --git a/src/dlls/shock.cpp b/src/dlls/shock.cpp index a7991d5..fb2bf60 100644 --- a/src/dlls/shock.cpp +++ b/src/dlls/shock.cpp @@ -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); } diff --git a/src/dlls/shockroach.cpp b/src/dlls/shockroach.cpp index 34d074d..b922984 100644 --- a/src/dlls/shockroach.cpp +++ b/src/dlls/shockroach.cpp @@ -131,6 +131,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); diff --git a/src/dlls/squeakgrenade.cpp b/src/dlls/squeakgrenade.cpp index 78d00b4..b9a7fe7 100644 --- a/src/dlls/squeakgrenade.cpp +++ b/src/dlls/squeakgrenade.cpp @@ -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 ); diff --git a/src/dlls/strooper.cpp b/src/dlls/strooper.cpp index 09dc91d..9cc046f 100644 --- a/src/dlls/strooper.cpp +++ b/src/dlls/strooper.cpp @@ -330,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; diff --git a/src/dlls/voltigore.cpp b/src/dlls/voltigore.cpp index 8e030b6..0e93cb7 100644 --- a/src/dlls/voltigore.cpp +++ b/src/dlls/voltigore.cpp @@ -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,7 +391,7 @@ 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; } @@ -1020,6 +1024,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 ); } } } From b757c65345e15b2a177589faf9e3b7e1c19c9653 Mon Sep 17 00:00:00 2001 From: Giegue Date: Thu, 16 Mar 2023 16:06:45 -0300 Subject: [PATCH 16/45] Forgotten header update for windows compilation. --- src/metamod/stdint_c99.h | 299 +++++++++++++++++++-------------------- 1 file changed, 144 insertions(+), 155 deletions(-) diff --git a/src/metamod/stdint_c99.h b/src/metamod/stdint_c99.h index a2907ae..5b1d31e 100644 --- a/src/metamod/stdint_c99.h +++ b/src/metamod/stdint_c99.h @@ -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 -* Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794) -* -* THIS SOFTWARE IS NOT COPYRIGHTED -* -* Contributor: Danny Smith -* -* 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 + * Modified for libusb/MSVC: Pete Batard + * + * 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 -#include - -#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 : + Accoding to Douglas Gwyn : "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 \ No newline at end of file From c813f6e76ae909e07515375d7d138c94213be9d2 Mon Sep 17 00:00:00 2001 From: Giegue Date: Sat, 25 Mar 2023 21:46:22 -0300 Subject: [PATCH 17/45] Fix entvars keyvalues not working. Fix monstermaker classname. --- src/dlls/cmbase.cpp | 6 +----- src/dlls/monstermaker.cpp | 3 ++- src/dlls/monsters.cpp | 5 ----- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/dlls/cmbase.cpp b/src/dlls/cmbase.cpp index e97cc96..5d01f46 100644 --- a/src/dlls/cmbase.cpp +++ b/src/dlls/cmbase.cpp @@ -111,11 +111,7 @@ void CMBaseEntity :: KeyValue( KeyValueData* pkvd ) if ( !pev || !pkvd ) return; - if ( pkvd->fHandled ) - { - // only handled data contain readable strings - EntvarsKeyvalue( pev, pkvd ); - } + EntvarsKeyvalue( pev, pkvd ); } // give health diff --git a/src/dlls/monstermaker.cpp b/src/dlls/monstermaker.cpp index 256dffb..0768114 100644 --- a/src/dlls/monstermaker.cpp +++ b/src/dlls/monstermaker.cpp @@ -109,6 +109,7 @@ void CMMonsterMaker :: Spawn( ) m_fFadeChildren = TRUE; m_flGround = 0; + pev->classname = MAKE_STRING("monstermaker"); } void CMMonsterMaker :: Precache( void ) @@ -169,7 +170,7 @@ void CMMonsterMaker::MakeMonster( void ) 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] NULL Ent in MonsterMaker!\n" ); return; } diff --git a/src/dlls/monsters.cpp b/src/dlls/monsters.cpp index 19d8284..e10ad0e 100644 --- a/src/dlls/monsters.cpp +++ b/src/dlls/monsters.cpp @@ -2626,11 +2626,6 @@ void CMBaseMonster :: KeyValue( KeyValueData *pkvd ) m_iClassifyOverride = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } - else if (FStrEq(pkvd->szKeyName, "model")) - { - pev->model = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } else { CMBaseToggle::KeyValue( pkvd ); From a3086aaaa4c42c01a88e99b97a0a25efdc4889da Mon Sep 17 00:00:00 2001 From: Giegue Date: Sat, 25 Mar 2023 21:48:27 -0300 Subject: [PATCH 18/45] Print number of entities found in BSP file. Add 'ambient_music' entity. --- src/dlls/Makefile | 2 + src/dlls/cmbaseextra.h | 14 ++ src/dlls/dllapi.cpp | 6 +- src/dlls/monster_config.cpp | 63 ++++- src/dlls/music.cpp | 61 +++++ src/dlls/ripent.cpp | 444 ++++++++++++++++++++++++++++++++++++ src/dlls/ripent.h | 97 ++++++++ src/dlls/util.h | 3 + src/dlls/zombie.cpp | 2 +- 9 files changed, 679 insertions(+), 13 deletions(-) create mode 100644 src/dlls/music.cpp create mode 100644 src/dlls/ripent.cpp create mode 100644 src/dlls/ripent.h diff --git a/src/dlls/Makefile b/src/dlls/Makefile index a87d2d4..60d8010 100644 --- a/src/dlls/Makefile +++ b/src/dlls/Makefile @@ -38,9 +38,11 @@ OBJ = \ monstermaker.o \ monsters.o \ monsterstate.o \ + music.o \ nodes.o \ otis.o \ pitdrone.o \ + ripent.o \ rgrunt.o \ scientist.o \ shock.o \ diff --git a/src/dlls/cmbaseextra.h b/src/dlls/cmbaseextra.h index 69ddd8b..ba38d05 100644 --- a/src/dlls/cmbaseextra.h +++ b/src/dlls/cmbaseextra.h @@ -33,4 +33,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 diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index 23678d9..4243c90 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -162,6 +162,7 @@ monster_type_t monster_types[]= "info_node", FALSE, // Nodes "info_node_air", FALSE, "monstermaker", FALSE, // Extra entities + "ambient_music", FALSE, "", FALSE }; @@ -705,6 +706,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) @@ -786,7 +788,7 @@ 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 ); } } } @@ -1416,6 +1418,7 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) // Extra entities CMMonsterMaker monstermaker; // 32 + CMAmbientMusic ambientmusic; g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" ); @@ -1465,6 +1468,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; } } } diff --git a/src/dlls/monster_config.cpp b/src/dlls/monster_config.cpp index 8ea9ba0..c7ca8da 100644 --- a/src/dlls/monster_config.cpp +++ b/src/dlls/monster_config.cpp @@ -13,6 +13,7 @@ #include "meta_api.h" #include "monster_plugin.h" +#include "ripent.h" extern cvar_t *dllapi_log; @@ -126,6 +127,21 @@ void scan_monster_cfg(FILE *fp) monster = TRUE; } } + else if (strcmp(monster_types[mIndex].name, "ambient_music") == 0) + { + // TODO - Extra entities should go towards a separate counter like nodes + if (monster_spawn_count == MAX_MONSTERS) + { + LOG_MESSAGE(PLID, "ERROR: can't add ambient_music, reached MAX_MONSTERS!"); + badent = TRUE; + } + else + { + monster_spawnpoint[monster_spawn_count].monster = mIndex; + monster_types[mIndex].need_to_precache = TRUE; + monster = TRUE; + } + } else if (strcmp(monster_types[mIndex].name, "info_node") == 0) { // Normal node @@ -260,7 +276,7 @@ void scan_monster_cfg(FILE *fp) { if (monster) { - // only applicable for monstermaket entity + // only applicable for monstermaker entity if (strcmp(data[kvd_index-1].value, "monstermaker") == 0) { // precache the custom model @@ -296,6 +312,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. @@ -374,36 +406,45 @@ void scan_monster_cfg(FILE *fp) bool process_monster_cfg(void) { char game_dir[256]; - char filename[256]; + char BSPfilename[256]; + char CFGfilename[256]; 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); + strcpy(CFGfilename, game_dir); #ifdef __linux__ - strcat(filename, "/maps/"); + strcat(CFGfilename, "/maps/"); #else - strcat(filename, "\\maps\\"); + strcat(CFGfilename, "\\maps\\"); #endif - strcat(filename, STRING(gpGlobals->mapname)); - strcat(filename, "_monster.cfg"); + strcat(CFGfilename, STRING(gpGlobals->mapname)); + strcpy(BSPfilename, CFGfilename); + + strcat(BSPfilename, ".bsp"); + strcat(CFGfilename, "_monster.cfg"); + + LoadBSPFile(BSPfilename); + ParseEntities(); + LOG_MESSAGE(PLID, "It works! LoadBSPFile: Parsed '%i' entities", num_entities); // check if the map specific filename exists... - if (access(filename, 0) == 0) + if (access(CFGfilename, 0) == 0) { if (dllapi_log->value) { //META_CONS("[MONSTER] Processing config file=%s", filename); - LOG_MESSAGE(PLID, "Processing config file=%s", filename); + LOG_MESSAGE(PLID, "Processing config file '%s'", CFGfilename); } - if ((fp = fopen(filename, "r")) == NULL) + if ((fp = fopen(CFGfilename, "r")) == NULL) { //META_CONS("[MONSTER] ERROR: Could not open \"%s\"!", filename); - LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\" file!", filename); + LOG_MESSAGE(PLID, "ERROR: Could not open \"%s\" file!", CFGfilename); return TRUE; // error } diff --git a/src/dlls/music.cpp b/src/dlls/music.cpp new file mode 100644 index 0000000..217fb9d --- /dev/null +++ b/src/dlls/music.cpp @@ -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_ALL, SVC_STUFFTEXT); + else + MESSAGE_BEGIN(MSG_ONE, SVC_STUFFTEXT, NULL, pActivator); + + // 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(); +} diff --git a/src/dlls/ripent.cpp b/src/dlls/ripent.cpp new file mode 100644 index 0000000..583075e --- /dev/null +++ b/src/dlls/ripent.cpp @@ -0,0 +1,444 @@ +/*** +* +* 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 +#endif + +//============================================================================= + +int entdatasize; +char dentdata[MAX_MAP_ENTSTRING]; +int dentdata_checksum; + +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; + + // + // 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 too long [strlen(token) >= MAX_KEY - 1]"); + return NULL; + } + e->key = copystring(token); + GetToken(false); + if (strlen(token) >= MAX_VALUE - 1) + { + LOG_MESSAGE(PLID, "ParseEpar: token too long [strlen(token) >= MAX_VALUE - 1]"); + 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\n", 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\n", 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\n", 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]) + LOG_MESSAGE(PLID, "Token too large on line %i\n", scriptline); + } + 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]) + LOG_MESSAGE(PLID, "Token too large on line %i\n", scriptline); + } + + *token_p = 0; + + if (!strcmp(token, "$include")) + { + GetToken(false); + AddScriptToStack(token); + return GetToken(crossline); + } + + return true; +} + diff --git a/src/dlls/ripent.h b/src/dlls/ripent.h new file mode 100644 index 0000000..83d7a46 --- /dev/null +++ b/src/dlls/ripent.h @@ -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 + +#define MAX_MAP_ENTITIES 1024 +#define MAX_MAP_ENTSTRING (128*1024) + +// 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 512 + +extern char token[MAXTOKEN]; +bool GetToken(bool crossline); +void ParseFromMemory(char *buffer, int size); diff --git a/src/dlls/util.h b/src/dlls/util.h index 23506f5..6b52571 100644 --- a/src/dlls/util.h +++ b/src/dlls/util.h @@ -400,6 +400,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 diff --git a/src/dlls/zombie.cpp b/src/dlls/zombie.cpp index 32b48cc..29c5910 100644 --- a/src/dlls/zombie.cpp +++ b/src/dlls/zombie.cpp @@ -245,7 +245,7 @@ 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 ); From 074635bf8d6646f5aa4d98f732a25050487ca4e6 Mon Sep 17 00:00:00 2001 From: Giegue Date: Sat, 25 Mar 2023 21:52:57 -0300 Subject: [PATCH 19/45] Derp. Fixed an inverted check. --- src/dlls/music.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dlls/music.cpp b/src/dlls/music.cpp index 217fb9d..6677af6 100644 --- a/src/dlls/music.cpp +++ b/src/dlls/music.cpp @@ -34,9 +34,9 @@ void CMAmbientMusic::MusicUse(edict_t *pActivator, edict_t *pCaller, USE_TYPE us return; if (pev->spawnflags & SF_MUSIC_ACTIVATOR_ONLY) - MESSAGE_BEGIN(MSG_ALL, SVC_STUFFTEXT); - else 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) From 79d4b3b21d56a9330d013075a6a091d491b6f987 Mon Sep 17 00:00:00 2001 From: Giegue Date: Wed, 29 Mar 2023 02:48:18 -0300 Subject: [PATCH 20/45] 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. --- README.md | 3 +- src/dlls/dllapi.cpp | 5 +- src/dlls/monster_api.cpp | 5 + src/dlls/monster_config.cpp | 366 ++++++++++++++++++++++++++++++++++-- src/dlls/ripent.cpp | 11 +- 5 files changed, 363 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 69afc20..d76ba1c 100644 --- a/README.md +++ b/README.md @@ -165,8 +165,6 @@ There are probably more issues that aren't listed here, I'll attempt to fix them 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 @@ -206,6 +204,7 @@ Current milestones are separated by "Tiers", which are as follows: - Add configurations to change AI behaviour. - Optimize code and enhance the AI. - Create "tool" entities for easier map customization. +- Do more fixes not covered in Tier 4. What will the future hold after all Tiers has been completed? diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index 4243c90..9c3d251 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -724,6 +724,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) { @@ -738,8 +741,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! diff --git a/src/dlls/monster_api.cpp b/src/dlls/monster_api.cpp index 7f5361f..86d8b9d 100644 --- a/src/dlls/monster_api.cpp +++ b/src/dlls/monster_api.cpp @@ -89,6 +89,8 @@ 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; // Metamod requesting info about this plugin: @@ -151,6 +153,9 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m 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"); + return(TRUE); } diff --git a/src/dlls/monster_config.cpp b/src/dlls/monster_config.cpp index c7ca8da..71cbd2a 100644 --- a/src/dlls/monster_config.cpp +++ b/src/dlls/monster_config.cpp @@ -16,6 +16,7 @@ #include "ripent.h" extern cvar_t *dllapi_log; +extern cvar_t *monster_entity_config; extern monster_type_t monster_types[]; extern int monster_spawn_count; @@ -403,6 +404,314 @@ 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; + int duplicate_ent; + 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; + duplicate_ent = 0; + use_monstermod = true; + + classname_kvdI = 0; + badent = monster = node = false; + + // examine all keys + while (kv_pair != NULL) + { + 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 + // + // if it is valid, this entity already exists and we should ignore it + edict_t *existsGAME = CREATE_NAMED_ENTITY( MAKE_STRING( kv_pair->value ) ); + if ( !FNullEnt( existsGAME ) ) + { + for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++) + { + if (strcmp(kv_pair->value, monster_types[mIndex].name) == 0) + { + // the entity exists BOTH in the game and monstermod! + // keep track of it + duplicate_ent = ent; + break; + } + } + UTIL_Remove( existsGAME ); // get rid of the temporary entity + use_monstermod = false; // use game entity + } + } + else if (duplicate_ent && strcmp(kv_pair->key, "use_monstermod") == 0) + { + if (atoi(kv_pair->value) == 1) + { + // EXPLICITY requested to use the monstermod entity + use_monstermod = true; + } + } + + 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) + { + // 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 + { + 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) + { + // precache the custom model here + PRECACHE_MODEL( data[i].value ); + + // the entity will need the keyvalue + strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key); + strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value); + } + } + } + else if (strcmp(data[i].key, "new_model") == 0) + { + if (monster) + { + // only applicable for monstermaker entity + if (strcmp(data[classname_kvdI].value, "monstermaker") == 0) + { + // precache the custom model + PRECACHE_MODEL( data[i].value ); + + // the entity will need the keyvalue as well + strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].key, data[i].key); + strcpy(monster_spawnpoint[monster_spawn_count].keyvalue[i].value, data[i].value); + } + } + } + else if (strcmp(data[i].key, "monstertype") == 0) + { + if (monster) + { + // this keyvalue is only valid for monstermaker entity + if (strcmp(data[classname_kvdI].value, "monstermaker") == 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); + } + } + } + } +} + bool process_monster_cfg(void) { char game_dir[256]; @@ -427,32 +736,49 @@ bool process_monster_cfg(void) strcat(BSPfilename, ".bsp"); strcat(CFGfilename, "_monster.cfg"); - - LoadBSPFile(BSPfilename); - ParseEntities(); - LOG_MESSAGE(PLID, "It works! LoadBSPFile: Parsed '%i' entities", num_entities); - - // check if the map specific filename exists... - if (access(CFGfilename, 0) == 0) + + // 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'", CFGfilename); + LoadBSPFile(BSPfilename); + ParseEntities(); + + scan_monster_bsp(); } - - if ((fp = fopen(CFGfilename, "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!", CFGfilename); - 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); + } } - - scan_monster_cfg(fp); - - fclose(fp); } - + return FALSE; // all ok } diff --git a/src/dlls/ripent.cpp b/src/dlls/ripent.cpp index 583075e..09988e9 100644 --- a/src/dlls/ripent.cpp +++ b/src/dlls/ripent.cpp @@ -23,7 +23,6 @@ int entdatasize; char dentdata[MAX_MAP_ENTSTRING]; -int dentdata_checksum; int num_entities; entity_t entities[MAX_MAP_ENTITIES]; @@ -57,8 +56,14 @@ LoadBSPFile */ void LoadBSPFile(char *filename) { - int i; - + //int i; + + // reset these values + entdatasize = 0; + num_entities = 0; + memset(dentdata, 0, sizeof(dentdata)); + memset(entities, 0, sizeof(entities)); + // // load the file header // From acc22bc9ef4d92184389115661ac0d35b9fd4dda Mon Sep 17 00:00:00 2001 From: Giegue Date: Wed, 29 Mar 2023 12:54:54 -0300 Subject: [PATCH 21/45] Fix BSP reader crashing the server. --- src/dlls/monster_config.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/dlls/monster_config.cpp b/src/dlls/monster_config.cpp index 71cbd2a..7b1c757 100644 --- a/src/dlls/monster_config.cpp +++ b/src/dlls/monster_config.cpp @@ -452,7 +452,13 @@ void scan_monster_bsp(void) break; } } - UTIL_Remove( existsGAME ); // get rid of the temporary entity + + // 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; // use game entity } } From 18268776ae00b054bfa9f027d8f7c40790196fad Mon Sep 17 00:00:00 2001 From: Giegue Date: Wed, 29 Mar 2023 12:57:37 -0300 Subject: [PATCH 22/45] This objetive is complete. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d76ba1c..059f607 100644 --- a/README.md +++ b/README.md @@ -194,7 +194,7 @@ Current milestones are separated by "Tiers", which are as follows: ### Tier 4 -- Implement reading entities within the BSP itself. +- Implement reading entities within the BSP itself. **[DONE]** - Add build instructions. **[DONE]** - Custom sound support, along with sentences. - Fix all pending bugs. From 28c18952f84775a2542dddabe76099846e25c88d Mon Sep 17 00:00:00 2001 From: Giegue Date: Sat, 1 Apr 2023 03:03:17 -0300 Subject: [PATCH 23/45] Fix BSP reader breaking when there are too many entities. --- src/dlls/ripent.cpp | 14 +++++++------- src/dlls/ripent.h | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/dlls/ripent.cpp b/src/dlls/ripent.cpp index 09988e9..f15f9a6 100644 --- a/src/dlls/ripent.cpp +++ b/src/dlls/ripent.cpp @@ -104,14 +104,14 @@ epair_t *ParseEpair(void) if (strlen(token) >= MAX_KEY - 1) { - LOG_MESSAGE(PLID, "ParseEpar: token too long [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 too long [strlen(token) >= MAX_VALUE - 1]"); + LOG_MESSAGE(PLID, "ParseEpar: token value too long"); return NULL; } e->value = copystring(token); @@ -315,7 +315,7 @@ bool EndOfScript(bool crossline) { if (!crossline) { - LOG_MESSAGE(PLID, "Line %i is incomplete\n", scriptline); + LOG_MESSAGE(PLID, "Line %i is incomplete", scriptline); return false; } @@ -382,7 +382,7 @@ skipspace: { if (!crossline) { - LOG_MESSAGE(PLID, "Line %i is incomplete\n", scriptline); + LOG_MESSAGE(PLID, "Line %i is incomplete", scriptline); return false; } scriptline = script->line++; @@ -397,7 +397,7 @@ skipspace: { if (!crossline) { - LOG_MESSAGE(PLID, "Line %i is incomplete\n", scriptline); + LOG_MESSAGE(PLID, "Line %i is incomplete", scriptline); return false; } while (*script->script_p++ != '\n') @@ -421,7 +421,7 @@ skipspace: if (script->script_p == script->end_p) break; if (token_p == &token[MAXTOKEN]) - LOG_MESSAGE(PLID, "Token too large on line %i\n", scriptline); + LOG_MESSAGE(PLID, "Token too large on line %i", scriptline); } script->script_p++; } @@ -432,7 +432,7 @@ skipspace: if (script->script_p == script->end_p) break; if (token_p == &token[MAXTOKEN]) - LOG_MESSAGE(PLID, "Token too large on line %i\n", scriptline); + LOG_MESSAGE(PLID, "Token too large on line %i", scriptline); } *token_p = 0; diff --git a/src/dlls/ripent.h b/src/dlls/ripent.h index 83d7a46..f3baa75 100644 --- a/src/dlls/ripent.h +++ b/src/dlls/ripent.h @@ -14,9 +14,9 @@ #include "extdll.h" // upper design bounds - -#define MAX_MAP_ENTITIES 1024 -#define MAX_MAP_ENTSTRING (128*1024) +// 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 From 62c17b14e43712b41d5bcd635568a221022e6160 Mon Sep 17 00:00:00 2001 From: Giegue Date: Sat, 1 Apr 2023 23:57:11 -0300 Subject: [PATCH 24/45] Even more BSP reader fixes. Also fix project file not including all files. --- src/dlls/.gitignore | 6 +++++- src/dlls/monster_config.cpp | 8 ++++++++ src/dlls/monster_mm.vcxproj.filters | 9 +++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/dlls/.gitignore b/src/dlls/.gitignore index b42cbff..b17895e 100644 --- a/src/dlls/.gitignore +++ b/src/dlls/.gitignore @@ -1,5 +1,9 @@ +Release/ +Debug/ msgs/ opt.*/ debug.*/ *.o -*.so \ No newline at end of file +*.so +*.suo +*.sdf \ No newline at end of file diff --git a/src/dlls/monster_config.cpp b/src/dlls/monster_config.cpp index 7b1c757..2e520e1 100644 --- a/src/dlls/monster_config.cpp +++ b/src/dlls/monster_config.cpp @@ -433,6 +433,14 @@ void scan_monster_bsp(void) // 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; + break; + } + if (strcmp(kv_pair->key, "classname") == 0) { // the entity we are trying to spawn could already exist within the game diff --git a/src/dlls/monster_mm.vcxproj.filters b/src/dlls/monster_mm.vcxproj.filters index 7d2721f..cc7fa73 100644 --- a/src/dlls/monster_mm.vcxproj.filters +++ b/src/dlls/monster_mm.vcxproj.filters @@ -177,6 +177,12 @@ Source Files + + Source Files + + + Source Files + @@ -266,5 +272,8 @@ Header Files + + Header Files + \ No newline at end of file From fb92c2369f9201c39897579248b08c79f7741bcb Mon Sep 17 00:00:00 2001 From: Giegue Date: Mon, 3 Apr 2023 12:51:01 -0300 Subject: [PATCH 25/45] Remove unsupported door info in AI navigation. Fix keyvalue length being too small. --- src/dlls/monster_plugin.h | 2 +- src/dlls/nodes.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/dlls/monster_plugin.h b/src/dlls/monster_plugin.h index 0162f02..08d4450 100644 --- a/src/dlls/monster_plugin.h +++ b/src/dlls/monster_plugin.h @@ -8,7 +8,7 @@ typedef struct { char key[33]; - char value[33]; + char value[481]; } pKVD; #define MAX_KEYVALUES 32 diff --git a/src/dlls/nodes.cpp b/src/dlls/nodes.cpp index a4d7eb0..727750e 100644 --- a/src/dlls/nodes.cpp +++ b/src/dlls/nodes.cpp @@ -232,7 +232,9 @@ int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, N // func_door if ( FClassnameIs( pevLinkEnt, "func_door" ) || FClassnameIs( pevLinkEnt, "func_door_rotating" ) ) {// ent is a door. - + // Can't retrieve door info right now, assume it's a hard wall and don't let the monster go through + return FALSE; + /* pDoor = ( CMBaseEntity::Instance( pevLinkEnt ) ); if ( ( pevLinkEnt->spawnflags & SF_DOOR_USE_ONLY ) ) @@ -269,6 +271,7 @@ int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, N return FALSE; } + */ } // func_breakable else if ( FClassnameIs( pevLinkEnt, "func_breakable" ) && queryType == NODEGRAPH_STATIC ) From 66be4861a3d697ceaff43cab5fa4c64578c83fef Mon Sep 17 00:00:00 2001 From: Giegue Date: Sat, 15 Apr 2023 19:23:20 -0300 Subject: [PATCH 26/45] 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. --- src/dlls/cmbasemonster.h | 5 ++ src/dlls/combat.cpp | 2 +- src/dlls/dllapi.cpp | 2 +- src/dlls/gonome.cpp | 10 --- src/dlls/massn.cpp | 122 ++++++++++++++++++++++++++++++++++++ src/dlls/monster_config.cpp | 26 +++----- src/dlls/monsters.cpp | 2 +- src/dlls/zombie.cpp | 10 --- src/metamod/comp_dep.h | 13 ++-- 9 files changed, 146 insertions(+), 46 deletions(-) diff --git a/src/dlls/cmbasemonster.h b/src/dlls/cmbasemonster.h index 26439b1..270c13e 100644 --- a/src/dlls/cmbasemonster.h +++ b/src/dlls/cmbasemonster.h @@ -1333,6 +1333,11 @@ public: void DeathSound(void); void PainSound(void); void IdleSound(void); + + void SetActivity(Activity NewActivity); + Schedule_t *GetScheduleOfType( int Type ); + + CUSTOM_SCHEDULES; }; //========================================================= diff --git a/src/dlls/combat.cpp b/src/dlls/combat.cpp index 0c6080e..ecb3e57 100644 --- a/src/dlls/combat.cpp +++ b/src/dlls/combat.cpp @@ -831,7 +831,7 @@ int CMBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker { float flTake; Vector vecDir; - + if (!pev->takedamage) return 0; diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index 9c3d251..fbf0fea 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -306,7 +306,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) ); } diff --git a/src/dlls/gonome.cpp b/src/dlls/gonome.cpp index 87a306c..2a4b2be 100644 --- a/src/dlls/gonome.cpp +++ b/src/dlls/gonome.cpp @@ -351,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(); diff --git a/src/dlls/massn.cpp b/src/dlls/massn.cpp index 1cc2b81..14e6d1d 100644 --- a/src/dlls/massn.cpp +++ b/src/dlls/massn.cpp @@ -61,6 +61,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. @@ -176,6 +178,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(); @@ -193,6 +200,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; @@ -307,3 +316,116 @@ void CMMassn::Precache() m_iBrassShell = PRECACHE_MODEL("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, CMBaseMonster ); + +//========================================================= +// 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 ); + } + } +} diff --git a/src/dlls/monster_config.cpp b/src/dlls/monster_config.cpp index 2e520e1..c4e77b1 100644 --- a/src/dlls/monster_config.cpp +++ b/src/dlls/monster_config.cpp @@ -411,7 +411,7 @@ void scan_monster_bsp(void) pKVD data[MAX_KEYVALUES]; int kvd_index; - int duplicate_ent; + bool use_monstermod_explicit; bool use_monstermod; int classname_kvdI, mIndex; @@ -424,7 +424,7 @@ void scan_monster_bsp(void) kv_pair = entities[ent].epairs; kvd_index = 0; - duplicate_ent = 0; + use_monstermod_explicit = false; use_monstermod = true; classname_kvdI = 0; @@ -438,6 +438,7 @@ void scan_monster_bsp(void) { LOG_MESSAGE(PLID, "WARNING: can't process entity #%i - too many keyvalues", ent); use_monstermod = false; + use_monstermod_explicit = false; break; } @@ -450,32 +451,21 @@ void scan_monster_bsp(void) edict_t *existsGAME = CREATE_NAMED_ENTITY( MAKE_STRING( kv_pair->value ) ); if ( !FNullEnt( existsGAME ) ) { - for (mIndex = 0; monster_types[mIndex].name[0]; mIndex++) - { - if (strcmp(kv_pair->value, monster_types[mIndex].name) == 0) - { - // the entity exists BOTH in the game and monstermod! - // keep track of it - duplicate_ent = ent; - break; - } - } - // 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; // use game entity + use_monstermod = false; // stick with game entity } } - else if (duplicate_ent && strcmp(kv_pair->key, "use_monstermod") == 0) + else if (strcmp(kv_pair->key, "use_monstermod") == 0) { if (atoi(kv_pair->value) == 1) { - // EXPLICITY requested to use the monstermod entity - use_monstermod = true; + // EXPLICITY requested to use monstermod for this entity + use_monstermod_explicit = true; } } @@ -487,7 +477,7 @@ void scan_monster_bsp(void) } // spawn a monstermod entity? - if (use_monstermod) + if (use_monstermod_explicit || use_monstermod) { // find classname keyvalue for (int i = 0; i < kvd_index; i++) diff --git a/src/dlls/monsters.cpp b/src/dlls/monsters.cpp index e10ad0e..18a181e 100644 --- a/src/dlls/monsters.cpp +++ b/src/dlls/monsters.cpp @@ -1554,7 +1554,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 ); } diff --git a/src/dlls/zombie.cpp b/src/dlls/zombie.cpp index 29c5910..6c1ca64 100644 --- a/src/dlls/zombie.cpp +++ b/src/dlls/zombie.cpp @@ -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(); diff --git a/src/metamod/comp_dep.h b/src/metamod/comp_dep.h index 3d49de0..8f4cbd5 100644 --- a/src/metamod/comp_dep.h +++ b/src/metamod/comp_dep.h @@ -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 From bfa59a24195bc975c4120841774e7bdd5a5c5f30 Mon Sep 17 00:00:00 2001 From: Giegue Date: Fri, 21 Apr 2023 20:55:47 -0300 Subject: [PATCH 27/45] 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. --- README.md | 18 ++-- src/dlls/agrunt.cpp | 49 ++++------- src/dlls/animation.cpp | 2 +- src/dlls/apache.cpp | 12 +-- src/dlls/bigmomma.cpp | 4 +- src/dlls/bullsquid.cpp | 2 +- src/dlls/cmbase.h | 4 + src/dlls/dllapi.cpp | 31 ++++--- src/dlls/effects.cpp | 2 +- src/dlls/enginecallback.h | 6 +- src/dlls/explode.cpp | 4 +- src/dlls/gargantua.cpp | 102 ++++++---------------- src/dlls/globalreplace.cpp | 121 ++++++++++++++++++++++++++ src/dlls/globalreplace.h | 19 +++++ src/dlls/hassassin.cpp | 2 +- src/dlls/hgrunt.cpp | 4 +- src/dlls/hornet.cpp | 4 +- src/dlls/houndeye.cpp | 2 +- src/dlls/islave.cpp | 17 +--- src/dlls/massn.cpp | 2 +- src/dlls/monster_api.cpp | 11 ++- src/dlls/monster_config.cpp | 164 ++++++++++++++++++++++++++++++++++-- src/dlls/pitdrone.cpp | 4 +- src/dlls/rgrunt.cpp | 4 +- src/dlls/sound.cpp | 7 +- src/dlls/sporegrenade.cpp | 6 +- src/dlls/strooper.cpp | 4 +- src/dlls/stukabat.cpp | 4 +- src/dlls/util.cpp | 2 +- src/dlls/util.h | 20 +++-- src/dlls/voltigore.cpp | 2 +- src/dlls/zombie.cpp | 25 ++---- 32 files changed, 448 insertions(+), 212 deletions(-) create mode 100644 src/dlls/globalreplace.cpp create mode 100644 src/dlls/globalreplace.h diff --git a/README.md b/README.md index 059f607..27602d2 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ 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. @@ -45,6 +45,8 @@ The plugin -should- be able to be used out-of-the-box by simply downloading the Additional configuration files are included in the release files, each explaining it's usage and installation instructions. +Extra MonsterMod features can be unlocked with additional AMX Mod X plugins which are located in the `extra` folder. All these plugins are optional, and only required based on your use-case. + ## Build Instructions The [wiki](https://github.com/JulianR0/monstermod-redo/wiki) contains instructions on how to compile MonsterMod by yourself. @@ -196,15 +198,21 @@ Current milestones are separated by "Tiers", which are as follows: - Implement reading entities within the BSP itself. **[DONE]** - Add build instructions. **[DONE]** -- Custom sound support, along with sentences. -- Fix all pending bugs. +- Global Model Replacement. **[DONE]** +- Global Sound Replacement. **[DONE]** +- Miscellaneous customization options, such as blood color. +- Individual sound replacement: "soundlist" keyvalue for monsters. +- Sentences support for speakable monsters. +- Attempt to fix bugs as they appear. ### Tier 5 +- Enhance the AI. - Add configurations to change AI behaviour. -- Optimize code and enhance the AI. - Create "tool" entities for easier map customization. -- Do more fixes not covered in Tier 4. +- 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? diff --git a/src/dlls/agrunt.cpp b/src/dlls/agrunt.cpp index f41d5c2..b27cc3f 100644 --- a/src/dlls/agrunt.cpp +++ b/src/dlls/agrunt.cpp @@ -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" //========================================================= @@ -532,7 +532,7 @@ 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; @@ -563,40 +563,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 +1013,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 ); } diff --git a/src/dlls/animation.cpp b/src/dlls/animation.cpp index 56d8d4d..c945636 100644 --- a/src/dlls/animation.cpp +++ b/src/dlls/animation.cpp @@ -213,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) ) ); } } } diff --git a/src/dlls/apache.cpp b/src/dlls/apache.cpp index a5f68ea..ec3b748 100644 --- a/src/dlls/apache.cpp +++ b/src/dlls/apache.cpp @@ -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(); @@ -178,7 +178,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 +193,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 ); @@ -930,7 +930,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"); } diff --git a/src/dlls/bigmomma.cpp b/src/dlls/bigmomma.cpp index f2f9f65..3604f54 100644 --- a/src/dlls/bigmomma.cpp +++ b/src/dlls/bigmomma.cpp @@ -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" ); diff --git a/src/dlls/bullsquid.cpp b/src/dlls/bullsquid.cpp index bbaaf94..dc0855d 100644 --- a/src/dlls/bullsquid.cpp +++ b/src/dlls/bullsquid.cpp @@ -642,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 diff --git a/src/dlls/cmbase.h b/src/dlls/cmbase.h index 824ae1c..b0d16eb 100644 --- a/src/dlls/cmbase.h +++ b/src/dlls/cmbase.h @@ -608,3 +608,7 @@ template T * CreateClassPtr( T *a ) return a; } + +#ifndef GLOBALREPLACE_H +#include "globalreplace.h" +#endif diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index fbf0fea..410db05 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -809,18 +809,18 @@ DLL_GLOBAL short g_sModelIndexLaserDot;// holds the index for the laser beam dot 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) @@ -1265,7 +1265,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; @@ -1276,6 +1278,9 @@ int mmDispatchSpawn( edict_t *pent ) process_monster_cfg(); + // precache last in the event of a GMR being present + world_precache(); + // node support. -Giegue // init the WorldGraph. WorldGraph.InitGraph(); @@ -1818,7 +1823,7 @@ void mmMessageEnd_Post( void ) RETURN_META( MRES_IGNORED ); } - +/* enginefuncs_t meta_engfuncs = { NULL, // pfnPrecacheModel() @@ -2042,7 +2047,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() diff --git a/src/dlls/effects.cpp b/src/dlls/effects.cpp index 13583a6..6d34f9b 100644 --- a/src/dlls/effects.cpp +++ b/src/dlls/effects.cpp @@ -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; diff --git a/src/dlls/enginecallback.h b/src/dlls/enginecallback.h index 19eb34b..cc59819 100644 --- a/src/dlls/enginecallback.h +++ b/src/dlls/enginecallback.h @@ -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) diff --git a/src/dlls/explode.cpp b/src/dlls/explode.cpp index 1b10789..3160e02 100644 --- a/src/dlls/explode.cpp +++ b/src/dlls/explode.cpp @@ -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 ) diff --git a/src/dlls/gargantua.cpp b/src/dlls/gargantua.cpp index 4e66181..644be51 100644 --- a/src/dlls/gargantua.cpp +++ b/src/dlls/gargantua.cpp @@ -712,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); } @@ -1379,51 +1356,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 ) diff --git a/src/dlls/globalreplace.cpp b/src/dlls/globalreplace.cpp new file mode 100644 index 0000000..28d02ac --- /dev/null +++ b/src/dlls/globalreplace.cpp @@ -0,0 +1,121 @@ +//========================================================= +// 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 +{ +typedef struct +{ + char source[128]; + char destination[128]; +} 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; +} + +const char* FindModelReplacement( edict_t *pMonster, const char *from ) +{ + // Individually set models takes priority! + if ( 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 ( pMonster ) + { + CMBaseMonster *castMonster = GetClassPtr((CMBaseMonster *)VARS(pMonster)); + //placeholder for soundlist keyvalue; + } + + for (int sound = 0; sound < numSounds; sound++) + { + if (strcmp(GSR[sound].source, from) == 0) + { + // If found, use that model instead + return GSR[sound].destination; + } + } + + // Nothing found, stick with default + return from; +} +} \ No newline at end of file diff --git a/src/dlls/globalreplace.h b/src/dlls/globalreplace.h new file mode 100644 index 0000000..3be64d9 --- /dev/null +++ b/src/dlls/globalreplace.h @@ -0,0 +1,19 @@ +#ifndef GLOBALREPLACE_H +#define GLOBALREPLACE_H + +#define MAX_REPLACEMENTS 255 + +namespace REPLACER +{ +void Init(void); +bool AddGlobalModel(const char *from, const char *to); +bool AddGlobalSound(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 \ No newline at end of file diff --git a/src/dlls/hassassin.cpp b/src/dlls/hassassin.cpp index 3546a6c..e58c90b 100644 --- a/src/dlls/hassassin.cpp +++ b/src/dlls/hassassin.cpp @@ -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 } diff --git a/src/dlls/hgrunt.cpp b/src/dlls/hgrunt.cpp index 6f6bcfa..e1ce35b 100644 --- a/src/dlls/hgrunt.cpp +++ b/src/dlls/hgrunt.cpp @@ -937,8 +937,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"); } //========================================================= diff --git a/src/dlls/hornet.cpp b/src/dlls/hornet.cpp index e4966e7..3649f01 100644 --- a/src/dlls/hornet.cpp +++ b/src/dlls/hornet.cpp @@ -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"); } //========================================================= diff --git a/src/dlls/houndeye.cpp b/src/dlls/houndeye.cpp index de64661..98c51c9 100644 --- a/src/dlls/houndeye.cpp +++ b/src/dlls/houndeye.cpp @@ -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" ); } //========================================================= diff --git a/src/dlls/islave.cpp b/src/dlls/islave.cpp index f3ae9fd..c8a64a7 100644 --- a/src/dlls/islave.cpp +++ b/src/dlls/islave.cpp @@ -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); } diff --git a/src/dlls/massn.cpp b/src/dlls/massn.cpp index 14e6d1d..685cdb0 100644 --- a/src/dlls/massn.cpp +++ b/src/dlls/massn.cpp @@ -314,7 +314,7 @@ 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 } //========================================================= diff --git a/src/dlls/monster_api.cpp b/src/dlls/monster_api.cpp index 86d8b9d..f81c378 100644 --- a/src/dlls/monster_api.cpp +++ b/src/dlls/monster_api.cpp @@ -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 }; @@ -91,6 +91,10 @@ cvar_t init_monster_turn_coeficient = {"monster_turn_coeficient", "1.75", FCVAR_ 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; // Metamod requesting info about this plugin: @@ -156,6 +160,11 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m 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"); + return(TRUE); } diff --git a/src/dlls/monster_config.cpp b/src/dlls/monster_config.cpp index c4e77b1..a5468bc 100644 --- a/src/dlls/monster_config.cpp +++ b/src/dlls/monster_config.cpp @@ -14,10 +14,14 @@ #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; extern int node_spawn_count; @@ -716,11 +720,107 @@ void scan_monster_bsp(void) } } +void scan_extra_cfg(FILE *fp) +{ + char input[1024]; + + while (get_input(fp, input)) + { + char *cmd = strtok(input, " "); + char *value = strtok(NULL, " "); + + // 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); + } + else 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)) + { + char *source = strtok(input, " "); + char *destination = strtok(NULL, " "); + + // 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 BSPfilename[256]; - char CFGfilename[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; @@ -729,18 +829,17 @@ bool process_monster_cfg(void) // find the directory name of the currently running MOD... (*g_engfuncs.pfnGetGameDir)(game_dir); + // build route... strcpy(CFGfilename, game_dir); -#ifdef __linux__ strcat(CFGfilename, "/maps/"); -#else - strcat(CFGfilename, "\\maps\\"); -#endif strcat(CFGfilename, STRING(gpGlobals->mapname)); strcpy(BSPfilename, CFGfilename); - + strcpy(EXTfilename, CFGfilename); + 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 @@ -783,6 +882,55 @@ bool process_monster_cfg(void) } } + /* The code is only getting worse from here, I have to finish T4 quickly + * so I can move into making actual clean and optimized code for the final tier... + * -Giegue */ + + // extra map configs + if (access(EXTfilename, 0) == 0) + { + // first read configs + if ((fp = fopen(EXTfilename, "r")) != NULL) + { + scan_extra_cfg(fp); + fclose(fp); + } + + // then process them here + if (strlen(globalmodellist->string)) + { + char gmrPath[192]; + + // SC globalmodellist path starts from models/MAPNAME + sprintf(gmrPath, "%s/models/%s/%s", game_dir, STRING(gpGlobals->mapname), globalmodellist->string); + + if (access(gmrPath, 0) == 0) + { + if ((fp = fopen(gmrPath, "r")) != NULL) + { + scan_monster_replace(fp, false); + fclose(fp); + } + } + } + if (strlen(globalsoundlist->string)) + { + char gsrPath[192]; + + // SC globalsoundlist path starts from sound/MAPNAME + sprintf(gsrPath, "%s/sound/%s/%s", game_dir, STRING(gpGlobals->mapname), globalsoundlist->string); + + if (access(gsrPath, 0) == 0) + { + if ((fp = fopen(gsrPath, "r")) != NULL) + { + scan_monster_replace(fp, true); + fclose(fp); + } + } + } + } + return FALSE; // all ok } diff --git a/src/dlls/pitdrone.cpp b/src/dlls/pitdrone.cpp index a1c3955..1ad3b06 100644 --- a/src/dlls/pitdrone.cpp +++ b/src/dlls/pitdrone.cpp @@ -605,7 +605,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); @@ -642,7 +642,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 } diff --git a/src/dlls/rgrunt.cpp b/src/dlls/rgrunt.cpp index 4fe806d..c38dfe1 100644 --- a/src/dlls/rgrunt.cpp +++ b/src/dlls/rgrunt.cpp @@ -387,7 +387,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"); @@ -419,5 +419,5 @@ void CMRGrunt::Precache() m_voicePitch = 100; */ - m_iBrassShell = PRECACHE_MODEL("models/shell.mdl");// brass shell + m_iBrassShell = PRECACHE_MODELINDEX("models/shell.mdl");// brass shell } diff --git a/src/dlls/sound.cpp b/src/dlls/sound.cpp index ca2eac6..6afa35a 100644 --- a/src/dlls/sound.cpp +++ b/src/dlls/sound.cpp @@ -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 diff --git a/src/dlls/sporegrenade.cpp b/src/dlls/sporegrenade.cpp index e270b26..7d8615b 100644 --- a/src/dlls/sporegrenade.cpp +++ b/src/dlls/sporegrenade.cpp @@ -31,9 +31,9 @@ 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"); } diff --git a/src/dlls/strooper.cpp b/src/dlls/strooper.cpp index 9cc046f..6d1b3ff 100644 --- a/src/dlls/strooper.cpp +++ b/src/dlls/strooper.cpp @@ -443,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"); @@ -480,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 } diff --git a/src/dlls/stukabat.cpp b/src/dlls/stukabat.cpp index 3490097..9fe7228 100644 --- a/src/dlls/stukabat.cpp +++ b/src/dlls/stukabat.cpp @@ -111,7 +111,7 @@ void CMStukabat :: Spawn() 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 } diff --git a/src/dlls/util.cpp b/src/dlls/util.cpp index c1a0d18..1f7f536 100644 --- a/src/dlls/util.cpp +++ b/src/dlls/util.cpp @@ -2141,7 +2141,7 @@ 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. + // Tell AMXX to call TakeDamage for us if it can. 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 ); diff --git a/src/dlls/util.h b/src/dlls/util.h index 6b52571..997588a 100644 --- a/src/dlls/util.h +++ b/src/dlls/util.h @@ -436,6 +436,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 @@ -469,9 +481,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) { @@ -488,7 +498,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) ); @@ -541,4 +551,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 ); \ No newline at end of file diff --git a/src/dlls/voltigore.cpp b/src/dlls/voltigore.cpp index 0e93cb7..4533d2b 100644 --- a/src/dlls/voltigore.cpp +++ b/src/dlls/voltigore.cpp @@ -692,7 +692,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"); diff --git a/src/dlls/zombie.cpp b/src/dlls/zombie.cpp index 6c1ca64..84d587e 100644 --- a/src/dlls/zombie.cpp +++ b/src/dlls/zombie.cpp @@ -263,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); } //========================================================= From 2cf22ab66bbb6f69909f6a7110ade6abb1d4553d Mon Sep 17 00:00:00 2001 From: Giegue Date: Sun, 23 Apr 2023 13:43:10 -0300 Subject: [PATCH 28/45] Fix Makefiles. --- src/dlls/Makefile | 5 +++-- src/dlls/monster_mm.vcxproj | 7 ++++++- src/dlls/monster_mm.vcxproj.filters | 8 +++++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/dlls/Makefile b/src/dlls/Makefile index 60d8010..2c5b3ed 100644 --- a/src/dlls/Makefile +++ b/src/dlls/Makefile @@ -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 \ @@ -42,8 +43,8 @@ OBJ = \ nodes.o \ otis.o \ pitdrone.o \ - ripent.o \ rgrunt.o \ + ripent.o \ scientist.o \ shock.o \ shockroach.o \ diff --git a/src/dlls/monster_mm.vcxproj b/src/dlls/monster_mm.vcxproj index 53658f6..0d74e15 100644 --- a/src/dlls/monster_mm.vcxproj +++ b/src/dlls/monster_mm.vcxproj @@ -148,6 +148,7 @@ + @@ -164,10 +165,12 @@ + + @@ -203,12 +206,14 @@ + + @@ -219,4 +224,4 @@ - \ No newline at end of file + diff --git a/src/dlls/monster_mm.vcxproj.filters b/src/dlls/monster_mm.vcxproj.filters index cc7fa73..399fb51 100644 --- a/src/dlls/monster_mm.vcxproj.filters +++ b/src/dlls/monster_mm.vcxproj.filters @@ -183,6 +183,9 @@ Source Files + + Source Files + @@ -275,5 +278,8 @@ Header Files + + Header Files + - \ No newline at end of file + From 1d8a6768aaf8cb7a4528e5a21791191010878d1c Mon Sep 17 00:00:00 2001 From: Giegue Date: Mon, 24 Apr 2023 01:30:52 -0300 Subject: [PATCH 29/45] Fix monster blood not working. Fix monster hitboxes not working. --- src/dlls/combat.cpp | 19 +++++++++---------- src/dlls/dllapi.cpp | 13 +++++++++---- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/dlls/combat.cpp b/src/dlls/combat.cpp index ecb3e57..b38ebd7 100644 --- a/src/dlls/combat.cpp +++ b/src/dlls/combat.cpp @@ -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 @@ -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 ); diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index 410db05..78eb2e4 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -298,7 +298,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; @@ -795,7 +795,6 @@ void check_respawn(void) } } - 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 @@ -807,6 +806,11 @@ 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_MODELINDEX("sprites/zerogxplode.spr");// fireball @@ -1254,10 +1258,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... From e1e2a48f8921e3b6a94c69f81879c0f64a509a19 Mon Sep 17 00:00:00 2001 From: Giegue Date: Mon, 24 Apr 2023 13:17:49 -0300 Subject: [PATCH 30/45] Fix Alien Grunt's TraceAttack method. Fix extra cfg file crashing the server. Added custom blood color for monsters. --- src/dlls/agrunt.cpp | 11 +++-------- src/dlls/barney.cpp | 2 +- src/dlls/bigmomma.cpp | 2 +- src/dlls/bullsquid.cpp | 2 +- src/dlls/cmbaseextra.h | 1 + src/dlls/controller.cpp | 2 +- src/dlls/gargantua.cpp | 4 ++-- src/dlls/gonome.cpp | 2 +- src/dlls/hassassin.cpp | 2 +- src/dlls/headcrab.cpp | 2 +- src/dlls/hgrunt.cpp | 2 +- src/dlls/houndeye.cpp | 2 +- src/dlls/hwgrunt.cpp | 2 +- src/dlls/islave.cpp | 2 +- src/dlls/massn.cpp | 2 +- src/dlls/monster_config.cpp | 2 ++ src/dlls/monstermaker.cpp | 14 +++++++++++++- src/dlls/monsters.cpp | 17 +++++++++++++++++ src/dlls/otis.cpp | 2 +- src/dlls/pitdrone.cpp | 2 +- src/dlls/scientist.cpp | 2 +- src/dlls/shockroach.cpp | 2 +- src/dlls/strooper.cpp | 2 +- src/dlls/stukabat.cpp | 2 +- src/dlls/util.h | 7 ++++++- src/dlls/voltigore.cpp | 4 ++-- src/dlls/zombie.cpp | 2 +- 27 files changed, 65 insertions(+), 33 deletions(-) diff --git a/src/dlls/agrunt.cpp b/src/dlls/agrunt.cpp index b27cc3f..34de414 100644 --- a/src/dlls/agrunt.cpp +++ b/src/dlls/agrunt.cpp @@ -184,13 +184,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); } //========================================================= @@ -537,7 +532,7 @@ void CMAGrunt :: 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.agruntHealth; m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) diff --git a/src/dlls/barney.cpp b/src/dlls/barney.cpp index c5252f7..b9c56a5 100644 --- a/src/dlls/barney.cpp +++ b/src/dlls/barney.cpp @@ -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; diff --git a/src/dlls/bigmomma.cpp b/src/dlls/bigmomma.cpp index 3604f54..9701eb4 100644 --- a/src/dlls/bigmomma.cpp +++ b/src/dlls/bigmomma.cpp @@ -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 ) diff --git a/src/dlls/bullsquid.cpp b/src/dlls/bullsquid.cpp index dc0855d..625fbb3 100644 --- a/src/dlls/bullsquid.cpp +++ b/src/dlls/bullsquid.cpp @@ -615,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 ) diff --git a/src/dlls/cmbaseextra.h b/src/dlls/cmbaseextra.h index ba38d05..cabde6f 100644 --- a/src/dlls/cmbaseextra.h +++ b/src/dlls/cmbaseextra.h @@ -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. diff --git a/src/dlls/controller.cpp b/src/dlls/controller.cpp index fd424f4..c8e9180 100644 --- a/src/dlls/controller.cpp +++ b/src/dlls/controller.cpp @@ -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 ) diff --git a/src/dlls/gargantua.cpp b/src/dlls/gargantua.cpp index 644be51..a19cfa4 100644 --- a/src/dlls/gargantua.cpp +++ b/src/dlls/gargantua.cpp @@ -683,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 ) @@ -1325,7 +1325,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 ) diff --git a/src/dlls/gonome.cpp b/src/dlls/gonome.cpp index 2a4b2be..f165e9d 100644 --- a/src/dlls/gonome.cpp +++ b/src/dlls/gonome.cpp @@ -613,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 ) diff --git a/src/dlls/hassassin.cpp b/src/dlls/hassassin.cpp index e58c90b..5564354 100644 --- a/src/dlls/hassassin.cpp +++ b/src/dlls/hassassin.cpp @@ -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 ) diff --git a/src/dlls/headcrab.cpp b/src/dlls/headcrab.cpp index 2a23f65..df5b607 100644 --- a/src/dlls/headcrab.cpp +++ b/src/dlls/headcrab.cpp @@ -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. diff --git a/src/dlls/hgrunt.cpp b/src/dlls/hgrunt.cpp index e1ce35b..cd25b19 100644 --- a/src/dlls/hgrunt.cpp +++ b/src/dlls/hgrunt.cpp @@ -832,7 +832,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 ) diff --git a/src/dlls/houndeye.cpp b/src/dlls/houndeye.cpp index 98c51c9..e52c5c3 100644 --- a/src/dlls/houndeye.cpp +++ b/src/dlls/houndeye.cpp @@ -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? diff --git a/src/dlls/hwgrunt.cpp b/src/dlls/hwgrunt.cpp index 8d85d4a..5bc94f0 100644 --- a/src/dlls/hwgrunt.cpp +++ b/src/dlls/hwgrunt.cpp @@ -199,7 +199,7 @@ 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 ) diff --git a/src/dlls/islave.cpp b/src/dlls/islave.cpp index c8a64a7..c943161 100644 --- a/src/dlls/islave.cpp +++ b/src/dlls/islave.cpp @@ -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. diff --git a/src/dlls/massn.cpp b/src/dlls/massn.cpp index 685cdb0..d688c86 100644 --- a/src/dlls/massn.cpp +++ b/src/dlls/massn.cpp @@ -227,7 +227,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 ) diff --git a/src/dlls/monster_config.cpp b/src/dlls/monster_config.cpp index a5468bc..dc6ed9a 100644 --- a/src/dlls/monster_config.cpp +++ b/src/dlls/monster_config.cpp @@ -728,6 +728,8 @@ void scan_extra_cfg(FILE *fp) { 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}; diff --git a/src/dlls/monstermaker.cpp b/src/dlls/monstermaker.cpp index 0768114..f61957b 100644 --- a/src/dlls/monstermaker.cpp +++ b/src/dlls/monstermaker.cpp @@ -65,6 +65,11 @@ 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 CMBaseMonster::KeyValue( pkvd ); } @@ -124,7 +129,7 @@ void CMMonsterMaker :: Precache( void ) void CMMonsterMaker::MakeMonster( void ) { 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 ) @@ -165,6 +170,13 @@ 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 ); + } // Attempt to spawn monster pent = spawn_monster(m_iMonsterIndex, pev->origin, pev->angles, createSF, keyvalue); diff --git a/src/dlls/monsters.cpp b/src/dlls/monsters.cpp index 18a181e..1b10c63 100644 --- a/src/dlls/monsters.cpp +++ b/src/dlls/monsters.cpp @@ -2626,6 +2626,23 @@ void CMBaseMonster :: KeyValue( KeyValueData *pkvd ) m_iClassifyOverride = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } + else if (FStrEq(pkvd->szKeyName, "bloodcolor")) + { + switch ( atoi( pkvd->szValue ) ) + { + case -1: m_bloodColor = DONT_BLEED; break; + case 1: m_bloodColor = BLOOD_COLOR_RED; break; + case 2: m_bloodColor = BLOOD_COLOR_YELLOW; break; + case 3: m_bloodColor = BLOOD_COLOR_BLUE; break; + case 4: m_bloodColor = BLOOD_COLOR_PINK; break; + case 5: m_bloodColor = BLOOD_COLOR_WHITE; break; + case 6: m_bloodColor = BLOOD_COLOR_ORANGE; break; + case 7: m_bloodColor = BLOOD_COLOR_BLACK; break; + case 8: m_bloodColor = BLOOD_COLOR_GREEN; break; + default: m_bloodColor = 0; break; // Invalid, set default + } + pkvd->fHandled = TRUE; + } else { CMBaseToggle::KeyValue( pkvd ); diff --git a/src/dlls/otis.cpp b/src/dlls/otis.cpp index cdf84af..989038e 100644 --- a/src/dlls/otis.cpp +++ b/src/dlls/otis.cpp @@ -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 diff --git a/src/dlls/pitdrone.cpp b/src/dlls/pitdrone.cpp index 1ad3b06..ced809d 100644 --- a/src/dlls/pitdrone.cpp +++ b/src/dlls/pitdrone.cpp @@ -570,7 +570,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 ) diff --git a/src/dlls/scientist.cpp b/src/dlls/scientist.cpp index e05ce3c..f6ccdec 100644 --- a/src/dlls/scientist.cpp +++ b/src/dlls/scientist.cpp @@ -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 diff --git a/src/dlls/shockroach.cpp b/src/dlls/shockroach.cpp index b922984..4dfd93e 100644 --- a/src/dlls/shockroach.cpp +++ b/src/dlls/shockroach.cpp @@ -69,7 +69,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; diff --git a/src/dlls/strooper.cpp b/src/dlls/strooper.cpp index 6d1b3ff..a2bfb01 100644 --- a/src/dlls/strooper.cpp +++ b/src/dlls/strooper.cpp @@ -367,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 ) diff --git a/src/dlls/stukabat.cpp b/src/dlls/stukabat.cpp index 9fe7228..479ce34 100644 --- a/src/dlls/stukabat.cpp +++ b/src/dlls/stukabat.cpp @@ -105,7 +105,7 @@ 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 ) diff --git a/src/dlls/util.h b/src/dlls/util.h index 997588a..87074d5 100644 --- a/src/dlls/util.h +++ b/src/dlls/util.h @@ -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 { diff --git a/src/dlls/voltigore.cpp b/src/dlls/voltigore.cpp index 4533d2b..1d04cc7 100644 --- a/src/dlls/voltigore.cpp +++ b/src/dlls/voltigore.cpp @@ -635,7 +635,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 ) @@ -1143,7 +1143,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 ) diff --git a/src/dlls/zombie.cpp b/src/dlls/zombie.cpp index 84d587e..6cd2c42 100644 --- a/src/dlls/zombie.cpp +++ b/src/dlls/zombie.cpp @@ -241,7 +241,7 @@ void CMZombie :: 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.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 ) From d00fec91b8bf1585ca53357935289e66331c177f Mon Sep 17 00:00:00 2001 From: Giegue Date: Tue, 25 Apr 2023 22:32:36 -0300 Subject: [PATCH 31/45] Update extra AMXX plugins. --- README.md | 97 -------------------- extra/base/README.md | 14 ++- extra/base/bin/glb_takedamage.amxx | Bin 0 -> 1875 bytes extra/base/src/glb_dispatchuse.sma | 35 ++++++- extra/base/src/glb_takedamage.sma | 42 +++++++++ extra/cstrike/README.md | 17 ++++ extra/cstrike/bin/cs_unprecacher.amxx | Bin 0 -> 2377 bytes extra/cstrike/src/cs_unprecacher.sma | 126 ++++++++++++++++++++++++++ extra/valve/README.md | 2 +- extra/valve/bin/hl_monsterbridge.amxx | Bin 4426 -> 4431 bytes extra/valve/src/hl_monsterbridge.sma | 122 ++++++++++++------------- 11 files changed, 288 insertions(+), 167 deletions(-) create mode 100644 extra/base/bin/glb_takedamage.amxx create mode 100644 extra/base/src/glb_takedamage.sma create mode 100644 extra/cstrike/README.md create mode 100644 extra/cstrike/bin/cs_unprecacher.amxx create mode 100644 extra/cstrike/src/cs_unprecacher.sma 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 0000000000000000000000000000000000000000..1f9807dd85ece497e51a203fa7c762a9751b7786 GIT binary patch literal 1875 zcmV-Z2dwy5SWQ6y0|5j(2LJ$T5C8zkNB{sB0001ZoSj!)Y+S_^K6iJ48{&Y|8fpR* z(?TI7{z-_5TOkGi#daI7?cGiJ5z;c=o!!0o{+N63nzizhheisIl~9#O5dS|yAW+Lg z1PDdKPyFVgl_27=g-E1QB>N#Kd^2-)_hudHmX*$abIzPOb7tn8nRC}{qObpB+bOcC zkRlqohG-44wP~VD_>B?ae}Kp$ItJYo5UR8TcnWlzMf!IS;{nEL#zz=k##P1> zj3*giWc(ZB2aF#xo@M-&aUGZerc%bA>wsyZ2X?9TfbRqDRek}7fy2Q2fRn(3R1iyY zLU^JosaULtSh&TS@QN}FgOHZpde!lZj_<@&m2t6B_e({mOeNvEy1giMe_OCzk8045 zJ0wvYwk6UpQ>3g3$3>5bC55mP#WF0K8QXkmMTBiG3Rg;A8N4VLMOZDhS}S_aHdk>2 z5t9=YSA^@7F=I@V4Oyzka$0y}G%Fh8t^;XA*&~M!7xRVOOm@n&|1>#Xn9I>2ZQ)?( zVlX_Cbg4bkt-J@)84`b5zrhkuuHh7=X+*bXsC;V^D*YxeGgl|n$>mKSj zGd1Q6<7vkG8N1ll)oi1?!}lZ(Sq9HD-_2vM;juke82hxV}Gwr>}zKnr?$}DNa&`w(7lk*&2;E)@6bJ;(7kF4 zyXROpnM+OGu7qxZ_s{12dpL2PL)4DHjsL;ML}qh5@8&gbHTGCyY;#YJ^E!_6+K+SJ zakiga+cw^hUY=tI&v8p)Ja;giBD%hgZ4g#(H8OtH_B_38=TBFoe~i_FIz zbCtK4i+;km|7Shw_Z%*h?@-664C})UGorInMaf_-@Z{j*b=ML8;Dn4ycppVHD7=Oj zlpFnf2Yxp&)L(Vt;e7}8_PdT>Z#4S`qf+QB$Bthebo`QAFU!HiGdBR4E_rO#UCrh6WE82AG4A>d2EHQ+12bHG=X9_TgD{g%18)ou5NWp4SmEK?!9 zZJA0)-CC!)^4hRW_U=!asQq)w%y|O%GvGTZ6TP1TZvcJ?yb<`Xl!^8pTroER9{}!B zrwqIqcrtCG|1|J6;Dxk_GL`AS0*(NGO(tvaP$vt#lT0S6Oi~$U>ALY9cxZuCsiPCl zIMfoO9MS@_9<`kr$Wg~cfzL;)7Ibf`Ta7|(rnh+CWm1%7=kx?$r_7zMgyvAj927e0 z8c5TbO`ZB)z?mdEL>!CKk_`1iu(Lqwy&%*xc7rn`M|~X6PO!7muOmaoqdx?WpVt-m&(-K!7(6-Q zgc9e7`0Ig4b=IRX6yZ03dr*qyz#n%-6lv2ps)_1xFjik}3xA=6o)>7Qw>4_UuLQ`p zmXRQewZ<;BkXU*x!Oc9rCAbBPccpILYMPE`*k4j16n^waxr#i^2Vp#GPNYvWTIF^c z4MVYtyqyTLL3|{VNZq`OZ=`M^bR;rY0bB^_Hj=kL5VXE)ob&g?=i z^li`CIx(&_7ti$PIlJ-qv+Lc=H;&BNkHtsyIH7Lp+O+*pX3p;Bi|Pd0&p==GkD`C$ zi3NM)LRRam+N$wc&OYfc*nLg?i`kYBJE8xww_x{vpVju%mGbV#IeX(`wrwB&uzU0t zs2BE>&WSH__OsyEj^^x_FD>Xb{6+PL3-(Ej(J?UN<3Qqk9O6kEla(NpWWm}o?1R!* z7jE~^l(zrxzkay>)&BR^KY8!{b$avc`ZpiF_)nYf6xxQ$W!D#%I`{LLqYIbqX9Y%= N+4iSIKLF(rHLUCYy!ikC literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f4af3386715ccf270606ad8fe033d15f67f1c89b GIT binary patch literal 2377 zcmV-P3AXlFSWQ6y0|5jv2><{IVE_Oqn*ab90001ZoaLNNY#iko$DehaWW!ei36MYl z10gXXfsmLGXi99aKVn$hi+2-JwbC-)o%K#VJF}XZjqSpLLl3P~AyARp8V(#dAhib$ zk?5g^R-$ST9D1l!4pd4d4yhEiAR&R;O7#ECJmcLMJG(pHNPcG@>GAvh@q6Bnd3V

sWtj!r#-mnZW z^j9SVIr^O8db*Pj66)cS?JQ_ckqWluX-JsV7E`97Tb@f(=hEqXHa9adH6HlSkEU|d zGc;z}nn!0GGhfo?^@{Fkbf#4I6D9T-pgb(5>a&=K-@)2FO;r3Y(aX;f{ooAvF~GSY z@DGDO1^yB6kAi;;{Nvz13;qf4KM(#Fz>fufU=sWo;QiC!$EL97MexsnKMVdG_%R_C zU;-V=>!b>`p%&DIJ|Xe*P;{4g?DNoB$!GFhka9H%n=-!_r0m6Y#&fes6#fDQoQ9M! zq>M`3p>%?u%kcQ~Tu{vht?)D39K~<$vuu>#6@OSh?)-6D`z#yfS9$HTw98+TJWfM7 z_Vc+cuKWv<)~)mZdi>om{~P&>lApt-~1- zezze$+zT4#L|CUQ{>^HGsQjLk<#>nGeD}-JjK3sl6{?SCoZf?XieJ_D;8FQi-0Rko zPVvX}{I?!|T;7AX!p~!TQSyb)voOqgRbCG_ieHuW&?)}4&O<6Z6K^EH3g^LQ{CvJY zAz}9OJ3p1z`)cVFzbfl}wM6A#Yrd<*9ZDH_4vDK{kOs&*Y(fm*#Sup z*M3~)K1&q-xXgW)PVlQb_gSLw$K~BWOB8-i3-`kC3|yf4nKv)>lteePU2Y`53VT8; z{KqM<0sq#easTJvm8iV;v22uI<-Lz33O~>FvXtq@@h?ce@EriJc~$=}u2cM~{$E%t z{G7(jy#Mp>v*L6Hj>;dGGjON)RecV$!q4&i+r>DIdng;_S9RP&X_tSk_kOcfUnBfm zIhE|tjGyE9xfi#6Ka_U)yKVh9-=AjKhE>N+4~-qe+L|e|9WR#)ojs>pXYS=4v@bC3f}{E%kMwd z(!U>Y=&3pOQ9QHpzKEeNgfQ zf729H)_7rf+D}bOa}B90SBUdGNzklqn`lI{me5#m6L>F`*mbzod`0)lc9FIs$DFBG z?4nNFC~eHD~1~IqLm|+!zs37K6O1Tpj%2}E@iIz>e4KX=gtGJkxDR;=J*pA=gE`)-T zLzYpY+Yy}9ts30{&-1onWj)Q)X*ZWHJNCke0V8;ZZNc0rmlJF5u;$R62)(3hRohCL zn(O*i-^C5pJbSpdRFAxyBP$i#5A0njHDQ%(+E=f{c0E7GJq+UMm6eElrTj|7e!!c$ z@4YYZ8kHb;Kjj?Fa$nGw=mE;wjyD;MNS`0@vph&cj-xHnLo{Mf+1@!|qeC>Jd0K|^^{;p{wo8vvb~2UG92fZyvwuc+Yob-K%i{f^Vt8#wThmyt&%Z^4GbIwU21xg0CZk6YdW_} z$0=B9e&7U+TAtx81%oy~;BiuwB0f3{nYtjKgpqW!==-0hVa?U+;ZxV%W&g~o+w23` zChnJ){_xf3pDrg4&ph|{o#CoVVpsp{kKeHOBom zw!aJi`ITQq-(XdH5u4A2U%Z}N{P6NuBl+R!>GbH(6tyqhFWyqQ{>6VSC;J9<9)rF& v5x(-z<>V)?|2#Q1F`6F9XU|U0r`QdF~%?VLdCm2KfIEL7rMNmNNaa literal 0 HcmV?d00001 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 ada2c3eb826b26a78c41e0c717ec36ede769cdaa..cb05ae8e7999f802f64b28e53d7de643552d7bdc 100644 GIT binary patch literal 4431 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 V@K}R++PB}-CVzMF{{fb3KvqnP0we$c literal 4426 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 Q{N^JnH@4UR11Ob1d3T58V*mgE 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 From 5da691b5fe1b711d03764e4aee526bdfbd9d4327 Mon Sep 17 00:00:00 2001 From: Giegue Date: Wed, 26 Apr 2023 01:44:36 -0300 Subject: [PATCH 32/45] 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. --- src/dlls/apache.cpp | 5 ++++ src/dlls/cmbase.h | 2 +- src/dlls/dllapi.cpp | 3 ++- src/dlls/monster_config.cpp | 22 ++++++++++------- src/dlls/monstermaker.cpp | 49 ++++++++++++++++++++++++++++++++++++- src/dlls/subs.cpp | 15 +++++++++++- src/dlls/turret.cpp | 2 ++ src/dlls/util.cpp | 9 ++++--- 8 files changed, 91 insertions(+), 16 deletions(-) diff --git a/src/dlls/apache.cpp b/src/dlls/apache.cpp index ec3b748..33d7490 100644 --- a/src/dlls/apache.cpp +++ b/src/dlls/apache.cpp @@ -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) { diff --git a/src/dlls/cmbase.h b/src/dlls/cmbase.h index b0d16eb..f9af751 100644 --- a/src/dlls/cmbase.h +++ b/src/dlls/cmbase.h @@ -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; } diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index 78eb2e4..90c0f8f 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -163,6 +163,7 @@ monster_type_t monster_types[]= "info_node_air", FALSE, "monstermaker", FALSE, // Extra entities "ambient_music", FALSE, + "squadmaker", FALSE, // Aliases "", FALSE }; @@ -1370,7 +1371,7 @@ void mmDispatchUse( void ) if ( FNullEnt( caller ) ) caller = NULL; if ( FNullEnt( activator ) ) activator = NULL; - monsters[index].pMonster->Use( caller, activator, useType, flValue ); + monsters[index].pMonster->Use( activator, caller, useType, flValue ); return; } } diff --git a/src/dlls/monster_config.cpp b/src/dlls/monster_config.cpp index dc6ed9a..b2dc6c1 100644 --- a/src/dlls/monster_config.cpp +++ b/src/dlls/monster_config.cpp @@ -116,7 +116,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) @@ -127,8 +127,8 @@ void scan_monster_cfg(FILE *fp) } else { - monster_spawnpoint[monster_spawn_count].monster = mIndex; - monster_types[mIndex].need_to_precache = TRUE; + monster_spawnpoint[monster_spawn_count].monster = 32; // monstermaker index is fixed at 32 + monster_types[32].need_to_precache = TRUE; monster = TRUE; } } @@ -266,7 +266,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 ); @@ -282,7 +282,7 @@ void scan_monster_cfg(FILE *fp) if (monster) { // only applicable 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) { // precache the custom model PRECACHE_MODEL( data[i].value ); @@ -298,7 +298,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; @@ -529,6 +529,10 @@ void scan_monster_bsp(void) } 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; @@ -619,7 +623,7 @@ void scan_monster_bsp(void) if (monster) { // only applicable for normal monsters - if (strcmp(data[classname_kvdI].value, "monstermaker") != 0) + 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 ); @@ -635,7 +639,7 @@ void scan_monster_bsp(void) if (monster) { // only applicable for monstermaker entity - if (strcmp(data[classname_kvdI].value, "monstermaker") == 0) + if (strcmp(data[classname_kvdI].value, "monstermaker") == 0 || strcmp(data[classname_kvdI].value, "squadmaker") == 0) { // precache the custom model PRECACHE_MODEL( data[i].value ); @@ -651,7 +655,7 @@ void scan_monster_bsp(void) if (monster) { // this keyvalue is only valid for monstermaker entity - if (strcmp(data[classname_kvdI].value, "monstermaker") == 0) + 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++) diff --git a/src/dlls/monstermaker.cpp b/src/dlls/monstermaker.cpp index f61957b..408ff0b 100644 --- a/src/dlls/monstermaker.cpp +++ b/src/dlls/monstermaker.cpp @@ -70,6 +70,19 @@ void CMMonsterMaker :: KeyValue( KeyValueData *pkvd ) m_iMonsterBlood = atoi(pkvd->szValue); 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 ); } @@ -163,6 +176,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 ) ) { @@ -175,7 +189,34 @@ void CMMonsterMaker::MakeMonster( void ) { // setup blood keyvalue strcpy(keyvalue[1].key, "bloodcolor"); - sprintf(keyvalue[1].value, "%i", m_iMonsterBlood ); + 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 @@ -201,6 +242,12 @@ 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; + m_cLiveChildren++;// count this monster m_cNumMonsters--; diff --git a/src/dlls/subs.cpp b/src/dlls/subs.cpp index f9fac79..3e7bd26 100644 --- a/src/dlls/subs.cpp +++ b/src/dlls/subs.cpp @@ -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 ); + } + } } } diff --git a/src/dlls/turret.cpp b/src/dlls/turret.cpp index b2239e0..5f41199 100644 --- a/src/dlls/turret.cpp +++ b/src/dlls/turret.cpp @@ -801,6 +801,7 @@ void CMBaseTurret :: TurretDeath( void ) if (pev->deadflag != DEAD_DEAD) { pev->deadflag = DEAD_DEAD; + FCheckAITrigger(); // trigger death condition float flRndSound = RANDOM_FLOAT ( 0 , 1 ); @@ -1105,6 +1106,7 @@ void CMSentry::SentryDeath( void ) if (pev->deadflag != DEAD_DEAD) { pev->deadflag = DEAD_DEAD; + FCheckAITrigger(); // trigger death condition float flRndSound = RANDOM_FLOAT ( 0 , 1 ); diff --git a/src/dlls/util.cpp b/src/dlls/util.cpp index 1f7f536..1d774fb 100644 --- a/src/dlls/util.cpp +++ b/src/dlls/util.cpp @@ -2142,7 +2142,10 @@ 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 if it can. - 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 ); + 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 ); + } } From f751720e59ed35bb774f2770ccafa84e9ebd0886 Mon Sep 17 00:00:00 2001 From: Giegue Date: Thu, 27 Apr 2023 12:59:29 -0300 Subject: [PATCH 33/45] Recompile AMXX plugins (Did I forget to update them?). --- extra/base/bin/glb_dispatchuse.amxx | Bin 1547 -> 1831 bytes extra/base/bin/glb_takedamage.amxx | Bin 1875 -> 1784 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/extra/base/bin/glb_dispatchuse.amxx b/extra/base/bin/glb_dispatchuse.amxx index 4d912151f45f71dfacc2b807711c721ccc8a8554..af5d9caf26a42c8731d3573db5b9731b8c84f735 100644 GIT binary patch literal 1831 zcmV+?2iW*nSWQ6y0|5jN2LJ$16952wN&o;D0001Zob6XjZyZGsuGw9Ki47PqAwYnT z1cD(LlLv_+q~NR_$H6w1y#YtEw6u5I-ce>}R`YOTkpl-T9{&JNAn_0oArK&O@F9mF z<-jc*k;o5-6p(W80SUgEuG#HfCm7DKQtj7WRb5s6s;NG|h3M+<-Q79rrVBZuxSQxa zc;`qfyqNfvvRkE! z^1QUYpi_B^(MX~i^y3ar6o)O2_Nx@JHRXDcs8~}7J5j8|vhmpJSC&;sGtxVu>McnW zE?4SR(thm5D`k#OSKUes%i%H)ge=smTE^rm&DL@nTdTL|1u7;tDlaR~ts=6RM$hR= z5^MN6Mw9AX(R0C#XzJ9&M0vI}Gd?wD+OLilORvn(@zlc6(8FLvuIcDvvlXUm87aSd z)~(c7Vt4U7C)+;=dRJ&K=ntIJJ!H-+V?T(I_xcSP!+O1-dqn?T(Q(91UiiIY=MZpB zbhtlY`N`}$mR(o+2W4E3^!I}|qiY-H)_fW^4?U6NM{95ou!CtX-o7m{< zh`kLRgTF|>PsZLZWBdPR?2wG@7JNqd{bD1V!?v5)_|9pa3&yvk|GLv|;||Nlt=3@+ zwV#D-@3vTb$Ll_yH)B>o+Xc4?_6zn2X10Eic(#en9vFmU4sl(3A+77j!r8}v0hC1(TZWG;gOEX=iu#-Z>_VmGvOW3fw?U3)IPj!%f4f74zRdslD( zucP+l8~r40rNe0!;8R&VGLLdAjPReR&<*Ct02TilD_&C7 z^H!ZO2wqx*E_n;(s+4X?qz9wAN|V<|jyaqkbD;|S#4!c#XTZzA&wkD(6^wAj!A@w-DJSAoxw zNj7{4cjMCUBa=9|P7`IWx{v*vA3p!Agy28mxS*L7SAs`%I{f63GJpsI1t zCftQ|FK(ydYTfmx!=QmsPN=AsvhSc-9hX#e=D4SpBHY95Jv6$EH89K`8q@K#r&f?- z45t^1=vNKPaPFjHH11=Zue?ck_D~NLqmo9h!56d`4Ttq0Og;9YXGRYDZXKWhVl=7! zgziP-WZ?R<>7(sF9$gEAvm@9o91dKJey~`WM91)MyC1#Rv}y!?(Nj^Bn%>Hek~lb) zthAU9Ftc6{($2Q#sBwQWKpJTp38FaFc!(zw>w1&%u#9gqwqx?1IpB|&rdv1NN2wGl zKYCfOAR)~LVLWMeWJlUbRUW6|FjOnFlSYE6Am$Ugi!iIo8RV)`=xU@Y280kI&CmL( z5!HeiiE9KWW}5Y$YBr~X2pMd4vN)|md;pNe(4Nsz;>E~hXpg36YcGvYjf={&RK%&^MR_3GS5{7l}@|HkwIZt`-a%Xx6av-E|| Vhv^|6aDqMl|NGDX{sKm6Ao*ekq$~gc literal 1547 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 N+4iSIKLF(rHLUCYy!ikC From ba9414ea6ee3b0beebcfdf7af6e8e3bb0d3b09fc Mon Sep 17 00:00:00 2001 From: Giegue Date: Thu, 27 Apr 2023 13:02:23 -0300 Subject: [PATCH 34/45] Add missing keyvalue in monstermaker. Fix duplicate entity spawn in Half-Life. --- src/dlls/monster_config.cpp | 14 ++++++++++---- src/dlls/monstermaker.cpp | 6 ++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/dlls/monster_config.cpp b/src/dlls/monster_config.cpp index b2dc6c1..30a5b0d 100644 --- a/src/dlls/monster_config.cpp +++ b/src/dlls/monster_config.cpp @@ -450,11 +450,11 @@ void scan_monster_bsp(void) { // 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 - // - // if it is valid, this entity already exists and we should ignore it 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 @@ -468,8 +468,14 @@ void scan_monster_bsp(void) { if (atoi(kv_pair->value) == 1) { - // EXPLICITY requested to use monstermod for this entity - use_monstermod_explicit = true; + // 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); } } diff --git a/src/dlls/monstermaker.cpp b/src/dlls/monstermaker.cpp index 408ff0b..c2b2d3f 100644 --- a/src/dlls/monstermaker.cpp +++ b/src/dlls/monstermaker.cpp @@ -70,6 +70,12 @@ void CMMonsterMaker :: KeyValue( KeyValueData *pkvd ) 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. From 92d14a6fd33645bd095dd48efccc2edeba45bcf3 Mon Sep 17 00:00:00 2001 From: Giegue Date: Sat, 29 Apr 2023 01:58:47 -0300 Subject: [PATCH 35/45] Update extra AMXX plugins. --- extra/valve/README.md | 21 +++ extra/valve/bin/hl_extra_keyvalues.amxx | Bin 0 -> 4080 bytes extra/valve/bin/hl_soundlist.amxx | Bin 0 -> 4415 bytes extra/valve/src/hl_extra_keyvalues.sma | 232 ++++++++++++++++++++++++ extra/valve/src/hl_soundlist.sma | 204 +++++++++++++++++++++ 5 files changed, 457 insertions(+) create mode 100644 extra/valve/bin/hl_extra_keyvalues.amxx create mode 100644 extra/valve/bin/hl_soundlist.amxx create mode 100644 extra/valve/src/hl_extra_keyvalues.sma create mode 100644 extra/valve/src/hl_soundlist.sma diff --git a/extra/valve/README.md b/extra/valve/README.md index 1b063f8..171cff3 100644 --- a/extra/valve/README.md +++ b/extra/valve/README.md @@ -17,3 +17,24 @@ MonsterMod monsters are hacked "func_wall"'s with simulated AI. Because of this, 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. diff --git a/extra/valve/bin/hl_extra_keyvalues.amxx b/extra/valve/bin/hl_extra_keyvalues.amxx new file mode 100644 index 0000000000000000000000000000000000000000..1a8e8fa62e1865beb119e18349b72a48f7064fc9 GIT binary patch literal 4080 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 literal 0 HcmV?d00001 diff --git a/extra/valve/bin/hl_soundlist.amxx b/extra/valve/bin/hl_soundlist.amxx new file mode 100644 index 0000000000000000000000000000000000000000..b2fb6cbbfe1493a8b26a24e4fec025584a421276 GIT binary patch literal 4415 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 Ff|sFl3L*di literal 0 HcmV?d00001 diff --git a/extra/valve/src/hl_extra_keyvalues.sma b/extra/valve/src/hl_extra_keyvalues.sma new file mode 100644 index 0000000..3b6ab21 --- /dev/null +++ b/extra/valve/src/hl_extra_keyvalues.sma @@ -0,0 +1,232 @@ +#pragma semicolon 1 + +#include +#include +#include +#include + +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; +} diff --git a/extra/valve/src/hl_soundlist.sma b/extra/valve/src/hl_soundlist.sma new file mode 100644 index 0000000..3fb08e4 --- /dev/null +++ b/extra/valve/src/hl_soundlist.sma @@ -0,0 +1,204 @@ +#pragma semicolon 1 + +#include +#include +#include +#include + +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 ); + } + } + } + } +} From efd801bdea1eb1c03e0e630a84a462b6378775ac Mon Sep 17 00:00:00 2001 From: Giegue Date: Sat, 29 Apr 2023 02:04:40 -0300 Subject: [PATCH 36/45] Add "soundlist" keyvalue for individual sound replacements. --- README.md | 4 +- src/dlls/cmbasemonster.h | 4 ++ src/dlls/dllapi.cpp | 6 ++ src/dlls/globalreplace.cpp | 48 +++++++++++++--- src/dlls/globalreplace.h | 7 +++ src/dlls/monster_config.cpp | 107 +++++++++++++++++++++++++++++++++++- src/dlls/monstermaker.cpp | 11 ++++ src/dlls/monsters.cpp | 10 +++- 8 files changed, 185 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6ffedc0..7212d31 100644 --- a/README.md +++ b/README.md @@ -103,8 +103,8 @@ Current milestones are separated by "Tiers", which are as follows: - Add build instructions. **[DONE]** - Global Model Replacement. **[DONE]** - Global Sound Replacement. **[DONE]** -- Miscellaneous customization options, such as blood color. -- Individual sound replacement: "soundlist" keyvalue for monsters. +- Miscellaneous customization options, such as blood color. **[DONE]** +- Individual sound replacement: "soundlist" keyvalue for monsters. **[DONE]** - Sentences support for speakable monsters. - Attempt to fix bugs as they appear. diff --git a/src/dlls/cmbasemonster.h b/src/dlls/cmbasemonster.h index 270c13e..cd6e2a6 100644 --- a/src/dlls/cmbasemonster.h +++ b/src/dlls/cmbasemonster.h @@ -104,6 +104,10 @@ 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 ); diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index 90c0f8f..9ab5958 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -1255,7 +1255,13 @@ int mmDispatchSpawn( edict_t *pent ) for (index = 0; index < MAX_MONSTER_ENTS; index++) { if (monsters[index].pMonster != NULL) + { + // free the soundlists first! + if (monsters[index].pMonster->m_srSoundList != NULL) + free(monsters[index].pMonster->m_srSoundList); + delete monsters[index].pMonster; + } } // free any allocated keyvalue memory diff --git a/src/dlls/globalreplace.cpp b/src/dlls/globalreplace.cpp index 28d02ac..5e98afb 100644 --- a/src/dlls/globalreplace.cpp +++ b/src/dlls/globalreplace.cpp @@ -12,12 +12,6 @@ namespace REPLACER { -typedef struct -{ - char source[128]; - char destination[128]; -} REPLACER; - REPLACER *GMR; REPLACER *GSR; int numModels; @@ -77,6 +71,32 @@ bool AddGlobalSound(const char *from, const char *to) 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! @@ -103,14 +123,26 @@ const char* FindSoundReplacement( edict_t *pMonster, const char *from ) if ( pMonster ) { CMBaseMonster *castMonster = GetClassPtr((CMBaseMonster *)VARS(pMonster)); - //placeholder for soundlist keyvalue; + if (castMonster->m_isrSounds) + { + 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 model instead + // If found, use that sound instead return GSR[sound].destination; } } diff --git a/src/dlls/globalreplace.h b/src/dlls/globalreplace.h index 3be64d9..c9f8b1b 100644 --- a/src/dlls/globalreplace.h +++ b/src/dlls/globalreplace.h @@ -5,9 +5,16 @@ 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 ); } diff --git a/src/dlls/monster_config.cpp b/src/dlls/monster_config.cpp index 30a5b0d..7a2a17f 100644 --- a/src/dlls/monster_config.cpp +++ b/src/dlls/monster_config.cpp @@ -68,6 +68,80 @@ 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)) + { + char *source = strtok(input, " "); + char *destination = strtok(NULL, " "); + + // 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 @@ -277,6 +351,22 @@ 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) @@ -640,6 +730,22 @@ void scan_monster_bsp(void) } } } + 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) @@ -946,7 +1052,6 @@ bool process_monster_cfg(void) return FALSE; // all ok } - bool scan_monster_precache_cfg(FILE *fp) { char input[1024]; diff --git a/src/dlls/monstermaker.cpp b/src/dlls/monstermaker.cpp index c2b2d3f..210adb5 100644 --- a/src/dlls/monstermaker.cpp +++ b/src/dlls/monstermaker.cpp @@ -254,6 +254,17 @@ void CMMonsterMaker::MakeMonster( void ) 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--; diff --git a/src/dlls/monsters.cpp b/src/dlls/monsters.cpp index 1b10c63..7afb3f8 100644 --- a/src/dlls/monsters.cpp +++ b/src/dlls/monsters.cpp @@ -41,7 +41,7 @@ extern CGraph WorldGraph;// the world node graph extern cvar_t *monster_turn_coeficient; - +extern void process_monster_sound(edict_t *pMonster, char *fileName); //========================================================= // Eat - makes a monster full for a little while. @@ -2643,6 +2643,14 @@ void CMBaseMonster :: KeyValue( KeyValueData *pkvd ) } pkvd->fHandled = TRUE; } + else if (FStrEq(pkvd->szKeyName, "soundlist")) + { + if (strlen( pkvd->szValue )) + { + process_monster_sound(edict(), pkvd->szValue); + } + pkvd->fHandled = TRUE; + } else { CMBaseToggle::KeyValue( pkvd ); From c782c2aaf5d0bdeaf2c81fc85864a388f1c6cb05 Mon Sep 17 00:00:00 2001 From: Giegue Date: Sun, 30 Apr 2023 11:32:12 -0300 Subject: [PATCH 37/45] Fixed a heap corruption. --- src/dlls/dllapi.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index 9ab5958..801e4cb 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -1259,6 +1259,7 @@ int mmDispatchSpawn( edict_t *pent ) // free the soundlists first! if (monsters[index].pMonster->m_srSoundList != NULL) free(monsters[index].pMonster->m_srSoundList); + monsters[index].pMonster->m_srSoundList = NULL; delete monsters[index].pMonster; } From 95461427b239ade1501f1b949dac495c3e4e3b6b Mon Sep 17 00:00:00 2001 From: Giegue Date: Tue, 2 May 2023 23:40:00 -0300 Subject: [PATCH 38/45] Add sentences support. --- README.md | 2 +- src/dlls/cmbasemonster.h | 5 ++--- src/dlls/dllapi.cpp | 4 ++++ src/dlls/hgrunt.cpp | 25 +++++++++++++------------ src/dlls/hwgrunt.cpp | 5 +---- src/dlls/monster_config.cpp | 2 +- src/dlls/rgrunt.cpp | 32 ++++++++++++++++---------------- src/dlls/strooper.cpp | 4 ++-- 8 files changed, 40 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 7212d31..c936417 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ Current milestones are separated by "Tiers", which are as follows: - 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. +- Sentences support for speakable monsters. **[DONE]** - Attempt to fix bugs as they appear. ### Tier 5 diff --git a/src/dlls/cmbasemonster.h b/src/dlls/cmbasemonster.h index cd6e2a6..319970a 100644 --- a/src/dlls/cmbasemonster.h +++ b/src/dlls/cmbasemonster.h @@ -1687,14 +1687,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 ); @@ -1712,6 +1709,8 @@ public: float m_flActiveDischarge; int m_iBodyGibs; + + static const char *pRobotSentences[]; }; //========================================================= diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index 801e4cb..112426b 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -62,6 +62,9 @@ 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; @@ -1293,6 +1296,7 @@ int mmDispatchSpawn( edict_t *pent ) // precache last in the event of a GMR being present world_precache(); + SENTENCEG_Init(); // node support. -Giegue // init the WorldGraph. diff --git a/src/dlls/hgrunt.cpp b/src/dlls/hgrunt.cpp index cd25b19..c4d8b56 100644 --- a/src/dlls/hgrunt.cpp +++ b/src/dlls/hgrunt.cpp @@ -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; @@ -808,8 +809,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(); } } @@ -1948,9 +1949,9 @@ Schedule_t *CMHGrunt :: 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), !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 ); } @@ -1995,14 +1996,14 @@ Schedule_t *CMHGrunt :: GetSchedule( void ) 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 + // 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 ); diff --git a/src/dlls/hwgrunt.cpp b/src/dlls/hwgrunt.cpp index 5bc94f0..c67455b 100644 --- a/src/dlls/hwgrunt.cpp +++ b/src/dlls/hwgrunt.cpp @@ -253,10 +253,7 @@ void CMHWGrunt::Precache() PRECACHE_SOUND("hassault/hw_spindown.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(); diff --git a/src/dlls/monster_config.cpp b/src/dlls/monster_config.cpp index 7a2a17f..57a6b97 100644 --- a/src/dlls/monster_config.cpp +++ b/src/dlls/monster_config.cpp @@ -872,7 +872,7 @@ void scan_extra_cfg(FILE *fp) if (dllapi_log->value) LOG_CONSOLE(PLID, "[DEBUG] Using global model replacement file: %s", value); } - else if (strcmp(cmd, "globalsoundlist") == 0) + if (strcmp(cmd, "globalsoundlist") == 0) { //globalsoundlist->string = value; CVAR_SET_STRING( "monster_gsr", value ); diff --git a/src/dlls/rgrunt.cpp b/src/dlls/rgrunt.cpp index c38dfe1..5d305f1 100644 --- a/src/dlls/rgrunt.cpp +++ b/src/dlls/rgrunt.cpp @@ -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 //========================================================= @@ -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_MODELINDEX("models/shell.mdl");// brass shell } diff --git a/src/dlls/strooper.cpp b/src/dlls/strooper.cpp index a2bfb01..25d6a18 100644 --- a/src/dlls/strooper.cpp +++ b/src/dlls/strooper.cpp @@ -792,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); } From fa39abd61c413050c4d06944a0b7027a6ebe0a44 Mon Sep 17 00:00:00 2001 From: Giegue Date: Wed, 31 May 2023 16:16:37 -0300 Subject: [PATCH 39/45] Fix BSP reader crashing the server, again. --- src/dlls/ripent.cpp | 11 +++++++++-- src/dlls/ripent.h | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/dlls/ripent.cpp b/src/dlls/ripent.cpp index f15f9a6..aa42e09 100644 --- a/src/dlls/ripent.cpp +++ b/src/dlls/ripent.cpp @@ -421,7 +421,11 @@ skipspace: if (script->script_p == script->end_p) break; if (token_p == &token[MAXTOKEN]) - LOG_MESSAGE(PLID, "Token too large on line %i", scriptline); + { + // 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++; } @@ -432,7 +436,10 @@ skipspace: if (script->script_p == script->end_p) break; if (token_p == &token[MAXTOKEN]) - LOG_MESSAGE(PLID, "Token too large on line %i", scriptline); + { + // ditto + ALERT(at_logged, "FATAL ERROR (shutting down): ReadEntsFromBSP: Line %i is too long (length > %i).", scriptline, MAXTOKEN); + } } *token_p = 0; diff --git a/src/dlls/ripent.h b/src/dlls/ripent.h index f3baa75..868abed 100644 --- a/src/dlls/ripent.h +++ b/src/dlls/ripent.h @@ -90,7 +90,7 @@ void SafeRead(FILE *f, void *buffer, int count); char *ExpandPath(char *path); // from scripts // -- scriplib.h -- -#define MAXTOKEN 512 +#define MAXTOKEN 4096 extern char token[MAXTOKEN]; bool GetToken(bool crossline); From b87538ff596155ebd0639a849a7e2558f3d267aa Mon Sep 17 00:00:00 2001 From: Giegue Date: Thu, 1 Jun 2023 10:32:28 -0300 Subject: [PATCH 40/45] Fix monstermaker attempting to spawn alien grunt when monster type is undefined or invalid. --- src/dlls/monstermaker.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/dlls/monstermaker.cpp b/src/dlls/monstermaker.cpp index 210adb5..ed51585 100644 --- a/src/dlls/monstermaker.cpp +++ b/src/dlls/monstermaker.cpp @@ -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") ) @@ -96,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; @@ -147,6 +163,13 @@ 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[MAX_KEYVALUES]; // sometimes, i don't know what am i doing. -Giegue int createSF = SF_MONSTER_FALL_TO_GROUND; @@ -229,7 +252,7 @@ void CMMonsterMaker::MakeMonster( void ) pent = spawn_monster(m_iMonsterIndex, pev->origin, pev->angles, createSF, keyvalue); if ( pent == NULL ) { - ALERT ( at_console, "[MONSTER] NULL Ent in MonsterMaker!\n" ); + ALERT ( at_console, "[MONSTER] MonsterMaker - failed to spawn monster! targetname: \"%s\"\n", STRING(pev->targetname) ); return; } From fbe70a5691d70d5997c55d31f77480c5e169a8ec Mon Sep 17 00:00:00 2001 From: Giegue Date: Thu, 1 Jun 2023 19:46:02 -0300 Subject: [PATCH 41/45] Fix sound replacements crashing the server. --- src/dlls/globalreplace.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/dlls/globalreplace.cpp b/src/dlls/globalreplace.cpp index 5e98afb..2774d6b 100644 --- a/src/dlls/globalreplace.cpp +++ b/src/dlls/globalreplace.cpp @@ -122,8 +122,20 @@ const char* FindSoundReplacement( edict_t *pMonster, const char *from ) // Individually set sounds takes priority! if ( pMonster ) { - CMBaseMonster *castMonster = GetClassPtr((CMBaseMonster *)VARS(pMonster)); - if (castMonster->m_isrSounds) + 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 (!FNullEnt(pMonster->v.owner)) + castMonster = GetClassPtr((CMBaseMonster *)VARS(pMonster->v.owner)); + } + + // If still no valid BaseMonster pointer, full stop, use GSR. + if (castMonster && castMonster->m_isrSounds) { for (int sound = 0; sound < castMonster->m_isrSounds; sound++) { From 1d2a284197fce45bc465846ed0c196f81104b6c9 Mon Sep 17 00:00:00 2001 From: Giegue Date: Sat, 1 Jul 2023 16:27:32 -0300 Subject: [PATCH 42/45] 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. --- src/dlls/bigmomma.cpp | 2 +- src/dlls/cmbasemonster.h | 1 + src/dlls/cmtalkmonster.h | 2 +- src/dlls/dllapi.cpp | 28 ++++++++++++++++++++++++---- src/dlls/gargantua.cpp | 9 ++++++--- src/dlls/globalreplace.cpp | 6 +++--- src/dlls/hgrunt.cpp | 4 +++- src/dlls/massn.cpp | 2 +- src/dlls/nodes.cpp | 10 ++++++---- src/dlls/shockroach.cpp | 23 ++++++++++++++++++++++- src/dlls/voltigore.cpp | 4 ++-- 11 files changed, 70 insertions(+), 21 deletions(-) diff --git a/src/dlls/bigmomma.cpp b/src/dlls/bigmomma.cpp index 9701eb4..3911456 100644 --- a/src/dlls/bigmomma.cpp +++ b/src/dlls/bigmomma.cpp @@ -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 ); diff --git a/src/dlls/cmbasemonster.h b/src/dlls/cmbasemonster.h index 319970a..7951975 100644 --- a/src/dlls/cmbasemonster.h +++ b/src/dlls/cmbasemonster.h @@ -1444,6 +1444,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[]; diff --git a/src/dlls/cmtalkmonster.h b/src/dlls/cmtalkmonster.h index 374d5ee..b718ccf 100644 --- a/src/dlls/cmtalkmonster.h +++ b/src/dlls/cmtalkmonster.h @@ -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 ); diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index 112426b..4f5e701 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -136,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, @@ -211,6 +211,11 @@ int GetMonsterIndex(void) void FreeMonsterIndex(int index) { + /* + if (monsters[index].pMonster->m_srSoundList != NULL) + free(monsters[index].pMonster->m_srSoundList); + monsters[index].pMonster->m_srSoundList = NULL; + */ delete monsters[index].pMonster; monsters[index].monster_index = 0; @@ -256,6 +261,11 @@ void monster_unload(void) { monsters[index].monster_pent->v.flags |= FL_KILLME; + /* + if (monsters[index].pMonster->m_srSoundList != NULL) + free(monsters[index].pMonster->m_srSoundList); + monsters[index].pMonster->m_srSoundList = NULL; + */ delete monsters[index].pMonster; monsters[index].monster_index = 0; @@ -1260,10 +1270,10 @@ int mmDispatchSpawn( edict_t *pent ) if (monsters[index].pMonster != NULL) { // free the soundlists first! - if (monsters[index].pMonster->m_srSoundList != NULL) + /*if (monsters[index].pMonster->m_srSoundList != NULL) free(monsters[index].pMonster->m_srSoundList); monsters[index].pMonster->m_srSoundList = NULL; - + */ delete monsters[index].pMonster; } } @@ -1604,6 +1614,16 @@ void mmClientKill_Post( edict_t *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) @@ -1624,7 +1644,7 @@ static DLL_FUNCTIONS gFunctionTable = NULL, // pfnRestoreGlobalState NULL, // pfnResetGlobalState - NULL, // pfnClientConnect + mmClientConnect, //! pfnClientConnect NULL, // pfnClientDisconnect NULL, // pfnClientKill NULL, // pfnClientPutInServer diff --git a/src/dlls/gargantua.cpp b/src/dlls/gargantua.cpp index a19cfa4..776cbd1 100644 --- a/src/dlls/gargantua.cpp +++ b/src/dlls/gargantua.cpp @@ -815,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 ); } diff --git a/src/dlls/globalreplace.cpp b/src/dlls/globalreplace.cpp index 2774d6b..ceacf3a 100644 --- a/src/dlls/globalreplace.cpp +++ b/src/dlls/globalreplace.cpp @@ -100,7 +100,7 @@ bool AddIndividualSound(edict_t *pMonster, const char *from, const char *to) const char* FindModelReplacement( edict_t *pMonster, const char *from ) { // Individually set models takes priority! - if ( pMonster && !FStringNull(pMonster->v.model)) + if (UTIL_IsValidEntity(pMonster) && !FStringNull(pMonster->v.model)) return STRING(pMonster->v.model); // Find the model @@ -120,7 +120,7 @@ const char* FindModelReplacement( edict_t *pMonster, const char *from ) const char* FindSoundReplacement( edict_t *pMonster, const char *from ) { // Individually set sounds takes priority! - if ( pMonster ) + if (UTIL_IsValidEntity(pMonster)) { CMBaseMonster *castMonster = NULL; @@ -133,7 +133,7 @@ const char* FindSoundReplacement( edict_t *pMonster, const char *from ) if (!FNullEnt(pMonster->v.owner)) castMonster = GetClassPtr((CMBaseMonster *)VARS(pMonster->v.owner)); } - + // If still no valid BaseMonster pointer, full stop, use GSR. if (castMonster && castMonster->m_isrSounds) { diff --git a/src/dlls/hgrunt.cpp b/src/dlls/hgrunt.cpp index c4d8b56..8c534e1 100644 --- a/src/dlls/hgrunt.cpp +++ b/src/dlls/hgrunt.cpp @@ -799,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; diff --git a/src/dlls/massn.cpp b/src/dlls/massn.cpp index d688c86..9ced4b9 100644 --- a/src/dlls/massn.cpp +++ b/src/dlls/massn.cpp @@ -345,7 +345,7 @@ DEFINE_CUSTOM_SCHEDULES( CMMassn ) slMassnSniperAttack, }; -IMPLEMENT_CUSTOM_SCHEDULES( CMMassn, CMBaseMonster ); +IMPLEMENT_CUSTOM_SCHEDULES( CMMassn, CMHGrunt ); //========================================================= // SetActivity diff --git a/src/dlls/nodes.cpp b/src/dlls/nodes.cpp index 727750e..e52f45d 100644 --- a/src/dlls/nodes.cpp +++ b/src/dlls/nodes.cpp @@ -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; @@ -232,9 +236,7 @@ int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, N // func_door if ( FClassnameIs( pevLinkEnt, "func_door" ) || FClassnameIs( pevLinkEnt, "func_door_rotating" ) ) {// ent is a door. - // Can't retrieve door info right now, assume it's a hard wall and don't let the monster go through - return FALSE; - /* + pDoor = ( CMBaseEntity::Instance( pevLinkEnt ) ); if ( ( pevLinkEnt->spawnflags & SF_DOOR_USE_ONLY ) ) @@ -271,7 +273,6 @@ int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, N return FALSE; } - */ } // func_breakable else if ( FClassnameIs( pevLinkEnt, "func_breakable" ) && queryType == NODEGRAPH_STATIC ) @@ -285,6 +286,7 @@ int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, N } return FALSE; +#endif } #if 0 diff --git a/src/dlls/shockroach.cpp b/src/dlls/shockroach.cpp index 4dfd93e..d1968f5 100644 --- a/src/dlls/shockroach.cpp +++ b/src/dlls/shockroach.cpp @@ -26,6 +26,8 @@ #include "schedule.h" #include "weapons.h" +#define SR_AE_JUMPATTACK ( 2 ) + const char *CMShockRoach::pIdleSounds[] = { "shockroach/shock_idle1.wav", @@ -219,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()); } diff --git a/src/dlls/voltigore.cpp b/src/dlls/voltigore.cpp index 1d04cc7..7366174 100644 --- a/src/dlls/voltigore.cpp +++ b/src/dlls/voltigore.cpp @@ -395,11 +395,11 @@ BOOL CMVoltigore::CheckRangeAttack1(float flDot, float flDist) 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; From 12f8eea0110e441c4a21ea77575e2e4804aaeae1 Mon Sep 17 00:00:00 2001 From: Giegue Date: Sat, 1 Jul 2023 18:23:59 -0300 Subject: [PATCH 43/45] Yet another GMR/GSR fix. Monster maximum viewable distance is now customizable. --- src/dlls/apache.cpp | 2 +- src/dlls/massn.cpp | 13 ++++++++++++- src/dlls/monster_api.cpp | 5 +++++ src/dlls/monster_config.cpp | 4 ++++ src/dlls/monsters.cpp | 11 +++++++++-- src/dlls/turret.cpp | 15 +++++++++------ 6 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/dlls/apache.cpp b/src/dlls/apache.cpp index 33d7490..940c65a 100644 --- a/src/dlls/apache.cpp +++ b/src/dlls/apache.cpp @@ -424,7 +424,7 @@ void CMApache :: HuntThink( void ) // if (m_hEnemy == NULL) { - Look( 4092 ); + Look( 4096 ); m_hEnemy = BestVisibleEnemy( ); } diff --git a/src/dlls/massn.cpp b/src/dlls/massn.cpp index 9ced4b9..e0ced67 100644 --- a/src/dlls/massn.cpp +++ b/src/dlls/massn.cpp @@ -31,6 +31,8 @@ #include "effects.h" #include "customentity.h" +extern cvar_t *monster_default_maxrange; + //========================================================= // monster-specific DEFINE's //========================================================= @@ -265,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 { @@ -280,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 ) { diff --git a/src/dlls/monster_api.cpp b/src/dlls/monster_api.cpp index f81c378..7f131a3 100644 --- a/src/dlls/monster_api.cpp +++ b/src/dlls/monster_api.cpp @@ -95,6 +95,8 @@ 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: @@ -165,6 +167,9 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m 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); } diff --git a/src/dlls/monster_config.cpp b/src/dlls/monster_config.cpp index 57a6b97..38994ca 100644 --- a/src/dlls/monster_config.cpp +++ b/src/dlls/monster_config.cpp @@ -890,6 +890,10 @@ void scan_monster_replace(FILE *fp, bool toGSR ) while (get_input(fp, input)) { + // might slip through + if (strlen(input) == 0) + continue; + char *source = strtok(input, " "); char *destination = strtok(NULL, " "); diff --git a/src/dlls/monsters.cpp b/src/dlls/monsters.cpp index 7afb3f8..a04e598 100644 --- a/src/dlls/monsters.cpp +++ b/src/dlls/monsters.cpp @@ -40,6 +40,7 @@ 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); @@ -1663,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(); @@ -2651,6 +2653,11 @@ void CMBaseMonster :: KeyValue( KeyValueData *pkvd ) } pkvd->fHandled = TRUE; } + else if (FStrEq(pkvd->szKeyName, "attackrange")) + { + m_flDistLook = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } else { CMBaseToggle::KeyValue( pkvd ); diff --git a/src/dlls/turret.cpp b/src/dlls/turret.cpp index 5f41199..2ca16e0 100644 --- a/src/dlls/turret.cpp +++ b/src/dlls/turret.cpp @@ -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(); } @@ -1042,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)) { From 272482c5e715e5b7848ccfa106b6abc90a4465a3 Mon Sep 17 00:00:00 2001 From: Giegue Date: Tue, 12 Sep 2023 13:51:25 -0300 Subject: [PATCH 44/45] 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. --- src/dlls/agrunt.cpp | 9 +++++++++ src/dlls/cmbasemonster.h | 4 ++++ src/dlls/dllapi.cpp | 17 ----------------- src/dlls/ggrenade.cpp | 17 ++++++++++++++--- src/dlls/globalreplace.cpp | 9 ++++----- src/dlls/hornet.cpp | 21 ++++++--------------- src/dlls/monster_api.cpp | 4 ++-- src/dlls/monster_config.cpp | 12 ++++++++---- src/dlls/monster_plugin.h | 4 ++-- src/dlls/monsters.cpp | 2 +- src/dlls/pitdrone.cpp | 8 +++++++- src/dlls/sporegrenade.cpp | 8 ++++++++ src/dlls/voltigore.cpp | 7 +++++++ src/dlls/weapons.h | 2 ++ 14 files changed, 74 insertions(+), 50 deletions(-) diff --git a/src/dlls/agrunt.cpp b/src/dlls/agrunt.cpp index 34de414..73d34f8 100644 --- a/src/dlls/agrunt.cpp +++ b/src/dlls/agrunt.cpp @@ -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", @@ -413,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 ) diff --git a/src/dlls/cmbasemonster.h b/src/dlls/cmbasemonster.h index 7951975..b9606c5 100644 --- a/src/dlls/cmbasemonster.h +++ b/src/dlls/cmbasemonster.h @@ -734,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[]; @@ -1381,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; }; //========================================================= @@ -1557,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 diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index 4f5e701..edbfa93 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -211,11 +211,6 @@ int GetMonsterIndex(void) void FreeMonsterIndex(int index) { - /* - if (monsters[index].pMonster->m_srSoundList != NULL) - free(monsters[index].pMonster->m_srSoundList); - monsters[index].pMonster->m_srSoundList = NULL; - */ delete monsters[index].pMonster; monsters[index].monster_index = 0; @@ -261,11 +256,6 @@ void monster_unload(void) { monsters[index].monster_pent->v.flags |= FL_KILLME; - /* - if (monsters[index].pMonster->m_srSoundList != NULL) - free(monsters[index].pMonster->m_srSoundList); - monsters[index].pMonster->m_srSoundList = NULL; - */ delete monsters[index].pMonster; monsters[index].monster_index = 0; @@ -1268,14 +1258,7 @@ int mmDispatchSpawn( edict_t *pent ) for (index = 0; index < MAX_MONSTER_ENTS; index++) { if (monsters[index].pMonster != NULL) - { - // free the soundlists first! - /*if (monsters[index].pMonster->m_srSoundList != NULL) - free(monsters[index].pMonster->m_srSoundList); - monsters[index].pMonster->m_srSoundList = NULL; - */ delete monsters[index].pMonster; - } } // free any allocated keyvalue memory diff --git a/src/dlls/ggrenade.cpp b/src/dlls/ggrenade.cpp index aa2f3d2..099d41f 100644 --- a/src/dlls/ggrenade.cpp +++ b/src/dlls/ggrenade.cpp @@ -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 @@ -309,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; @@ -369,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; @@ -398,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 @@ -451,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 ); diff --git a/src/dlls/globalreplace.cpp b/src/dlls/globalreplace.cpp index ceacf3a..71a0bde 100644 --- a/src/dlls/globalreplace.cpp +++ b/src/dlls/globalreplace.cpp @@ -123,19 +123,19 @@ const char* FindSoundReplacement( edict_t *pMonster, const char *from ) 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 (!FNullEnt(pMonster->v.owner)) + 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 && castMonster->m_isrSounds) + if (castMonster != NULL && castMonster->m_srSoundList != NULL && castMonster->m_isrSounds > 0) { for (int sound = 0; sound < castMonster->m_isrSounds; sound++) { @@ -145,7 +145,6 @@ const char* FindSoundReplacement( edict_t *pMonster, const char *from ) return castMonster->m_srSoundList[sound].destination; } } - // If nothing is found stick to GSR if available } } diff --git a/src/dlls/hornet.cpp b/src/dlls/hornet.cpp index 3649f01..d841745 100644 --- a/src/dlls/hornet.cpp +++ b/src/dlls/hornet.cpp @@ -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; } //========================================================= diff --git a/src/dlls/monster_api.cpp b/src/dlls/monster_api.cpp index 7f131a3..028509a 100644 --- a/src/dlls/monster_api.cpp +++ b/src/dlls/monster_api.cpp @@ -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 diff --git a/src/dlls/monster_config.cpp b/src/dlls/monster_config.cpp index 38994ca..5b2950a 100644 --- a/src/dlls/monster_config.cpp +++ b/src/dlls/monster_config.cpp @@ -74,8 +74,12 @@ void scan_monster_sound(FILE *fp, edict_t *pMonster ) while (get_input(fp, input)) { - char *source = strtok(input, " "); - char *destination = strtok(NULL, " "); + // 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}; @@ -894,8 +898,8 @@ void scan_monster_replace(FILE *fp, bool toGSR ) if (strlen(input) == 0) continue; - char *source = strtok(input, " "); - char *destination = strtok(NULL, " "); + char *source = strtok(input, " \t"); + char *destination = strtok(NULL, " \t"); // Remove all quotes char parse[128] = {0}; diff --git a/src/dlls/monster_plugin.h b/src/dlls/monster_plugin.h index 08d4450..eda2632 100644 --- a/src/dlls/monster_plugin.h +++ b/src/dlls/monster_plugin.h @@ -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 diff --git a/src/dlls/monsters.cpp b/src/dlls/monsters.cpp index a04e598..947a8ce 100644 --- a/src/dlls/monsters.cpp +++ b/src/dlls/monsters.cpp @@ -172,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) ) ) diff --git a/src/dlls/pitdrone.cpp b/src/dlls/pitdrone.cpp index ced809d..7c20a85 100644 --- a/src/dlls/pitdrone.cpp +++ b/src/dlls/pitdrone.cpp @@ -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 ) @@ -141,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; diff --git a/src/dlls/sporegrenade.cpp b/src/dlls/sporegrenade.cpp index 7d8615b..6dca0fb 100644 --- a/src/dlls/sporegrenade.cpp +++ b/src/dlls/sporegrenade.cpp @@ -40,6 +40,9 @@ void CMSporeGrenade::Precache() 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); diff --git a/src/dlls/voltigore.cpp b/src/dlls/voltigore.cpp index 7366174..6bf81ab 100644 --- a/src/dlls/voltigore.cpp +++ b/src/dlls/voltigore.cpp @@ -449,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 diff --git a/src/dlls/weapons.h b/src/dlls/weapons.h index 3fc94dd..d5c15c5 100644 --- a/src/dlls/weapons.h +++ b/src/dlls/weapons.h @@ -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 From 91f34169b5bde5c659fe5359172eeef2bb1a6617 Mon Sep 17 00:00:00 2001 From: Giegue Date: Tue, 12 Sep 2023 16:43:12 -0300 Subject: [PATCH 45/45] Update some texts. --- README.md | 14 ++++++++------ cfg/example_monster.cfg | 28 +++------------------------- cfg/monster_precache.cfg | 8 ++++---- 3 files changed, 15 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index c936417..71eae64 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ 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... @@ -43,13 +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 -The [wiki](https://github.com/JulianR0/monstermod-redo/wiki) contains instructions on how to compile MonsterMod by yourself. +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 @@ -57,11 +57,13 @@ 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. -## 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: -- Rarely, Stukabats will become unable to fly towards their target, standing in air doing seemingly nothing. Cause of bug unknown. +- Rarely, Stukabats will become unable to fly towards their target, standing in air doing seemingly nothing. + +- Monsters are very prone to gibbing when hurt during death animations. There are probably more issues that aren't listed here, I'll attempt to fix them as I find them. Of course, any bug report is welcome. If reporting a bug, try to explain step by step how the bug ocurred. The easier it is to replicate a bug, the easier it is to locate it and fix it. @@ -106,7 +108,7 @@ Current milestones are separated by "Tiers", which are as follows: - 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. +- Attempt to fix bugs as they appear. **[DONE]** ### Tier 5 diff --git a/cfg/example_monster.cfg b/cfg/example_monster.cfg index e403115..02666f4 100755 --- a/cfg/example_monster.cfg +++ b/cfg/example_monster.cfg @@ -2,34 +2,13 @@ // Make a copy of this file and rename it to "_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" diff --git a/cfg/monster_precache.cfg b/cfg/monster_precache.cfg index 3c098a6..97b7e42 100755 --- a/cfg/monster_precache.cfg +++ b/cfg/monster_precache.cfg @@ -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