#include "ns.h" #include //useful almost everywhere #include #include CSpawn ns_spawnpoints; CPlayer g_player[33]; edict_t *player_edicts[33]; BOOL CheckForPublic(const char *publicname); int gmsgHudText2=0; int ChangeclassForward = -1; int BuiltForward = -1; int SpawnForward = -1; int TeamForward = -1; // Index of last entity hooked in CreateNamedEntity int iCreateEntityIndex; BOOL iscombat; int gmsgScoreInfo=0; // Module is attaching to AMXX void OnAmxxAttach() { MF_AddNatives(ns_misc_natives); MF_AddNatives(ns_pdata_natives); } // All plugins have loaded (probably around Spawning worldspawn.. void OnPluginsLoaded() { gmsgHudText2 = GET_USER_MSG_ID(&Plugin_info,"HudText2",NULL); // Check the map name and see if it's combat or not. iscombat=FALSE; char mapname[255]; strcpy(mapname,STRING(gpGlobals->mapname)); if ((mapname[0]=='c' || mapname[0]=='C') && (mapname[1]=='o' || mapname[1]=='O') && mapname[2]=='_') iscombat=TRUE; ChangeclassForward = MF_RegisterForward("client_changeclass", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE); // No sense in this if it's combat.. if (!iscombat) { if (CheckForPublic("client_built")) { BuiltForward = MF_RegisterForward("client_built", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE); g_pengfuncsTable_Post->pfnAlertMessage=AlertMessage_Post; g_pengfuncsTable->pfnCreateNamedEntity=CreateNamedEntity; } else { g_pengfuncsTable_Post->pfnAlertMessage=NULL; g_pengfuncsTable->pfnCreateNamedEntity=NULL; } } else { // no need for these hooks in co g_pengfuncsTable_Post->pfnAlertMessage=NULL; g_pengfuncsTable->pfnCreateNamedEntity=NULL; } SpawnForward = MF_RegisterForward("client_spawn",ET_IGNORE,FP_CELL/*id*/,FP_DONE); TeamForward = MF_RegisterForward("client_changeteam",ET_IGNORE,FP_CELL/*id*/,FP_CELL/*new team*/,FP_CELL/*old team*/,FP_DONE); } int DispatchSpawn(edict_t *pEntity) { // Everything starting up: // - Reset CPlayer classes // - Reset CSpawn classes if (FStrEq(STRING(pEntity->v.classname),"worldspawn")) { int i; for (i=0;i<=32;i++) { CPlayer *player = GET_PLAYER_I(i); player->Reset(); } ns_spawnpoints.clear(); } else if (FStrEq(STRING(pEntity->v.classname),"info_player_start")) { // Mark down the ready room spawn point. ns_spawnpoints.put(0,pEntity->v.origin); } else if (FStrEq(STRING(pEntity->v.classname),"info_team_start")) { // Mark down the team based spawn point. ns_spawnpoints.put(pEntity->v.team,pEntity->v.origin); } RETURN_META_VALUE(MRES_IGNORED, 0); } void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax) { // Mark down proper edicts (fixes INDEXENT() bug). // Reset CPlayer classes (again?) for(int i = 1; i <= gpGlobals->maxClients;i++) { player_edicts[i]=pEdictList + i; CPlayer *player = GET_PLAYER_I(i); player->edict=pEdictList + i; //player->index=i; player->pev=&player->edict->v; player->oldimpulse=0; player->Reset(); player->connected=false; } RETURN_META(MRES_IGNORED); } void PlayerPreThink(edict_t *pEntity) { CPlayer *player = GET_PLAYER_E(pEntity); player->PreThink(); RETURN_META(MRES_IGNORED); } void PlayerPreThink_Post(edict_t *pEntity) { CPlayer *player = GET_PLAYER_E(pEntity); player->PreThink_Post(); RETURN_META(MRES_IGNORED); } void PlayerPostThink_Post(edict_t *pEntity) { CPlayer *player = GET_PLAYER_E(pEntity); player->PostThink_Post(); RETURN_META(MRES_IGNORED); } // Parse log messages here for any desired information (structure_built, etc.) // The following logs are needed: // name triggered "structure_built" (type "type") -- client_built // name changed role to "class" -- client_changeclass void AlertMessage_Post(ALERT_TYPE atype, char *szFmt, ...) { if (atype != at_logged) RETURN_META(MRES_IGNORED); va_list LogArg; char *sz, *message; const char *b; char szParm[5][128]; int argc,len; va_start(LogArg, szFmt); sz = va_arg(LogArg, char *); va_end(LogArg); message = sz; b=message; argc=0; // Parse the damn message while (*b && *b!='\0' && argc<5) { len=0; if (*b == '"') { b++; // Skip over the " while (*b && *b != '"' && len < 127) { szParm[argc][len]=*b; b++; len++; } //*szParm='\0'; szParm[argc][len]='\0'; if (*b && *b == '"' && *b+1 != '\0' && *b+2 != '\0') { b+=2; argc++; } else { argc++; break; } } else if (*b == '(') { b++; // Skip over the ( while (*b && *b != ')' && len < 127) { szParm[argc][len]=*b; b++; len++; } szParm[argc][len]='\0'; if (*b && *b == ')' && *b+1 != '\0' && *b+2 != '\0') { b+=2; argc++; } else { argc++; break; } } else { while (*b && *b != '"' && *b != '(' && len < 127) { szParm[argc][len]=*b; b++; len++; } szParm[argc][len]='\0'; if (*b != '"' && *b != '(' && *b != '\0' && *b+1 != '\0' && *b+2 != '\0') { b+=2; argc++; } else { argc++; if (*b == '\0') break; } } } /* if (argc == 3) // changed role to = 3 long { if (FStrEq((const char *)szParm[1],"changed role to ")) { int index=LogToIndex(szParm[0]); if (!index) RETURN_META(MRES_IGNORED); CPlayer *player = GET_PLAYER_I(index); int iImpulse=0; int iClass=1; if (INDEXENT2(index)->v.team != 0) { if (FStrEq((const char *)szParm[2],"gestate")) { iImpulse = player->oldpev.impulse; } if (FStrEq((const char *)szParm[2],"none")) iClass=0; if (iClass > 0) { ns2amx_changeclass.execute(index,player->oldpev.iuser3,player->pev->iuser3,iImpulse); } } } } else */ if (argc == 4) // structure_built / structure_destroyed are 4 long { //"NAME" triggered "structure_built" (type "TYPE") if (FStrEq((const char *)szParm[2],"structure_built")) { int index=LogToIndex(szParm[0]); if (!index) RETURN_META(MRES_IGNORED); CPlayer *player = GET_PLAYER_I(index); int iForward=0; int iType=player->pev->impulse; if (FStrEq((const char *)szParm[3],"type \"team_hive\"")) { iForward=2; iCreateEntityIndex=Find_Building_Hive(); } else if (FStrEq((const char *)szParm[3],"type \"offensechamber\"")) { iForward=2; } else if (FStrEq((const char *)szParm[3],"type \"movementchamber\"")) { iForward=2; } else if (FStrEq((const char *)szParm[3],"type \"sensorychamber\"")) { iForward=2; } else if (FStrEq((const char *)szParm[3],"type \"defensechamber\"")) { iForward=2; } else if (FStrEq((const char *)szParm[3],"type \"alienresourcetower\"")) { iForward=2; } else { iForward = 1; } // ns2amx_built.execute(index,iCreateEntityIndex,iForward,iType); if (BuiltForward != -1) { MF_ExecuteForward(BuiltForward, index, FStrEq((const char *)szParm[3],"type \"weapon_mine\"") ? 0 : iCreateEntityIndex, iForward, iType); } iCreateEntityIndex=0; } } RETURN_META(MRES_IGNORED); } // We hook newly created entities here. // This is where we check for client_built created entities. edict_t* CreateNamedEntity(int className) { if (iscombat) RETURN_META_VALUE(MRES_IGNORED,0); edict_t *pEntity; // Incase another plugin supercedes/overrides, use their returned value here. // (Untested). if (gpMetaGlobals->status >= MRES_OVERRIDE) { pEntity=META_RESULT_OVERRIDE_RET(edict_t *); iCreateEntityIndex=ENTINDEX(pEntity); RETURN_META_VALUE(MRES_IGNORED, false); } else { pEntity=CREATE_NAMED_ENTITY(className); if (!FNullEnt(pEntity)) { iCreateEntityIndex=ENTINDEX(pEntity); RETURN_META_VALUE(MRES_SUPERCEDE,pEntity); } RETURN_META_VALUE(MRES_SUPERCEDE,pEntity); } RETURN_META_VALUE(MRES_IGNORED,false); } // Map is changing/server is shutting down. // We do all cleanup routines here, since, as noted in metamod's dllapi // ServerDeactivate is the very last function called before the server loads up a new map. void ServerDeactivate(void) { for (int i=1;i<=gpGlobals->maxClients;i++) { CPlayer *player = GET_PLAYER_I(i); if (player->connected) player->Disconnect(); } ns_spawnpoints.clear(); RETURN_META(MRES_IGNORED); } // Reset player data here.. qboolean ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ]) { // Client's connecting. Freshen up his save data, and mark him as being connected. CPlayer *player = GET_PLAYER_E(pEntity); player->Connect(); RETURN_META_VALUE(MRES_HANDLED,0); } void ClientDisconnect(edict_t *pEntity) { // Client is disconnecting, clear all his saved information. CPlayer *player = GET_PLAYER_E(pEntity); player->Disconnect(); RETURN_META(MRES_HANDLED); } // NS resets pev->fov every single frame, but this is called right before the data is sent to the client. // Reset FOV if we need to. void UpdateClientData( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) { edict_t *pEntity = (edict_t*)ent; CPlayer *player = GET_PLAYER_E(pEntity); if (player->foved) pEntity->v.fov = player->fov; RETURN_META(MRES_HANDLED); } int LogToIndex(char logline[128]) { char *cname; // Format of log line: // name // We need to find their ID from their name... int x,y=0; char cindex[64]; // first we find the location of the start of the index // Name can contain <>'s, so we go from the end up. for (x=strlen(logline);x>=0;x--) { if (logline[x]=='<') { y++; if (y==3) { y=x; break; } } } // We found the end of the name, now copy the rest down. y--; x=0; while (x<=y) { cindex[x]=logline[x]; x++; } cindex[x]='\0'; // Now we have their name, now cycle through all players to find which index it is for (x=1;x<=gpGlobals->maxClients;x++) { cname=strdup(cindex); if (!FNullEnt(INDEXENT2(x))) { if (FStrEq(cname,STRING(INDEXENT2(x)->v.netname))) { return x; } } } return 0; } int Find_Building_Hive(void) { edict_t *pEntity=NULL; while ((pEntity = UTIL_FindEntityByString(pEntity,"classname","team_hive"))) { if (pEntity->v.health > 0 && pEntity->v.solid > 0 && pEntity->v.fuser1 < 1000) { return ENTINDEX(pEntity); } } return 0; } int AMX_MAKE_STRING(AMX *oPlugin, cell tParam, int &iLength) { char *szNewValue = MF_GetAmxString(oPlugin, tParam, 0, &iLength); return ALLOC_STRING(szNewValue); } // Makes a char pointer out of an AMX cell. char *AMX_GET_STRING(AMX *oPlugin, cell tParam, int &iLength) { char *szNewValue = MF_GetAmxString(oPlugin, tParam, 0, &iLength); return (char*)STRING(ALLOC_STRING(szNewValue)); } edict_t *UTIL_PlayerByIndexE( int playerIndex ) { if ( playerIndex > 0 && playerIndex <= gpGlobals->maxClients ) { edict_t *pPlayerEdict = INDEXENT2( playerIndex ); if ( pPlayerEdict && !pPlayerEdict->free ) { return pPlayerEdict; } } return NULL; } edict_t *UTIL_FindEntityByString(edict_t *pentStart, const char *szKeyword, const char *szValue) { edict_t *pentEntity; pentEntity=FIND_ENTITY_BY_STRING(pentStart, szKeyword, szValue); if(!FNullEnt(pentEntity)) return pentEntity; return NULL; } BOOL CheckForPublic(const char *publicname) { AMX* amx; char blah[64]; strncpy(blah,publicname,63); int iFunctionIndex; int i=0; // Loop through all running scripts while((amx=MF_GetScriptAmx(i++))!=NULL) { // Scan for public if (MF_AmxFindPublic(amx, blah, &iFunctionIndex) == AMX_ERR_NONE) { // Public was found. return TRUE; } } return FALSE; // no public found in any loaded script }