(Kural İhlali Sıkıntısı Bir Script'te)
Gönderilme zamanı: Cmt Ara 21, 2019 5:33 pm
@Yek'-ta
@Taha Demirbaş
@seypa
@Fatih ~ EjderYa
@Colditz
@Taha Demirbaş
@seypa
@Fatih ~ EjderYa
@Colditz
Kod: Tümünü seç
/* AMX Mod X
* [HL] Set Animation API
*
* http://aghl.ru/forum/ - Russian Half-Life and Adrenaline Gamer Community
*
* This file is provided as is (no warranties)
*/
#pragma semicolon 1
#pragma ctrlchar '\'
#include <amxmodx>
#include <fakemeta>
#include <xs>
#define PLUGIN "[HL] Set Animation API"
#define VERSION "0.1"
#define AUTHOR "KORD_12.7"
#define ACTIVITY_NOT_AVAILABLE -1
#define STUDIO_LOOPING 0x0001
#define DEFAULT_MODEL "gordon"
enum _:SEQ_DESC
{
SEQ_LABEL[33],
SEQ_FPS,
SEQ_FLAGS,
SEQ_ACTIVITY,
SEQ_ACTWEIGHT,
SEQ_NUMFRAMES,
SEQ_LINEARMOVEMENT_X,
SEQ_LINEARMOVEMENT_Y,
SEQ_LINEARMOVEMENT_Z
};
enum _:PLAYER_ANIM
{
PLAYER_IDLE,
PLAYER_WALK,
PLAYER_JUMP,
PLAYER_SUPERJUMP,
PLAYER_DIE,
PLAYER_ATTACK1
};
enum _:Activity
{
ACT_RESET = 0, // Set m_Activity to this invalid value to force a reset to m_IdealActivity
ACT_IDLE = 1,
ACT_GUARD,
ACT_WALK,
ACT_RUN,
ACT_FLY, // Fly (and flap if appropriate)
ACT_SWIM,
ACT_HOP, // vertical jump
ACT_LEAP, // long forward jump
ACT_FALL,
ACT_LAND,
ACT_STRAFE_LEFT,
ACT_STRAFE_RIGHT,
ACT_ROLL_LEFT, // tuck and roll, left
ACT_ROLL_RIGHT, // tuck and roll, right
ACT_TURN_LEFT, // turn quickly left (stationary)
ACT_TURN_RIGHT, // turn quickly right (stationary)
ACT_CROUCH, // the act of crouching down from a standing position
ACT_CROUCHIDLE, // holding body in crouched position (loops)
ACT_STAND, // the act of standing from a crouched position
ACT_USE,
ACT_SIGNAL1,
ACT_SIGNAL2,
ACT_SIGNAL3,
ACT_TWITCH,
ACT_COWER,
ACT_SMALL_FLINCH,
ACT_BIG_FLINCH,
ACT_RANGE_ATTACK1,
ACT_RANGE_ATTACK2,
ACT_MELEE_ATTACK1,
ACT_MELEE_ATTACK2,
ACT_RELOAD,
ACT_ARM, // pull out gun, for instance
ACT_DISARM, // reholster gun
ACT_EAT, // monster chowing on a large food item (loop)
ACT_DIESIMPLE,
ACT_DIEBACKWARD,
ACT_DIEFORWARD,
ACT_DIEVIOLENT,
ACT_BARNACLE_HIT, // barnacle tongue hits a monster
ACT_BARNACLE_PULL, // barnacle is lifting the monster ( loop )
ACT_BARNACLE_CHOMP, // barnacle latches on to the monster
ACT_BARNACLE_CHEW, // barnacle is holding the monster in its mouth ( loop )
ACT_SLEEP,
ACT_INSPECT_FLOOR, // for active idles, look at something on or near the floor
ACT_INSPECT_WALL, // for active idles, look at something directly ahead of you ( doesn't HAVE to be a wall or on a wall )
ACT_IDLE_ANGRY, // alternate idle animation in which the monster is clearly agitated. (loop)
ACT_WALK_HURT, // limp (loop)
ACT_RUN_HURT, // limp (loop)
ACT_HOVER, // Idle while in flight
ACT_GLIDE, // Fly (don't flap)
ACT_FLY_LEFT, // Turn left in flight
ACT_FLY_RIGHT, // Turn right in flight
ACT_DETECT_SCENT, // this means the monster smells a scent carried by the air
ACT_SNIFF, // this is the act of actually sniffing an item in front of the monster
ACT_BITE, // some large monsters can eat small things in one bite. This plays one time, EAT loops.
ACT_THREAT_DISPLAY, // without attacking, monster demonstrates that it is angry. (Yell, stick out chest, etc )
ACT_FEAR_DISPLAY, // monster just saw something that it is afraid of
ACT_EXCITED, // for some reason, monster is excited. Sees something he really likes to eat, or whatever.
ACT_SPECIAL_ATTACK1, // very monster specific special attacks.
ACT_SPECIAL_ATTACK2,
ACT_COMBAT_IDLE, // agitated idle.
ACT_WALK_SCARED,
ACT_RUN_SCARED,
ACT_VICTORY_DANCE, // killed a player, do a victory dance.
ACT_DIE_HEADSHOT, // die, hit in head.
ACT_DIE_CHESTSHOT, // die, hit in chest
ACT_DIE_GUTSHOT, // die, hit in gut
ACT_DIE_BACKSHOT, // die, hit in back
ACT_FLINCH_HEAD,
ACT_FLINCH_CHEST,
ACT_FLINCH_STOMACH,
ACT_FLINCH_LEFTARM,
ACT_FLINCH_RIGHTARM,
ACT_FLINCH_LEFTLEG,
ACT_FLINCH_RIGHTLEG
};
const m_flFrameRate = 23 ; // computed FPS for current sequence
const m_flGroundSpeed = 24; // computed linear movement rate for current sequence
const m_flLastEventCheck = 25; // last time the event list was checked
const m_fSequenceFinished = 26; // flag set when StudioAdvanceFrame moves across a frame boundry
const m_fSequenceLoops = 27; // true if the sequence loops
const m_Activity = 88; // what the monster is doing (animation)
const m_IdealActivity = 89; // monster should switch to this activity
const m_LastHitGroup = 90;
const m_szAnimExtention = 387;
const XTRA_OFS_PLAYER = 5;
new Trie: g_TrieModels;
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR);
LoadModels();
}
//*************************************
//* Set the activity based on *
//* an event or current state *
//*************************************
Player_SetAnimation(const iPlayer, iPlayerAnim)
{
new iActivity;
new iAnimDesired;
new iIdealActivity;
new iSequenceLoops;
new iSequenceFinished;
new szAnim[64];
new szModel[32];
new Float: flSpeed;
new Float: flVelocity[3];
new Array: iSeqArrayHandle;
get_user_info(iPlayer, "model", szModel, charsmax(szModel));
if (!TrieKeyExists(g_TrieModels, szModel))
{
copy(szModel, charsmax(szModel), DEFAULT_MODEL);
}
TrieGetCell(g_TrieModels, szModel, iSeqArrayHandle);
if (iSeqArrayHandle == Invalid_Array)
{
return;
}
if (pev(iPlayer, pev_flags) & FL_FROZEN)
{
flSpeed = 0.0;
iPlayerAnim = PLAYER_IDLE;
}
pev(iPlayer, pev_velocity, flVelocity);
flSpeed = vector_length(flVelocity);
iActivity = get_pdata_int(iPlayer, m_Activity, XTRA_OFS_PLAYER);
iSequenceLoops = get_pdata_int(iPlayer, m_fSequenceLoops, XTRA_OFS_PLAYER);
iSequenceFinished = get_pdata_int(iPlayer, m_fSequenceFinished, XTRA_OFS_PLAYER);
get_pdata_string(iPlayer, m_szAnimExtention * 4, szAnim, charsmax(szAnim), 0, XTRA_OFS_PLAYER * 4);
switch (iPlayerAnim)
{
case PLAYER_JUMP:
{
set_pdata_int(iPlayer, m_IdealActivity, iIdealActivity = ACT_HOP, XTRA_OFS_PLAYER);
}
case PLAYER_SUPERJUMP:
{
set_pdata_int(iPlayer, m_IdealActivity, iIdealActivity = ACT_LEAP, XTRA_OFS_PLAYER);
}
case PLAYER_DIE:
{
set_pdata_int(iPlayer, m_IdealActivity, iIdealActivity = GetDeathActivity(iPlayer, iSeqArrayHandle), XTRA_OFS_PLAYER);
}
case PLAYER_ATTACK1:
{
switch (iActivity)
{
case ACT_HOVER, ACT_SWIM, ACT_HOP, ACT_LEAP, ACT_DIESIMPLE:
{
set_pdata_int(iPlayer, m_IdealActivity, iIdealActivity = iActivity, XTRA_OFS_PLAYER);
}
default:
{
set_pdata_int(iPlayer, m_IdealActivity, iIdealActivity = ACT_RANGE_ATTACK1, XTRA_OFS_PLAYER);
}
}
}
case PLAYER_IDLE, PLAYER_WALK:
{
if (!(pev(iPlayer, pev_flags) & FL_ONGROUND) && (iActivity == ACT_HOP || iActivity == ACT_LEAP)) // Still jumping
{
set_pdata_int(iPlayer, m_IdealActivity, iIdealActivity = iActivity, XTRA_OFS_PLAYER);
}
else if(pev(iPlayer, pev_waterlevel) > 1)
{
set_pdata_int(iPlayer, m_IdealActivity, iIdealActivity = flSpeed ? ACT_SWIM : ACT_HOVER, XTRA_OFS_PLAYER);
}
else
{
set_pdata_int(iPlayer, m_IdealActivity, iIdealActivity = ACT_WALK, XTRA_OFS_PLAYER);
}
}
}
switch (iIdealActivity)
{
case ACT_RANGE_ATTACK1:
{
format(szAnim, charsmax(szAnim), (pev(iPlayer, pev_flags) & FL_DUCKING) ? "crouch_shoot_%s" : "ref_shoot_%s", szAnim);
if ((iAnimDesired = LookupSequence(iSeqArrayHandle, szAnim)) == -1)
{
iAnimDesired = 0;
}
if (pev(iPlayer, pev_sequence) != iAnimDesired || !iSequenceLoops)
{
set_pev(iPlayer, pev_frame, 0.0);
}
if (!iSequenceLoops)
{
set_pev(iPlayer, pev_effects, pev(iPlayer, pev_effects) | EF_NOINTERP);
}
set_pdata_int(iPlayer, m_Activity, iActivity = iIdealActivity, XTRA_OFS_PLAYER);
set_pev(iPlayer, pev_sequence, iAnimDesired);
ResetSequenceInfo(iSeqArrayHandle, iPlayer, iAnimDesired);
}
case ACT_WALK:
{
if (iActivity != ACT_RANGE_ATTACK1 || iSequenceFinished)
{
format(szAnim, charsmax(szAnim), (pev(iPlayer, pev_flags) & FL_DUCKING) ? "crouch_aim_%s" : "ref_aim_%s", szAnim);
if ((iAnimDesired = LookupSequence(iSeqArrayHandle, szAnim)) == -1)
{
iAnimDesired = 0;
}
set_pdata_int(iPlayer, m_Activity, iActivity = ACT_WALK, XTRA_OFS_PLAYER);
}
else
{
iAnimDesired = pev(iPlayer, pev_sequence);
}
}
default:
{
if (iActivity == iIdealActivity)
{
return;
}
set_pdata_int(iPlayer, m_Activity, iActivity = iIdealActivity, XTRA_OFS_PLAYER);
iAnimDesired = LookupActivity(iSeqArrayHandle, iActivity);
// Already using the desired animation?
if (pev(iPlayer, pev_sequence) == iAnimDesired)
{
return;
}
set_pev(iPlayer, pev_gaitsequence, 0);
set_pev(iPlayer, pev_sequence, iAnimDesired);
set_pev(iPlayer, pev_frame, 0.0);
ResetSequenceInfo(iSeqArrayHandle, iPlayer, iAnimDesired);
return;
}
}
if (pev(iPlayer, pev_flags) & FL_DUCKING)
{
if (!flSpeed)
{
set_pev(iPlayer, pev_gaitsequence, LookupActivity(iSeqArrayHandle, ACT_CROUCHIDLE));
}
else
{
set_pev(iPlayer, pev_gaitsequence, LookupActivity(iSeqArrayHandle, ACT_CROUCH));
}
}
else if (flSpeed > 220.0)
{
set_pev(iPlayer, pev_gaitsequence, LookupActivity(iSeqArrayHandle, ACT_RUN));
}
else if (flSpeed > 0.0)
{
set_pev(iPlayer, pev_gaitsequence, LookupActivity(iSeqArrayHandle, ACT_WALK));
}
else
{
set_pev(iPlayer, pev_gaitsequence, LookupSequence(iSeqArrayHandle, "deep_idle"));
}
// Already using the desired animation?
if (pev(iPlayer, pev_sequence) == iAnimDesired)
{
return;
}
// Reset to first frame of desired animation
set_pev(iPlayer, pev_sequence, iAnimDesired);
set_pev(iPlayer, pev_frame, 0.0);
ResetSequenceInfo(iSeqArrayHandle, iPlayer, iAnimDesired);
}
//*************************************
//* GetDeathActivity - determines the *
//* best type of death . *
//*************************************
GetDeathActivity(const iPlayer, const Array: iSeqArrayHandle)
{
if (pev(iPlayer, pev_deadflag) != DEAD_NO)
{
// don't run this while dying.
return get_pdata_int(iPlayer, m_IdealActivity, XTRA_OFS_PLAYER);
}
new iDeathActivity = ACT_DIESIMPLE;
new iInflictor = pev(iPlayer, pev_dmg_inflictor);
new bool: bTriedDirection;
new Float: flDot;
new Float: vecSrc[3];
new Float: vecAngles[3];
new Float: vecForward[3];
new Float: vecInflictorCenter[3];
new Float: vecAttackDir[3];
GetCenter(iPlayer, vecSrc);
// grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit).
if (pev_valid(iInflictor))
{
GetCenter(iInflictor, vecInflictorCenter);
xs_vec_sub(vecInflictorCenter, Float:{0.0, 0.0, 10.0}, vecInflictorCenter);
xs_vec_sub(vecInflictorCenter, vecSrc, vecAttackDir);
xs_vec_normalize(vecAttackDir, vecAttackDir);
}
pev(iPlayer, pev_angles, vecAngles);
engfunc(EngFunc_MakeVectors, vecAngles);
global_get(glb_v_forward, vecForward);
xs_vec_mul_scalar(vecAttackDir, -1.0, vecAttackDir);
flDot = xs_vec_dot(vecForward, vecAttackDir);
switch (get_pdata_int(iPlayer, m_LastHitGroup, XTRA_OFS_PLAYER))
{
// try to pick a region-specific death.
case HIT_HEAD:
{
iDeathActivity = ACT_DIE_HEADSHOT;
}
case HIT_STOMACH:
{
iDeathActivity = ACT_DIE_GUTSHOT;
}
default:
{
// try to pick a death based on attack direction
bTriedDirection = true;
if (flDot > 0.3)
{
iDeathActivity = ACT_DIEFORWARD;
}
else if (flDot <= -0.3)
{
iDeathActivity = ACT_DIEBACKWARD;
}
}
}
// can we perform the prescribed death?
if (LookupActivity(iSeqArrayHandle, iDeathActivity) == ACTIVITY_NOT_AVAILABLE)
{
// no! did we fail to perform a directional death?
if (bTriedDirection)
{
// if yes, we're out of options. Go simple.
iDeathActivity = ACT_DIESIMPLE;
}
else
{
// cannot perform the ideal region-specific death, so try a direction.
if (flDot > 0.3)
{
iDeathActivity = ACT_DIEFORWARD;
}
else if (flDot <= -0.3)
{
iDeathActivity = ACT_DIEBACKWARD;
}
}
}
if (LookupActivity(iSeqArrayHandle, iDeathActivity) == ACTIVITY_NOT_AVAILABLE)
{
// if we're still invalid, simple is our only option.
iDeathActivity = ACT_DIESIMPLE;
}
if (iDeathActivity == ACT_DIEFORWARD || iDeathActivity == ACT_DIEBACKWARD)
{
// make sure there's room to fall forward or backward.
new pTrace;
new Float: flFraction;
xs_vec_mul_scalar(vecForward, 64.0, vecForward);
(iDeathActivity == ACT_DIEFORWARD) ? xs_vec_add(vecSrc, vecForward, vecForward) : xs_vec_sub(vecSrc, vecForward, vecForward);
engfunc(EngFunc_TraceHull, vecSrc, vecForward, DONT_IGNORE_MONSTERS, 3, iPlayer, (pTrace = create_tr2()));
get_tr2(pTrace, TR_flFraction, flFraction);
if (flFraction != 1.0)
{
iDeathActivity = ACT_DIESIMPLE;
}
free_tr2(pTrace);
}
return iDeathActivity;
}
// center point of entity
GetCenter(const iEntity, Float: vecSrc[3])
{
new Float: vecAbsMax[3];
new Float: vecAbsMin[3];
pev(iEntity, pev_absmax, vecAbsMax);
pev(iEntity, pev_absmin, vecAbsMin);
xs_vec_add(vecAbsMax, vecAbsMin, vecSrc);
xs_vec_mul_scalar(vecSrc, 0.5, vecSrc);
}
//*************************************
//* Sequences . *
//*************************************
LookupSequence(const Array: iSeqArrayHandle, const szLabel[])
{
new i;
new iNumSeq;
new aSeqDesc[SEQ_DESC];
iNumSeq = ArraySize(iSeqArrayHandle);
for (i = 0; i < iNumSeq; i++)
{
ArrayGetArray(iSeqArrayHandle, i, aSeqDesc);
if (!strcmp(aSeqDesc[SEQ_LABEL], szLabel))
{
return i;
}
}
return -1;
}
LookupActivity(const Array: iSeqArrayHandle, const iActivity)
{
new i;
new iNumSeq;
new iSequence;
new iWeightTotal;
new aSeqDesc[SEQ_DESC];
iSequence = ACTIVITY_NOT_AVAILABLE;
iNumSeq = ArraySize(iSeqArrayHandle);
for (i = 0; i < iNumSeq; i++)
{
ArrayGetArray(iSeqArrayHandle, i, aSeqDesc);
if (aSeqDesc[SEQ_ACTIVITY] == iActivity)
{
iWeightTotal += aSeqDesc[SEQ_ACTWEIGHT];
if (!iWeightTotal || random_num(0, iWeightTotal - 1) < aSeqDesc[SEQ_ACTWEIGHT])
{
iSequence = i;
}
}
}
return iSequence;
}
ResetSequenceInfo(const Array: iSeqArrayHandle, const iPlayer, const iSequence)
{
new Float: flFrameRate;
new Float: flGroundSpeed;
GetSequenceInfo(iSeqArrayHandle, iSequence, flFrameRate, flGroundSpeed);
set_pdata_float(iPlayer, m_flFrameRate, flFrameRate, XTRA_OFS_PLAYER);
set_pdata_float(iPlayer, m_flGroundSpeed, flGroundSpeed, XTRA_OFS_PLAYER);
set_pdata_int(iPlayer, m_fSequenceLoops, ((GetSequenceFlags(iSeqArrayHandle, iSequence) & STUDIO_LOOPING) != 0), XTRA_OFS_PLAYER);
set_pev(iPlayer, pev_animtime, get_gametime());
set_pev(iPlayer, pev_framerate, 1.0);
set_pdata_int(iPlayer, m_fSequenceFinished, 0, XTRA_OFS_PLAYER);
set_pdata_float(iPlayer, m_flLastEventCheck, get_gametime(), XTRA_OFS_PLAYER);
}
GetSequenceInfo(const Array: iSeqArrayHandle, const iSequence, &Float: flFrameRate, &Float: flGroundSpeed)
{
new aSeqDesc[SEQ_DESC];
if (iSequence >= ArraySize(iSeqArrayHandle))
{
flFrameRate = 0.0;
flGroundSpeed = 0.0;
return;
}
ArrayGetArray(iSeqArrayHandle, iSequence, aSeqDesc);
if (aSeqDesc[SEQ_NUMFRAMES] > 1)
{
flFrameRate = 256.0 * Float: aSeqDesc[SEQ_FPS] / (aSeqDesc[SEQ_NUMFRAMES] - 1);
flGroundSpeed = floatsqroot(Float: aSeqDesc[SEQ_LINEARMOVEMENT_X] * Float: aSeqDesc[SEQ_LINEARMOVEMENT_X] + Float: aSeqDesc[SEQ_LINEARMOVEMENT_Y] * Float: aSeqDesc[SEQ_LINEARMOVEMENT_Y] + Float: aSeqDesc[SEQ_LINEARMOVEMENT_Z] * Float: aSeqDesc[SEQ_LINEARMOVEMENT_Z]);
flGroundSpeed *= flGroundSpeed * Float: aSeqDesc[SEQ_FPS] / (aSeqDesc[SEQ_NUMFRAMES] - 1);
}
else
{
flFrameRate = 256.0;
flGroundSpeed = 0.0;
}
}
GetSequenceFlags(const Array: iSeqArrayHandle, const iSequence)
{
if (iSequence >= ArraySize(iSeqArrayHandle))
{
return 0;
}
new aSeqDesc[SEQ_DESC];
ArrayGetArray(iSeqArrayHandle, iSequence, aSeqDesc);
return aSeqDesc[SEQ_FLAGS];
}
//*************************************
//* Load models and get sequences *
//*************************************
LoadModels()
{
g_TrieModels = TrieCreate();
new szModelFolder[32];
new iDirictory = open_dir("models/player", szModelFolder, charsmax(szModelFolder));
while (iDirictory && next_file(iDirictory, szModelFolder, charsmax(szModelFolder)))
{
if (szModelFolder[0] != '.')
{
GetModelSequences(szModelFolder);
}
}
close_dir(iDirictory);
}
// Thanks to PomanoB
GetModelSequences(const szModel[])
{
new i;
new iFile;
new iNumSeq;
new iSeqIndex;
new szModelPath[512];
new aSeqDesc[SEQ_DESC];
new Array: iSeqArrayHandle;
formatex(szModelPath, charsmax(szModelPath), "models/player/%s/%s.mdl", szModel, szModel);
if ((iFile = fopen(szModelPath, "rt")))
{
iSeqArrayHandle = ArrayCreate(SEQ_DESC, 1);
fseek(iFile, 164, SEEK_SET);
fread(iFile, iNumSeq, BLOCK_INT);
fread(iFile, iSeqIndex, BLOCK_INT);
for (i = 0; i < iNumSeq; i++)
{
fseek(iFile, iSeqIndex + 176 * i, SEEK_SET);
fread_blocks(iFile, aSeqDesc[SEQ_LABEL], 32, BLOCK_CHAR);
fread(iFile, aSeqDesc[SEQ_FPS], BLOCK_INT);
fread(iFile, aSeqDesc[SEQ_FLAGS], BLOCK_INT);
fread(iFile, aSeqDesc[SEQ_ACTIVITY], BLOCK_INT);
fread(iFile, aSeqDesc[SEQ_ACTWEIGHT], BLOCK_INT);
fseek(iFile, 8, SEEK_CUR);
fread(iFile, aSeqDesc[SEQ_NUMFRAMES], BLOCK_INT);
fseek(iFile, 16, SEEK_CUR);
fread(iFile, aSeqDesc[SEQ_LINEARMOVEMENT_X], BLOCK_INT);
fread(iFile, aSeqDesc[SEQ_LINEARMOVEMENT_Y], BLOCK_INT);
fread(iFile, aSeqDesc[SEQ_LINEARMOVEMENT_Z], BLOCK_INT);
ArrayPushArray(iSeqArrayHandle, aSeqDesc);
}
TrieSetCell(g_TrieModels, szModel, iSeqArrayHandle);
}
fclose(iFile);
}
//*************************************
//* API . *
//*************************************
public plugin_natives()
{
register_library("hl_set_anim");
register_native("hl_user_set_animation", "_hl_user_set_animation");
}
/* Set the activity based on an event or current state
*
* native hl_user_set_animation(const iPlayer, const iPlayerAnim);
*/
public _hl_user_set_animation(iPlugin, iParams)
{
if (iParams != 2)
{
log_error(AMX_ERR_NATIVE, "Bad arguments num, expected 2, passed %d", iParams);
return 0;
}
new iPlayer = get_param(1);
new iPlayerAnim = get_param(2);
if (!is_user_connected(iPlayer))
{
log_error(AMX_ERR_NATIVE, "Invalid player index (%d)", iPlayer);
return 0;
}
Player_SetAnimation(iPlayer, iPlayerAnim);
return 1;
}