345 lines
15 KiB
C++
345 lines
15 KiB
C++
|
/* AMX Mod X
|
||
|
* Sven Co-op Module
|
||
|
*
|
||
|
* by the AMX Mod X Development Team
|
||
|
*
|
||
|
* This file is part of AMX Mod X.
|
||
|
*
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify it
|
||
|
* under the terms of the GNU General Public License as published by the
|
||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||
|
* your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful, but
|
||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software Foundation,
|
||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*
|
||
|
* In addition, as a special exception, the author gives permission to
|
||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||
|
* respects for all of the code used other than the HL Engine and MODs
|
||
|
* from Valve. If you modify this file, you may extend this exception
|
||
|
* to your version of the file, but you are not obligated to do so. If
|
||
|
* you do not wish to do so, delete this exception statement from your
|
||
|
* version.
|
||
|
*/
|
||
|
|
||
|
#include "svencoop.h"
|
||
|
|
||
|
//
|
||
|
// EXTERNS
|
||
|
//
|
||
|
|
||
|
int gmsgScoreInfo;
|
||
|
KeyValueData g_kvd;
|
||
|
Trie<char,String> g_allyNameTrie, g_enemyNameTrie;
|
||
|
|
||
|
//
|
||
|
// GLOBALS
|
||
|
//
|
||
|
|
||
|
int g_lastDeadflag[33] = { 0 }, g_grenadeCount = 0,
|
||
|
g_spawnFwd = -1, g_healFwd = -1, g_grenadeFwd = -1;
|
||
|
|
||
|
edict_t *g_grenadeList[32] = { NULL };
|
||
|
|
||
|
//
|
||
|
// AMXX HOOKS
|
||
|
//
|
||
|
|
||
|
void OnAmxxAttach()
|
||
|
{
|
||
|
MF_AddNatives(svencoop_Exports);
|
||
|
|
||
|
// sc_set_displayname
|
||
|
g_kvd.szClassName = "";
|
||
|
g_kvd.szKeyName = "";
|
||
|
g_kvd.szValue = "";
|
||
|
g_kvd.fHandled = 0;
|
||
|
|
||
|
// sc_get_displayname, default displaynames
|
||
|
g_allyNameTrie.Insert("monster_alien_babyvoltigore", 27, String("Friendly Baby Voltigore"));
|
||
|
g_enemyNameTrie.Insert("monster_alien_babyvoltigore", 27, String("Baby Voltigore"));
|
||
|
g_allyNameTrie.Insert("monster_alien_controller", 24, String("Friendly Alien Controller"));
|
||
|
g_enemyNameTrie.Insert("monster_alien_controller", 24, String("Alien Controller"));
|
||
|
g_allyNameTrie.Insert("monster_alien_grunt", 19, String("Friendly Alien Grunt"));
|
||
|
g_enemyNameTrie.Insert("monster_alien_grunt", 19, String("Alien Grunt"));
|
||
|
g_allyNameTrie.Insert("monster_alien_slave", 19, String("Friendly Alien Slave"));
|
||
|
g_enemyNameTrie.Insert("monster_alien_slave", 19, String("Alien Slave"));
|
||
|
g_allyNameTrie.Insert("monster_vortigaunt", 18, String("Friendly Alien Slave"));
|
||
|
g_enemyNameTrie.Insert("monster_vortigaunt", 18, String("Alien Slave"));
|
||
|
g_allyNameTrie.Insert("monster_alien_voltigore", 23, String("Friendly Voltigore"));
|
||
|
g_enemyNameTrie.Insert("monster_alien_voltigore", 23, String("Voltigore"));
|
||
|
g_allyNameTrie.Insert("monster_apache", 14, String("Apache"));
|
||
|
g_enemyNameTrie.Insert("monster_apache", 14, String("Apache"));
|
||
|
g_allyNameTrie.Insert("monster_blkop_apache", 20, String("Apache"));
|
||
|
g_enemyNameTrie.Insert("monster_blkop_apache", 20, String("Apache"));
|
||
|
g_allyNameTrie.Insert("monster_assassin_repel", 22, String("Friendly Male Assassin"));
|
||
|
g_enemyNameTrie.Insert("monster_assassin_repel", 22, String("Male Assassin"));
|
||
|
g_allyNameTrie.Insert("monster_male_assassin", 21, String("Friendly Male Assassin"));
|
||
|
g_enemyNameTrie.Insert("monster_male_assassin", 21, String("Male Assassin"));
|
||
|
g_allyNameTrie.Insert("monster_babycrab", 16, String("Friendly Head Crab"));
|
||
|
g_enemyNameTrie.Insert("monster_babycrab", 16, String("Head Crab"));
|
||
|
g_allyNameTrie.Insert("monster_headcrab", 16, String("Friendly Head Crab"));
|
||
|
g_enemyNameTrie.Insert("monster_headcrab", 16, String("Head Crab"));
|
||
|
g_allyNameTrie.Insert("monster_babygarg", 16, String("Friendly Baby Gargantua"));
|
||
|
g_enemyNameTrie.Insert("monster_babygarg", 16, String("Baby Gargantua"));
|
||
|
g_allyNameTrie.Insert("monster_barnacle", 16, String("Barnacle"));
|
||
|
g_enemyNameTrie.Insert("monster_barnacle", 16, String("Barnacle"));
|
||
|
g_allyNameTrie.Insert("monster_barney", 14, String("Barney"));
|
||
|
g_enemyNameTrie.Insert("monster_barney", 14, String("Barnabus"));
|
||
|
g_allyNameTrie.Insert("monster_bigmomma", 16, String("Friendly Big Momma"));
|
||
|
g_enemyNameTrie.Insert("monster_bigmomma", 16, String("Big Momma"));
|
||
|
g_allyNameTrie.Insert("monster_blkop_osprey", 20, String("Friendly Black Ops Osprey"));
|
||
|
g_enemyNameTrie.Insert("monster_blkop_osprey", 20, String("Black Ops Osprey"));
|
||
|
g_allyNameTrie.Insert("monster_bloater", 15, String("Friendly Bloater"));
|
||
|
g_enemyNameTrie.Insert("monster_bloater", 15, String("Bloater"));
|
||
|
g_allyNameTrie.Insert("monster_bullchicken", 19, String("Friendly Bull Squid"));
|
||
|
g_enemyNameTrie.Insert("monster_bullchicken", 19, String("Bull Squid"));
|
||
|
g_allyNameTrie.Insert("monster_chumtoad", 16, String("Chubby"));
|
||
|
g_enemyNameTrie.Insert("monster_chumtoad", 16, String("Chumtoad"));
|
||
|
g_allyNameTrie.Insert("monster_cleansuit_scientist", 27, String("Cleansuit Scientist"));
|
||
|
g_enemyNameTrie.Insert("monster_cleansuit_scientist", 27, String("Cleansuit Scientist"));
|
||
|
g_allyNameTrie.Insert("monster_cockroach", 17, String("Roach"));
|
||
|
g_enemyNameTrie.Insert("monster_cockroach", 17, String("Roach"));
|
||
|
g_allyNameTrie.Insert("monster_gargantua", 17, String("Friendly Gargantua"));
|
||
|
g_enemyNameTrie.Insert("monster_gargantua", 17, String("Gargantua"));
|
||
|
g_allyNameTrie.Insert("monster_gman", 12, String("Government Man"));
|
||
|
g_enemyNameTrie.Insert("monster_gman", 12, String("Government Man"));
|
||
|
g_allyNameTrie.Insert("monster_gonome", 14, String("Friendly Gonome"));
|
||
|
g_enemyNameTrie.Insert("monster_gonome", 14, String("Gonome"));
|
||
|
g_allyNameTrie.Insert("monster_houndeye", 16, String("Friendly Hound Eye"));
|
||
|
g_enemyNameTrie.Insert("monster_houndeye", 16, String("Hound Eye"));
|
||
|
g_allyNameTrie.Insert("monster_human_assassin", 22, String("Friendly Female Assassin"));
|
||
|
g_enemyNameTrie.Insert("monster_human_assassin", 22, String("Female Assassin"));
|
||
|
g_allyNameTrie.Insert("monster_human_grunt", 19, String("Friendly Human Grunt"));
|
||
|
g_enemyNameTrie.Insert("monster_human_grunt", 19, String("Human Grunt"));
|
||
|
g_allyNameTrie.Insert("monster_grunt_repel", 19, String("Friendly Human Grunt"));
|
||
|
g_enemyNameTrie.Insert("monster_grunt_repel", 19, String("Human Grunt"));
|
||
|
g_allyNameTrie.Insert("monster_human_grunt_ally", 24, String("Ally Grunt"));
|
||
|
g_enemyNameTrie.Insert("monster_human_grunt_ally", 24, String("Enemy Grunt"));
|
||
|
g_allyNameTrie.Insert("monster_grunt_ally_repel", 24, String("Ally Grunt"));
|
||
|
g_enemyNameTrie.Insert("monster_grunt_ally_repel", 24, String("Enemy Grunt"));
|
||
|
g_allyNameTrie.Insert("monster_human_medic_ally", 24, String("Medic Grunt"));
|
||
|
g_enemyNameTrie.Insert("monster_human_medic_ally", 24, String("Enemy Medic Grunt"));
|
||
|
g_allyNameTrie.Insert("monster_medic_ally_repel", 24, String("Medic Grunt"));
|
||
|
g_enemyNameTrie.Insert("monster_medic_ally_repel", 24, String("Enemy Medic Grunt"));
|
||
|
g_allyNameTrie.Insert("monster_human_torch_ally", 24, String("Torch Grunt"));
|
||
|
g_enemyNameTrie.Insert("monster_human_torch_ally", 24, String("Enemy Torch Grunt"));
|
||
|
g_allyNameTrie.Insert("monster_torch_ally_repel", 24, String("Torch Grunt"));
|
||
|
g_enemyNameTrie.Insert("monster_torch_ally_repel", 24, String("Enemy Torch Grunt"));
|
||
|
g_allyNameTrie.Insert("monster_hwgrunt", 15, String("Friendly Heavy Weapons Grunt"));
|
||
|
g_enemyNameTrie.Insert("monster_hwgrunt", 15, String("Heavy Weapons Grunt"));
|
||
|
g_allyNameTrie.Insert("monster_hwgrunt_repel", 21, String("Friendly Heavy Weapons Grunt"));
|
||
|
g_enemyNameTrie.Insert("monster_hwgrunt_repel", 21, String("Heavy Weapons Grunt"));
|
||
|
g_allyNameTrie.Insert("monster_ichthyosaur", 19, String("Friendly Ichthyosaur"));
|
||
|
g_enemyNameTrie.Insert("monster_ichthyosaur", 19, String("Ichthyosaur"));
|
||
|
g_allyNameTrie.Insert("monster_leech", 13, String("Leech"));
|
||
|
g_enemyNameTrie.Insert("monster_leech", 13, String("Leech"));
|
||
|
g_allyNameTrie.Insert("monster_miniturret", 18, String("Mini-Turret"));
|
||
|
g_enemyNameTrie.Insert("monster_miniturret", 18, String("Mini-Turret"));
|
||
|
g_allyNameTrie.Insert("monster_nihilanth", 17, String(""));
|
||
|
g_enemyNameTrie.Insert("monster_nihilanth", 17, String(""));
|
||
|
g_allyNameTrie.Insert("monster_osprey", 14, String("Friendly Osprey Helicopter"));
|
||
|
g_enemyNameTrie.Insert("monster_osprey", 14, String("Osprey Helicopter"));
|
||
|
g_allyNameTrie.Insert("monster_otis", 12, String("Otis"));
|
||
|
g_enemyNameTrie.Insert("monster_otis", 12, String("Enemy Otis"));
|
||
|
g_allyNameTrie.Insert("monster_pitdrone", 16, String("Friendly Pit Drone"));
|
||
|
g_enemyNameTrie.Insert("monster_pitdrone", 16, String("Pit Drone"));
|
||
|
g_allyNameTrie.Insert("monster_rat", 11, String("Rat"));
|
||
|
g_enemyNameTrie.Insert("monster_rat", 11, String("Rat"));
|
||
|
g_allyNameTrie.Insert("monster_robogrunt", 17, String("Friendly Robo Grunt"));
|
||
|
g_enemyNameTrie.Insert("monster_robogrunt", 17, String("Robo Grunt"));
|
||
|
g_allyNameTrie.Insert("monster_robogrunt_repel", 23, String("Friendly Robo Grunt"));
|
||
|
g_enemyNameTrie.Insert("monster_robogrunt_repel", 23, String("Robo Grunt"));
|
||
|
g_allyNameTrie.Insert("monster_scientist", 17, String("Scientist"));
|
||
|
g_enemyNameTrie.Insert("monster_scientist", 17, String("Scientist"));
|
||
|
g_allyNameTrie.Insert("monster_sitting_scientist", 25, String("Scientist"));
|
||
|
g_enemyNameTrie.Insert("monster_sitting_scientist", 25, String("Scientist"));
|
||
|
g_allyNameTrie.Insert("monster_sentry", 14, String("Sentry Turret"));
|
||
|
g_enemyNameTrie.Insert("monster_sentry", 14, String("Sentry Turret"));
|
||
|
g_allyNameTrie.Insert("monster_shockroach", 18, String("Friendly Shock Roach"));
|
||
|
g_enemyNameTrie.Insert("monster_shockroach", 18, String("Shock Roach"));
|
||
|
g_allyNameTrie.Insert("monster_shocktrooper", 20, String("Friendly Shock Trooper"));
|
||
|
g_enemyNameTrie.Insert("monster_shocktrooper", 20, String("Shock Trooper"));
|
||
|
g_allyNameTrie.Insert("monster_snark", 13, String("Snark"));
|
||
|
g_enemyNameTrie.Insert("monster_snark", 13, String("Snark"));
|
||
|
g_allyNameTrie.Insert("monster_tentacle", 16, String("Tentacle"));
|
||
|
g_enemyNameTrie.Insert("monster_tentacle", 16, String("Tentacle"));
|
||
|
g_allyNameTrie.Insert("monster_tentaclemaw", 19, String("Tentacle"));
|
||
|
g_enemyNameTrie.Insert("monster_tentaclemaw", 19, String("Tentacle"));
|
||
|
g_allyNameTrie.Insert("monster_turret", 14, String("Turret"));
|
||
|
g_enemyNameTrie.Insert("monster_turret", 14, String("Turret"));
|
||
|
g_allyNameTrie.Insert("monster_zombie", 14, String("Friendly Zombie"));
|
||
|
g_enemyNameTrie.Insert("monster_zombie", 14, String("Zombie"));
|
||
|
g_allyNameTrie.Insert("monster_zombie_barney", 21, String("Friendly Zombie Barney"));
|
||
|
g_enemyNameTrie.Insert("monster_zombie_barney", 21, String("Zombie Barney"));
|
||
|
g_allyNameTrie.Insert("monster_zombie_soldier", 22, String("Friendly Zombie Soldier"));
|
||
|
g_enemyNameTrie.Insert("monster_zombie_soldier", 22, String("Zombie Soldier"));
|
||
|
}
|
||
|
|
||
|
void OnPluginsLoaded()
|
||
|
{
|
||
|
g_spawnFwd = MF_RegisterForward("sc_client_spawn", ET_IGNORE, FP_CELL, FP_DONE);
|
||
|
g_healFwd = MF_RegisterForward("sc_client_heal", ET_IGNORE, FP_CELL, FP_CELL, FP_FLOAT, FP_CELL, FP_CELL, FP_DONE);
|
||
|
g_grenadeFwd = MF_RegisterForward("sc_grenade_throw", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// METAMOD HOOKS
|
||
|
//
|
||
|
|
||
|
/***GetEntityAPI2******************/
|
||
|
|
||
|
// sc_client_heal
|
||
|
void DispatchThink(edict_t *pEntity)
|
||
|
{
|
||
|
if(g_healFwd != -1 && UTIL_IsMonster(pEntity))
|
||
|
*((float *)pEntity->pvPrivateData + OFFSET_LAST_HEALTH) = pEntity->v.health;
|
||
|
|
||
|
RETURN_META(MRES_IGNORED);
|
||
|
}
|
||
|
|
||
|
// sc_get_displayname
|
||
|
void DispatchKeyValue(edict_t *pentKeyvalue, KeyValueData *pkvd)
|
||
|
{
|
||
|
// catch displayname and store it ourselves for our native
|
||
|
// TODO: store this somewhere else besides in the pev
|
||
|
if(FStrEq(pkvd->szKeyName, "displayname"))
|
||
|
pentKeyvalue->v.message = ALLOC_STRING(pkvd->szValue);
|
||
|
|
||
|
RETURN_META(MRES_IGNORED);
|
||
|
}
|
||
|
|
||
|
// sc_client_spawn
|
||
|
void ClientPutInServer(edict_t *pPlayer)
|
||
|
{
|
||
|
g_lastDeadflag[ENTINDEX(pPlayer)] = -1;
|
||
|
|
||
|
RETURN_META(MRES_IGNORED);
|
||
|
}
|
||
|
|
||
|
// sc_client_spawn / sc_client_heal
|
||
|
void PlayerPreThink(edict_t *pPlayer)
|
||
|
{
|
||
|
if(g_spawnFwd != -1)
|
||
|
{
|
||
|
int index = ENTINDEX(pPlayer);
|
||
|
|
||
|
if(g_lastDeadflag[index] == -1 || (g_lastDeadflag[index] != DEAD_NO && pPlayer->v.deadflag == DEAD_NO))
|
||
|
MF_ExecuteForward(g_spawnFwd, index);
|
||
|
|
||
|
g_lastDeadflag[index] = pPlayer->v.deadflag;
|
||
|
}
|
||
|
|
||
|
if(g_healFwd != -1)
|
||
|
*((float *)pPlayer->pvPrivateData + OFFSET_LAST_HEALTH) = pPlayer->v.health;
|
||
|
|
||
|
RETURN_META(MRES_IGNORED);
|
||
|
}
|
||
|
|
||
|
// sc_grenade_throw
|
||
|
void StartFrame()
|
||
|
{
|
||
|
if(g_grenadeFwd == -1 || !g_grenadeCount)
|
||
|
RETURN_META(MRES_IGNORED);
|
||
|
|
||
|
edict_t *pGrenade = g_grenadeList[0];
|
||
|
|
||
|
if(!FNullEnt(pGrenade) && pGrenade->v.owner)
|
||
|
{
|
||
|
const char *model = STRING(pGrenade->v.model);
|
||
|
|
||
|
int wId = 0;
|
||
|
switch(model[7])
|
||
|
{
|
||
|
case 'g': wId = SCW_ARGRENADE; break; // models/grenade.mdl
|
||
|
case 'w': wId = SCW_HANDGRENADE; break; // models/w_grenade.mdl
|
||
|
//case 'c': wId = SCW_BANANA; break; // models/cretegibs.mdl
|
||
|
}
|
||
|
|
||
|
if(wId) MF_ExecuteForward(g_grenadeFwd, ENTINDEX(pGrenade->v.owner),
|
||
|
ENTINDEX(pGrenade), wId, UTIL_IsPlayer(pGrenade->v.owner));
|
||
|
}
|
||
|
|
||
|
// shift the list
|
||
|
g_grenadeList[0] = NULL;
|
||
|
if(--g_grenadeCount)
|
||
|
{
|
||
|
for(int i=1;i<=g_grenadeCount;i++) g_grenadeList[i-1] = g_grenadeList[i];
|
||
|
g_grenadeList[g_grenadeCount] = NULL;
|
||
|
}
|
||
|
|
||
|
RETURN_META(MRES_IGNORED);
|
||
|
}
|
||
|
|
||
|
/***GetEntityAPI2_Post*************/
|
||
|
|
||
|
// sc_set_frags
|
||
|
void ServerActivate_Post(struct edict_s *, int, int)
|
||
|
{
|
||
|
gmsgScoreInfo = GET_USER_MSG_ID(PLID, "ScoreInfo", NULL);
|
||
|
RETURN_META(MRES_IGNORED);
|
||
|
}
|
||
|
|
||
|
/***GetEngineAPI*******************/
|
||
|
|
||
|
// sc_client_heal
|
||
|
void EmitSound(edict_t *pEntity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch)
|
||
|
{
|
||
|
if(g_healFwd == -1 || !UTIL_IsPlayer(pEntity) || channel != CHAN_WEAPON || strcmp(sample, "items/medshot4.wav") != 0)
|
||
|
RETURN_META(MRES_IGNORED);
|
||
|
|
||
|
Vector trStart = pEntity->v.origin;
|
||
|
|
||
|
if(pEntity->v.flags & FL_DUCKING) trStart.z += 12.0;
|
||
|
else trStart.z += 28.0;
|
||
|
|
||
|
Vector trEnd = trStart + gpGlobals->v_forward * 32;
|
||
|
|
||
|
TraceResult tr;
|
||
|
TRACE_LINE(trStart, trEnd, dont_ignore_monsters, pEntity, &tr);
|
||
|
|
||
|
if(tr.flFraction == 1.0)
|
||
|
TRACE_HULL(trStart, trEnd, dont_ignore_monsters, head_hull, pEntity, &tr);
|
||
|
|
||
|
if(!FNullEnt(tr.pHit))
|
||
|
{
|
||
|
float amount = tr.pHit->v.health - *((float *)tr.pHit->pvPrivateData + OFFSET_LAST_HEALTH);
|
||
|
|
||
|
if(UTIL_IsPlayer(tr.pHit))
|
||
|
MF_ExecuteForward(g_healFwd, ENTINDEX(pEntity), ENTINDEX(tr.pHit), amount, 1, 1);
|
||
|
|
||
|
else if(UTIL_IsMonster(tr.pHit))
|
||
|
MF_ExecuteForward(g_healFwd, ENTINDEX(pEntity), ENTINDEX(tr.pHit), amount, 0, *((int *)tr.pHit->pvPrivateData + OFFSET_MONSTER_ALLY));
|
||
|
}
|
||
|
|
||
|
RETURN_META(MRES_IGNORED);
|
||
|
}
|
||
|
|
||
|
/***GetEngineAPI_Post**************/
|
||
|
|
||
|
// sc_grenade_throw
|
||
|
void SetModel_Post(edict_t *pEntity, const char *model)
|
||
|
{
|
||
|
if(g_grenadeFwd == -1)
|
||
|
RETURN_META(MRES_IGNORED);
|
||
|
|
||
|
const char *classname = STRING(pEntity->v.classname);
|
||
|
|
||
|
if(!pEntity->v.owner && classname[0] == 'g' && classname[2] == 'e' && model[7] == 'g')
|
||
|
{
|
||
|
if(g_grenadeCount < sizeof g_grenadeList)
|
||
|
g_grenadeList[g_grenadeCount++] = pEntity;
|
||
|
}
|
||
|
|
||
|
RETURN_META(MRES_IGNORED);
|
||
|
}
|