480 lines
12 KiB
C++
480 lines
12 KiB
C++
|
/* 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);
|
||
|
}
|