Update Fun module (#421)
* Fun: Replace ENTINDEX with TypeConversion for consistency * Fun: Add a class wrapping player's data * Fun: Make TraceLine a post forward Reason: as it is it breaks plugins hooking TraceLine because of the original game call is being superceded and other modules can't catch it. It looks like it's this way from the very start fun module has been introduced 13 years ago before. Fakemeta module comes a little later. * Fun: Clean up code * Fun: Toggle PlayerPreThink forward on demand * Fun: Toggle TraceLine forward on demand * Fun: Add HITZONE* constants for use with set/get_user_hitzone() * Fun: Refactor a litte the player class * Fun: Clean up a little more * Fun: Fix typo in set_user_hitzones from previous commit
This commit is contained in:
parent
6e9947b64f
commit
1a2dd9e7ea
@ -11,590 +11,464 @@
|
||||
// Fun Module
|
||||
//
|
||||
|
||||
#include <string.h>
|
||||
#include "fun.h"
|
||||
#include <HLTypeConversion.h>
|
||||
|
||||
/*
|
||||
JGHG says:
|
||||
|
||||
Ok this is what I use below, it may probably not be right with all natives etc but I try to maintain this style to natives.
|
||||
Note that this is still very much subject to change, regarding return values etc!
|
||||
(Ok I haven't checked all natives that they comply with this yet, this is just a model I'm working on and which I might implement soon.)
|
||||
|
||||
static cell AMX_NATIVE_CALL nativename(AMX *amx, cell *params) // nativename(argument1, argument2); = 2 params
|
||||
{
|
||||
// Description what this native does. <--- Description what this native does
|
||||
// params[1] = argument1 <--- Description of each argument, so we don't have to allocate new variables and can
|
||||
// params[2] = argument2 <--- use the ones in params[n] directly, to save some time.
|
||||
|
||||
// Check receiver and sender validity. <--- Check ents, maybe need to do this better and more proper later?
|
||||
CHECK_PLAYER(params[1])
|
||||
CHECK_PLAYER(params[2])
|
||||
|
||||
// Get * pointer.
|
||||
edict_t *pPlayer = MF_GetPlayerEdict(params[1]); <--- Players require a different function than INDEXENT because of an HLSDK bug
|
||||
|
||||
return 1 <--- If native succeeded, return 1, if the native isn't supposed to return a specific value.
|
||||
Note: Should be able to do: if (thenative()) and it should return false when it fails, and true when succeeds... is -1 treated as false, or is 0 a must?
|
||||
}
|
||||
*/
|
||||
|
||||
char g_bodyhits[33][33]; // where can the guy in the first dimension hit the people in the 2nd dimension? :-)
|
||||
bool g_silent[33]; // used for set_user_footsteps()
|
||||
|
||||
HLTypeConversion TypeConversion;
|
||||
CPlayers Players;
|
||||
|
||||
// ######## Utils:
|
||||
void FUNUTIL_ResetPlayer(int index)
|
||||
// native get_client_listen(receiver, sender)
|
||||
static cell AMX_NATIVE_CALL get_client_listening(AMX *amx, cell *params)
|
||||
{
|
||||
//MF_PrintSrvConsole("Resetting player index %d! maxclients: %d\n", index, gpGlobals->maxClients);
|
||||
for (int i = 1; i <= gpGlobals->maxClients; i++) {
|
||||
g_bodyhits[index][i] = (char)((1<<HITGROUP_GENERIC) |
|
||||
(1<<HITGROUP_HEAD) |
|
||||
(1<<HITGROUP_CHEST) |
|
||||
(1<<HITGROUP_STOMACH) |
|
||||
(1<<HITGROUP_LEFTARM) |
|
||||
(1<<HITGROUP_RIGHTARM)|
|
||||
(1<<HITGROUP_LEFTLEG) |
|
||||
(1<<HITGROUP_RIGHTLEG));
|
||||
}
|
||||
// Reset silent slippers
|
||||
g_silent[index] = false;
|
||||
enum args { arg_count, arg_receiver, arg_sender };
|
||||
|
||||
CHECK_PLAYER(params[arg_receiver]);
|
||||
CHECK_PLAYER(params[arg_sender]);
|
||||
|
||||
return GETCLIENTLISTENING(params[arg_receiver], params[arg_sender]);
|
||||
}
|
||||
|
||||
// ######## Natives:
|
||||
static cell AMX_NATIVE_CALL get_client_listening(AMX *amx, cell *params) // get_client_listening(receiver, sender); = 2 params
|
||||
// native set_client_listen(receiver, sender, listen)
|
||||
static cell AMX_NATIVE_CALL set_client_listening(AMX *amx, cell *params)
|
||||
{
|
||||
// Gets who can listen to who.
|
||||
// params[1] = receiver
|
||||
// params[2] = sender
|
||||
enum args { arg_count, arg_receiver, arg_sender, arg_listen };
|
||||
|
||||
// Check receiver and sender validity.
|
||||
CHECK_PLAYER(params[1]);
|
||||
CHECK_PLAYER(params[2]);
|
||||
CHECK_PLAYER(params[arg_receiver]);
|
||||
CHECK_PLAYER(params[arg_sender]);
|
||||
|
||||
// GET- AND SETCLIENTLISTENING returns "qboolean", an int, probably 0 or 1...
|
||||
return GETCLIENTLISTENING(params[1], params[2]);
|
||||
return SETCLIENTLISTENING(params[arg_receiver], params[arg_sender], params[arg_listen]);
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL set_client_listening(AMX *amx, cell *params) // set_client_listening(receiver, sender, listen); = 3 params
|
||||
// native set_user_godmode(index, godmode = 0)
|
||||
static cell AMX_NATIVE_CALL set_user_godmode(AMX *amx, cell *params)
|
||||
{
|
||||
// Sets who can listen to who.
|
||||
// params[1] = receiver
|
||||
// params[2] = sender
|
||||
// params[3] = listen
|
||||
enum args { arg_count, arg_user, arg_godmode };
|
||||
|
||||
// Check receiver and sender validity.
|
||||
CHECK_PLAYER(params[1]);
|
||||
CHECK_PLAYER(params[2]);
|
||||
CHECK_PLAYER(params[arg_user]);
|
||||
|
||||
// Make a check on params[3] here later, and call run time error when it's wrong.
|
||||
// To do: find out the possible values to set (0, 1?)
|
||||
const auto pPlayer = TypeConversion.id_to_edict(params[arg_user]);
|
||||
|
||||
// GET- AND SETCLIENTLISTENING returns "qboolean", an int, probably 0 or 1...
|
||||
return SETCLIENTLISTENING(params[1], params[2], params[3]);
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL set_user_godmode(AMX *amx, cell *params) // set_user_godmode(index, godmode = 0); = 2 params
|
||||
{
|
||||
/* Sets player godmode. If you want to disable godmode set only first parameter. */
|
||||
// params[1] = index
|
||||
// params[2] = godmode = 0
|
||||
|
||||
// Check index.
|
||||
CHECK_PLAYER(params[1]);
|
||||
|
||||
// Get player pointer.
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
|
||||
if (params[2] == 1) {
|
||||
// Enable godmode
|
||||
pPlayer->v.takedamage = 0.0; // 0.0, the player doesn't seem to be able to get hurt.
|
||||
}
|
||||
else {
|
||||
// Disable godmode
|
||||
pPlayer->v.takedamage = 2.0; // 2.0 seems to be standard value?
|
||||
}
|
||||
pPlayer->v.takedamage = params[arg_godmode] != 0 ? DAMAGE_NO : DAMAGE_AIM;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL get_user_godmode(AMX *amx, cell *params) // get_user_godmode(index); = 1 param
|
||||
// native get_user_godmode(index)
|
||||
static cell AMX_NATIVE_CALL get_user_godmode(AMX *amx, cell *params)
|
||||
{
|
||||
/* Returns 1 if godmode is set. */
|
||||
// params[1] = index
|
||||
enum args { arg_count, arg_user };
|
||||
|
||||
// Check index.
|
||||
CHECK_PLAYER(params[1]);
|
||||
CHECK_PLAYER(params[arg_user]);
|
||||
|
||||
// Get player pointer.
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
const auto pPlayer = TypeConversion.id_to_edict(params[arg_user]);
|
||||
|
||||
int godmode = 0;
|
||||
|
||||
if (pPlayer->v.takedamage == 0.0) {
|
||||
// God mode is enabled
|
||||
godmode = 1;
|
||||
}
|
||||
|
||||
return godmode;
|
||||
return pPlayer->v.takedamage == DAMAGE_NO;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL give_item(AMX *amx, cell *params) // native give_item(index, const item[]); = 2 params
|
||||
// native give_item(index, const item[])
|
||||
static cell AMX_NATIVE_CALL give_item(AMX *amx, cell *params)
|
||||
{
|
||||
/* Gives item to player, name of item can start
|
||||
* with weapon_, ammo_ and item_. This event
|
||||
* is announced with proper message to all players. */
|
||||
// params[1] = index
|
||||
// params[2] = item...
|
||||
enum args { arg_count, arg_index, arg_item };
|
||||
|
||||
// Check index.
|
||||
CHECK_PLAYER(params[1]);
|
||||
CHECK_PLAYER(params[arg_index]);
|
||||
|
||||
// Get player pointer.
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
auto itemLength = 0;
|
||||
const auto item = MF_GetAmxString(amx, params[arg_item], 1, &itemLength);
|
||||
|
||||
// Create item entity pointer
|
||||
edict_t *pItemEntity;
|
||||
|
||||
// Make an "intstring" out of 2nd parameter
|
||||
int length;
|
||||
const char *szItem = MF_GetAmxString(amx, params[2], 1, &length);
|
||||
|
||||
//check for valid item
|
||||
if (strncmp(szItem, "weapon_", 7) &&
|
||||
strncmp(szItem, "ammo_", 5) &&
|
||||
strncmp(szItem, "item_", 5) &&
|
||||
strncmp(szItem, "tf_weapon_", 10)
|
||||
) {
|
||||
if (!itemLength
|
||||
||(strncmp(item, "weapon_", 7) != 0
|
||||
&& strncmp(item, "ammo_", 5) != 0
|
||||
&& strncmp(item, "item_", 5) != 0
|
||||
&& strncmp(item, "tf_weapon_", 10) != 0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//string_t item = MAKE_STRING(szItem);
|
||||
string_t item = ALLOC_STRING(szItem); // Using MAKE_STRING makes "item" contents get lost when we leave this scope! ALLOC_STRING seems to allocate properly...
|
||||
// Create the entity, returns to pointer
|
||||
pItemEntity = CREATE_NAMED_ENTITY(item);
|
||||
auto pEntity = CREATE_NAMED_ENTITY(ALLOC_STRING(item));
|
||||
|
||||
if (FNullEnt(pItemEntity)) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Item \"%s\" failed to create", szItem);
|
||||
if (FNullEnt(pEntity))
|
||||
{
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Item \"%s\" failed to create", item);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//VARS(pItemEntity)->origin = VARS(pPlayer)->origin; // nice to do VARS(ent)->origin instead of ent->v.origin? :-I
|
||||
//I'm not sure, normally I use macros too =P
|
||||
pItemEntity->v.origin = pPlayer->v.origin;
|
||||
pItemEntity->v.spawnflags |= SF_NORESPAWN; //SF_NORESPAWN;
|
||||
const auto pPlayer = TypeConversion.id_to_edict(params[arg_index]);
|
||||
|
||||
MDLL_Spawn(pItemEntity);
|
||||
pEntity->v.origin = pPlayer->v.origin;
|
||||
pEntity->v.spawnflags |= SF_NORESPAWN;
|
||||
|
||||
int save = pItemEntity->v.solid;
|
||||
MDLL_Spawn(pEntity);
|
||||
|
||||
MDLL_Touch(pItemEntity, ENT(pPlayer));
|
||||
const auto oldSolid = pEntity->v.solid;
|
||||
|
||||
//The problem with the original give_item was the
|
||||
// item was not removed. I had tried this but it
|
||||
// did not work. OLO's implementation is better.
|
||||
/*
|
||||
int iEnt = ENTINDEX(pItemEntity->v.owner);
|
||||
if (iEnt > 32 || iEnt <1 ) {
|
||||
MDLL_Think(pItemEntity);
|
||||
}*/
|
||||
MDLL_Touch(pEntity, pPlayer);
|
||||
|
||||
if (pItemEntity->v.solid == save) {
|
||||
REMOVE_ENTITY(pItemEntity);
|
||||
//the function did not fail - we're just deleting the item
|
||||
if (pEntity->v.solid == oldSolid)
|
||||
{
|
||||
REMOVE_ENTITY(pEntity); // The function did not fail - we're just deleting the item
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ENTINDEX(pItemEntity);
|
||||
return TypeConversion.edict_to_id(pEntity);
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL spawn(AMX *amx, cell *params) // spawn(id) = 1 param
|
||||
// native spawn(index)
|
||||
static cell AMX_NATIVE_CALL spawn(AMX *amx, cell *params)
|
||||
{
|
||||
// Spawns an entity, this can be a user/player -> spawns at spawnpoints, or created entities seems to need this as a final "kick" into the game? :-)
|
||||
// params[1] = entity to spawn
|
||||
enum args { arg_count, arg_index };
|
||||
|
||||
CHECK_ENTITY(params[1]);
|
||||
CHECK_ENTITY(params[arg_index]);
|
||||
|
||||
edict_t *pEnt = TypeConversion.id_to_edict(params[1]);
|
||||
const auto pEntity = TypeConversion.id_to_edict(params[arg_index]);
|
||||
|
||||
MDLL_Spawn(pEnt);
|
||||
MDLL_Spawn(pEntity);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL set_user_health(AMX *amx, cell *params) // set_user_health(index, health); = 2 arguments
|
||||
// native set_user_health(index, health)
|
||||
static cell AMX_NATIVE_CALL set_user_health(AMX *amx, cell *params)
|
||||
{
|
||||
// Sets user health. If health is 0 and below, also kill...
|
||||
// params[1] = index
|
||||
// params[2] = health
|
||||
enum args { arg_count, arg_index, arg_health };
|
||||
|
||||
// Check index
|
||||
CHECK_PLAYER(params[1]);
|
||||
CHECK_PLAYER(params[arg_index]);
|
||||
|
||||
// Fetch player pointer
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
const auto pPlayer = TypeConversion.id_to_edict(params[arg_index]);
|
||||
const auto health = float(params[arg_health]);
|
||||
|
||||
// Kill if health too low.
|
||||
if (params[2] > 0)
|
||||
pPlayer->v.health = float(params[2]);
|
||||
if (health > 0.0f)
|
||||
{
|
||||
pPlayer->v.health = health;
|
||||
}
|
||||
else
|
||||
{
|
||||
MDLL_ClientKill(pPlayer);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL set_user_frags(AMX *amx, cell *params) // set_user_frags(index, frags); = 2 arguments
|
||||
// native set_user_frags(index, frags)
|
||||
static cell AMX_NATIVE_CALL set_user_frags(AMX *amx, cell *params)
|
||||
{
|
||||
// Sets user frags.
|
||||
// params[1] = index
|
||||
// params[2] = frags
|
||||
enum args { arg_count, arg_index, arg_frags };
|
||||
|
||||
// Check index
|
||||
CHECK_PLAYER(params[1]);
|
||||
CHECK_PLAYER(params[arg_index]);
|
||||
|
||||
// Fetch player pointer
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
const auto pPlayer = TypeConversion.id_to_edict(params[arg_index]);
|
||||
|
||||
pPlayer->v.frags = params[2];
|
||||
pPlayer->v.frags = float(params[arg_frags]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL set_user_armor(AMX *amx, cell *params) // set_user_armor(index, armor); = 2 arguments
|
||||
// native set_user_armor(index, armor)
|
||||
static cell AMX_NATIVE_CALL set_user_armor(AMX *amx, cell *params)
|
||||
{
|
||||
// Sets user armor.
|
||||
// params[1] = index
|
||||
// params[2] = armor
|
||||
enum args { arg_count, arg_index, arg_armor };
|
||||
|
||||
// Check index
|
||||
CHECK_PLAYER(params[1]);
|
||||
CHECK_PLAYER(params[arg_index]);
|
||||
|
||||
// Fetch player pointer
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
const auto pPlayer = TypeConversion.id_to_edict(params[arg_index]);
|
||||
|
||||
pPlayer->v.armorvalue = params[2];
|
||||
pPlayer->v.armorvalue = float(params[arg_armor]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL set_user_origin(AMX *amx, cell *params) // set_user_origin(index, origin[3]); = 2 arguments
|
||||
// native set_user_origin(index, const origin[3])
|
||||
static cell AMX_NATIVE_CALL set_user_origin(AMX *amx, cell *params)
|
||||
{
|
||||
// Sets user origin.
|
||||
// params[1] = index
|
||||
// params[2] = origin
|
||||
enum args { arg_count, arg_index, arg_origin };
|
||||
|
||||
// Check index
|
||||
CHECK_PLAYER(params[1]);
|
||||
CHECK_PLAYER(params[arg_index]);
|
||||
|
||||
// Fetch player pointer
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
|
||||
cell *newVectorCell = MF_GetAmxAddr(amx, params[2]);
|
||||
auto pPlayer = TypeConversion.id_to_edict(params[arg_index]);
|
||||
const auto pVector = MF_GetAmxAddr(amx, params[arg_origin]);
|
||||
|
||||
SET_SIZE(pPlayer, pPlayer->v.mins, pPlayer->v.maxs);
|
||||
SET_ORIGIN(pPlayer, Vector((float)newVectorCell[0], (float)newVectorCell[1], (float)newVectorCell[2]));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL set_user_rendering(AMX *amx, cell *params) // set_user_rendering(index, fx = kRenderFxNone, r = 255, g = 255, b = 255, render = kRenderNormal, amount = 16); = 7 arguments
|
||||
{
|
||||
// Sets user rendering.
|
||||
// params[1] = index
|
||||
// params[2] = fx
|
||||
// params[3] = r
|
||||
// params[4] = g
|
||||
// params[5] = b
|
||||
// params[6] = render
|
||||
// params[7] = amount
|
||||
|
||||
// Check index
|
||||
CHECK_PLAYER(params[1]);
|
||||
|
||||
// Fetch player pointer
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
|
||||
pPlayer->v.renderfx = params[2];
|
||||
Vector newVector = Vector(float(params[3]), float(params[4]), float(params[5]));
|
||||
pPlayer->v.rendercolor = newVector;
|
||||
pPlayer->v.rendermode = params[6];
|
||||
pPlayer->v.renderamt = params[7];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL get_user_rendering(AMX *amx, cell *params) // get_user_rendering(index, &fx = kRenderFxNone, &r = 0, &g = 0, &b = 0, &render = kRenderNormal, &amount = 0); = 7 arguments
|
||||
{
|
||||
// Gets user rendering.
|
||||
// params[1] = index
|
||||
// params[2] = fx
|
||||
// params[3] = r
|
||||
// params[4] = g
|
||||
// params[5] = b
|
||||
// params[6] = render
|
||||
// params[7] = amount
|
||||
|
||||
// Check index
|
||||
CHECK_PLAYER(params[1]);
|
||||
|
||||
// Fetch player pointer
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
|
||||
*MF_GetAmxAddr(amx, params[2]) = pPlayer->v.renderfx;
|
||||
*MF_GetAmxAddr(amx, params[3]) = pPlayer->v.rendercolor[0];
|
||||
*MF_GetAmxAddr(amx, params[4]) = pPlayer->v.rendercolor[1];
|
||||
*MF_GetAmxAddr(amx, params[5]) = pPlayer->v.rendercolor[2];
|
||||
*MF_GetAmxAddr(amx, params[6]) = pPlayer->v.rendermode;
|
||||
*MF_GetAmxAddr(amx, params[7]) = pPlayer->v.renderamt;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL set_user_maxspeed(AMX *amx, cell *params) // set_user_maxspeed(index, Float:speed = -1.0) = 2 arguments
|
||||
{
|
||||
// Sets user maxspeed.
|
||||
// params[1] = index
|
||||
// params[2] = speed (should be -1.0 if not specified) (JGHG: unspecified parameters seems to always be -1.0!)
|
||||
|
||||
REAL fNewSpeed = amx_ctof(params[2]);
|
||||
|
||||
// Check index
|
||||
CHECK_PLAYER(params[1]);
|
||||
|
||||
// Fetch player pointer
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
|
||||
SETCLIENTMAXSPEED(pPlayer, fNewSpeed);
|
||||
pPlayer->v.maxspeed = fNewSpeed;
|
||||
SET_ORIGIN(pPlayer, Vector(float(pVector[0]), float(pVector[1]), float(pVector[2])));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL get_user_maxspeed(AMX *amx, cell *params) // Float:get_user_maxspeed(index) = 1 argument
|
||||
// native set_user_rendering(index, fx = kRenderFxNone, r = 0, g = 0, b = 0, render = kRenderNormal, amount = 0)
|
||||
static cell AMX_NATIVE_CALL set_user_rendering(AMX *amx, cell *params)
|
||||
{
|
||||
// Gets user maxspeed.
|
||||
// params[1] = index
|
||||
enum args { arg_count, arg_index, arg_fx, arg_red, arg_green, arg_blue, arg_render, arg_amount };
|
||||
|
||||
// Check index
|
||||
CHECK_PLAYER(params[1]);
|
||||
CHECK_PLAYER(params[arg_index]);
|
||||
|
||||
// Fetch player pointer
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
auto pPlayer = TypeConversion.id_to_edict(params[arg_index]);
|
||||
|
||||
pPlayer->v.renderfx = params[arg_fx];
|
||||
pPlayer->v.rendercolor = Vector(float(params[arg_red]), float(params[arg_green]), float(params[arg_blue]));
|
||||
pPlayer->v.rendermode = params[arg_render];
|
||||
pPlayer->v.renderamt = float(params[arg_amount]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// get_user_rendering(index, &fx = kRenderFxNone, &r = 0, &g = 0, &b = 0, &render = kRenderNormal, &amount = 0);
|
||||
static cell AMX_NATIVE_CALL get_user_rendering(AMX *amx, cell *params)
|
||||
{
|
||||
enum args { arg_count, arg_index, arg_fx, arg_red, arg_green, arg_blue, arg_render, arg_amount };
|
||||
|
||||
CHECK_PLAYER(params[arg_index]);
|
||||
|
||||
auto pPlayer = TypeConversion.id_to_edict(params[arg_index]);
|
||||
|
||||
*MF_GetAmxAddr(amx, params[arg_fx]) = pPlayer->v.renderfx;
|
||||
*MF_GetAmxAddr(amx, params[arg_red]) = pPlayer->v.rendercolor[0];
|
||||
*MF_GetAmxAddr(amx, params[arg_green]) = pPlayer->v.rendercolor[1];
|
||||
*MF_GetAmxAddr(amx, params[arg_blue]) = pPlayer->v.rendercolor[2];
|
||||
*MF_GetAmxAddr(amx, params[arg_render]) = pPlayer->v.rendermode;
|
||||
*MF_GetAmxAddr(amx, params[arg_amount]) = pPlayer->v.renderamt;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// native set_user_maxspeed(index, Float:speed = -1.0)
|
||||
static cell AMX_NATIVE_CALL set_user_maxspeed(AMX *amx, cell *params)
|
||||
{
|
||||
enum args { arg_count, arg_index, arg_speed };
|
||||
|
||||
CHECK_PLAYER(params[arg_index]);
|
||||
|
||||
const auto pPlayer = TypeConversion.id_to_edict(params[arg_index]);
|
||||
const auto newSpeed = amx_ctof(params[arg_speed]);
|
||||
|
||||
SETCLIENTMAXSPEED(pPlayer, newSpeed);
|
||||
pPlayer->v.maxspeed = newSpeed;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// native Float:get_user_maxspeed(index)
|
||||
static cell AMX_NATIVE_CALL get_user_maxspeed(AMX *amx, cell *params)
|
||||
{
|
||||
enum args { arg_count, arg_index };
|
||||
|
||||
CHECK_PLAYER(params[arg_index]);
|
||||
|
||||
const auto pPlayer = TypeConversion.id_to_edict(params[arg_index]);
|
||||
|
||||
return amx_ftoc(pPlayer->v.maxspeed);
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL set_user_gravity(AMX *amx, cell *params) // set_user_gravity(index, Float:gravity = 1.0) = 2 arguments
|
||||
// native set_user_gravity(index, Float:gravity = 1.0)
|
||||
static cell AMX_NATIVE_CALL set_user_gravity(AMX *amx, cell *params)
|
||||
{
|
||||
// Sets user gravity.
|
||||
// params[1] = index
|
||||
// params[2] = gravity (=-1.0)
|
||||
// Check index
|
||||
CHECK_PLAYER(params[1]);
|
||||
enum args { arg_count, arg_index, arg_gravity };
|
||||
|
||||
// Fetch player pointer
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
CHECK_PLAYER(params[arg_index]);
|
||||
|
||||
pPlayer->v.gravity = amx_ctof(params[2]);
|
||||
const auto pPlayer = TypeConversion.id_to_edict(params[arg_index]);
|
||||
|
||||
pPlayer->v.gravity = amx_ctof(params[arg_gravity]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL get_user_gravity(AMX *amx, cell *params) // Float:get_user_gravity(index) = 1 argument
|
||||
// native Float:get_user_gravity(index)
|
||||
static cell AMX_NATIVE_CALL get_user_gravity(AMX *amx, cell *params)
|
||||
{
|
||||
// Gets user gravity.
|
||||
// params[1] = index
|
||||
enum args { arg_count, arg_index };
|
||||
|
||||
// Check index
|
||||
CHECK_PLAYER(params[1]);
|
||||
CHECK_PLAYER(params[arg_index]);
|
||||
|
||||
// Fetch player pointer
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
const auto pPlayer = TypeConversion.id_to_edict(params[arg_index]);
|
||||
|
||||
return amx_ftoc(pPlayer->v.gravity);
|
||||
return amx_ftoc(pPlayer->v.gravity);
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL set_user_hitzones(AMX *amx, cell *params) // set_user_hitzones(index = 0, target = 0, body = 255); = 3 arguments
|
||||
// native set_user_hitzones(index = 0, target = 0, body = HITZONES_DEFAULT)
|
||||
static cell AMX_NATIVE_CALL set_user_hitzones(AMX *amx, cell *params)
|
||||
{
|
||||
// Sets user hitzones.
|
||||
// params[1] = the one(s) who shoot(s), shooter
|
||||
int shooter = params[1];
|
||||
enum args { arg_count, arg_attacker, arg_target, arg_hitzones };
|
||||
|
||||
// params[2] = the one getting hit
|
||||
int gettingHit = params[2];
|
||||
const int attacker = params[arg_attacker];
|
||||
const int target = params[arg_target];
|
||||
const int hitzones = params[arg_hitzones];
|
||||
|
||||
// params[3] = specified hit zones
|
||||
int hitzones = params[3];
|
||||
|
||||
//set_user_hitzones(id, 0, 0) // Makes ID not able to shoot EVERYONE - id can shoot on 0 (all) at 0
|
||||
//set_user_hitzones(0, id, 0) // Makes EVERYONE not able to shoot ID - 0 (all) can shoot id at 0
|
||||
if (shooter == 0 && gettingHit == 0) {
|
||||
for (int i = 1; i <= gpGlobals->maxClients; i++) {
|
||||
for (int j = 1; j <= gpGlobals->maxClients; j++) {
|
||||
g_bodyhits[i][j] = hitzones;
|
||||
}
|
||||
//g_zones_toHit[i] = hitzones;
|
||||
//g_zones_getHit[i] = hitzones;
|
||||
}
|
||||
if (attacker == 0 && target == 0)
|
||||
{
|
||||
Players.SetEveryoneBodyHits(hitzones);
|
||||
}
|
||||
else if (shooter == 0 && gettingHit != 0) {
|
||||
// "All" shooters, target (gettingHit) should be existing player id
|
||||
CHECK_PLAYER(gettingHit);
|
||||
// Where can all hit gettingHit?
|
||||
for (int i = 1; i <= gpGlobals->maxClients; i++)
|
||||
g_bodyhits[i][gettingHit] = hitzones;
|
||||
else if (attacker == 0 && target != 0)
|
||||
{
|
||||
CHECK_PLAYER(target);
|
||||
|
||||
Players.SetAttackersBodyHits(target, hitzones);
|
||||
}
|
||||
else if (shooter != 0 && gettingHit == 0) {
|
||||
// Shooter can hit all in bodyparts.
|
||||
CHECK_PLAYER(shooter);
|
||||
for (int i = 1; i <= gpGlobals->maxClients; i++)
|
||||
g_bodyhits[shooter][i] = hitzones;
|
||||
else if (attacker != 0 && target == 0)
|
||||
{
|
||||
CHECK_PLAYER(attacker);
|
||||
|
||||
Players.SetTargetsBodyHits(attacker, hitzones);
|
||||
}
|
||||
else {
|
||||
// Specified, where can player A hit player B?
|
||||
CHECK_PLAYER(shooter);
|
||||
CHECK_PLAYER(gettingHit);
|
||||
g_bodyhits[shooter][gettingHit] = hitzones;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL get_user_hitzones(AMX *amx, cell *params) // get_user_hitzones(index, target); = 2 arguments
|
||||
{
|
||||
int shooter = params[1];
|
||||
CHECK_PLAYER(shooter);
|
||||
int target = params[2];
|
||||
CHECK_PLAYER(target);
|
||||
return g_bodyhits[shooter][target];
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL set_user_noclip(AMX *amx, cell *params) // set_user_noclip(index, noclip = 0); = 2 arguments
|
||||
{
|
||||
// Sets user to no clipping mode.
|
||||
// params[1] = index
|
||||
// params[2] = no clip or not...
|
||||
|
||||
// Check index
|
||||
CHECK_PLAYER(params[1]);
|
||||
|
||||
// Fetch player pointer
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
|
||||
if (params[2] == 1)
|
||||
pPlayer->v.movetype = MOVETYPE_NOCLIP;
|
||||
else
|
||||
pPlayer->v.movetype = MOVETYPE_WALK;
|
||||
{
|
||||
CHECK_PLAYER(attacker);
|
||||
CHECK_PLAYER(target);
|
||||
|
||||
Players.SetBodyHits(attacker, target, hitzones);
|
||||
}
|
||||
|
||||
g_pengfuncsTable_Post->pfnTraceLine = Players.HaveBodyHits() ? TraceLine_Post : nullptr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL get_user_noclip(AMX *amx, cell *params) // get_user_noclip(index); = 1 argument
|
||||
// native get_user_hitzones(index, target)
|
||||
static cell AMX_NATIVE_CALL get_user_hitzones(AMX *amx, cell *params)
|
||||
{
|
||||
// Gets user noclip.
|
||||
// params[1] = index
|
||||
enum args { arg_count, arg_attacker, arg_target };
|
||||
|
||||
// Check index
|
||||
CHECK_PLAYER(params[1]);
|
||||
const auto attacker = params[arg_attacker];
|
||||
|
||||
// Fetch player pointer
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
CHECK_PLAYER(attacker);
|
||||
|
||||
const auto target = params[arg_target];
|
||||
|
||||
CHECK_PLAYER(target);
|
||||
|
||||
return Players[attacker].GetBodyHits(target);
|
||||
}
|
||||
|
||||
// native set_user_noclip(index, noclip = 0)
|
||||
static cell AMX_NATIVE_CALL set_user_noclip(AMX *amx, cell *params)
|
||||
{
|
||||
enum args { arg_count, arg_index, arg_noclip };
|
||||
|
||||
CHECK_PLAYER(params[arg_index]);
|
||||
|
||||
const auto pPlayer = TypeConversion.id_to_edict(params[arg_index]);
|
||||
|
||||
pPlayer->v.movetype = params[arg_noclip] != 0 ? MOVETYPE_NOCLIP : MOVETYPE_WALK;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// native get_user_noclip(index)
|
||||
static cell AMX_NATIVE_CALL get_user_noclip(AMX *amx, cell *params)
|
||||
{
|
||||
enum args { arg_count, arg_index };
|
||||
|
||||
CHECK_PLAYER(params[arg_index]);
|
||||
|
||||
const auto pPlayer = TypeConversion.id_to_edict(params[arg_index]);
|
||||
|
||||
return pPlayer->v.movetype == MOVETYPE_NOCLIP;
|
||||
}
|
||||
|
||||
// JustinHoMi made this one originally
|
||||
static cell AMX_NATIVE_CALL set_user_footsteps(AMX *amx, cell *params) // set_user_footsteps(id, set = 1); = 2 params
|
||||
// native set_user_footsteps(id, set = 1)
|
||||
static cell AMX_NATIVE_CALL set_user_footsteps(AMX *amx, cell *params)
|
||||
{
|
||||
// Gives player silent footsteps.
|
||||
// if set=0 it will return footsteps to normal
|
||||
// params[1] = index of player
|
||||
// params[2] = 0 = normal footstep sound, 1 = silent slippers
|
||||
enum args { arg_count, arg_index, arg_footsteps };
|
||||
|
||||
// Check index
|
||||
CHECK_PLAYER(params[1]);
|
||||
const auto index = params[arg_index];
|
||||
|
||||
// Fetch player pointer
|
||||
edict_t *pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
CHECK_PLAYER(index);
|
||||
|
||||
if (params[2]) {
|
||||
const auto pPlayer = TypeConversion.id_to_edict(index);
|
||||
|
||||
if (params[arg_footsteps] != 0)
|
||||
{
|
||||
pPlayer->v.flTimeStepSound = 999;
|
||||
g_silent[params[1]] = true;
|
||||
Players[index].SetSilentFootsteps(true);
|
||||
|
||||
g_pFunctionTable->pfnPlayerPreThink = PlayerPreThink;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
pPlayer->v.flTimeStepSound = STANDARDTIMESTEPSOUND;
|
||||
g_silent[params[1]] = false;
|
||||
Players[index].SetSilentFootsteps(false);
|
||||
|
||||
if (g_pFunctionTable->pfnPlayerPreThink && !Players.HaveSilentFootsteps())
|
||||
{
|
||||
g_pFunctionTable->pfnPlayerPreThink = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// native get_user_footsteps(index)
|
||||
static cell AMX_NATIVE_CALL get_user_footsteps(AMX *amx, cell *params)
|
||||
{
|
||||
CHECK_PLAYER(params[1]);
|
||||
enum args { arg_count, arg_index };
|
||||
|
||||
return g_silent[params[1]];
|
||||
const auto index = params[arg_index];
|
||||
|
||||
CHECK_PLAYER(index);
|
||||
|
||||
return Players[index].HasSilentFootsteps();
|
||||
}
|
||||
|
||||
// SidLuke
|
||||
static cell AMX_NATIVE_CALL strip_user_weapons(AMX *amx, cell *params) // index
|
||||
// native strip_user_weapons(index)
|
||||
static cell AMX_NATIVE_CALL strip_user_weapons(AMX *amx, cell *params)
|
||||
{
|
||||
CHECK_PLAYER(params[1]);
|
||||
enum args { arg_count, arg_index };
|
||||
|
||||
edict_t* pPlayer = TypeConversion.id_to_edict(params[1]);
|
||||
const auto index = params[arg_index];
|
||||
|
||||
string_t item = MAKE_STRING("player_weaponstrip");
|
||||
edict_t *pent = CREATE_NAMED_ENTITY(item);
|
||||
CHECK_PLAYER(index);
|
||||
|
||||
if (FNullEnt(pent))
|
||||
const auto pPlayer = TypeConversion.id_to_edict(index);
|
||||
const auto pEntity = CREATE_NAMED_ENTITY(MAKE_STRING("player_weaponstrip"));
|
||||
|
||||
if (FNullEnt(pEntity))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
MDLL_Spawn(pent);
|
||||
MDLL_Use(pent, pPlayer);
|
||||
REMOVE_ENTITY(pent);
|
||||
MDLL_Spawn(pEntity);
|
||||
MDLL_Use(pEntity, pPlayer);
|
||||
REMOVE_ENTITY(pEntity);
|
||||
|
||||
*reinterpret_cast<int *>(MF_PlayerPropAddr(params[1], Player_CurrentWeapon)) = 0;
|
||||
*reinterpret_cast<int *>(MF_PlayerPropAddr(index, Player_CurrentWeapon)) = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AMX_NATIVE_INFO fun_Exports[] = {
|
||||
{"get_client_listen", get_client_listening},
|
||||
{"set_client_listen", set_client_listening},
|
||||
{"set_user_godmode", set_user_godmode},
|
||||
{"get_user_godmode", get_user_godmode},
|
||||
{"set_user_health", set_user_health},
|
||||
{"give_item", give_item},
|
||||
{"spawn", spawn},
|
||||
{"set_user_frags", set_user_frags},
|
||||
{"set_user_armor", set_user_armor},
|
||||
{"set_user_origin", set_user_origin},
|
||||
{"set_user_rendering", set_user_rendering},
|
||||
{"get_user_rendering", get_user_rendering},
|
||||
{"set_user_maxspeed", set_user_maxspeed},
|
||||
{"get_user_maxspeed", get_user_maxspeed},
|
||||
{"set_user_gravity", set_user_gravity},
|
||||
{"get_user_gravity", get_user_gravity},
|
||||
{"get_user_footsteps", get_user_footsteps},
|
||||
{"set_user_hitzones", set_user_hitzones},
|
||||
{"get_user_hitzones", get_user_hitzones},
|
||||
{"set_user_noclip", set_user_noclip},
|
||||
{"get_user_noclip", get_user_noclip},
|
||||
{"set_user_footsteps", set_user_footsteps},
|
||||
{"strip_user_weapons", strip_user_weapons},
|
||||
/////////////////// <--- 19 chars max in current small version
|
||||
{NULL, NULL}
|
||||
|
||||
AMX_NATIVE_INFO fun_Exports[] =
|
||||
{
|
||||
{ "get_client_listen" , get_client_listening },
|
||||
{ "set_client_listen" , set_client_listening },
|
||||
{ "set_user_godmode" , set_user_godmode },
|
||||
{ "get_user_godmode" , get_user_godmode },
|
||||
{ "set_user_health" , set_user_health },
|
||||
{ "give_item" , give_item },
|
||||
{ "spawn" , spawn },
|
||||
{ "set_user_frags" , set_user_frags },
|
||||
{ "set_user_armor" , set_user_armor },
|
||||
{ "set_user_origin" , set_user_origin },
|
||||
{ "set_user_rendering", set_user_rendering },
|
||||
{ "get_user_rendering", get_user_rendering },
|
||||
{ "set_user_maxspeed" , set_user_maxspeed },
|
||||
{ "get_user_maxspeed" , get_user_maxspeed },
|
||||
{ "set_user_gravity" , set_user_gravity },
|
||||
{ "get_user_gravity" , get_user_gravity },
|
||||
{ "get_user_footsteps", get_user_footsteps },
|
||||
{ "set_user_hitzones" , set_user_hitzones },
|
||||
{ "get_user_hitzones" , get_user_hitzones },
|
||||
{ "set_user_noclip" , set_user_noclip },
|
||||
{ "get_user_noclip" , get_user_noclip },
|
||||
{ "set_user_footsteps", set_user_footsteps },
|
||||
{ "strip_user_weapons", strip_user_weapons },
|
||||
{ nullptr , nullptr }
|
||||
};
|
||||
|
||||
/******************************************************************************************/
|
||||
|
||||
void PlayerPreThink(edict_t *pEntity)
|
||||
{
|
||||
if (g_silent[ENTINDEX(pEntity)]) {
|
||||
pEntity->v.flTimeStepSound = 999;
|
||||
const auto index = TypeConversion.edict_to_id(pEntity);
|
||||
|
||||
if (Players[index].HasSilentFootsteps())
|
||||
{
|
||||
pEntity->v.flTimeStepSound = 999;
|
||||
RETURN_META(MRES_HANDLED);
|
||||
}
|
||||
|
||||
@ -603,76 +477,51 @@ void PlayerPreThink(edict_t *pEntity)
|
||||
|
||||
int ClientConnect(edict_t *pPlayer, const char *pszName, const char *pszAddress, char szRejectReason[128])
|
||||
{
|
||||
// Reset stuff:
|
||||
FUNUTIL_ResetPlayer(ENTINDEX(pPlayer));
|
||||
const auto index = TypeConversion.edict_to_id(pPlayer);
|
||||
|
||||
Players[index].Clear();
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, 0);
|
||||
}
|
||||
|
||||
void TraceLine(const float *v1, const float *v2, int fNoMonsters, edict_t *shooter, TraceResult *ptr) {
|
||||
TRACE_LINE(v1, v2, fNoMonsters, shooter, ptr);
|
||||
if ( ptr->pHit && (ptr->pHit->v.flags& (FL_CLIENT | FL_FAKECLIENT))
|
||||
&& shooter && (shooter->v.flags & (FL_CLIENT | FL_FAKECLIENT)) ) {
|
||||
int shooterIndex = ENTINDEX(shooter);
|
||||
if ( !(g_bodyhits[shooterIndex][ENTINDEX(ptr->pHit)] & (1<<ptr->iHitgroup)) )
|
||||
void TraceLine_Post(const float *v1, const float *v2, int fNoMonsters, edict_t *shooter, TraceResult *ptr)
|
||||
{
|
||||
if (ptr->pHit && (ptr->pHit->v.flags & (FL_CLIENT | FL_FAKECLIENT))
|
||||
&& shooter && (shooter->v.flags & (FL_CLIENT | FL_FAKECLIENT)) )
|
||||
{
|
||||
const auto shooterIndex = TypeConversion.edict_to_id(shooter);
|
||||
const auto targetIndex = TypeConversion.edict_to_id(ptr->pHit);
|
||||
|
||||
if (!(Players[shooterIndex].GetBodyHits(targetIndex) & (1 << ptr->iHitgroup)))
|
||||
{
|
||||
ptr->flFraction = 1.0;
|
||||
RETURN_META(MRES_HANDLED);
|
||||
}
|
||||
}
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
|
||||
//int g_hitIndex, g_canTargetGetHit, g_canShooterHitThere;
|
||||
//void TraceLine(const float *v1, const float *v2, int fNoMonsters, edict_t *shooter, TraceResult *ptr) {
|
||||
// if (!pentToSkip || (pentToSkip->v.flags & (FL_CLIENT | FL_FAKECLIENT)) == false || pentToSkip->v.deadflag != DEAD_NO)
|
||||
// RETURN_META(MRES_IGNORED);
|
||||
//
|
||||
// TRACE_LINE(v1, v2, fNoMonsters, shooter, ptr); // Filter shooter
|
||||
//
|
||||
// if (!ptr->pHit || (ptr->pHit->v.flags & (FL_CLIENT | FL_FAKECLIENT)) == false )
|
||||
// RETURN_META(MRES_SUPERCEDE);
|
||||
//
|
||||
// g_hitIndex = ENTINDEX(ptr->pHit);
|
||||
// //bool blocked = false;
|
||||
// g_canTargetGetHit = g_zones_getHit[g_hitIndex] & (1 << ptr->iHitgroup);
|
||||
// g_canShooterHitThere = g_zones_toHit[ENTINDEX(shooter)] & (1 << ptr->iHitgroup);
|
||||
//
|
||||
// if (!g_canTargetGetHit || !g_canShooterHitThere) {
|
||||
// ptr->flFraction = 1.0; // set to not hit anything (1.0 = shot doesn't hit anything)
|
||||
// //blocked = true;
|
||||
// }
|
||||
// /*
|
||||
// if (blocked) {
|
||||
// MF_PrintSrvConsole("%s was blocked from hitting %s: %d and %d\n", MF_GetPlayerName(ENTINDEX(pentToSkip)), MF_GetPlayerName(hitIndex), canTargetGetHit, canShooterHitThere);
|
||||
// }
|
||||
// else {
|
||||
// MF_PrintSrvConsole("%s was NOT blocked from hitting %s: %d and %d\n", MF_GetPlayerName(ENTINDEX(pentToSkip)), MF_GetPlayerName(hitIndex), canTargetGetHit, canShooterHitThere);
|
||||
// }
|
||||
// */
|
||||
//
|
||||
// RETURN_META(MRES_SUPERCEDE);
|
||||
//}
|
||||
|
||||
void OnAmxxAttach()
|
||||
{
|
||||
MF_AddNatives(fun_Exports);
|
||||
}
|
||||
|
||||
// The content of OnPluginsLoaded() was moved from OnAmxxAttach with AMXx 1.5 because for some reason gpGlobals->maxClients wasn't
|
||||
// initialized to its proper value until some time after OnAmxxAttach(). In OnAmxxAttach() it always showed 0. /JGHG
|
||||
void OnPluginsLoaded() {
|
||||
// Reset stuff - hopefully this should
|
||||
for (int i = 1; i <= gpGlobals->maxClients; i++) {
|
||||
// Reset all hitzones
|
||||
FUNUTIL_ResetPlayer(i);
|
||||
}
|
||||
void OnPluginsLoaded()
|
||||
{
|
||||
Players.Clear();
|
||||
|
||||
TypeConversion.init();
|
||||
|
||||
g_pFunctionTable->pfnPlayerPreThink = nullptr;
|
||||
g_pengfuncsTable_Post->pfnTraceLine = nullptr;
|
||||
}
|
||||
/*
|
||||
void ClientConnectFakeBot(int index)
|
||||
|
||||
void ServerDeactivate()
|
||||
{
|
||||
FUNUTIL_ResetPlayer(index);
|
||||
//MF_Log("A bot connects, forwarded to fun! The bot is %d!", index);
|
||||
//CPlayer* player;
|
||||
g_pFunctionTable->pfnPlayerPreThink = nullptr;
|
||||
g_pengfuncsTable_Post->pfnTraceLine = nullptr;
|
||||
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
*/
|
||||
|
@ -11,7 +11,9 @@
|
||||
// Fun Module
|
||||
//
|
||||
|
||||
#include "amxxmodule.h"
|
||||
#pragma once
|
||||
|
||||
#include <amxxmodule.h>
|
||||
|
||||
// Fun-specific defines below
|
||||
#define GETCLIENTLISTENING (*g_engfuncs.pfnVoice_GetClientListening)
|
||||
@ -29,19 +31,181 @@
|
||||
#define HITGROUP_RIGHTARM 5 // 32
|
||||
#define HITGROUP_LEFTLEG 6 // 64
|
||||
#define HITGROUP_RIGHTLEG 7 // 128
|
||||
#define HITGROUP_MAX 8
|
||||
|
||||
extern DLL_FUNCTIONS *g_pFunctionTable;
|
||||
extern enginefuncs_t *g_pengfuncsTable_Post;
|
||||
|
||||
void PlayerPreThink(edict_t *pEntity);
|
||||
void TraceLine_Post(const float *v1, const float *v2, int fNoMonsters, edict_t *shooter, TraceResult *ptr);
|
||||
|
||||
static const auto kHitGroupsBits = (1 << HITGROUP_MAX) - 1;
|
||||
static const auto kMaxClients = 32u;
|
||||
|
||||
class CPlayer
|
||||
{
|
||||
public:
|
||||
|
||||
CPlayer()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool HasBodyHits() const
|
||||
{
|
||||
for (auto i = 1; i <= gpGlobals->maxClients; ++i)
|
||||
{
|
||||
if (GetBodyHits(i) != kHitGroupsBits)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int GetBodyHits(const int other) const
|
||||
{
|
||||
return bodyHits_[other];
|
||||
}
|
||||
|
||||
void SetBodyHits(const int other, const int flags)
|
||||
{
|
||||
bodyHits_[other] = flags;
|
||||
}
|
||||
|
||||
void SetBodyHits(const int flags)
|
||||
{
|
||||
memset(bodyHits_, flags, sizeof bodyHits_);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool HasSilentFootsteps() const
|
||||
{
|
||||
return silentFootsteps_;
|
||||
}
|
||||
|
||||
void SetSilentFootsteps(const bool state)
|
||||
{
|
||||
silentFootsteps_ = state;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void Clear()
|
||||
{
|
||||
SetBodyHits(kHitGroupsBits);
|
||||
SetSilentFootsteps(false);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
int bodyHits_[kMaxClients + 1] {};
|
||||
bool silentFootsteps_ {};
|
||||
};
|
||||
|
||||
class CPlayers
|
||||
{
|
||||
using Internal = CPlayer;
|
||||
|
||||
public:
|
||||
|
||||
bool HaveBodyHits() const
|
||||
{
|
||||
for (auto i = 1; i <= gpGlobals->maxClients; ++i)
|
||||
{
|
||||
if (players_[i].HasBodyHits())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetBodyHits(const int attacker, const int target, const int flags)
|
||||
{
|
||||
players_[attacker].SetBodyHits(target, flags);
|
||||
}
|
||||
|
||||
void SetTargetsBodyHits(const int attacker, const int flags)
|
||||
{
|
||||
players_[attacker].SetBodyHits(flags);
|
||||
}
|
||||
|
||||
void SetAttackersBodyHits(const int target, const int flags)
|
||||
{
|
||||
for (auto i = 1; i <= gpGlobals->maxClients; ++i)
|
||||
{
|
||||
players_[i].SetBodyHits(target, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void SetEveryoneBodyHits(const int flags)
|
||||
{
|
||||
for (auto i = 1; i <= gpGlobals->maxClients; ++i)
|
||||
{
|
||||
players_[i].SetBodyHits(flags);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool HaveSilentFootsteps() const
|
||||
{
|
||||
for (auto i = 1; i <= gpGlobals->maxClients; ++i)
|
||||
{
|
||||
if (players_[i].HasSilentFootsteps())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for (auto i = 1; i <= gpGlobals->maxClients; ++i)
|
||||
{
|
||||
players_[i].Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Internal& operator [](const size_t index)
|
||||
{
|
||||
return players_[index];
|
||||
}
|
||||
|
||||
const Internal& operator [](const size_t index) const
|
||||
{
|
||||
return players_[index];
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Internal players_[kMaxClients + 1];
|
||||
};
|
||||
|
||||
#define CHECK_ENTITY(x) \
|
||||
if (x < 0 || x > gpGlobals->maxEntities) { \
|
||||
if ((x) < 0 || (x) > gpGlobals->maxEntities) { \
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Entity out of range (%d)", x); \
|
||||
return 0; \
|
||||
} else { \
|
||||
if (x <= gpGlobals->maxClients) { \
|
||||
if ((x) <= gpGlobals->maxClients) { \
|
||||
if (!MF_IsPlayerIngame(x)) { \
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid player %d (not in-game)", x); \
|
||||
return 0; \
|
||||
} \
|
||||
} else { \
|
||||
if (x != 0 && FNullEnt(TypeConversion.id_to_edict(x))) { \
|
||||
if ((x) != 0 && FNullEnt(TypeConversion.id_to_edict(x))) { \
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid entity %d", x); \
|
||||
return 0; \
|
||||
} \
|
||||
@ -49,7 +213,7 @@
|
||||
}
|
||||
|
||||
#define CHECK_PLAYER(x) \
|
||||
if (x < 1 || x > gpGlobals->maxClients) { \
|
||||
if ((x) < 1 || (x) > gpGlobals->maxClients) { \
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "Player out of range (%d)", x); \
|
||||
return 0; \
|
||||
} else { \
|
||||
|
@ -119,8 +119,8 @@
|
||||
// #define FN_ClientCommand ClientCommand /* pfnClientCommand() (wd) Player has sent a command (typed or from a bind) */
|
||||
// #define FN_ClientUserInfoChanged ClientUserInfoChanged /* pfnClientUserInfoChanged() (wd) Client has updated their setinfo structure */
|
||||
// #define FN_ServerActivate ServerActivate /* pfnServerActivate() (wd) Server is starting a new map */
|
||||
// #define FN_ServerDeactivate ServerDeactivate /* pfnServerDeactivate() (wd) Server is leaving the map (shutdown or changelevel); SDK2 */
|
||||
#define FN_PlayerPreThink PlayerPreThink /* pfnPlayerPreThink() */
|
||||
#define FN_ServerDeactivate ServerDeactivate /* pfnServerDeactivate() (wd) Server is leaving the map (shutdown or changelevel); SDK2 */
|
||||
// #define FN_PlayerPreThink PlayerPreThink /* pfnPlayerPreThink() */
|
||||
// #define FN_PlayerPostThink PlayerPostThink /* pfnPlayerPostThink() */
|
||||
// #define FN_StartFrame StartFrame /* pfnStartFrame() */
|
||||
// #define FN_ParmsNewLevel ParmsNewLevel /* pfnParmsNewLevel() */
|
||||
@ -232,7 +232,7 @@
|
||||
// #define FN_SetOrigin SetOrigin
|
||||
// #define FN_EmitSound EmitSound
|
||||
// #define FN_EmitAmbientSound EmitAmbientSound
|
||||
#define FN_TraceLine TraceLine
|
||||
// #define FN_TraceLine TraceLine
|
||||
// #define FN_TraceToss TraceToss
|
||||
// #define FN_TraceMonsterHull TraceMonsterHull
|
||||
// #define FN_TraceHull TraceHull
|
||||
|
@ -21,6 +21,21 @@
|
||||
#pragma loadlib fun
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Parts of body for hits, for use with set_user_hitzones().
|
||||
*/
|
||||
const HITZONE_GENERIC = (1 << HIT_GENERIC); // 1
|
||||
const HITZONE_HEAD = (1 << HIT_HEAD); // 2
|
||||
const HITZONE_CHEST = (1 << HIT_CHEST); // 4
|
||||
const HITZONE_STOMATCH = (1 << HIT_STOMATCH); // 8
|
||||
const HITZONE_LEFTARM = (1 << HIT_LEFTARM); // 16
|
||||
const HITZONE_RIGHTARM = (1 << HIT_RIGHTARM); // 32
|
||||
const HITZONE_LEFTLEG = (1 << HIT_LEFTLEG); // 64
|
||||
const HITZONE_RIGHTLEG = (1 << HIT_RIGHTLEG); // 128
|
||||
const HITZONES_DEFAULT = HITZONE_GENERIC | HITZONE_HEAD | HITZONE_CHEST | HITZONE_STOMATCH |
|
||||
HITZONE_LEFTARM | HITZONE_RIGHTARM | HITZONE_LEFTLEG | HITZONE_RIGHTLEG; // 255
|
||||
|
||||
/**
|
||||
* Tells whether receiver hears sender via voice communication.
|
||||
*
|
||||
@ -169,26 +184,18 @@ native give_item(index, const item[]);
|
||||
*
|
||||
* @param index Client index
|
||||
* @param target The target player
|
||||
* @param body A bitsum of the body parts that can/can't be shot:
|
||||
* 1 - generic
|
||||
* 2 - head
|
||||
* 4 - chest
|
||||
* 8 - stomach
|
||||
* 16 - left arm
|
||||
* 32 - right arm
|
||||
* 64 - left leg
|
||||
* 128 - right leg
|
||||
* @param body A bitsum of the body parts that can/can't be shot. See HITZONE* constants.
|
||||
*
|
||||
* @noreturn
|
||||
* @error If player is not connected or not within the range
|
||||
* of 1 to MaxClients.
|
||||
*/
|
||||
native set_user_hitzones(index = 0, target = 0, body = 255);
|
||||
native set_user_hitzones(index = 0, target = 0, body = HITZONES_DEFAULT);
|
||||
|
||||
/**
|
||||
* Gets the set of hit zone "rules" between @index and @target players.
|
||||
*
|
||||
* @note For the body part bitsum take a look at the set_user_hitzones() native.
|
||||
* @note For the body part bitsum, see HITZONE* constants.
|
||||
*
|
||||
* @param index Client index
|
||||
* @param target The target player
|
||||
|
Loading…
Reference in New Issue
Block a user