/* 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 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); }