diff --git a/reapi/extra/amxmodx/scripting/include/reapi_engine.inc b/reapi/extra/amxmodx/scripting/include/reapi_engine.inc index f3cedd0a..ce3aabb8 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi_engine.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi_engine.inc @@ -123,6 +123,48 @@ native GetBonePosition(const entity, const bone, Float:vecOrigin[3], Float:vecAn */ native GetAttachment(const entity, const attachment, Float:vecOrigin[3], Float:vecAngles[3] = {0.0, 0.0, 0.0}); +/* +* Sets body group value based on entity's model group +* +* @param entity Entity index +* @param group Number of entity's model group index +* @param value Value to assign +* +* @return 1 on success, 0 otherwise +* @error If the index is not within the range of 1 to maxEntities or +* the entity is not valid, an error will be thrown. +* +*/ +native SetBodygroup(const entity, const group, const value); + +/* +* Gets body group value based on entity's model group +* +* @param entity Entity index +* @param group Number of entity's model group index +* +* @return Body group value +* @error If the index is not within the range of 1 to maxEntities or +* the entity is not valid, an error will be thrown. +* +*/ +native GetBodygroup(const entity, const group); + +/* +* Gets sequence information based on entity's model current sequence index +* +* @param entity Entity index +* @param piFlags Sequence flags (1 = sequence loops) +* @param pflFrameRate Sequence framerate +* @param pflGroundSpeed Sequence ground speed +* +* @return True on success, false otherwise +* @error If the index is not within the range of 1 to maxEntities or +* the entity is not valid, an error will be thrown. +* +*/ +native bool:GetSequenceInfo(const entity, &piFlags, &Float:pflFrameRate, &Float:pflGroundSpeed); + /* * Sets the name of the map. * diff --git a/reapi/src/natives/natives_common.cpp b/reapi/src/natives/natives_common.cpp index e36c465f..416521a7 100644 --- a/reapi/src/natives/natives_common.cpp +++ b/reapi/src/natives/natives_common.cpp @@ -312,6 +312,107 @@ cell AMX_NATIVE_CALL amx_GetAttachment(AMX *amx, cell *params) return TRUE; } +/* +* Sets body group value based on entity's model group +* +* @param entity Entity index +* @param group Number of entity's model group index +* @param value Value to assign +* +* @return 1 on success, 0 otherwise +* @error If the index is not within the range of 1 to maxEntities or +* the entity is not valid, an error will be thrown. +* +*/ +cell AMX_NATIVE_CALL amx_GetBodygroup(AMX *amx, cell *params) +{ + enum args_e { arg_count, arg_index, arg_group }; + + CHECK_ISENTITY(arg_index); + + CBaseEntity *pEntity = getPrivate(params[arg_index]); + if (unlikely(pEntity == nullptr)) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__); + return 0; + } + + if (FNullEnt(params[arg_index])) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: worldspawn not allowed", __FUNCTION__); + return 0; + } + + return (cell)GetBodygroup(pEntity, params[arg_group]); +} + +/* +* Gets body group value based on entity's model group +* +* @param entity Entity index +* @param group Number of entity's model group index +* +* @return Body group value +* @error If the index is not within the range of 1 to maxEntities or +* the entity is not valid, an error will be thrown. +* +*/ +cell AMX_NATIVE_CALL amx_SetBodygroup(AMX *amx, cell *params) +{ + enum args_e { arg_count, arg_index, arg_group, arg_value }; + + CHECK_ISENTITY(arg_index); + + CBaseEntity *pEntity = getPrivate(params[arg_index]); + if (unlikely(pEntity == nullptr)) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__); + return FALSE; + } + + if (FNullEnt(params[arg_index])) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: worldspawn not allowed", __FUNCTION__); + return FALSE; + } + + SetBodygroup(pEntity, params[arg_group], params[arg_value]); + return TRUE; +} + +/* +* Gets sequence information based on entity's model current sequence index +* +* @param entity Entity index +* @param piFlags Sequence flags (1 = sequence loops) +* @param pflFrameRate Sequence framerate +* @param pflGroundSpeed Sequence ground speed +* +* @return True on success, false otherwise +* @error If the index is not within the range of 1 to maxEntities or +* the entity is not valid, an error will be thrown. +* +*/ +cell AMX_NATIVE_CALL amx_GetSequenceInfo(AMX *amx, cell *params) +{ + enum args_e { arg_count, arg_index, arg_flags, arg_framerate, arg_groundspeed }; + + CHECK_ISENTITY(arg_index); + + CBaseEntity *pEntity = getPrivate(params[arg_index]); + if (unlikely(pEntity == nullptr)) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__); + return FALSE; + } + + if (FNullEnt(params[arg_index])) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: worldspawn not allowed", __FUNCTION__); + return FALSE; + } + + int* pflags = reinterpret_cast(getAmxAddr(amx, params[arg_flags])); + float* pframerate = reinterpret_cast(getAmxAddr(amx, params[arg_framerate])); + float* pgroundspeed = reinterpret_cast(getAmxAddr(amx, params[arg_groundspeed])); + + return (cell)GetSequenceInfo2(pEntity, pflags, pframerate, pgroundspeed); +} + /* * Sets Think callback for entity * @@ -545,6 +646,9 @@ AMX_NATIVE_INFO Natives_Common[] = { "set_key_value_buffer", amx_set_key_value_buffer }, { "GetBonePosition", amx_GetBonePosition }, { "GetAttachment", amx_GetAttachment }, + { "GetBodygroup", amx_GetBodygroup }, + { "SetBodygroup", amx_SetBodygroup }, + { "GetSequenceInfo", amx_GetSequenceInfo }, { "SetThink", amx_SetThink }, { "SetTouch", amx_SetTouch }, { "SetUse", amx_SetUse }, diff --git a/reapi/src/reapi_utils.cpp b/reapi/src/reapi_utils.cpp index d285b347..ade7779a 100644 --- a/reapi/src/reapi_utils.cpp +++ b/reapi/src/reapi_utils.cpp @@ -223,6 +223,74 @@ void GetAttachment(CBaseEntity *pEntity, int iAttachment, Vector *pVecOrigin, Ve } } +void SetBodygroup(CBaseEntity *pEntity, int iGroup, int iValue) +{ + studiohdr_t *pstudiohdr = static_cast(GET_MODEL_PTR(pEntity->edict())); + if (!pstudiohdr || iGroup > pstudiohdr->numbodyparts) + { + return; + } + + mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; + + if (iValue >= pbodypart->nummodels) + { + return; + } + + int iCurrent = (pEntity->pev->body / pbodypart->base) % pbodypart->nummodels; + pEntity->pev->body += (iValue - iCurrent) * pbodypart->base; +} + +int GetBodygroup(CBaseEntity *pEntity, int iGroup) +{ + studiohdr_t *pstudiohdr = static_cast(GET_MODEL_PTR(pEntity->edict())); + + if (!pstudiohdr || iGroup > pstudiohdr->numbodyparts) + { + return 0; + } + + mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; + + if (pbodypart->nummodels <= 1) + { + return 0; + } + + int iCurrent = (pEntity->pev->body / pbodypart->base) % pbodypart->nummodels; + return iCurrent; +} + +bool GetSequenceInfo2(CBaseEntity *pEntity, int *piFlags, float *pflFrameRate, float *pflGroundSpeed) +{ + studiohdr_t *pstudiohdr = static_cast(GET_MODEL_PTR(pEntity->edict())); + + if (!pstudiohdr || pEntity->pev->sequence >= pstudiohdr->numseq) + { + *piFlags = 0; + *pflFrameRate = 0; + *pflGroundSpeed = 0; + return false; + } + + mstudioseqdesc_t *pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + int(pEntity->pev->sequence); + *piFlags = pseqdesc->flags; + if (pseqdesc->numframes <= 1) + { + *pflFrameRate = 256.0f; + *pflGroundSpeed = 0.0f; + } + else + { + *pflFrameRate = pseqdesc->fps * 256.0f / (pseqdesc->numframes - 1); + *pflGroundSpeed = Q_sqrt(pseqdesc->linearmovement[0] * pseqdesc->linearmovement[0] + pseqdesc->linearmovement[1] * pseqdesc->linearmovement[1] + pseqdesc->linearmovement[2] * pseqdesc->linearmovement[2]); + *pflGroundSpeed = *pflGroundSpeed * pseqdesc->fps / (pseqdesc->numframes - 1); + } + + return true; +} + void RemoveOrDropItem(CBasePlayer *pPlayer, CBasePlayerItem *pItem, GiveType type) { switch (type) diff --git a/reapi/src/reapi_utils.h b/reapi/src/reapi_utils.h index bad3c0f0..b8d3a4c0 100644 --- a/reapi/src/reapi_utils.h +++ b/reapi/src/reapi_utils.h @@ -55,6 +55,9 @@ CBaseEntity *GiveNamedItemInternal(AMX *amx, CBasePlayer *pPlayer, const char *p void GetBonePosition(CBaseEntity *pEntity, int iBone, Vector *pVecOrigin, Vector *pVecAngles); void GetAttachment(CBaseEntity *pEntity, int iAttachment, Vector *pVecOrigin, Vector *pVecAngles); +void SetBodygroup(CBaseEntity *pEntity, int iGroup, int iValue); +int GetBodygroup(CBaseEntity *pEntity, int iGroup); +bool GetSequenceInfo2(CBaseEntity *pEntity, int *piFlags, float *pflFrameRate, float *pflGroundSpeed); void RemoveOrDropItem(CBasePlayer *pPlayer, CBasePlayerItem *pItem, GiveType type); const char *getATypeStr(AType type);