Merge of rewritten NS module into trunk

This commit is contained in:
Steve Dudenhoeffer
2007-08-02 16:20:32 +00:00
parent 48022d3c5c
commit c604eefde0
44 changed files with 7697 additions and 1804 deletions

553
dlls/ns/natives/general.cpp Normal file
View File

@ -0,0 +1,553 @@
/* AMX Mod X
* Natural Selection 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 <string.h>
#include "../sdk/amxxmodule.h"
#include "cbase.h" // TakeDamage
#include "../ns.h"
#include "../utilfunctions.h"
#include "../NEW_Util.h"
#include "../GameManager.h"
#include "../SpawnManager.h"
#include "../LocationManager.h"
#include "../TitleManager.h"
#include "../CPlayer.h"
edict_t* avhgameplay=NULL;
// drop-in replacement for user_kill
static cell AMX_NATIVE_CALL ns_user_kill(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
// 2 is commander, never slay commander
if (player->GetPev()->iuser3 == 2)
{
return 0;
}
if (MF_IsPlayerIngame(params[1]) && MF_IsPlayerAlive(params[1]))
{
REAL bef = player->GetPev()->frags;
edict_t *pEntity = CREATE_NAMED_ENTITY(MAKE_STRING("trigger_hurt"));
if (pEntity)
{
KeyValueData kvd;
kvd.szClassName="trigger_hurt";
kvd.szKeyName="classname";
kvd.szValue="trigger_hurt";
kvd.fHandled=0;
MDLL_KeyValue(pEntity,&kvd);
kvd.szClassName="trigger_hurt";
kvd.szKeyName="dmg";
kvd.szValue="50000.0";
kvd.fHandled=0;
MDLL_KeyValue(pEntity,&kvd);
kvd.szClassName="trigger_hurt";
kvd.szKeyName="damagetype";
kvd.szValue="1";
kvd.fHandled=0;
MDLL_KeyValue(pEntity,&kvd);
kvd.szClassName="trigger_hurt";
kvd.szKeyName="origin";
kvd.szValue="8192 8192 8192";
kvd.fHandled=0;
MDLL_KeyValue(pEntity,&kvd);
MDLL_Spawn(pEntity);
pEntity->v.classname=MAKE_STRING("slay");
MDLL_Touch(pEntity,player->GetEdict());
REMOVE_ENTITY(pEntity);
}
// If the optional parameter is 1, restore the frag count
if (params[2])
{
player->GetPev()->frags = bef;
}
return 1;
}
return 0;
}
// drop-in replacement for user_slap
#define ANGLEVECTORS (*g_engfuncs.pfnAngleVectors)
static cell AMX_NATIVE_CALL ns_user_slap(AMX *amx, cell *params) /* 2 param */
{
CreatePlayerPointer(amx,params[1]);
int power = abs((int)params[2]);
// Check if commander, if player is comm then stop
if (player->GetPev()->iuser3 == 2)
{
return 0;
}
if (MF_IsPlayerIngame(player->index()) && MF_IsPlayerAlive(player->index()))
{
if (player->GetPev()->health <= power)
{
float bef = player->GetPev()->frags;
/*MDLL_ClientKill(pPlayer->pEdict);*/
edict_t *pEntity = CREATE_NAMED_ENTITY(MAKE_STRING("trigger_hurt"));
if (pEntity)
{
KeyValueData kvd;
kvd.szClassName="trigger_hurt";
kvd.szKeyName="classname";
kvd.szValue="trigger_hurt";
kvd.fHandled=0;
MDLL_KeyValue(pEntity,&kvd);
kvd.szClassName="trigger_hurt";
kvd.szKeyName="dmg";
kvd.szValue="20000.0";
kvd.fHandled=0;
MDLL_KeyValue(pEntity,&kvd);
kvd.szClassName="trigger_hurt";
kvd.szKeyName="damagetype";
kvd.szValue="1";
kvd.fHandled=0;
MDLL_KeyValue(pEntity,&kvd);
kvd.szClassName="trigger_hurt";
kvd.szKeyName="origin";
kvd.szValue="8192 8192 8192";
kvd.fHandled=0;
MDLL_KeyValue(pEntity,&kvd);
MDLL_Spawn(pEntity);
pEntity->v.classname=MAKE_STRING("slap");
MDLL_Touch(pEntity,player->GetEdict());
REMOVE_ENTITY(pEntity);
}
player->GetPev()->frags = bef;
}
else
{
int numparam = *params/sizeof(cell);
if (numparam<3 || params[3])
{
player->GetPev()->velocity.x += RANDOM_LONG(-600,600);
player->GetPev()->velocity.y += RANDOM_LONG(-180,180);
player->GetPev()->velocity.z += RANDOM_LONG(100,200);
}
else
{
vec3_t v_forward, v_right;
vec3_t vang = player->GetPev()->angles;
float fang[3];
fang[0] = vang.x;
fang[1] = vang.y;
fang[2] = vang.z;
ANGLEVECTORS( fang, v_forward, v_right, NULL );
player->GetPev()->velocity = player->GetPev()->velocity + v_forward * 220 + Vector(0,0,200);
}
player->GetPev()->punchangle.x = RANDOM_LONG(-10,10);
player->GetPev()->punchangle.y = RANDOM_LONG(-10,10);
player->GetPev()->health -= power;
int armor = (int)player->GetPev()->armorvalue;
armor -= power;
if (armor < 0)
{
armor = 0;
}
player->GetPev()->armorvalue = armor;
player->GetPev()->dmg_inflictor = player->GetEdict();
static const char *bit_sound[3] = {
"weapons/cbar_hitbod1.wav",
"weapons/cbar_hitbod2.wav",
"weapons/cbar_hitbod3.wav"
};
EMIT_SOUND_DYN2(player->GetEdict(), CHAN_VOICE, bit_sound[RANDOM_LONG(0,2)], 1.0, ATTN_NORM, 0, PITCH_NORM);
}
return 1;
}
return 0;
}
// native ns_get_locationname(Float:x, Float:y, name[], len, lookup=0);
static cell AMX_NATIVE_CALL ns_get_locationname(AMX *amx, cell *params)
{
vec3_t location;
location.x=amx_ctof2(params[1]);
location.y=amx_ctof2(params[2]);
if ((params[0] / sizeof(cell)) >= 5)
{
return MF_SetAmxString(amx,params[3],LocationMan.Lookup(location,params[5]),params[4]);
}
else
{
return MF_SetAmxString(amx,params[3],LocationMan.Lookup(location,0),params[4]);
}
}
// ns_lookup_title(const Key[], Output[], Size)
static cell AMX_NATIVE_CALL ns_lookup_title(AMX *amx, cell *params)
{
// FIX: some keys have upper case characters; to fix i store all keys as lower case
String Input(MF_GetAmxString(amx,params[1],0,NULL));
Input.toLower();
const char *Output=TitleMan.Lookup(Input);
if (Output==NULL) // not found
{
return -1;
}
return MF_SetAmxString(amx,params[2],Output,params[3]);
};
// ns_round_in_progress()
static cell AMX_NATIVE_CALL ns_round_in_progress(AMX *amx, cell *params)
{
return GameMan.RoundInProgress();
}
// ns_get_spawn(team,number=0,Float:ret[3])
static cell AMX_NATIVE_CALL ns_get_spawn(AMX *amx, cell *params)
{
return SpawnMan.Lookup(amx,params);
}
// ns_get_mask(id,MASK_*)
static cell AMX_NATIVE_CALL ns_get_mask(AMX *amx, cell *params)
{
CreateEdict(amx,params[1],-1);
if (Entity->v.iuser4 & static_cast<int>(params[2]))
{
return 1;
}
return 0;
}
// ns_set_mask(id,MASK_*,1 or 0)
static cell AMX_NATIVE_CALL ns_set_mask(AMX *amx, cell *params)
{
CreateEdict(amx,params[1],-1);
if (static_cast<int>(params[3]) > 0)
{
if (Entity->v.iuser4 & static_cast<int>(params[2]))
{
return 0;
}
Entity->v.iuser4 |= static_cast<int>(params[2]);
return 1;
}
if (Entity->v.iuser4 & static_cast<int>(params[2]))
{
Entity->v.iuser4 &= ~static_cast<int>(params[2]);
return 1;
}
return 0;
}
// ns_popup(id (0 for all),"text",OnlyShowWithCLHelpOn=0)
static cell AMX_NATIVE_CALL ns_popup(AMX *amx, cell *params)
{
GameMan.UpdateHudText2();
if (params[1])
{
CreatePlayerPointer(amx, params[1]);
if (!player->IsConnected())
{
return 0;
}
MESSAGE_BEGIN(MSG_ONE,GameMan.GetHudText2(),NULL,player->GetEdict());
}
else
{
MESSAGE_BEGIN(MSG_ALL,GameMan.GetHudText2());
}
char msg[190];
strncpy(&msg[0],MF_GetAmxString(amx,params[2],0,NULL),188);
WRITE_STRING(msg);
WRITE_BYTE(params[3]);
MESSAGE_END();
return 1;
}
// ns_is_combat()
static cell AMX_NATIVE_CALL ns_is_combat(AMX *amx, cell *params)
{
return GameMan.IsCombat();
}
/**
* Pretty much a direct port of CheezyPeteza's unstick routine
* from the old unstuck.amxx plugin. This is included here
* to remove the engine requirement.
* -
* Return values:
* 1 success
* 0 no spot to move to
* -1 invalid state (stunned/webbed)
* -2 invalid class (commander/gorge)
* -3 player is dead or a spectator
* -4 player is invalid (unknown)
* -5 player is invalid (disconnected)
*/
inline int GetPlayerHullSize(CPlayer *Player, int PlayerClass)
{
switch (PlayerClass)
{
case CLASS_SKULK:
case CLASS_GORGE:
case CLASS_LERK:
return static_cast<int>(head_hull);
case CLASS_FADE:
case CLASS_JETPACK:
case CLASS_HEAVY:
case CLASS_MARINE:
if (Player->GetPev()->button & IN_DUCK || Player->GetPev()->flags & FL_DUCKING)
{
return static_cast<int>(head_hull);
}
return static_cast<int>(human_hull);
case CLASS_ONOS:
if (Player->GetPev()->button & IN_DUCK || Player->GetPev()->flags & FL_DUCKING)
{
return static_cast<int>(human_hull);
}
return static_cast<int>(large_hull);
default:
return -1;
}
return -1;
}
static cell AMX_NATIVE_CALL ns_unstick_player(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected())
{
return -5;
}
if (player->GetPev()->iuser4 & (MASK_ENSNARED | MASK_PLAYER_STUNNED))
{
return -1;
}
int PlayerClass=player->GetClass();
if (PlayerClass == CLASS_GESTATE || PlayerClass == CLASS_COMMANDER)
{
return -2;
}
if (PlayerClass == CLASS_DEAD || PlayerClass == CLASS_NOTEAM || PlayerClass == CLASS_UNKNOWN)
{
return -3;
}
int HullSize=GetPlayerHullSize(player, PlayerClass);
if (HullSize==-1)
{
return -4;
}
Vector OriginalOrigin=player->GetPev()->origin;
Vector NewOrigin;
int Distance=params[2];
int Attempts;
TraceResult Result;
while (Distance < 1000)
{
Attempts=params[3];
while (Attempts--)
{
NewOrigin.x = RANDOM_FLOAT(OriginalOrigin.x - Distance,OriginalOrigin.x + Distance);
NewOrigin.y = RANDOM_FLOAT(OriginalOrigin.y - Distance,OriginalOrigin.y + Distance);
NewOrigin.z = RANDOM_FLOAT(OriginalOrigin.z - Distance,OriginalOrigin.z + Distance);
// (const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr);
TRACE_HULL(NewOrigin, NewOrigin, 0, HullSize, player->GetEdict(), &Result);
if (Result.fInOpen && !Result.fAllSolid && !Result.fStartSolid)
{
SET_ORIGIN(player->GetEdict(),NewOrigin);
return 1;
}
}
Distance += params[2];
}
return 0; // Couldn't be found
}
// Type: 131072 = DoT
// ns_takedamage
static cell AMX_NATIVE_CALL ns_takedamage(AMX *amx, cell *params)
{
// NASTY
// Reinterprets pvPrivateData as CBaseEntity, then calls TakeDamage with the entvar of Inflictor, and Attacker, with the float value and damage type
// The NS offset of TakeDamage hasn't changed from the HLSDK fortunately, so no offset digging is necessary
return (reinterpret_cast<CBaseEntity *>(INDEXENT_NEW(params[1])->pvPrivateData))->TakeDamage(&(INDEXENT_NEW(params[2])->v),&(INDEXENT_NEW(params[3])->v),amx_ctof2(params[4]),static_cast<int>(params[5]));
}
static cell AMX_NATIVE_CALL ns_get_gameplay(AMX* amx, cell* params)
{
if (avhgameplay == NULL)
{
avhgameplay = FIND_ENTITY_BY_CLASSNAME(NULL, "avhgameplay");
}
if (avhgameplay == NULL ||
avhgameplay->pvPrivateData == NULL) // Still null? Get out of here
{
return NSGame_CantTell;
}
int ATeam /* i pity da foo */ = *reinterpret_cast<int*>(reinterpret_cast<char*>(avhgameplay->pvPrivateData) + MAKE_OFFSET(GAMEPLAY_TEAMA));
int BTeam = *reinterpret_cast<int*>(reinterpret_cast<char*>(avhgameplay->pvPrivateData) + MAKE_OFFSET(GAMEPLAY_TEAMB));
if (ATeam == 2 && // alien
BTeam == 2) // alien
{
return NSGame_AlienVAlien;
}
if (ATeam == 1 && // marine
BTeam == 1) // marine
{
return NSGame_MarineVMarine;
}
if (ATeam == 1 && // marine
BTeam == 2) // alien
{
return NSGame_MarineVAlien;
}
return NSGame_Unknown;
}
#ifdef DEVELOPER_BUILD
static cell AMX_NATIVE_CALL refmem(AMX *amx, cell *params)
{
return *(reinterpret_cast<int *>(params[1]));
};
static cell AMX_NATIVE_CALL setmem(AMX *amx, cell *params)
{
int *ptr=reinterpret_cast<int *>(params[1]);
*ptr=params[2];
return 1;
};
#endif
AMX_NATIVE_INFO general_natives[] = {
{ "user_kill", ns_user_kill }, // replacement natives
{ "user_slap", ns_user_slap }, // since ClientKill is changed in NS
{ "ns_get_locationname", ns_get_locationname },
{ "ns_lookup_title", ns_lookup_title },
{ "ns_round_in_progress", ns_round_in_progress },
{ "ns_get_spawn", ns_get_spawn },
{ "ns_get_mask", ns_get_mask },
{ "ns_set_mask", ns_set_mask },
{ "ns_is_combat", ns_is_combat },
{ "ns_unstick_player", ns_unstick_player },
{ "ns_popup", ns_popup },
{ "ns_takedamage", ns_takedamage},
{ "ns_get_gameplay", ns_get_gameplay },
#ifdef DEVELOPER_BUILD
{ "refmem", refmem },
{ "setmem", setmem },
#endif
{ NULL, NULL }
};
void AddNatives_General()
{
MF_AddNatives(general_natives);
}

View File

@ -0,0 +1,275 @@
#include <string.h>
#include "../sdk/amxxmodule.h"
#include "../ns.h"
#include "../ns_const.h"
#include "../utilfunctions.h"
#include "../FastDelegate.h"
#include "../GameManager.h"
extern int IsValidBuilding[AVH_USER3_MAX + 1];
using namespace fastdelegate::detail;
void *GameRules=NULL;
mBOOL dlclose_handle_invalid; // Linking errors with metamod
// void AvHBaseBuildable::StartRecycle()
static void (GenericClass::*MFP_Recycle)();
// void AvHWeldable::AddBuildTime(float)
static void (GenericClass::*MFP_WeldFinished)(float);
// AvHGameRules *GetGameRules(void)
static void *(*FP_GetGameRules)();
char *FuncBase;
/**
* sizeof(void (detail::GenericClass::*fptr)())
* is 8 in GCC. Add an empty void * pointer at
* the end to compensate.
* Layout in GCC:
* union {
* void *address; // When this is an address it will always be positive
* int vtable_index; // When it is a vtable index it will always be odd = (vindex*2)+1
* };
* int delta;
* -
* Delta is the adjustment to the this pointer
* For my implementations I will only need it to 0
*/
#ifdef __GNUC__
template <typename OutType>
inline void set_mfp(OutType &out, void *in)
{
union
{
void *in[2];
OutType out;
} mfpu;
mfpu.in[0]=in;
mfpu.in[1]=NULL;
out=mfpu.out;
};
#else
template <typename OutType>
inline void set_mfp(OutType &out, void *in)
{
out=horrible_cast<OutType>(in);
};
#endif
void MFuncs_Initialize(void)
{
char FileName[256];
DLHANDLE DLLBase;
#ifdef __linux__
snprintf(FileName,sizeof(FileName)-1,"%s/dlls/ns_i386.so",MF_GetModname());
#else
snprintf(FileName,sizeof(FileName)-1,"%s\\dlls\\ns.dll",MF_GetModname());
#endif
DLLBase=DLOPEN(FileName);
FuncBase=(char *)DLSYM(DLLBase, MAKE_OFFSET(BASE));
DLCLOSE(DLLBase);
#define MFP(Offs) (((void *)(((char *)FuncBase)+MAKE_OFFSET(Offs))))
set_mfp(MFP_Recycle,MFP(MEMBER_RECYCLE));
set_mfp(MFP_WeldFinished,MFP(MEMBER_TRIGGER_WELDABLE));
// This is not a member function pointer, but use MFP since it
// uses the same address conversion as MFPs do
FP_GetGameRules=horrible_cast<void *(*)()>(MFP(GETGAMERULES));
};
static cell AMX_NATIVE_CALL ns_recycle(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->free || Entity->pvPrivateData==NULL)
{
return 0;
}
if (Entity->v.iuser3 <= AVH_USER3_NONE || Entity->v.iuser3 >= AVH_USER3_MAX)
{
return 0;
}
if (IsValidBuilding[Entity->v.iuser3]!=1) // Not a marine structure?
{
return 0;
}
// Make sure it's a marine building, undefined stuff happens on alien structures
(reinterpret_cast<GenericClass *>(Entity->pvPrivateData)->*(MFP_Recycle))();
return 1;
};
static cell AMX_NATIVE_CALL ns_finish_weldable(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->free || Entity->pvPrivateData==NULL)
{
return 0;
}
// verify the classname since this will crash if it's the wrong class!
if (strcmp(STRING(Entity->v.classname),"avhweldable")!=0)
{
return 0;
}
// First need to set the weldable to 100% complete
set_private_f(Entity,MAKE_OFFSET(WELD_DONE),get_private_f(Entity,MAKE_OFFSET(WELD_TIME)));
// Now make NS think the weldable has been welded again
// This has to call AvHWeldable::AddBuildTime(float)
// because AvHWeldable::TriggerFinished() does not work properly
(reinterpret_cast<GenericClass *>(Entity->pvPrivateData)->*(MFP_WeldFinished))(100.0);
return 1;
};
static cell AMX_NATIVE_CALL ns_get_teamres(AMX *amx, cell *params)
{
if (GameMan.IsCombat())
{
return 0;
}
if (GameRules==NULL) // GameRules not initialized yet
{
GameRules=(*(FP_GetGameRules))();
}
if (GameRules==NULL) // Still null? Get out of here
{
return 0;
}
switch(params[1])
{
case 1:
{
return amx_ftoc2(*(REAL *)((char *)GameRules+GAMERULES_TEAMA_RESOURCES));
}
case 2:
{
return amx_ftoc2(*(REAL *)((char *)GameRules+GAMERULES_TEAMB_RESOURCES));
}
default:
{
MF_LogError(amx, AMX_ERR_NATIVE, "ns_get_teamres: Expected 1 for team a or 2 for team b, got %d", params[1]);
return 0;
}
}
return 0;
}
static cell AMX_NATIVE_CALL ns_set_teamres(AMX *amx, cell *params)
{
if (GameMan.IsCombat())
{
return 0;
}
if (GameRules==NULL) // GameRules not initialized yet
{
GameRules=(*(FP_GetGameRules))();
}
if (GameRules==NULL) // Still null? Get out of here
{
return 0;
}
switch(params[1])
{
case 1:
{
*(REAL *)((char *)GameRules+GAMERULES_TEAMA_RESOURCES)=amx_ctof2(params[2]);
return 1;
}
case 2:
{
*(REAL *)((char *)GameRules+GAMERULES_TEAMB_RESOURCES)=amx_ctof2(params[2]);
return 1;
}
default:
{
MF_LogError(amx, AMX_ERR_NATIVE, "ns_set_teamres: Expected 1 for team a or 2 for team b, got %d", params[1]);
return 0;
}
}
return 0;
}
static cell AMX_NATIVE_CALL ns_add_teamres(AMX *amx, cell *params)
{
if (GameMan.IsCombat())
{
return 0;
}
if (GameRules==NULL) // GameRules not initialized yet
{
GameRules=(*(FP_GetGameRules))();
}
if (GameRules==NULL) // Still null? Get out of here
{
return 0;
}
switch(params[1])
{
case 1:
{
return amx_ftoc2(*(REAL *)((char *)GameRules+GAMERULES_TEAMA_RESOURCES)+=amx_ctof2(params[2]));
}
case 2:
{
return amx_ftoc2(*(REAL *)((char *)GameRules+GAMERULES_TEAMB_RESOURCES)+=amx_ctof2(params[2]));
}
default:
{
MF_LogError(amx, AMX_ERR_NATIVE, "ns_add_teamres: Expected 1 for team a or 2 for team b, got %d", params[1]);
return 0;
}
}
return 0;
}
#ifdef DEVELOPER_BUILD
static cell AMX_NATIVE_CALL findgameinfo(AMX *amx, cell *params)
{
void *Ret=(*(FP_GetGameRules))();
union
{
void *v;
int i;
}vi;
vi.v=Ret;
printf("GameRules=%d\n",vi.i);
return 1;
};
#endif
AMX_NATIVE_INFO memberfunc_natives[] = {
#ifdef DEVELOPER_BUILD
{ "getgameinfo", findgameinfo },
#endif
{ "ns_recycle", ns_recycle },
{ "ns_finish_weldable", ns_finish_weldable },
{ "ns_get_teamres", ns_get_teamres },
{ "ns_set_teamres", ns_set_teamres },
{ "ns_add_teamres", ns_add_teamres },
{ NULL, NULL }
};
void AddNatives_MemberFunc()
{
MF_AddNatives(memberfunc_natives);
};

View File

@ -0,0 +1,276 @@
/* AMX Mod X
* Natural Selection 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 "../sdk/amxxmodule.h"
#include "../ns.h"
#include "../utilfunctions.h"
#include "../NEW_Util.h"
#include "../CVector.h"
#include "../CString.h"
#include "../ParticleManager.h"
#define KVI(__KEY) PSKeyValueI(__KEY,amx,params)
#define KVF(__KEY) PSKeyValueF(__KEY,amx,params)
#define KVS(__KEY) PSKeyValueS(__KEY,amx,params)
#define NEXT params[__pcount++]
typedef enum partsystype_e
{
PSYS_TYPE_INT,
PSYS_TYPE_FLOAT,
PSYS_TYPE_STRING
}partsystype;
typedef struct partsyskey_s
{
const char *Name;
partsystype type;
}partsyskey;
cell PSKeyValueI(char *name, AMX *amx, cell *params)
{
if (params[1]==0)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Invalid particle system handle provided!");
return 0;
}
KeyValueData kvd;
char StrData[1024];
snprintf(StrData,sizeof(StrData)-1,"%d",params[2]);
kvd.szClassName=const_cast<char *>(STRING(reinterpret_cast<edict_t *>(params[1])->v.classname));
kvd.szKeyName=name;
kvd.szValue=&StrData[0];
kvd.fHandled=0;
//printf("\"%s\" \"%s\"\n",kvd.szKeyName,kvd.szValue);
MDLL_KeyValue(reinterpret_cast<edict_t *>(params[1]),&kvd);
return 1;
}
cell PSKeyValueF(char *name, AMX *amx, cell *params)
{
if (params[1]==0)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Invalid particle system handle provided!");
return 0;
}
KeyValueData kvd;
char StrData[1024];
snprintf(StrData,sizeof(StrData)-1,"%f",amx_ctof2(params[2]));
kvd.szClassName=const_cast<char *>(STRING(reinterpret_cast<edict_t *>(params[1])->v.classname));
kvd.szKeyName=name;
kvd.szValue=&StrData[0];
kvd.fHandled=0;
//printf("\"%s\" \"%s\"\n",kvd.szKeyName,kvd.szValue);
MDLL_KeyValue(reinterpret_cast<edict_t *>(params[1]),&kvd);
return 1;
}
cell PSKeyValueS(char *name, AMX *amx, cell *params)
{
if (params[1]==0)
{
MF_LogError(amx,AMX_ERR_NATIVE,"Invalid particle system handle provided!");
return 0;
}
KeyValueData kvd;
kvd.szClassName=const_cast<char *>(STRING(reinterpret_cast<edict_t *>(params[1])->v.classname));
kvd.szKeyName=name;
kvd.szValue=MF_GetAmxString(amx,params[2],0,NULL);
kvd.fHandled=0;
//printf("\"%s\" \"%s\"\n",kvd.szKeyName,kvd.szValue);
MDLL_KeyValue(reinterpret_cast<edict_t *>(params[1]),&kvd);
return 1;
}
static cell AMX_NATIVE_CALL ns_set_ps_name(AMX *amx, cell *params)
{
return KVS("targetname");
}
static cell AMX_NATIVE_CALL ns_set_ps_sprite(AMX *amx, cell *params)
{
return KVS("pSprite");
}
static cell AMX_NATIVE_CALL ns_set_ps_genrate(AMX *amx, cell *params)
{
return KVI("pGenRate");
}
static cell AMX_NATIVE_CALL ns_set_ps_genshape(AMX *amx, cell *params)
{
return KVI("pGenShape");
}
static cell AMX_NATIVE_CALL ns_set_ps_genshape_params(AMX *amx, cell *params)
{
return KVS("pGenShapeParams");
}
static cell AMX_NATIVE_CALL ns_set_ps_spriteframes(AMX *amx, cell *params)
{
return KVI("pSpriteNumFrames");
}
static cell AMX_NATIVE_CALL ns_set_ps_numparticles(AMX *amx, cell *params)
{
return KVI("pNumParticles");
}
static cell AMX_NATIVE_CALL ns_set_ps_size(AMX *amx, cell *params)
{
return KVF("pSize");
}
static cell AMX_NATIVE_CALL ns_set_ps_vel_params(AMX *amx, cell *params)
{
return KVS("pVelParams");
}
static cell AMX_NATIVE_CALL ns_set_ps_vel_shape(AMX *amx, cell *params)
{
return KVI("pVelShape");
}
static cell AMX_NATIVE_CALL ns_set_ps_sys_life(AMX *amx, cell *params)
{
return KVF("pSystemLifetime");
}
static cell AMX_NATIVE_CALL ns_set_ps_particle_life(AMX *amx, cell *params)
{
return KVF("pLifetime");
}
static cell AMX_NATIVE_CALL ns_set_ps_rendermode(AMX *amx, cell *params)
{
return KVI("pRenderMode");
}
static cell AMX_NATIVE_CALL ns_set_ps_to_gen(AMX *amx, cell *params)
{
return KVS("pPSToGen");
}
static cell AMX_NATIVE_CALL ns_set_ps_anim_speed(AMX *amx, cell *params)
{
return KVI("pAnimationSpeed");
}
static cell AMX_NATIVE_CALL ns_set_ps_spawn_flags(AMX *amx, cell *params)
{
return KVI("spawnflags");
}
static cell AMX_NATIVE_CALL ns_set_ps_base_color(AMX *amx, cell *params)
{
return KVS("pBaseColor");
}
static cell AMX_NATIVE_CALL ns_set_ps_scale(AMX *amx, cell *params)
{
return KVF("pScale");
}
static cell AMX_NATIVE_CALL ns_set_ps_max_alpha(AMX *amx, cell *params)
{
return KVF("pMaxAlpha");
}
// ns_create_partsys(const name[], pGenShape, const pGenShapeParams[], pGenRate, const pSprite[],
// pSpriteFrames, pNumParticles, Float:pSize, const pVelParams[], pVelShape,
// Float:pSystemLifetime, Float:pParticleLifetime, pRenderMode, const pPSToGen[], pAnimationSpeed, pSpawnFlags)
static cell AMX_NATIVE_CALL ns_create_partsys(AMX *amx, cell *params)
{
return (cell)CREATE_NAMED_ENTITY(MAKE_STRING("env_particles_custom"));
};
static cell AMX_NATIVE_CALL ns_spawn_ps(AMX *amx, cell *params)
{
if (params[1]==0)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid particle system handle");
return 0;
}
edict_t *Ent=reinterpret_cast<edict_t *>(params[1]);
MDLL_Spawn(Ent);
if (!Ent->free)
{
REMOVE_ENTITY(Ent);
}
return ParticleMan.Add(STRING(Ent->v.targetname),0);
}
// ns_fire_ps(Particle:id,Float:origin[3],Float:angles[3],flags=0)
static cell AMX_NATIVE_CALL ns_fire_partsys(AMX *amx, cell *params)
{
float *origin=(float*)MF_GetAmxAddr(amx,params[2]);
float *angles=(float*)MF_GetAmxAddr(amx,params[3]);
ParticleMan.FireSystem(static_cast<int>(params[1]),origin,angles,static_cast<int>(params[4]));
return 0;
};
static cell AMX_NATIVE_CALL ns_get_partsys_id(AMX *amx, cell *params)
{
return ParticleMan.Find(MF_GetAmxString(amx,params[1],0,NULL));;
};
AMX_NATIVE_INFO particle_natives[] = {
{ "ns_create_ps", ns_create_partsys },
{ "ns_set_ps_name", ns_set_ps_name },
{ "ns_set_ps_sprite", ns_set_ps_sprite },
{ "ns_set_ps_genrate", ns_set_ps_genrate },
{ "ns_set_ps_genshape", ns_set_ps_genshape },
{ "ns_set_ps_genshape_params", ns_set_ps_genshape_params },
{ "ns_set_ps_spriteframes", ns_set_ps_spriteframes },
{ "ns_set_ps_numparticles", ns_set_ps_numparticles },
{ "ns_set_ps_size", ns_set_ps_size },
{ "ns_set_ps_vel_params", ns_set_ps_vel_params },
{ "ns_set_ps_vel_shape", ns_set_ps_vel_shape },
{ "ns_set_ps_sys_life", ns_set_ps_sys_life },
{ "ns_set_ps_particle_life", ns_set_ps_particle_life },
{ "ns_set_ps_rendermode", ns_set_ps_rendermode },
{ "ns_set_ps_to_gen", ns_set_ps_to_gen },
{ "ns_set_ps_anim_speed", ns_set_ps_anim_speed },
{ "ns_set_ps_spawn_flags", ns_set_ps_spawn_flags },
{ "ns_set_ps_base_color", ns_set_ps_base_color },
{ "ns_set_ps_scale", ns_set_ps_scale },
{ "ns_set_ps_max_alpha", ns_set_ps_max_alpha },
{ "ns_spawn_ps", ns_spawn_ps },
{ "ns_fire_ps", ns_fire_partsys },
{ "ns_get_ps_id", ns_get_partsys_id },
{ NULL, NULL }
};
void AddNatives_Particles()
{
MF_AddNatives(particle_natives);
}

222
dlls/ns/natives/player.cpp Normal file
View File

@ -0,0 +1,222 @@
/* AMX Mod X
* Natural Selection 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 "../sdk/amxxmodule.h"
#include "../ns.h"
#include "../utilfunctions.h"
#include "../NEW_Util.h"
#include "../GameManager.h"
#include "../CPlayer.h"
#include "../AllocString.h"
StringManager AllocStringList;
// ns_set_player_model(id,const Model[]="")
static cell AMX_NATIVE_CALL ns_set_player_model(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
player->SetModel(MF_GetAmxString(amx,params[2],0,NULL));
GameMan.HookPostThink_Post();
return 1;
}
// ns_set_player_skin(id,skin=-1)
static cell AMX_NATIVE_CALL ns_set_player_skin(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
player->SetSkin(params[2]);
GameMan.HookPostThink_Post();
return 1;
}
// ns_set_player_body(id,body=-1)
static cell AMX_NATIVE_CALL ns_set_player_body(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
player->SetBody(params[2]);
GameMan.HookPostThink_Post();
return 1;
}
// ns_get_class(id)
static cell AMX_NATIVE_CALL ns_get_class(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
return player->GetClass();
}
// ns_get_jpfuel(id)
static cell AMX_NATIVE_CALL ns_get_jpfuel(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
REAL ret=(player->GetPev()->fuser3) / 10.0;
return amx_ftoc2(ret);
}
// ns_set_jpfuel(id,Float:fuelpercent)
static cell AMX_NATIVE_CALL ns_set_jpfuel(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
REAL fuel = amx_ctof2(params[2]);
if (fuel > 100.0)
{
fuel = 100.0;
}
if (fuel < 0.0)
{
fuel = 0.0;
}
player->GetPev()->fuser3 = fuel * 10.0;
return 1;
}
static cell AMX_NATIVE_CALL ns_add_jpfuel(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
REAL fuel = clamp(amx_ctof2(params[2]),0.0,100.0);
return amx_ftoc2(player->GetPev()->fuser3 = clamp(static_cast<float>(player->GetPev()->fuser3 + (fuel * 10.0)),static_cast<float>(0.0)));
};
// ns_get_speedchange(index)
static cell AMX_NATIVE_CALL ns_get_speedchange(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
return player->GetSpeedChange();
}
// ns_set_speedchange(index,speedchange=0)
static cell AMX_NATIVE_CALL ns_set_speedchange(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
player->SetSpeedChange(params[2]);
// Update PreThink_Post if we need to
GameMan.HookPreThink_Post();
return 1;
}
// ns_get_maxspeed(index) (returns the max speed of the player BEFORE speed change is factored in.)
static cell AMX_NATIVE_CALL ns_get_maxspeed(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
return player->GetMaxSpeed();
}
// ns_set_fov(id,Float:fov);
static cell AMX_NATIVE_CALL ns_set_fov(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
return player->SetFOV(amx_ctof3(&params[2]));
}
// ns_giveiteM(id,"item");
static cell AMX_NATIVE_CALL ns_giveitem(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
char *classname = MF_GetAmxString(amx,params[2],0,NULL);
if (!player->IsConnected())
{
return 0;
}
if (player->GetPev()->deadflag > 0)
{
return 0;
}
edict_t *object=CREATE_NAMED_ENTITY(ALLOC_STRING2(classname));
if (!object)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Error creating entity \"%s\"", classname);
return 0;
}
SET_ORIGIN(object,player->GetPev()->origin); // move to player
gpGamedllFuncs->dllapi_table->pfnSpawn(object); // emulate spawn
object->v.flags |= FL_ONGROUND; // make it think it's touched the ground
gpGamedllFuncs->dllapi_table->pfnThink(object); //
gpGamedllFuncs->dllapi_table->pfnTouch(object,player->GetEdict()); // give it to the player
return 1;
}
AMX_NATIVE_INFO player_natives[] = {
{ "ns_set_player_model", ns_set_player_model },
{ "ns_set_player_skin", ns_set_player_skin },
{ "ns_set_player_body", ns_set_player_body },
{ "ns_get_class", ns_get_class },
{ "ns_get_jpfuel", ns_get_jpfuel },
{ "ns_set_jpfuel", ns_set_jpfuel },
{ "ns_add_jpfuel", ns_add_jpfuel },
{ "ns_get_energy", ns_get_jpfuel }, // They do the same thing...
{ "ns_set_energy", ns_set_jpfuel }, //
{ "ns_add_energy", ns_add_jpfuel },
{ "ns_get_speedchange", ns_get_speedchange },
{ "ns_set_speedchange", ns_set_speedchange },
{ "ns_get_maxspeed", ns_get_maxspeed },
{ "ns_set_fov", ns_set_fov },
{ "ns_give_item", ns_giveitem },
{ NULL, NULL }
};
void AddNatives_Player()
{
MF_AddNatives(player_natives);
}

View File

@ -0,0 +1,355 @@
/* AMX Mod X
* Natural Selection 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 "../sdk/amxxmodule.h"
#include "../ns.h"
#include "../utilfunctions.h"
#include "../NEW_Util.h"
#include "../GameManager.h"
#include "../CPlayer.h"
// Float:ns_get_res(Player)
static cell AMX_NATIVE_CALL ns_get_res(AMX *amx, cell *params)
{
if (GameMan.IsCombat())
{
return 0;
}
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected())
{
return 0;
}
if (!player->HasPrivateData())
{
return 0;
}
return amx_ftoc2(get_private_f(player->GetEdict(),MAKE_OFFSET(RESOURCES)));
}
// ns_set_res(Player,Float:res)
static cell AMX_NATIVE_CALL ns_set_res(AMX *amx, cell *params)
{
if (GameMan.IsCombat())
{
return 0;
}
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected())
{
return 0;
}
if (!player->HasPrivateData())
{
return 0;
}
set_private_f(player->GetEdict(),MAKE_OFFSET(RESOURCES),amx_ctof2(params[2]));
return 1;
}
// Float:ns_add_res(Player,Float:res)
static cell AMX_NATIVE_CALL ns_add_res(AMX *amx, cell *params)
{
if (GameMan.IsCombat())
{
return 0;
}
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected())
{
return 0;
}
if (!player->HasPrivateData())
{
return 0;
}
return amx_ftoc2(inc_private_f(player->GetEdict(),MAKE_OFFSET(RESOURCES),amx_ctof2(params[2]),0.0,100.0));
}
// Float:ns_get_exp(Player)
static cell AMX_NATIVE_CALL ns_get_exp(AMX *amx, cell *params)
{
if (!GameMan.IsCombat())
{
return 0;
}
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected())
{
return 0;
}
if (!player->HasPrivateData())
{
return 0;
}
return amx_ftoc2(get_private_f(player->GetEdict(),MAKE_OFFSET(EXP)));
}
// ns_set_exp(Player,Float:exp)
static cell AMX_NATIVE_CALL ns_set_exp(AMX *amx, cell *params)
{
if (!GameMan.IsCombat())
{
return 0;
}
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected())
{
return 0;
}
if (!player->HasPrivateData())
{
return 0;
}
set_private_f(player->GetEdict(),MAKE_OFFSET(EXP),amx_ctof2(params[2]));
return 1;
}
// Float:ns_add_exp(Player,Float:exp)
static cell AMX_NATIVE_CALL ns_add_exp(AMX *amx, cell *params)
{
if (!GameMan.IsCombat())
{
return 0;
}
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected())
{
return 0;
}
if (!player->HasPrivateData())
{
return 0;
}
return amx_ftoc2(inc_private_f(player->GetEdict(),MAKE_OFFSET(EXP),amx_ctof2(params[2]),0.0));
}
// ns_get_points(Player)
static cell AMX_NATIVE_CALL ns_get_points(AMX *amx, cell *params)
{
if (!GameMan.IsCombat())
{
return 0;
}
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected())
{
return 0;
}
if (!player->HasPrivateData())
{
return 0;
}
return get_private(player->GetEdict(),MAKE_OFFSET(POINTS));
}
// ns_set_points(Player,points)
static cell AMX_NATIVE_CALL ns_set_points(AMX *amx, cell *params)
{
if (!GameMan.IsCombat())
{
return 0;
}
CreatePlayerPointer(amx, params[1]);
if (!player->IsConnected())
{
return 0;
}
if (!player->HasPrivateData())
{
return 0;
}
set_private(player->GetEdict(),MAKE_OFFSET(POINTS),static_cast<int>(params[2]));
return 1;
}
// ns_add_points(Player,points)
static cell AMX_NATIVE_CALL ns_add_points(AMX *amx, cell *params)
{
if (!GameMan.IsCombat())
{
return 0;
}
CreatePlayerPointer(amx, params[1]);
if (!player->IsConnected())
{
return 0;
}
if (!player->HasPrivateData())
{
return 0;
}
return inc_private(player->GetEdict(),MAKE_OFFSET(POINTS),static_cast<int>(params[2]),0,9);
}
static cell AMX_NATIVE_CALL ns_get_score(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected() || !player->HasPrivateData())
{
return 0;
}
return get_private(player->GetEdict(),MAKE_OFFSET(SCORE));
}
static cell AMX_NATIVE_CALL ns_set_score(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected() || !player->HasPrivateData())
{
return 0;
}
set_private(player->GetEdict(),MAKE_OFFSET(SCORE),static_cast<int>(params[2]));
return 1;
}
static cell AMX_NATIVE_CALL ns_add_score(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected() || !player->HasPrivateData())
{
return 0;
}
return inc_private(player->GetEdict(),MAKE_OFFSET(SCORE),static_cast<int>(params[2]));
}
static cell AMX_NATIVE_CALL ns_get_deaths(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected() || !player->HasPrivateData())
{
return 0;
}
return get_private(player->GetEdict(),MAKE_OFFSET(DEATHS));
}
static cell AMX_NATIVE_CALL ns_set_deaths(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected() || !player->HasPrivateData())
{
return 0;
}
set_private(player->GetEdict(),MAKE_OFFSET(DEATHS),static_cast<int>(params[2]));
return 1;
}
static cell AMX_NATIVE_CALL ns_add_deaths(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected() || !player->HasPrivateData())
{
return 0;
}
return inc_private(player->GetEdict(),MAKE_OFFSET(DEATHS),static_cast<int>(params[2]));
}
static cell AMX_NATIVE_CALL ns_get_hive_ability(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
int result = get_private(player->GetEdict(), MAKE_OFFSET(HIVEABILITY));
return (params[2] > 0) ? (result >= params[2] - 1) : result;
}
AMX_NATIVE_INFO player_memory_natives[] = {
{ "ns_get_res", ns_get_res },
{ "ns_set_res", ns_set_res },
{ "ns_add_res", ns_add_res },
{ "ns_get_exp", ns_get_exp },
{ "ns_set_exp", ns_set_exp },
{ "ns_add_exp", ns_add_exp },
{ "ns_get_points", ns_get_points },
{ "ns_set_points", ns_set_points },
{ "ns_add_points", ns_add_points },
{ "ns_set_score", ns_set_score },
{ "ns_get_score", ns_get_score },
{ "ns_add_score", ns_add_score },
{ "ns_get_deaths", ns_get_deaths },
{ "ns_set_deaths", ns_set_deaths },
{ "ns_add_deaths", ns_add_deaths },
{ "ns_get_hive_ability", ns_get_hive_ability},
{ NULL, NULL }
};
void AddNatives_PlayerMemory()
{
MF_AddNatives(player_memory_natives);
}

View File

@ -0,0 +1,405 @@
/* AMX Mod X
* Natural Selection 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 "../sdk/amxxmodule.h"
#include "../ns.h"
#include "../utilfunctions.h"
#include "../NEW_Util.h"
int IsValidBuilding[AVH_USER3_MAX + 1] = {
0, // AVH_USER3_NONE = 0,
0, // AVH_USER3_MARINE_PLAYER,
0, // AVH_USER3_COMMANDER_PLAYER,
0, // AVH_USER3_ALIEN_PLAYER1,
0, // AVH_USER3_ALIEN_PLAYER2,
0, // AVH_USER3_ALIEN_PLAYER3,
0, // AVH_USER3_ALIEN_PLAYER4,
0, // AVH_USER3_ALIEN_PLAYER5,
0, // AVH_USER3_ALIEN_EMBRYO,
0, // AVH_USER3_SPAWN_TEAMONE,
0, // AVH_USER3_SPAWN_TEAMTWO,
0, // AVH_USER3_PARTICLE_ON, // only valid for AvHParticleEntity: entindex as int in fuser1, template index stored in fuser2
0, // AVH_USER3_PARTICLE_OFF, // only valid for AvHParticleEntity: particle system handle in fuser1
0, // AVH_USER3_WELD, // float progress (0 - 100) stored in fuser1
0, // AVH_USER3_ALPHA, // fuser1 indicates how much alpha this entity toggles to in commander mode, fuser2 for players
0, // AVH_USER3_MARINEITEM, // Something a friendly marine can pick up
0, // AVH_USER3_WAYPOINT,
2, // AVH_USER3_HIVE,
0, // AVH_USER3_NOBUILD,
0, // AVH_USER3_USEABLE,
0, // AVH_USER3_AUDIO_ON,
0, // AVH_USER3_AUDIO_OFF,
0, // AVH_USER3_FUNC_RESOURCE,
1, // AVH_USER3_COMMANDER_STATION,
1, // AVH_USER3_TURRET_FACTORY,
1, // AVH_USER3_ARMORY,
1, // AVH_USER3_ADVANCED_ARMORY,
1, // AVH_USER3_ARMSLAB,
1, // AVH_USER3_PROTOTYPE_LAB,
1, // AVH_USER3_OBSERVATORY,
0, // AVH_USER3_CHEMLAB,
0, // AVH_USER3_MEDLAB,
0, // AVH_USER3_NUKEPLANT,
1, // AVH_USER3_TURRET,
1, // AVH_USER3_SIEGETURRET,
1, // AVH_USER3_RESTOWER,
0, // AVH_USER3_PLACEHOLDER,
1, // AVH_USER3_INFANTRYPORTAL,
0, // AVH_USER3_NUKE,
0, // AVH_USER3_BREAKABLE,
0, // AVH_USER3_UMBRA,
1, // AVH_USER3_PHASEGATE,
2, // AVH_USER3_DEFENSE_CHAMBER,
2, // AVH_USER3_MOVEMENT_CHAMBER,
2, // AVH_USER3_OFFENSE_CHAMBER,
2, // AVH_USER3_SENSORY_CHAMBER,
2, // AVH_USER3_ALIENRESTOWER,
0, // AVH_USER3_HEAVY,
0, // AVH_USER3_JETPACK,
1, // AVH_USER3_ADVANCED_TURRET_FACTORY,
0, // AVH_USER3_SPAWN_READYROOM,
0, // AVH_USER3_CLIENT_COMMAND,
0, // AVH_USER3_FUNC_ILLUSIONARY,
0, // AVH_USER3_MENU_BUILD,
0, // AVH_USER3_MENU_BUILD_ADVANCED,
0, // AVH_USER3_MENU_ASSIST,
0, // AVH_USER3_MENU_EQUIP,
0, // AVH_USER3_MINE,
0 // AVH_USER3_MAX
};
// ns_build_structure(idStructure);
static cell AMX_NATIVE_CALL ns_build_structure(AMX *amx, cell *params)
{
// Trick NS into thinking that this structure is being spawned from the map
// set the "startbuilt" setting to 1, then remove it.
// "startbuilt" is set as "spawnflag" "1" in the ns.fgd
CreateNonPlayerEdict(amx,params[1]);
if (Entity->free)
{
return 0;
};
if (Entity->v.iuser3 <= AVH_USER3_NONE || Entity->v.iuser3 >= AVH_USER3_MAX)
{
return 0;
}
int StructureType=IsValidBuilding[Entity->v.iuser3];
if (StructureType==0)
{
return 0;
}
if (Entity->v.iuser3==AVH_USER3_HIVE)
{
return 0;
}
// Already set?
if (Entity->v.spawnflags & 1)
{
MDLL_Spawn(Entity);
goto undo_ghost;
}
Entity->v.spawnflags |= 1;
MDLL_Spawn(Entity);
Entity->v.spawnflags &= ~1;
undo_ghost:
if (StructureType==1) // marine, remove "ghost" appearance
{
if (get_private(Entity,MAKE_OFFSET(GHOST_STRUCTURE))!=0)
{
set_private(Entity,MAKE_OFFSET(GHOST_STRUCTURE),0);
Entity->v.rendermode=kRenderNormal;
Entity->v.renderamt=100.0;
}
}
return 1;
};
#define MASK_ELECTRICITY 8192
static cell AMX_NATIVE_CALL ns_get_build(AMX *amx, cell *params)
{
int iLength;
char *buildtype = MF_GetAmxString(amx,params[1],0,&iLength);
int iBuiltOnly = params[2];
int iNumber = params[3];
edict_t* pBuild = NULL;
int iCount=0;
while ((pBuild = UTIL_FindEntityByString(pBuild,"classname",buildtype)) != NULL)
{
if (iBuiltOnly > 0)
{
if (FStrEq("team_advarmory",buildtype) || FStrEq("team_advturretfactory",buildtype))
{
iCount++;
}
else
{
if (pBuild->v.fuser1 >= 1000 || pBuild->v.iuser4 & MASK_ELECTRICITY)
{
iCount++;
}
}
}
else
{
iCount++;
}
if (iNumber > 0 && iCount == iNumber)
return ENTINDEX_NEW(pBuild);
}
return iCount++;
}
static cell AMX_NATIVE_CALL ns_set_hive_trait(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL)
{
return 0;
}
set_private(Entity,MAKE_OFFSET(HIVE_TRAIT),static_cast<int>(params[2]));
return 1;
}
static cell AMX_NATIVE_CALL ns_get_hive_trait(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL)
{
return 0;
}
return get_private(Entity,MAKE_OFFSET(HIVE_TRAIT));
}
static cell AMX_NATIVE_CALL ns_get_struct_owner(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL)
{
return 0;
}
return get_private(Entity,MAKE_OFFSET(STRUCTOWNER));
}
// ns_set_struct_owner(idStructure,idPlayer) - -1 means no owner
static cell AMX_NATIVE_CALL ns_set_struct_owner(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (params[2] > gpGlobals->maxClients || params[2] < -1)
{
return 0;
}
if (Entity->pvPrivateData == NULL)
{
return 0;
}
set_private(Entity,MAKE_OFFSET(STRUCTOWNER),params[2]);
return 1;
}
// Float:ns_get_obs_energy(id);
static cell AMX_NATIVE_CALL ns_get_obs_energy(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL)
{
return 0;
}
return amx_ftoc2(get_private(Entity,MAKE_OFFSET(OBS_ENERGY)));
};
// Float:ns_set_obs_energy(id,Float:energy);
static cell AMX_NATIVE_CALL ns_set_obs_energy(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL)
{
return 0;
}
set_private_f(Entity,MAKE_OFFSET(OBS_ENERGY),amx_ctof2(params[2]));
return 1;
};
// Float:ns_add_obs_energy(id,Float:energy);
static cell AMX_NATIVE_CALL ns_add_obs_energy(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL)
{
return 0;
}
return amx_ftoc2(inc_private_f(Entity,MAKE_OFFSET(OBS_ENERGY),amx_ctof2(params[2]),0.0,100.0));
};
// Float:ns_get_weld_time(idWeldable);
static cell AMX_NATIVE_CALL ns_get_weld_time(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL)
{
return 0;
}
return amx_ftoc2(get_private_f(Entity,MAKE_OFFSET(WELD_TIME)));
};
// ns_set_weld_time(idWeldable,Float:value);
static cell AMX_NATIVE_CALL ns_set_weld_time(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL)
{
return 0;
}
set_private_f(Entity,MAKE_OFFSET(WELD_TIME),amx_ctof2(params[2]));
return 1;
};
// Float:ns_add_weld_time(idWeldable,Float:value);
static cell AMX_NATIVE_CALL ns_add_weld_time(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL)
{
return 0;
}
return amx_ftoc2(inc_private_f(Entity,MAKE_OFFSET(WELD_TIME),amx_ctof2(params[2]),0.0));
};
// Float:ns_get_weld_done(idWeldable);
static cell AMX_NATIVE_CALL ns_get_weld_done(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL)
{
return 0;
}
return amx_ftoc2(get_private_f(Entity,MAKE_OFFSET(WELD_DONE)));
};
// ns_set_weld_done(idWeldable,Float:value);
static cell AMX_NATIVE_CALL ns_set_weld_done(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL)
{
return 0;
}
set_private_f(Entity,MAKE_OFFSET(WELD_DONE),amx_ctof2(params[2]));
return 1;
};
// Float:ns_add_weld_done(idWeldable,Float:value);
static cell AMX_NATIVE_CALL ns_add_weld_done(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL)
{
return 0;
}
return amx_ftoc2(inc_private_f(Entity,MAKE_OFFSET(WELD_DONE),amx_ctof2(params[2]),0.0));
};
AMX_NATIVE_INFO structure_natives[] = {
{ "ns_build_structure", ns_build_structure },
{ "ns_get_build", ns_get_build },
{ "ns_get_hive_trait", ns_get_hive_trait },
{ "ns_set_hive_trait", ns_set_hive_trait },
{ "ns_get_struct_owner", ns_get_struct_owner },
{ "ns_set_struct_owner", ns_set_struct_owner },
{ "ns_get_obs_energy", ns_get_obs_energy },
{ "ns_set_obs_energy", ns_set_obs_energy },
{ "ns_add_obs_energy", ns_add_obs_energy },
{ "ns_get_weld_time", ns_get_weld_time },
{ "ns_set_weld_time", ns_set_weld_time },
{ "ns_add_weld_time", ns_add_weld_time },
{ "ns_get_weld_done", ns_get_weld_done },
{ "ns_set_weld_done", ns_set_weld_done },
{ "ns_add_weld_done", ns_add_weld_done },
/* prototypes for natives i have planned */
//{ "ns_get_phase_target", ns_get_phase_target },
//{ "ns_set_phase_target", ns_set_phase_target },
//{ "ns_set_phase_nextuse", ns_set_phase_nextuse },
//{ "ns_get_phase_nextuse", ns_get_phase_nextuse },
//{ "ns_add_phase_nextuse", ns_add_phase_nextuse },
{ NULL, NULL }
};
void AddNatives_Structure()
{
MF_AddNatives(structure_natives);
}

479
dlls/ns/natives/weapons.cpp Normal file
View File

@ -0,0 +1,479 @@
/* AMX Mod X
* Natural Selection 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 "../sdk/amxxmodule.h"
#include "../ns.h"
#include "../utilfunctions.h"
#include "../NEW_Util.h"
#include "../GameManager.h"
#include "../CPlayer.h"
// ns_has_weapon(idPlayer,NsWeapon,set=0)
static cell AMX_NATIVE_CALL ns_has_weapon(AMX *amx,cell *params)
{
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected())
{
return 0;
}
if (params[3] == -1)
{
if ((player->GetPev()->weapons & (1<<params[2])) > 0)
{
return 1;
}
}
else
{
if ((player->GetPev()->weapons & (1<<params[2])) > 0)
{
if (params[3] == 0)
{
player->GetPev()->weapons &= ~(1<<params[2]);
return 1;
}
return 0;
}
else
{
if (params[3] == 1)
{
player->GetPev()->weapons |= (1<<params[2]);
return 1;
}
}
return 0;
}
return 0;
}
// ns_set_weap_dmg(WeaponID,Float:damage)
static cell AMX_NATIVE_CALL ns_set_weapon_dmg(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL || Entity->free)
{
return 0;
}
set_private_f(Entity,MAKE_OFFSET(WEAPDMG),amx_ctof2(params[2]));
return 1;
}
// Float:ns_get_weap_dmg(WeaponID)
static cell AMX_NATIVE_CALL ns_get_weapon_dmg(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL || Entity->free)
{
return 0;
}
REAL ret=get_private_f(Entity,MAKE_OFFSET(WEAPDMG));
return amx_ftoc2(ret);
}
// ns_set_weap_range(WeaponID,Float:range)
static cell AMX_NATIVE_CALL ns_set_weapon_range(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL || Entity->free)
{
return 0;
}
set_private_f(Entity,MAKE_OFFSET(WEAPRANGE),amx_ctof2(params[2]));
return 1;
}
// Float:ns_get_weap_range(WeaponID)
static cell AMX_NATIVE_CALL ns_get_weapon_range(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL || Entity->free)
{
return 0;
}
REAL ret=get_private_f(Entity,MAKE_OFFSET(WEAPRANGE));
return amx_ftoc2(ret);
}
// ns_get_weap_ammo(WeaponID)
static cell AMX_NATIVE_CALL ns_get_weapon_clip(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL || Entity->free)
{
return 0;
}
return get_private(Entity,MAKE_OFFSET(WEAPCLIP));
}
// ns_set_weap_ammo(WeaponID,ammo)
static cell AMX_NATIVE_CALL ns_set_weapon_clip(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL || Entity->free)
{
return 0;
}
set_private(Entity,MAKE_OFFSET(WEAPCLIP),params[2]);
return 1;
}
static cell AMX_NATIVE_CALL ns_add_weapon_clip(AMX *amx, cell *params)
{
CreateNonPlayerEdict(amx,params[1]);
if (Entity->pvPrivateData == NULL || Entity->free)
{
return 0;
}
return inc_private(Entity,MAKE_OFFSET(WEAPCLIP),static_cast<int>(params[2]),0);
}
// ns_get_weap_reserve(PlayerID,WeaponType)
static cell AMX_NATIVE_CALL ns_get_weap_reserve(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected())
{
return 0;
}
if (!player->HasPrivateData())
{
return 0;
}
switch (params[2])
{
case WEAPON_PISTOL:
return get_private(player->GetEdict(),MAKE_OFFSET(AMMO_PISTOL));
case WEAPON_LMG:
return get_private(player->GetEdict(),MAKE_OFFSET(AMMO_LMG));
case WEAPON_SHOTGUN:
return get_private(player->GetEdict(),MAKE_OFFSET(AMMO_SHOTGUN));
case WEAPON_HMG:
return get_private(player->GetEdict(),MAKE_OFFSET(AMMO_HMG));
case WEAPON_GRENADE_GUN:
return get_private(player->GetEdict(),MAKE_OFFSET(AMMO_GL));
case WEAPON_GRENADE:
return get_private(player->GetEdict(),MAKE_OFFSET(AMMO_HG));
default:
return 0;
}
return 0;
}
static cell AMX_NATIVE_CALL ns_set_weap_reserve(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected() || !player->HasPrivateData())
{
return 0;
}
switch (params[2])
{
case WEAPON_PISTOL:
set_private(player->GetEdict(),MAKE_OFFSET(AMMO_PISTOL),params[3]);
return 1;
case WEAPON_LMG:
set_private(player->GetEdict(),MAKE_OFFSET(AMMO_LMG),(int)params[3]);
return 1;
case WEAPON_SHOTGUN:
set_private(player->GetEdict(),MAKE_OFFSET(AMMO_SHOTGUN),(int)params[3]);
return 1;
case WEAPON_HMG:
set_private(player->GetEdict(),MAKE_OFFSET(AMMO_HMG),(int)params[3]);
return 1;
case WEAPON_GRENADE_GUN:
set_private(player->GetEdict(),MAKE_OFFSET(AMMO_GL),(int)params[3]);
return 1;
case WEAPON_GRENADE:
set_private(player->GetEdict(),MAKE_OFFSET(AMMO_HG),(int)params[3]);
return 1;
default:
return 0;
}
return 0;
}
static cell AMX_NATIVE_CALL ns_add_weap_reserve(AMX *amx, cell *params)
{
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected() || !player->HasPrivateData())
{
return 0;
}
switch (params[2])
{
case WEAPON_PISTOL:
return inc_private(player->GetEdict(),MAKE_OFFSET(AMMO_PISTOL),params[3],0);
case WEAPON_LMG:
return inc_private(player->GetEdict(),MAKE_OFFSET(AMMO_LMG),(int)params[3],0);
case WEAPON_SHOTGUN:
return inc_private(player->GetEdict(),MAKE_OFFSET(AMMO_SHOTGUN),(int)params[3],0);
case WEAPON_HMG:
return inc_private(player->GetEdict(),MAKE_OFFSET(AMMO_HMG),(int)params[3],0);
case WEAPON_GRENADE_GUN:
return inc_private(player->GetEdict(),MAKE_OFFSET(AMMO_GL),(int)params[3],0);
case WEAPON_GRENADE:
return inc_private(player->GetEdict(),MAKE_OFFSET(AMMO_HG),(int)params[3],0);
default:
return 0;
}
return 0;
}
// ns_get_weapon(idPlayer,weaponid,&weapontype=0)
static cell AMX_NATIVE_CALL ns_get_weapon(AMX *amx, cell *params)
{
// Peachy did it like this:
// if weapontype is 0, return the primary weapon index of the player
// if weapontype is < 0, return the last inventory weapon index of the player
// otherwise, scan the player's inventory and look for a weapon of the given type
// such as WEAPON_KNIFE, etc, etc
// I added the last parameter, which will byref the weapontype of the weapon found
// returns 0 on failure
// last param default value added to not conflict with his version
CreatePlayerPointer(amx,params[1]);
if (!player->IsConnected())
{
return 0;
}
if (!player->HasPrivateData())
{
return 0;
}
if (params[2]<0) // find lastinv weapon
{
edict_t *Weapon=private_to_edict(get_private_p<void *>(player->GetEdict(),MAKE_OFFSET(LAST_WEAPON)));
if (Weapon==NULL) // no weapon
{
return 0;
}
if ((params[0] / sizeof(cell))>2) // If this plugin was compiled with peachy's .inc then don't byref
{
*MF_GetAmxAddr_NEW(amx,params[3])=get_private(Weapon,MAKE_OFFSET(WEAPID));
}
return ENTINDEX_NEW(Weapon);
}
if (params[2]==0) // find current weapon
{
edict_t *Weapon=private_to_edict(get_private_p<void *>(player->GetEdict(),MAKE_OFFSET(CURRENT_WEAPON)));
if (Weapon==NULL) // no weapon
{
return 0;
}
if ((params[0] / sizeof(cell))>2) // If this plugin was compiled with peachy's .inc then don't byref
{
*MF_GetAmxAddr_NEW(amx,params[3])=get_private(Weapon,MAKE_OFFSET(WEAPID));
}
return ENTINDEX_NEW(Weapon);
}
// Finding weapon by ID
char **pPlayerItems = reinterpret_cast<char**>(static_cast<char*>(player->GetEdict()->pvPrivateData) + MAKE_OFFSET(PLAYER_ITEMS));
char *pItem;
int weapon=params[2];
for (int i = 0; i < 6; i++)
{
pItem = pPlayerItems[i];
while (pItem)
{
if (*(int *)(pItem + MAKE_OFFSET(WEAPID)) == weapon)
{
return ENTINDEX_NEW(private_to_edict(pItem));
}
else
{
pItem = *(char **)(pItem + MAKE_OFFSET(WEAP_NEXT));
}
}
}
return 0;
}
#ifdef DEVELOPER_BUILD
// ns_find_weapon_offset(idPlayer,"primweapon","lastinvweapon")
static cell AMX_NATIVE_CALL ns_find_weapon_offset(AMX *amx, cell *params)
{
char *SPrimWeapon=MF_GetAmxString(amx,params[2],0,NULL);
char *SLastInv=MF_GetAmxString(amx,params[3],1,NULL);
edict_t *ePlayer=INDEXENT_NEW(params[1]);
// Locate entities by name
edict_t *PrimWeapon=NULL;
edict_t *LastInv=NULL;
edict_t *Temp=NULL;
while ((Temp=UTIL_FindEntityByString(Temp,"classname",SPrimWeapon))!=NULL)
{
if (Temp->v.owner==ePlayer)
{
PrimWeapon=Temp;
break;
}
}
Temp=NULL;
while ((Temp=UTIL_FindEntityByString(Temp,"classname",SLastInv))!=NULL)
{
if (Temp->v.owner==ePlayer)
{
LastInv=Temp;
break;
}
}
if (LastInv == NULL || PrimWeapon == NULL)
{
if (LastInv==NULL)
{
MF_Log("LastInv==NULL");
}
if (PrimWeapon==NULL)
{
MF_Log("PrimWeapon=NULL");
}
return 0;
}
// now iterate through the client's private data until we find the pointer to PrimWeapon/LastInv's offset
unsigned int *Ptr=(unsigned int*)ePlayer->pvPrivateData;
int FoundLastInv=0;
int FoundPrim=0;
size_t count=0;
unsigned int iPrim;
unsigned int iLast;
// so nasty D: this is basically horrible_cast
union bleh
{
void *ptr;
unsigned int ival;
}blah;
blah.ptr=PrimWeapon->pvPrivateData;
iPrim=blah.ival;
blah.ptr=LastInv->pvPrivateData;
iLast=blah.ival;
while (count<4000)
{
if (*Ptr==iLast)
{
MF_Log("Found LastInv: %d",count);
FoundLastInv=1;
}
if (*Ptr==iPrim)
{
MF_Log("Found Primary: %d",count);
FoundPrim=1;
}
if (FoundLastInv && FoundPrim)
{
//break;
}
count+=4;
Ptr++;
}
return 1;
}
#endif
AMX_NATIVE_INFO weapon_natives[] = {
{ "ns_has_weapon", ns_has_weapon },
{ "ns_set_weap_dmg", ns_set_weapon_dmg },
{ "ns_get_weap_dmg", ns_get_weapon_dmg },
{ "ns_set_weap_range", ns_set_weapon_range },
{ "ns_get_weap_range", ns_get_weapon_range },
{ "ns_set_weap_clip", ns_set_weapon_clip },
{ "ns_get_weap_clip", ns_get_weapon_clip },
{ "ns_add_weap_clip", ns_add_weapon_clip },
{ "ns_set_weap_reserve", ns_set_weap_reserve },
{ "ns_get_weap_reserve", ns_get_weap_reserve },
{ "ns_add_weap_reserve", ns_add_weap_reserve },
{ "ns_get_weapon", ns_get_weapon},
#ifdef DEVELOPER_BUILD
{ "ns_find_weapon_offset", ns_find_weapon_offset},
#endif
{ NULL, NULL }
};
void AddNatives_Weapons()
{
MF_AddNatives(weapon_natives);
}