diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7e72430b..2f8746ea 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ on: jobs: windows: name: 'Windows' - runs-on: windows-latest + runs-on: windows-2019 env: solution: 'msvc/reapi.sln' @@ -23,12 +23,14 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - name: Setup MSBuild - uses: microsoft/setup-msbuild@v1.0.2 + uses: microsoft/setup-msbuild@v1.1.3 + with: + vs-version: '16.8' - name: Build run: | @@ -43,7 +45,7 @@ jobs: move msvc\${{ env.buildRelease }}\reapi_amxx.pdb publish\debug\reapi_amxx.pdb - name: Deploy artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3.1.1 with: name: win32 path: publish/* @@ -52,10 +54,12 @@ jobs: name: 'Linux' runs-on: ubuntu-latest container: s1lentq/linux86buildtools:latest + outputs: + app-version: ${{ steps.app-version.outputs.version }} steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 @@ -63,6 +67,21 @@ jobs: run: | rm -rf build && CC=icc CXX=icpc cmake -B build && cmake --build build -j8 + - name: Reading appversion.h + id: app-version + run: | + if [ -e "reapi/version/appversion.h" ]; then + APP_VERSION=$(cat "reapi/version/appversion.h" | grep -wi '#define APP_VERSION_STRD' | sed -e 's/#define APP_VERSION_STRD[ \t\r\n\v\f]\+\(.*\)/\1/i' -e 's/\r//g') + if [ $? -ne 0 ]; then + APP_VERSION="" + else + # Remove quotes + APP_VERSION=$(echo $APP_VERSION | xargs) + fi + fi + echo "version=${APP_VERSION}" >> "$GITHUB_OUTPUT" + shell: bash + - name: Prepare AMXX run: | mkdir -p publish/addons/amxmodx/modules @@ -72,7 +91,6 @@ jobs: - name: Move files run: | mv build/reapi/reapi_amxx_i386.so publish/addons/amxmodx/modules/reapi_amxx_i386.so - mv reapi/version/appversion.h publish/appversion.h - name: Run GLIBC/ABI version compat test run: | @@ -86,17 +104,12 @@ jobs: shell: bash - name: Deploy artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3.1.1 id: upload-job with: name: linux32 path: publish/* - - name: Cleanup temporary artifacts - if: success() && steps.upload-job.outcome == 'success' - run: | - rm -f appversion.h - publish: name: 'Publish' runs-on: ubuntu-latest @@ -104,29 +117,15 @@ jobs: steps: - name: Deploying linux artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: linux32 - name: Deploying windows artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: win32 - - name: Reading appversion.h - run: | - if [ -e appversion.h ]; then - APP_VERSION=$(cat appversion.h | grep -wi '#define APP_VERSION_STRD' | sed -e 's/#define APP_VERSION_STRD[ \t\r\n\v\f]\+\(.*\)/\1/i' -e 's/\r//g') - if [ $? -ne 0 ]; then - APP_VERSION="" - else - # Remove quotes - APP_VERSION=$(echo $APP_VERSION | xargs) - echo "APP_VERSION=${APP_VERSION}" >> $GITHUB_ENV - fi - fi - rm -f appversion.h - - name: Packaging binaries id: packaging-job if: | @@ -134,7 +133,7 @@ jobs: github.event.action == 'published' && startsWith(github.ref, 'refs/tags/') run: | - 7z a -tzip reapi-bin-${{ env.APP_VERSION }}.zip addons/ + 7z a -tzip reapi-bin-${{ needs.linux.outputs.app-version }}.zip addons/ - name: Publish artifacts uses: softprops/action-gh-release@v1 @@ -147,9 +146,3 @@ jobs: *.zip env: GITHUB_TOKEN: ${{ secrets.API_TOKEN }} - - - name: Cleanup temporary artifacts - if: success() && steps.publish-job.outcome == 'success' - run: | - rm -rf addons debug - rm -f *.zip appversion.h diff --git a/reapi/CMakeLists.txt b/reapi/CMakeLists.txt index 5e064074..cfe8f930 100644 --- a/reapi/CMakeLists.txt +++ b/reapi/CMakeLists.txt @@ -111,7 +111,7 @@ set(REAPI_SRCS "src/amxxmodule.cpp" "src/h_export.cpp" "src/dllapi.cpp" - "src/entity_callback.cpp" + "src/entity_callback_dispatcher.cpp" "src/hook_callback.cpp" "src/hook_list.cpp" "src/hook_manager.cpp" diff --git a/reapi/common/info.cpp b/reapi/common/info.cpp index 5e0f096c..8ebcfcf3 100644 --- a/reapi/common/info.cpp +++ b/reapi/common/info.cpp @@ -282,7 +282,7 @@ void Info_SetValueForStarKey(char *s, const char *key, const char *value, int ma return; } - if (Q_strstr(key, "..") || Q_strstr(value, "..")) + if (Q_strstr(key, "..") || (Q_strcmp(key, "name") != 0 && Q_strstr(value, ".."))) { // TODO: Why silently return? //UTIL_ServerPrint("Can't use keys or values with a ..\n"); diff --git a/reapi/extra/amxmodx/scripting/include/cssdk_const.inc b/reapi/extra/amxmodx/scripting/include/cssdk_const.inc index 8ce08874..a3bfc5e9 100644 --- a/reapi/extra/amxmodx/scripting/include/cssdk_const.inc +++ b/reapi/extra/amxmodx/scripting/include/cssdk_const.inc @@ -71,6 +71,14 @@ #define FL_KILLME (1<<30) // This entity is marked for death -- This allows the engine to kill ents at the appropriate time #define FL_DORMANT (1<<31) // Entity is dormant, no updates to client +/** +* global_get(glb_trace_flags) values +* @note Custom flags that we can retrieve in pfnShouldCollide/TraceLine/TraceHull +*/ +#define FTRACE_BULLET (1<<16) +#define FTRACE_FLASH (1<<17) +#define FTRACE_KNIFE (1<<18) + /** * get_entvar(entity, var_movetype) values */ @@ -272,6 +280,7 @@ #define ITEM_FLAG_NOAUTOSWITCHEMPTY (1<<2) #define ITEM_FLAG_LIMITINWORLD (1<<3) #define ITEM_FLAG_EXHAUSTIBLE (1<<4) +#define ITEM_FLAG_NOFIREUNDERWATER (1<<5) /** * @section get_entvar(entity, var_spawnflags) values @@ -897,10 +906,11 @@ enum WeaponIdType /** * For CBaseMonster::m_rgbTimeBasedDamage +* prefix should be ITBD_ */ enum TimeBasedDamage { - ITDB_PRALYZE, + ITDB_PARALYZE, ITDB_NERVEGAS, ITDB_POISON, ITDB_RADIATION, @@ -1358,3 +1368,174 @@ enum InfoMapBuyParam #define SCORE_STATUS_BOMB (1<<1) #define SCORE_STATUS_VIP (1<<2) #define SCORE_STATUS_DEFKIT (1<<3) + +/** +* For RG_CBotManager_OnEvent +*/ +enum GameEventType +{ + EVENT_INVALID = 0, + EVENT_WEAPON_FIRED, // tell bots the player is attack (argumens: 1 = attacker, 2 = NULL) + EVENT_WEAPON_FIRED_ON_EMPTY, // tell bots the player is attack without clip ammo (argumens: 1 = attacker, 2 = NULL) + EVENT_WEAPON_RELOADED, // tell bots the player is reloading his weapon (argumens: 1 = reloader, 2 = NULL) + + EVENT_HE_GRENADE_EXPLODED, // tell bots the HE grenade is exploded (argumens: 1 = grenade thrower, 2 = NULL) + EVENT_FLASHBANG_GRENADE_EXPLODED, // tell bots the flashbang grenade is exploded (argumens: 1 = grenade thrower, 2 = explosion origin) + EVENT_SMOKE_GRENADE_EXPLODED, // tell bots the smoke grenade is exploded (argumens: 1 = grenade thrower, 2 = NULL) + EVENT_GRENADE_BOUNCED, + + EVENT_BEING_SHOT_AT, + EVENT_PLAYER_BLINDED_BY_FLASHBANG, // tell bots the player is flashed (argumens: 1 = flashed player, 2 = NULL) + EVENT_PLAYER_FOOTSTEP, // tell bots the player is running (argumens: 1 = runner, 2 = NULL) + EVENT_PLAYER_JUMPED, // tell bots the player is jumped (argumens: 1 = jumper, 2 = NULL) + EVENT_PLAYER_DIED, // tell bots the player is killed (argumens: 1 = victim, 2 = killer) + EVENT_PLAYER_LANDED_FROM_HEIGHT, // tell bots the player is fell with some damage (argumens: 1 = felled player, 2 = NULL) + EVENT_PLAYER_TOOK_DAMAGE, // tell bots the player is take damage (argumens: 1 = victim, 2 = attacker) + EVENT_HOSTAGE_DAMAGED, // tell bots the player has injured a hostage (argumens: 1 = hostage, 2 = injurer) + EVENT_HOSTAGE_KILLED, // tell bots the player has killed a hostage (argumens: 1 = hostage, 2 = killer) + + EVENT_DOOR, // tell bots the door is moving (argumens: 1 = door, 2 = NULL) + EVENT_BREAK_GLASS, // tell bots the glass has break (argumens: 1 = glass, 2 = NULL) + EVENT_BREAK_WOOD, // tell bots the wood has break (argumens: 1 = wood, 2 = NULL) + EVENT_BREAK_METAL, // tell bots the metal/computer has break (argumens: 1 = metal/computer, 2 = NULL) + EVENT_BREAK_FLESH, // tell bots the flesh has break (argumens: 1 = flesh, 2 = NULL) + EVENT_BREAK_CONCRETE, // tell bots the concrete has break (argumens: 1 = concrete, 2 = NULL) + + EVENT_BOMB_PLANTED, // tell bots the bomb has been planted (argumens: 1 = planter, 2 = NULL) + EVENT_BOMB_DROPPED, // tell bots the bomb has been dropped (argumens: 1 = NULL, 2 = NULL) + EVENT_BOMB_PICKED_UP, // let the bots hear the bomb pickup (argumens: 1 = player that pickup c4, 2 = NULL) + EVENT_BOMB_BEEP, // let the bots hear the bomb beeping (argumens: 1 = c4, 2 = NULL) + EVENT_BOMB_DEFUSING, // tell the bots someone has started defusing (argumens: 1 = defuser, 2 = NULL) + EVENT_BOMB_DEFUSE_ABORTED, // tell the bots someone has aborted defusing (argumens: 1 = NULL, 2 = NULL) + EVENT_BOMB_DEFUSED, // tell the bots the bomb is defused (argumens: 1 = defuser, 2 = NULL) + EVENT_BOMB_EXPLODED, // let the bots hear the bomb exploding (argumens: 1 = NULL, 2 = NULL) + + EVENT_HOSTAGE_USED, // tell bots the hostage is used (argumens: 1 = user, 2 = NULL) + EVENT_HOSTAGE_RESCUED, // tell bots the hostage is rescued (argumens: 1 = rescuer (CBasePlayer *), 2 = hostage (CHostage *)) + EVENT_ALL_HOSTAGES_RESCUED, // tell bots the all hostages are rescued (argumens: 1 = NULL, 2 = NULL) + + EVENT_VIP_ESCAPED, // tell bots the VIP is escaped (argumens: 1 = NULL, 2 = NULL) + EVENT_VIP_ASSASSINATED, // tell bots the VIP is assassinated (argumens: 1 = NULL, 2 = NULL) + EVENT_TERRORISTS_WIN, // tell bots the terrorists won the round (argumens: 1 = NULL, 2 = NULL) + EVENT_CTS_WIN, // tell bots the CTs won the round (argumens: 1 = NULL, 2 = NULL) + EVENT_ROUND_DRAW, // tell bots the round was a draw (argumens: 1 = NULL, 2 = NULL) + EVENT_ROUND_WIN, // tell carreer the round was a win (argumens: 1 = NULL, 2 = NULL) + EVENT_ROUND_LOSS, // tell carreer the round was a loss (argumens: 1 = NULL, 2 = NULL) + EVENT_ROUND_START, // tell bots the round was started (when freeze period is expired) (argumens: 1 = NULL, 2 = NULL) + EVENT_PLAYER_SPAWNED, // tell bots the player is spawned (argumens: 1 = spawned player, 2 = NULL) + EVENT_CLIENT_CORPSE_SPAWNED, + EVENT_BUY_TIME_START, + EVENT_PLAYER_LEFT_BUY_ZONE, + EVENT_DEATH_CAMERA_START, + EVENT_KILL_ALL, + EVENT_ROUND_TIME, + EVENT_DIE, + EVENT_KILL, + EVENT_HEADSHOT, + EVENT_KILL_FLASHBANGED, + EVENT_TUTOR_BUY_MENU_OPENNED, + EVENT_TUTOR_AUTOBUY, + EVENT_PLAYER_BOUGHT_SOMETHING, + EVENT_TUTOR_NOT_BUYING_ANYTHING, + EVENT_TUTOR_NEED_TO_BUY_PRIMARY_WEAPON, + EVENT_TUTOR_NEED_TO_BUY_PRIMARY_AMMO, + EVENT_TUTOR_NEED_TO_BUY_SECONDARY_AMMO, + EVENT_TUTOR_NEED_TO_BUY_ARMOR, + EVENT_TUTOR_NEED_TO_BUY_DEFUSE_KIT, + EVENT_TUTOR_NEED_TO_BUY_GRENADE, + EVENT_CAREER_TASK_DONE, + + EVENT_START_RADIO_1, + EVENT_RADIO_COVER_ME, + EVENT_RADIO_YOU_TAKE_THE_POINT, + EVENT_RADIO_HOLD_THIS_POSITION, + EVENT_RADIO_REGROUP_TEAM, + EVENT_RADIO_FOLLOW_ME, + EVENT_RADIO_TAKING_FIRE, + EVENT_START_RADIO_2, + EVENT_RADIO_GO_GO_GO, + EVENT_RADIO_TEAM_FALL_BACK, + EVENT_RADIO_STICK_TOGETHER_TEAM, + EVENT_RADIO_GET_IN_POSITION_AND_WAIT, + EVENT_RADIO_STORM_THE_FRONT, + EVENT_RADIO_REPORT_IN_TEAM, + EVENT_START_RADIO_3, + EVENT_RADIO_AFFIRMATIVE, + EVENT_RADIO_ENEMY_SPOTTED, + EVENT_RADIO_NEED_BACKUP, + EVENT_RADIO_SECTOR_CLEAR, + EVENT_RADIO_IN_POSITION, + EVENT_RADIO_REPORTING_IN, + EVENT_RADIO_GET_OUT_OF_THERE, + EVENT_RADIO_NEGATIVE, + EVENT_RADIO_ENEMY_DOWN, + EVENT_END_RADIO, + + EVENT_NEW_MATCH, // tell bots the game is new (argumens: 1 = NULL, 2 = NULL) + EVENT_PLAYER_CHANGED_TEAM, // tell bots the player is switch his team (also called from ClientPutInServer()) (argumens: 1 = switcher, 2 = NULL) + EVENT_BULLET_IMPACT, // tell bots the player is shoot at wall (argumens: 1 = shooter, 2 = shoot trace end position) + EVENT_GAME_COMMENCE, // tell bots the game is commencing (argumens: 1 = NULL, 2 = NULL) + EVENT_WEAPON_ZOOMED, // tell bots the player is switch weapon zoom (argumens: 1 = zoom switcher, 2 = NULL) + EVENT_HOSTAGE_CALLED_FOR_HELP, // tell bots the hostage is talking (argumens: 1 = listener, 2 = NULL) + NUM_GAME_EVENTS, +}; + +/** +* Weapon secondary attack states +* For CCSPlayerWeapon::m_iStateSecondaryAttack +*/ +enum SecondaryAtkState +{ + WEAPON_SECONDARY_ATTACK_NONE = 0, + WEAPON_SECONDARY_ATTACK_SET, + WEAPON_SECONDARY_ATTACK_BLOCK +}; + +/** +* Decal list for rg_decal_trace +*/ +enum Decal +{ + DECAL_GUNSHOT1 = 0, + DECAL_GUNSHOT2, + DECAL_GUNSHOT3, + DECAL_GUNSHOT4, + DECAL_GUNSHOT5, + DECAL_LAMBDA1, + DECAL_LAMBDA2, + DECAL_LAMBDA3, + DECAL_LAMBDA4, + DECAL_LAMBDA5, + DECAL_LAMBDA6, + DECAL_SCORCH1, + DECAL_SCORCH2, + DECAL_BLOOD1, + DECAL_BLOOD2, + DECAL_BLOOD3, + DECAL_BLOOD4, + DECAL_BLOOD5, + DECAL_BLOOD6, + DECAL_YBLOOD1, + DECAL_YBLOOD2, + DECAL_YBLOOD3, + DECAL_YBLOOD4, + DECAL_YBLOOD5, + DECAL_YBLOOD6, + DECAL_GLASSBREAK1, + DECAL_GLASSBREAK2, + DECAL_GLASSBREAK3, + DECAL_BIGSHOT1, + DECAL_BIGSHOT2, + DECAL_BIGSHOT3, + DECAL_BIGSHOT4, + DECAL_BIGSHOT5, + DECAL_SPIT1, + DECAL_SPIT2, + DECAL_BPROOF1, // Bulletproof glass decal + DECAL_GARGSTOMP1, // Gargantua stomp crack + DECAL_SMALLSCORCH1, // Small scorch mark + DECAL_SMALLSCORCH2, // Small scorch mark + DECAL_SMALLSCORCH3, // Small scorch mark + DECAL_MOMMABIRTH, // Big momma birth splatter + DECAL_MOMMASPLAT, +}; diff --git a/reapi/extra/amxmodx/scripting/include/reapi.inc b/reapi/extra/amxmodx/scripting/include/reapi.inc index 45338253..ba2ad484 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi.inc @@ -25,7 +25,8 @@ enum hooks_tables_e ht_weaponbox, ht_weapon, ht_gib, - ht_cbaseentity + ht_cbaseentity, + ht_botmanager }; enum members_tables_e @@ -78,9 +79,13 @@ enum members_tables_e mt_rebuystruct, mt_mapinfo, mt_csplayerweapon, - mt_gib + mt_gib, + mt_netadr, + mt_csentity }; +#define ReAPIFunc {EngineFunc, GamedllFunc, GamedllFunc_CBaseAnimating, GamedllFunc_CBasePlayer, GamedllFunc_CSGameRules, GamedllFunc_CGrenade, GamedllFunc_CWeaponBox, ReCheckerFunc, GamedllFunc_CBasePlayerWeapon, GamedllFunc_CGib, GamedllFunc_CBaseEntity, GamedllFunc_CBotManager} + // Is like FNullEnt #define is_nullent(%0) (%0 == 0 || is_entity(%0) == false) @@ -130,7 +135,8 @@ enum AType ATYPE_EDICT, ATYPE_EVARS, ATYPE_BOOL, - ATYPE_VECTOR + ATYPE_VECTOR, + ATYPE_TRACE }; enum HookChain @@ -148,7 +154,7 @@ enum HookChain * * @return Returns a hook handle. Use EnableHookChain/DisableHookChain to toggle the forward on or off */ -native HookChain:RegisterHookChain({EngineFunc, GamedllFunc, GamedllFunc_CBaseAnimating, GamedllFunc_CBasePlayer, GamedllFunc_CSGameRules, GamedllFunc_CGrenade, GamedllFunc_CWeaponBox, ReCheckerFunc, GamedllFunc_CBasePlayerWeapon, GamedllFunc_CGib, GamedllFunc_CBaseEntity}:function_id, const callback[], post = 0); +native HookChain:RegisterHookChain(ReAPIFunc:function_id, const callback[], post = 0); /* * Stops a hook from triggering. @@ -209,7 +215,7 @@ native SetHookChainArg(number, AType:type, any:...); * * @return Returns true if the original function was called, otherwise false */ -native bool:IsReapiHookOriginalWasCalled({EngineFunc, GamedllFunc, GamedllFunc_CBaseAnimating, GamedllFunc_CBasePlayer, GamedllFunc_CSGameRules, GamedllFunc_CGrenade, GamedllFunc_CWeaponBox, ReCheckerFunc, GamedllFunc_CBasePlayerWeapon, GamedllFunc_CGib}:function_id); +native bool:IsReapiHookOriginalWasCalled(ReAPIFunc:function_id); /* * Returns the current hookchain handle. diff --git a/reapi/extra/amxmodx/scripting/include/reapi_engine.inc b/reapi/extra/amxmodx/scripting/include/reapi_engine.inc index e5a2ac8d..ce3aabb8 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi_engine.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi_engine.inc @@ -30,6 +30,24 @@ native set_ucmd(const ucmd, const UCmd:var, any:...); */ native any:get_ucmd(const ucmd, const UCmd:var, any:...); +/* +* Sets a NetAdr var. +* +* @param var The specified mvar, look at the enum NetAdrVars +* +* @return 1 on success. +*/ +native set_netadr(const adr, const NetAdrVars:var, any:...); + +/* +* Returns a NetAdr var +* +* @param var The specified mvar, look at the enum NetAdrVars +* +* @return If an integer or boolean or one byte, array or everything else is passed via the 3rd argument and more, look at the argument list for the specified mvar +*/ +native any:get_netadr(const adr, const NetAdrVars:var, any:...); + /* * Gets value for key in buffer * @@ -55,6 +73,28 @@ native get_key_value(const pbuffer, const key[], const value[], const maxlen); */ native set_key_value(const pbuffer, const key[], const value[]); +/* +* Gets an AMXX string buffer from a infobuffer pointer +* +* @param buffer Info string pointer +* @param value String to copy value to +* @param maxlen Maximum size of the output buffer +* +* @return Returns a string buffer on infobuffer pointer +*/ +native get_key_value_buffer(const pbuffer, const output[], const maxlen); + +/* +* Sets value string to entire buffer +* +* @param buffer Pointer to buffer +* @param value Value to set +* @param maxlen Maximum size of the value buffer to set, -1 means copy all characters +* +* @return 1 on success, 0 otherwise +*/ +native set_key_value_buffer(const pbuffer, const value[], const maxlen = -1); + /* * Gets the position of the bone * @@ -83,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. * @@ -156,6 +238,15 @@ native rh_drop_client(const index, const message[] = ""); * @param len Maximum buffer size * * @noreturn -* +* */ native rh_get_net_from(output[], len); + +/* +* Returns client's netchan playing time in seconds. +* +* @param index Client index +* +* @return Netchan connection time in seconds or 0 if client index is invalid or client is not connected +*/ +native rh_get_client_connect_time(const index); diff --git a/reapi/extra/amxmodx/scripting/include/reapi_engine_const.inc b/reapi/extra/amxmodx/scripting/include/reapi_engine_const.inc index 3c8cd50c..d1b114e9 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi_engine_const.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi_engine_const.inc @@ -13,6 +13,23 @@ enum MapNameType MNT_SET // return the name of the current map }; +/* +* For RH_SV_AddResource hook +*/ +enum ResourceType_t +{ + t_sound = 0, + t_skin, + t_model, + t_decal, + t_generic, + t_eventscript, + t_world, // Fake type for world, is really t_model + rt_unk, + + rt_max +}; + /** * rh_emit_sound2 flags */ @@ -91,10 +108,73 @@ enum EngineFunc RH_ED_Free, /* - * Description: - + * Description: Called when a message is being sent to the server's console. * Params: (const string[]) */ RH_Con_Printf, + + /* + * Description: Called when a player's userinfo is being checked. + * Params: (adr, buffer, bool:reconnect, reconnectSlot, name[]) + * + * @note Param adr is unused, guaranteed to return nothing also, don't send anything through it. + * @note In order for param name work, hook needs to be registered as Post. + */ + RH_SV_CheckUserInfo, + + /* + * Description: Called when a generic resource is being added to generic precache list. + * Return type: int + * Params: (const string[]) + */ + RH_PF_precache_generic_I, + + /* + * Description: Called when a model is being added to model precache list. + * Return type: int + * Params: (const string[]) + */ + RH_PF_precache_model_I, + + /* + * Description: Called when a sound is being added to sound precache list. + * Return type: int + * Params: (const string[]) + */ + RH_PF_precache_sound_I, + + /* + * Description: Called when an event is being added to event precache list. + * Return type: int + * Params: (const string[]) + */ + RH_EV_Precache, + + /* + * Description: Called when a resource is being added to resource list. + * Params: (ResourceType_t:type, const filename[], size, flags, index) + */ + RH_SV_AddResource, + + /* + * Description: Called when message is being printed to client console. + * Params: (const string[]) + */ + RH_SV_ClientPrintf, + + /* + * Description: Called when a command is being sent to server. + * Params: (const cmd[], source, id) + */ + RH_ExecuteServerStringCmd, + + /* + * Description: Called before adding an entity to the physents of a player. + * Return type: bool + * Params: (const entity, const client) + */ + RH_SV_AllowPhysent, + }; /** @@ -1188,3 +1268,40 @@ enum UCmd */ ucmd_impact_position }; + +enum NetAdrType +{ + NA_NULL = 0, + NA_LOOPBACK, + NA_BROADCAST, + NA_IP, + NA_IPX, // Deprecated: GoldSrc + NA_BROADCAST_IPX, // Deprecated: GoldSrc +}; + +enum NetAdrVars +{ + /* + * Description: - + * Member type: NetAdrType + * Get params: get_netadr(const NetAdr:adr, const NetAdrVars:var); + * Set params: set_netadr(const NetAdr:adr, const NetAdrVars:var, const value); + */ + netadr_type = BEGIN_MEMBER_REGION(netadr), + + /* + * Description: - + * Member type: unsigned char [4] + * Get params: get_netadr(const NetAdr:adr, const NetAdrVars:var, dest[], const lenght); // Also returns a iplong value + * Set params: set_netadr(const NetAdr:adr, const NetAdrVars:var, const iplong_value); // Only iplong can to set + */ + netadr_ip, + + /* + * Description: - + * Member type: unsigned short + * Get params: get_netadr(const NetAdr:adr, const NetAdrVars:var); + * Set params: set_netadr(const NetAdr:adr, const NetAdrVars:var, const value); + */ + netadr_port +}; diff --git a/reapi/extra/amxmodx/scripting/include/reapi_gamedll.inc b/reapi/extra/amxmodx/scripting/include/reapi_gamedll.inc index 00b8970c..a91bd509 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi_gamedll.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi_gamedll.inc @@ -338,12 +338,15 @@ native rg_multidmg_add(const inflictor, const victim, const Float:flDamage, cons * @param iTracerFreq Tracer frequency * @param iDamage Damage amount * +* @note: This native doesn't create a decal effect +* @note: Decal creation is handled by PlaybackEvent, including shot animation and shot sound +* * @noreturn */ native rg_fire_bullets(const inflictor, const attacker, const shots, Float:vecSrc[3], Float:vecDirShooting[3], Float:vecSpread[3], const Float:flDistance, const Bullet:iBulletType, const iTracerFreq, const iDamage); /* -* Fires buckshots from entity. +* Fires buckshots from entity (used at XM1014 and M3 weapons). * * @param inflictor Inflictor is the entity that caused the damage (such as a gun) * @param attacker Attacker is the entity that triggered the damage (such as the gun's owner) @@ -355,6 +358,9 @@ native rg_fire_bullets(const inflictor, const attacker, const shots, Float:vecSr * @param iTracerFreq Tracer frequency * @param iDamage Damage amount * +* @note: This native doesn't create a decal effect +* @note: Decal creation is handled by PlaybackEvent, including shot animation and shot sound +* * @noreturn */ native rg_fire_buckshots(const inflictor, const attacker, const shots, Float:vecSrc[3], Float:vecDirShooting[3], Float:vecSpread[3], const Float:flDistance, const iTracerFreq, const iDamage); @@ -375,6 +381,9 @@ native rg_fire_buckshots(const inflictor, const attacker, const shots, Float:vec * @param bPistol Pistol shot * @param shared_rand Use player's random seed, get circular gaussian spread * +* @note: This native doesn't create a decal effect +* @note: Decal creation is handled by PlaybackEvent, including shot animation and shot sound +* * @return Float:[3] The spread result */ native Float:[3] rg_fire_bullets3(const inflictor, const attacker, Float:vecSrc[3], Float:vecDirShooting[3], const Float:vecSpread, const Float:flDistance, const iPenetration, const Bullet:iBulletType, const iDamage, const Float:flRangeModifier, const bool:bPistol, const shared_rand); @@ -410,8 +419,9 @@ native rg_update_teamscores(const iCtsWins = 0, const iTsWins = 0, const bool:bA * * @param classname Entity classname * @param useHashTable Use this only for known game entities -* -* @note: Do not use this if you use a custom classname +* @note: Do not use this if you plan to change custom classname an entity after creation, +* otherwise it will never be release from hash table even if an entity was destroyed, +* and that to lead table to inflate/memory leaks * * @return Index of the created entity or 0 otherwise */ @@ -466,6 +476,8 @@ native bool:rg_has_item_by_name(const index, const item[]); * @param weapon name or id Weapon id, see WEAPON_* constants, WeaponIdType or weapon_* name * @param WpnInfo:type Info type, see WI_* constants * +* @note weapon_* name can only be used to get WI_ID +* * @return Weapon information * @error If weapon_id or type are out of bounds, an error will be thrown */ @@ -484,12 +496,14 @@ native rg_set_weapon_info(const {WeaponIdType,_}:weapon_id, WpnInfo:type, any:.. /* * Remove all the player's stuff in a specific slot. * -* @param index Client index -* @param slot The slot that will be emptied +* @param index Client index +* @param slot The slot that will be emptied +* @param removeAmmo Remove ammunition * -* @return 1 on success, 0 otherwise +* @return 1 - successful removal of all items in the slot or the slot is empty +* 0 - if at least one item failed to remove */ -native rg_remove_items_by_slot(const index, const InventorySlotType:slot); +native rg_remove_items_by_slot(const index, const InventorySlotType:slot, const bool:removeAmmo = true); /* * Drop to floor all the player's stuff by specific slot. @@ -497,7 +511,8 @@ native rg_remove_items_by_slot(const index, const InventorySlotType:slot); * @param index Client index * @param slot Specific slot for remove of each item. * -* @return 1 on success, 0 otherwise +* @return 1 - successful drop of all items in the slot or the slot is empty +* 0 - if at least one item failed to drop */ native rg_drop_items_by_slot(const index, const InventorySlotType:slot); @@ -515,9 +530,9 @@ native rg_remove_all_items(const index, const bool:removeSuit = false); * Forces the player to drop the specified item classname. * * @param index Client index -* @param item_name Item classname +* @param item_name Item classname, if no name, the active item classname * -* @return 1 on success, 0 otherwise +* @return Entity index of weaponbox, AMX_NULLENT (-1) otherwise * */ native rg_drop_item(const index, const item_name[]); @@ -682,7 +697,7 @@ native rg_get_user_footsteps(const index); * @param index Client index * @param receiver Receiver index, if 0 it will transfer to a random player * -* @return 1 on success, 0 otherwise +* @return Index of player entity if successfull, 0 otherwise */ native rg_transfer_c4(const index, const receiver = 0); @@ -853,7 +868,7 @@ native rg_send_bartime(const index, const duration, const bool:observer = true); * * @noreturn */ -native rg_send_bartime2(const index, const duration, const startPercent, const bool:observer = true); +native rg_send_bartime2(const index, const duration, const Float:startPercent, const bool:observer = true); /* * Sends the SendAudio message - plays the specified audio. @@ -884,6 +899,28 @@ native rg_set_iteminfo(const entity, ItemInfo:type, any:...); */ native rg_get_iteminfo(const ent, ItemInfo:type, any:...); +/** +* Sets a parameter of the global CBasePlayerItem::m_ItemInfoArray array +* @note To have effect on client side (i.g. ammo size on HUD) you should +* alter this value BEFORE WeaponList message is sent to client, or +* force it's alteration by sending again to the specific client. +* Hooking WeaponList message with AMXX's register_message is a choice. +* +* @param weapon_id Weapon id, see WEAPON_* constants +* @param type Item info type. See ItemInfo constants. +* +*/ +native rg_set_global_iteminfo(const {WeaponIdType,_}:weapon_id, ItemInfo:type, any:...); + +/** +* Gets a parameter of the global CBasePlayerItem::m_ItemInfoArray array +* +* @param weapon_id Weapon id, see WEAPON_* constants +* @param type Item info type. See ItemInfo constants. +* +*/ +native rg_get_global_iteminfo(const {WeaponIdType,_}:weapon_id, ItemInfo:type, any:...); + /* * Adds hint message to the queue. * @@ -971,3 +1008,190 @@ native rg_spawn_head_gib(const index); * @noreturn */ native rg_spawn_random_gibs(const index, const cGibs, const bool:bHuman = true); + +/* +* Spawn a grenade (HEGrenade, Flashbang, SmokeGrenade, or C4) +* +* @param weaponId WEAPON_HEGRENADE, WEAPON_SMOKEGRENADE, WEAPON_FLASHBANG or WEAPON_C4 +* @param pevOwner Grenade owner +* @param vecSrc Grenade spawn position +* @param vecThrow Grenade velocity vector +* @param time Grenade explosion time +* @param iTeam Grenade team, see TEAM_* constants +* @param usEvent Event index related to grenade (returned value of precache_event) +* +* @return Entity index on success, AMX_NULLENT (-1) otherwise +*/ +native rg_spawn_grenade(WeaponIdType:weaponId, pevOwner, Float:vecSrc[3], Float:vecThrow[3], Float:time, TeamName:iTeam, usEvent = 0); + +/* +* Spawn a weaponbox entity with its properties +* +* @param pItem Weapon entity index to attach +* @param pPlayerOwner Player index to remove pItem entity (0 = no weapon owner) +* @param modelName Model name ("models/w_*.mdl") +* @param origin Weaponbox origin position +* @param angles Weaponbox angles +* @param velocity Weaponbox initial velocity vector +* @param lifeTime Time to stay in world (< 0.0 = use mp_item_staytime cvar value) +* @param packAmmo Set if ammo should be removed from weapon owner +* +* @return Weaponbox ent index on success, AMX_NULLENT (-1) otherwise +*/ +native rg_create_weaponbox(const pItem, const pPlayerOwner, const modelName[], Float:origin[3], Float:angles[3], Float:velocity[3], Float:lifeTime, bool:packAmmo); + +/* +* Removes an entity using gamedll's UTIL_Remove function, which sets a frame delay to ensure its removal. +* +* @param pEntity Entity index to remove +* +* @return 1 on success, 0 otherwise +*/ +native rg_remove_entity(const pEntity); + +/* +* Creates a Decal in world based on a traceresult. +* +* @param ptr Traceresult pointer, use Fakemeta's create_tr2 to instantiate one +* @param decalNumber Number of decal to spray, see DECAL_ constants on cssdk_const.inc +* +* @noreturn +*/ +native rg_decal_trace(const ptr, Decal:decalNumber); + +/* +* Emits a sound based on a traceresult simulating a bullet hit (metal, wood, concrete, etc.). +* @note Used mostly on trace attacks (bullets, knife). +* +* @param ptr Traceresult pointer, use Fakemeta's create_tr2 to instantiate one +* @param vecSrc Start position +* @param vecEnd End position, must match ptr's vecEndPos member +* @param iBulletType Bullet type, see BULLET_* constants in cssdk_const.inc +* +* @noreturn +*/ +native rg_emit_texture_sound(const ptr, Float:vecSrc[3], Float:vecEnd[3], Bullet:iBulletType); + +/* +* Generates an ammo slot in game's logic +* @note To see a visual effect, WeaponList message should be sent using the custom ammo name, +* where ammo icon HUD will be the one listed in "sprites/weapon_.txt" file. +* +* @param szAmmoname Ammo name to create. +* +* @note Maximum ammo index is 31, after that every ammo instantiation will start from 1 overriding existing ones. +* @return New ammo index. If name already exists, will return the matched index from memory. +*/ +native rg_add_ammo_registry(const szAmmoname[]); + +/* +* Deploys a weapon attached to a player using the CBasePlayerWeapon::DefaultDeploy function. +* +* @param entity Weapon to deploy. Must be attached to a player. +* @param szViewModel Weapon view model name ("models/v_*.mdl") +* @param szWeaponModel Weapon world model bame ("models/p_*.mdl") +* @param iAnim Weapon view model animation to play (often "deploy", use HLMV to see anim index) +* @param szAnimExt Player anim extension name to assign. Examples: "carbine", "shotgun", "knife", etc. +* Use HLMV on a player model to see animext names. +* @param skiplocal If 0, weapon animation will be forced to play on client ignoring active client prediction. +* +* @return 1 on successful weapon deploy, 0 otherwise. +*/ +native rg_weapon_deploy(const entity, const szViewModel[], const szWeaponModel[], iAnim, const szAnimExt[], skiplocal = 0); + +/* +* Reloads a weapon or a player's active weapon using the CBasePlayerWeapon::DefaultReload function. +* +* @param entity Weapon to reload (> MaxClients) OR player index to reload his current active weapon (>= 1 & <= MaxClients). +* @param iClipSize Weapon max clip to check. 0 = weapon max clip stored in ItemInfo +* @param iAnim Weapon view model animation to play (often "reload", use HLMV to see anim index) +* @param fDelay Player reload duration before clip refill. +* +* @return 1 on successful weapon reload, 0 otherwise. +*/ +native rg_weapon_reload(const entity, iClipSize, iAnim, Float:fDelay); + +/* +* Forces shotgun reload thinking on a weapon or a player's active weapon using the CBasePlayerWeapon::DefaultShotgunReload function. +* +* @param entity Weapon to reload (> MaxClients) OR player index to reload his current active weapon (>= 1 & <= MaxClients). +* @param iAnim Weapon view model "insert" animation to play (use HLMV to see anim index) +* @param iStartAnim Weapon view model "start reload" animation to play (use HLMV to see anim index) +* @param fDelay Delay between each buckshot inserted +* @param fStartDelay Delay before buckshots insertion starts +* @param pszReloadSound1 Sound to play on every insertion +* @param pszReloadSound2 Another sound to play on every insertion +* +* @note This is used inside weapon's Reload function and is often called every frame player is pressing IN_RELOAD button. +* @return 1 while weapon not in delay and with ammo remaining to load, 0 otherwise. +*/ +native rg_weapon_shotgun_reload(const entity, iAnim, iStartAnim, Float:fDelay, Float:fStartDelay, const pszReloadSound1[] = "", const pszReloadSound2[] = ""); + +/* +* Sends a weapon animation using the CBasePlayerWeapon::SendWeaponAnim function. +* +* @param entity Weapon to send animation on owner (> MaxClients) OR player index to send animation (>= 1 & <= MaxClients). +* @param iAnim Weapon view model animation to play (use HLMV to see anim index) +* @param skiplocal If 0, weapon animation will be forced to play on client ignoring active client prediction. +* +* @noreturn +*/ +native rg_weapon_send_animation(const entity, iAnim, skiplocal = 0); + +/* +* Emits a "recoil" effect on weapon's player using the CBasePlayerWeapon::KickBack function. +* +* @param entity Weapon to reload (> MaxClients) OR player index to reload his current active weapon (>= 1 & <= MaxClients). +* @param up_base Minimum vertical punchangle +* @param lateral_base Minimum horizontal punchangle +* @param up_modifier Vertical punchangle units to multiply to m_iShotsFired member +* @param lateral_modifier Horizontal punchangle units to multiply to m_iShotsFired member +* @param up_max Maximum vertical punchangle +* @param lateral_max Maximum horizontal punchangle +* @param direction_change Probability to change punchangle orientation (positive or negative). 0 = 100% (1/1), 1 = 50% (1/2), 2 = 33.3% (1/3), ... +* +* @noreturn +*/ +native rg_weapon_kickback(const entity, Float:up_base, Float:lateral_base, Float:up_modifier, Float:lateral_modifier, Float:up_max, Float:lateral_max, direction_change); + +/* +* Switches player current weapon into the best one on its inventory using the CHalfLifeMultiplay::GetNextBestWeapon function. +* +* @param player Player index. +* @param currentWeapon Current player active weapon. 0 = retrieve from m_pActiveItem member +* +* @note Weapon selection is based on weapon's Weight attribute from ItemInfo structure. +* @return 1 if weapon was found and switched to, 0 otherwise +*/ +native rg_switch_best_weapon(const player, const currentWeapon = 0); + +/* +* Disappear a player from the world. Used when VIP reaches escape zone. Basically a silent kill. +* +* @param player Player index. +* +* @noreturn +*/ +native rg_disappear(const player); + +/* +* Sets player current Observer mode. +* @note Player must be a valid observer (m_afPhysicsFlags & PFLAG_OBSERVER). +* +* @param player Player index. +* @param mode Observer mode, see OBS_* constants in cssdk_const.inc +* +* @noreturn +*/ +native rg_set_observer_mode(const player, const mode); + +/* +* Emits a death notice (logs, DeathMsg event, win conditions check) +* +* @param pVictim Player index. +* @param pKiller Killer entity. +* @param pevInflictor Inflictor entity. 0 = world +* +* @noreturn +*/ +native rg_death_notice(const pVictim, const pKiller, const pevInflictor); diff --git a/reapi/extra/amxmodx/scripting/include/reapi_gamedll_const.inc b/reapi/extra/amxmodx/scripting/include/reapi_gamedll_const.inc index 5265f7ed..f1d1fbac 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi_gamedll_const.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi_gamedll_const.inc @@ -9,7 +9,7 @@ * * @note Use this for hookchain RG_RoundEnd with the parameter ScenarioEventEndRound:event */ -#define IsRoundExpireEvent(%0) (((1<<_:(%0) + ScenarioEventEndRound:0)) & ((1<<_:ROUND_TARGET_SAVED) | (1<<_:ROUND_HOSTAGE_NOT_RESCUED) | (1<<_:ROUND_TERRORISTS_NOT_ESCAPED) | (1<<_:ROUND_VIP_NOT_ESCAPED) | (1<<_:ROUND_GAME_OVER))) != 0) +#define IsRoundExpireEvent(%0) (((1 << _:(%0) + _:ScenarioEventEndRound:0) & ((1 << _:ROUND_TARGET_SAVED) | (1 << _:ROUND_HOSTAGE_NOT_RESCUED) | (1 << _:ROUND_TERRORISTS_NOT_ESCAPED) | (1 << _:ROUND_VIP_NOT_ESCAPED) | (1 << _:ROUND_GAME_OVER))) != 0) /** * suppress warning: 200 on amxmodx 1.8.2 @@ -138,7 +138,7 @@ enum WpnInfo }; /** -* Item's info types for use with rg_set_iteminfo/rg_get_iteminfo() +* Item's info types for use with rg_set_[global_]iteminfo/rg_get_[global_]iteminfo() */ enum ItemInfo { @@ -400,6 +400,85 @@ enum GamedllFunc * Params: (pevVictim, cGibs, human) */ RG_SpawnRandomGibs, + + /* + * Description: Called when a player drops a weapon (usually manual drop or death) + * Return type: CWeaponBox * (Entity index of weaponbox) + * Params: (const weaponent, const owner, modelName[], Float:origin[3], Float:angles[3], Float:velocity[3], Float:lifeTime, bool:packAmmo) + */ + RG_CreateWeaponBox, + + /* + * Description: Called when a player is on a ladder. + * Params: (const pLadder, const playerIndex) + */ + RG_PM_LadderMove, + + /* + * Description: Called on every frame after a player jumps on water for a short period of time + * Params: (const playerIndex) + */ + RG_PM_WaterJump, + + /* + * Description: Called when a player jumps on water for the first time + * Params: (const playerIndex) + */ + RG_PM_CheckWaterJump, + + /* + * Description: Called on every frame while player presses jump button + * Params: (const playerIndex) + */ + RG_PM_Jump, + + /* + * Description: Called on every frame to check player ducking + * Params: (const playerIndex) + */ + RG_PM_Duck, + + /* + * Description: Called whenever player tries to unduck + * Params: (const playerIndex) + */ + RG_PM_UnDuck, + + /* + * Description: Called whenever player emits an step sound + * Params: (step, Float:fvol, const playerIndex) + */ + RG_PM_PlayStepSound, + + /* + * Description: Called whenever player is on air (not touching floor) + * Params: (Float:wishdir[3], Float:wishspeed, Float:accel, const playerIndex) + */ + RG_PM_AirAccelerate, + + /* + * Description: Called when game clears multidamage data (before TraceAttack) + * Params: () + */ + RG_ClearMultiDamage, + + /* + * Description: Called inside TraceAttack to store entity damage to multidamage data + * Params: (const pevInflictor, const pEntity, Float:flDamage, bitsDamageType) + */ + RG_AddMultiDamage, + + /* + * Description: Called after game finished a bullet tracing for applying damage cached on multidamage data + * Params: (const pevInflictor, const pevAttacker) + */ + RG_ApplyMultiDamage, + + /* + * Description: Called when player buys an item from buy menu (Nightvision, Kevlar, etc.) + * Params: (const pPlayer, iSlot) + */ + RG_BuyItem, }; /** @@ -806,14 +885,14 @@ enum GamedllFunc_CBasePlayer * Params: (const this) */ RG_CBasePlayer_Pain, - + /* * Description: Called when a client emits a "death sound" after death. * Return type: void * Params: (const this, lastHitGroup, bool:hasArmour) */ RG_CBasePlayer_DeathSound, - + /* * Description: Called when a client "thinks for the join status". * (permanently called on each call of "CBasePlayer::PreThink", and only when he is not assigned as specatator or not playing) @@ -821,6 +900,20 @@ enum GamedllFunc_CBasePlayer * Params: (const this) */ RG_CBasePlayer_JoiningThink, + + /* + * Description: Called every client frame to check time based damage + * Return type: void + * Params: (const this) + */ + RG_CBasePlayer_CheckTimeBasedDamage, + + /* + * Description: Called when game selects a spawn point (info_player_start/deathmatch) to position the player + * Return type: edict_t * (Entity index of selected spawn point) + * Params: (const this) + */ + RG_CBasePlayer_EntSelectSpawnPoint, }; /** @@ -855,6 +948,29 @@ enum GamedllFunc_CBasePlayerWeapon * Params: (const this, iAnim, iStartAnim, Float:fDelay, Float:fStartDelay, const pszReloadSound1[], const pszReloadSound2[]) */ RG_CBasePlayerWeapon_DefaultShotgunReload, + + /* + * Description: Called every client frame (PlayerPostThink) for the player's active weapon + * Return type: void + * Params: (const this) + */ + RG_CBasePlayerWeapon_ItemPostFrame, + + /* + * Description: Called whenever player fires a weapon and shakes player screen (punchangles altering) + * @note Weapons that use KickBack: AK47, AUG, FAMAS, GALIL, M249, M4A1, MAC10, MP5NAVY, P90, SG552, TMP, UMP45 + * Return type: void + * Params: (const this, Float:up_base, Float:lateral_base, Float:up_modifier, Float:lateral_modifier, Float:p_max, Float:lateral_max, direction_change) + */ + RG_CBasePlayerWeapon_KickBack, + + /* + * Description: Called whenever game sends an animation to his current holder (player) + * @note This is often called for all animations in exception of "fire" and "idle" sequences (both called via client prediction) + * Return type: void + * Params: (const this, iAnim, skiplocal) + */ + RG_CBasePlayerWeapon_SendWeaponAnim, }; /** @@ -909,6 +1025,21 @@ enum GamedllFunc_CBaseEntity RG_CBaseEntity_FireBullets3, }; +/** +* GamedllFunc CBotManager +*/ +enum GamedllFunc_CBotManager +{ + /* + * Description: Called on each improved bot event + * Return type: void + * Params: (GameEventType:event, const pEntity, const pOther) + + */ + RG_CBotManager_OnEvent = BEGIN_FUNC_REGION(botmanager), +} + + /** * GamedllFunc CSGameRules */ @@ -1034,6 +1165,7 @@ enum GamedllFunc_CSGameRules /* * Description: - + * Return type: CBasePlayer * (Entity index of player) * Params: () */ RG_CSGameRules_GiveC4, @@ -1068,6 +1200,32 @@ enum GamedllFunc_CSGameRules * Params: (const listener, const sender) */ RG_CSGameRules_CanPlayerHearPlayer, + + /* + * Description: Called every server frame to process game rules + * Params: () + */ + RG_CSGameRules_Think, + + /* + * Description: Called each time player tries to join a team to ensure availability + * Return type: bool + * Params: (team_id) + */ + RG_CSGameRules_TeamFull, + + /* + * Description: Called each time player tries to join a team to ensure a fair distribution of players (based on mp_limitteams cvar) + * Return type: bool + * Params: (newTeam_id, curTeam_id) + */ + RG_CSGameRules_TeamStacked, + + /* + * Description: Called each time player gets a weapon linked to his inventory + * Params: (const pPlayer, const pWeapon) + */ + RG_CSGameRules_PlayerGotWeapon, }; /** @@ -2278,7 +2436,7 @@ enum CBasePlayer_Members m_bResumeZoom, /* - * Description: - + * Description: Delay to call EjectBrass function on M3, Scout and AWP (rest of weapons are client-side). * Member type: float * Get params: Float:get_member(index, member); * Set params: set_member(index, member, Float:value); @@ -4643,6 +4801,70 @@ enum CCSPlayer_Members * Set params: set_member(index, member, bool:value); */ m_bMegaBunnyJumping, + + /* + * Description: - + * Member type: bool + * Get params: get_member(index, member); + * Set params: set_member(index, member, bool:value); + */ + m_bPlantC4Anywhere, + + /* + * Description: - + * Member type: bool + * Get params: get_member(index, member); + * Set params: set_member(index, member, bool:value); + */ + m_bSpawnProtectionEffects, + + /* + * Description: Player vertical jump height + * Member type: float + * Get params: Float:get_member(index, member); + * Set params: set_member(index, member, Float:value); + */ + m_flJumpHeight, + + /* + * Description: Player vertical jump height with longjump + * Member type: float + * Get params: Float:get_member(index, member); + * Set params: set_member(index, member, Float:value); + */ + m_flLongJumpHeight, + + /* + * Description: Player horizontal jump height with longjump + * Member type: float + * Get params: Float:get_member(index, member); + * Set params: set_member(index, member, Float:value); + */ + m_flLongJumpForce, + + /* + * Description: Player crouch maxspeed multiplier + * Member type: float + * Get params: Float:get_member(index, member); + * Set params: set_member(index, member, Float:value); + */ + m_flDuckSpeedMultiplier, + + /* + * Description: How many unanswered kills this player has been dealt by each other player (0-31) + * Member type: int [32] + * Get params: get_member(index, member, element); + * Set params: set_member(index, member, value, element); + */ + m_iNumKilledByUnanswered, + + /* + * Description: Array of state per other player whether player is dominating other players (0-31) + * Member type: bool [32] + * Get params: get_member(index, member, element); + * Set params: set_member(index, member, value, element); + */ + m_bPlayerDominated, }; /** @@ -5937,7 +6159,7 @@ enum CKnife_Members m_Knife_usKnife, /* - * Description: - + * Description: Stab damage (default: 65.0) * Member type: float * Get params: get_member(index, member); * Set params: set_member(index, member, value); @@ -5945,7 +6167,7 @@ enum CKnife_Members m_Knife_flStabBaseDamage, /* - * Description: - + * Description: Swing damage (default: 15.0) * Member type: float * Get params: get_member(index, member); * Set params: set_member(index, member, value); @@ -5953,7 +6175,7 @@ enum CKnife_Members m_Knife_flSwingBaseDamage, /* - * Description: - + * Description: Fast Swing (first one) damage (default: 20.0) * Member type: float * Get params: get_member(index, member); * Set params: set_member(index, member, value); @@ -5961,7 +6183,7 @@ enum CKnife_Members m_Knife_flSwingBaseDamage_Fast, /* - * Description: - + * Description: Stab distance (default: 32.0) * Member type: float * Get params: get_member(index, member); * Set params: set_member(index, member, value); @@ -5969,12 +6191,20 @@ enum CKnife_Members m_Knife_flStabDistance, /* - * Description: - + * Description: Swing distance (default: 64.0) * Member type: float * Get params: get_member(index, member); * Set params: set_member(index, member, value); */ m_Knife_flSwingDistance, + + /* + * Description: Back Stab damage multiplier (default: 3.0) + * Member type: float + * Get params: get_member(index, member); + * Set params: set_member(index, member, value); + */ + m_Knife_flBackStabMultiplier, }; /** @@ -6057,12 +6287,12 @@ enum CMapInfo_Members enum CCSPlayerWeapon_Members { /* - * Description: Can the weapon have secondary attack - * Member type: bool + * Description: Weapon secondary attack state + * Member type: enum SecondaryAtkState * Get params: get_member(index, member); - * Set params: set_member(index, member, bool:value); + * Set params: set_member(index, member, SecondaryAtkState:value); */ - m_Weapon_bHasSecondaryAttack = BEGIN_MEMBER_REGION(csplayerweapon), + m_Weapon_iStateSecondaryAttack = BEGIN_MEMBER_REGION(csplayerweapon), /* * Description: Basic damage that weapon deals before any multiplier, such as hitgroup, armor, distance and bullet penetration @@ -6073,6 +6303,9 @@ enum CCSPlayerWeapon_Members m_Weapon_flBaseDamage, }; +// API compatibility +#define m_Weapon_bHasSecondaryAttack m_Weapon_iStateSecondaryAttack + /** * CGib Members */ @@ -6110,3 +6343,25 @@ enum CGib_Members */ m_Gib_lifeTime, }; + +/** +* CCSEntity API Members +*/ +enum CCSEntity_Members +{ + /* + * Description: Penetration level of the damage caused by the inflictor + * Member type: unsigned char + * Get params: get_member(index, member); + * Set params: set_member(index, member, value); + */ + m_ucDmgPenetrationLevel = BEGIN_MEMBER_REGION(csplayerweapon), + + /* + * Description: Cached inflictor passed inside TakeDamage to retrieve in Killed + * Member type: entvars_t * + * Get params: get_member(index, member); + * Set params: set_member(index, member, value); + */ + m_pevLastInflictor, +}; diff --git a/reapi/extra/amxmodx/scripting/include/reapi_reunion.inc b/reapi/extra/amxmodx/scripting/include/reapi_reunion.inc index ea85bcee..311f0c2c 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi_reunion.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi_reunion.inc @@ -39,6 +39,18 @@ native REU_GetProtocol(const index); */ native client_auth_type:REU_GetAuthtype(const index); +/* +* Get client authkey +* +* @param index Client index +* @param index Buffer to copy the authkey +* @param index Maximum buffer size +* +* @return Number of cells copied to buffer +* +*/ +native REU_GetAuthKey(const index, dest[], maxlen); + /* * Check if the client is running RevEmu with limited user rights. * diff --git a/reapi/include/cssdk/dlls/API/CSEntity.h b/reapi/include/cssdk/dlls/API/CSEntity.h index 1e9ca2b9..aa8de82e 100644 --- a/reapi/include/cssdk/dlls/API/CSEntity.h +++ b/reapi/include/cssdk/dlls/API/CSEntity.h @@ -36,6 +36,7 @@ class CCSEntity CCSEntity() : m_pContainingEntity(nullptr) { + m_ucDmgPenetrationLevel = 0; } virtual ~CCSEntity() {} @@ -43,9 +44,17 @@ class CCSEntity virtual void FireBuckshots(ULONG cShots, Vector &vecSrc, Vector &vecDirShooting, Vector &vecSpread, float flDistance, int iTracerFreq, int iDamage, entvars_t *pevAttacker) = 0; virtual Vector FireBullets3(Vector &vecSrc, Vector &vecDirShooting, float vecSpread, float flDistance, int iPenetration, int iBulletType, int iDamage, float flRangeModifier, entvars_t *pevAttacker, bool bPistol, int shared_rand) = 0; +public: + CBaseEntity *m_pContainingEntity; + unsigned char m_ucDmgPenetrationLevel; // penetration level of the damage caused by the inflictor + entvars_t *m_pevLastInflictor; + +private: #if defined(_MSC_VER) -#pragma region reserve_vfuncs_Region +#pragma region reserve_data_Region #endif + char CCSEntity_Reserve[0x3FF7]; + virtual void func_reserve1() {}; virtual void func_reserve2() {}; virtual void func_reserve3() {}; @@ -79,9 +88,6 @@ class CCSEntity #if defined(_MSC_VER) #pragma endregion #endif - -public: - CBaseEntity *m_pContainingEntity; }; class CCSDelay: public CCSEntity @@ -89,6 +95,8 @@ class CCSDelay: public CCSEntity DECLARE_CLASS_TYPES(CCSDelay, CCSEntity); public: +private: + int CCSDelay_Reserve[0x100]; }; class CCSAnimating: public CCSDelay @@ -96,6 +104,8 @@ class CCSAnimating: public CCSDelay DECLARE_CLASS_TYPES(CCSAnimating, CCSDelay); public: +private: + int CCSAnimating_Reserve[0x100]; }; class CCSToggle: public CCSAnimating @@ -103,6 +113,8 @@ class CCSToggle: public CCSAnimating DECLARE_CLASS_TYPES(CCSToggle, CCSAnimating); public: +private: + int CCSToggle_Reserve[0x100]; }; class CCSMonster: public CCSToggle @@ -110,6 +122,8 @@ class CCSMonster: public CCSToggle DECLARE_CLASS_TYPES(CCSMonster, CCSToggle); public: +private: + int CCSMonster_Reserve[0x100]; }; -#define CSENTITY_API_INTERFACE_VERSION "CSENTITY_API_INTERFACE_VERSION002" +#define CSENTITY_API_INTERFACE_VERSION "CSENTITY_API_INTERFACE_VERSION003" diff --git a/reapi/include/cssdk/dlls/API/CSPlayer.h b/reapi/include/cssdk/dlls/API/CSPlayer.h index 99273c97..3495ee29 100644 --- a/reapi/include/cssdk/dlls/API/CSPlayer.h +++ b/reapi/include/cssdk/dlls/API/CSPlayer.h @@ -30,6 +30,7 @@ #include #include +#include enum WeaponInfiniteAmmoMode { @@ -50,9 +51,23 @@ class CCSPlayer: public CCSMonster m_bCanShootOverride(false), m_bGameForcingRespawn(false), m_bAutoBunnyHopping(false), - m_bMegaBunnyJumping(false) + m_bMegaBunnyJumping(false), + m_bPlantC4Anywhere(false), + m_bSpawnProtectionEffects(false), + m_flJumpHeight(0), + m_flLongJumpHeight(0), + m_flLongJumpForce(0), + m_flDuckSpeedMultiplier(0), + m_iUserID(-1) { m_szModel[0] = '\0'; + + // Resets the kill history for this player + for (int i = 0; i < MAX_CLIENTS; i++) + { + m_iNumKilledByUnanswered[i] = 0; + m_bPlayerDominated[i] = false; + } } virtual bool IsConnected() const = 0; @@ -62,8 +77,8 @@ class CCSPlayer: public CCSMonster virtual CBaseEntity *GiveNamedItemEx(const char *pszName) = 0; virtual void GiveDefaultItems() = 0; virtual void GiveShield(bool bDeploy = true) = 0; - virtual void DropShield(bool bDeploy = true) = 0; - virtual void DropPlayerItem(const char *pszItemName) = 0; + virtual CBaseEntity *DropShield(bool bDeploy = true) = 0; + virtual CBaseEntity *DropPlayerItem(const char *pszItemName) = 0; virtual bool RemoveShield() = 0; virtual void RemoveAllItems(bool bRemoveSuit) = 0; virtual bool RemovePlayerItem(const char* pszItemName) = 0; @@ -100,11 +115,9 @@ class CCSPlayer: public CCSMonster virtual void SetSpawnProtection(float flProtectionTime) = 0; virtual void RemoveSpawnProtection() = 0; virtual bool HintMessageEx(const char *pMessage, float duration = 6.0f, bool bDisplayIfPlayerDead = false, bool bOverride = false) = 0; - - void Reset(); - - void OnSpawn(); - void OnKilled(); + virtual void Reset() = 0; + virtual void OnSpawnEquip(bool addDefault = true, bool equipGame = true) = 0; + virtual void SetScoreboardAttributes(CBasePlayer *destination = nullptr) = 0; CBasePlayer *BasePlayer() const; @@ -131,6 +144,25 @@ class CCSPlayer: public CCSMonster bool m_bGameForcingRespawn; bool m_bAutoBunnyHopping; bool m_bMegaBunnyJumping; + bool m_bPlantC4Anywhere; + bool m_bSpawnProtectionEffects; + double m_flJumpHeight; + double m_flLongJumpHeight; + double m_flLongJumpForce; + double m_flDuckSpeedMultiplier; + + int m_iUserID; + struct CDamageRecord_t + { + float flDamage = 0.0f; + float flFlashDurationTime = 0.0f; + int userId = -1; + }; + using DamageList_t = CUtlArray; + DamageList_t m_DamageList; // A unified array of recorded damage that includes giver and taker in each entry + DamageList_t &GetDamageList() { return m_DamageList; } + int m_iNumKilledByUnanswered[MAX_CLIENTS]; // [0-31] how many unanswered kills this player has been dealt by each other player + bool m_bPlayerDominated[MAX_CLIENTS]; // [0-31] array of state per other player whether player is dominating other players }; // Inlines diff --git a/reapi/include/cssdk/dlls/API/CSPlayerItem.h b/reapi/include/cssdk/dlls/API/CSPlayerItem.h index 74abc0b2..e4bec454 100644 --- a/reapi/include/cssdk/dlls/API/CSPlayerItem.h +++ b/reapi/include/cssdk/dlls/API/CSPlayerItem.h @@ -39,6 +39,7 @@ class CCSPlayerItem: public CCSAnimating } virtual void SetItemInfo(ItemInfo *pInfo) = 0; + virtual int GetItemInfo(ItemInfo *pInfo) = 0; CBasePlayerItem *BasePlayerItem() const; diff --git a/reapi/include/cssdk/dlls/API/CSPlayerWeapon.h b/reapi/include/cssdk/dlls/API/CSPlayerWeapon.h index 70317c93..837347c4 100644 --- a/reapi/include/cssdk/dlls/API/CSPlayerWeapon.h +++ b/reapi/include/cssdk/dlls/API/CSPlayerWeapon.h @@ -28,19 +28,33 @@ #pragma once +enum SecondaryAtkState : uint8_t +{ + WEAPON_SECONDARY_ATTACK_NONE = 0, + WEAPON_SECONDARY_ATTACK_SET, + WEAPON_SECONDARY_ATTACK_BLOCK +}; + class CBasePlayerWeapon; class CCSPlayerWeapon: public CCSPlayerItem { + DECLARE_CLASS_TYPES(CCSPlayerWeapon, CCSPlayerItem); public: CCSPlayerWeapon() : - m_bHasSecondaryAttack(false) + m_iStateSecondaryAttack(WEAPON_SECONDARY_ATTACK_NONE) { } + virtual BOOL DefaultDeploy(char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal = 0) = 0; + virtual int DefaultReload(int iClipSize, int iAnim, float fDelay) = 0; + virtual bool DefaultShotgunReload(int iAnim, int iStartAnim, float fDelay, float fStartDelay, const char *pszReloadSound1 = nullptr, const char *pszReloadSound2 = nullptr) = 0; + virtual void KickBack(float up_base, float lateral_base, float up_modifier, float lateral_modifier, float up_max, float lateral_max, int direction_change) = 0; + virtual void SendWeaponAnim(int iAnim, int skiplocal = 0) = 0; + CBasePlayerWeapon *BasePlayerWeapon() const; public: - bool m_bHasSecondaryAttack; + SecondaryAtkState m_iStateSecondaryAttack; float m_flBaseDamage; }; diff --git a/reapi/include/cssdk/dlls/cbase.h b/reapi/include/cssdk/dlls/cbase.h index 53d4a031..96731bbd 100644 --- a/reapi/include/cssdk/dlls/cbase.h +++ b/reapi/include/cssdk/dlls/cbase.h @@ -173,6 +173,7 @@ class CBaseEntity public: CCSEntity *m_pEntity; // NOTE: it was replaced on member "int *current_ammo" because it is useless. + CCSEntity *CSEntity() const; // We use this variables to store each ammo count. float currentammo; @@ -253,6 +254,11 @@ inline void CBaseEntity::SetBlocked(std::nullptr_t) m_pfnBlocked = nullptr; } +inline CCSEntity *CBaseEntity::CSEntity() const +{ + return m_pEntity; +} + class CPointEntity: public CBaseEntity { DECLARE_CLASS_TYPES(CPointEntity, CBaseEntity); diff --git a/reapi/include/cssdk/dlls/gamerules.h b/reapi/include/cssdk/dlls/gamerules.h index 6778601a..d0781beb 100644 --- a/reapi/include/cssdk/dlls/gamerules.h +++ b/reapi/include/cssdk/dlls/gamerules.h @@ -531,7 +531,7 @@ class CHalfLifeMultiplay: public CGameRules // check if the scenario has been won/lost virtual void CheckWinConditions() = 0; virtual void RemoveGuns() = 0; - virtual void GiveC4() = 0; + virtual CBasePlayer *GiveC4() = 0; virtual void ChangeLevel() = 0; virtual void GoToIntermission() = 0; diff --git a/reapi/include/cssdk/dlls/regamedll_api.h b/reapi/include/cssdk/dlls/regamedll_api.h index 53a6d661..762d06d6 100644 --- a/reapi/include/cssdk/dlls/regamedll_api.h +++ b/reapi/include/cssdk/dlls/regamedll_api.h @@ -36,10 +36,11 @@ #include #include #include +#include #include #define REGAMEDLL_API_VERSION_MAJOR 5 -#define REGAMEDLL_API_VERSION_MINOR 21 +#define REGAMEDLL_API_VERSION_MINOR 22 // CBasePlayer::Spawn hook typedef IHookChainClass IReGameHook_CBasePlayer_Spawn; @@ -338,8 +339,8 @@ typedef IHookChain IReGameHook_CSGameRules_RemoveGuns; typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_RemoveGuns; // CHalfLifeMultiplay::GiveC4 hook -typedef IHookChain IReGameHook_CSGameRules_GiveC4; -typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_GiveC4; +typedef IHookChain IReGameHook_CSGameRules_GiveC4; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_GiveC4; // CHalfLifeMultiplay::ChangeLevel hook typedef IHookChain IReGameHook_CSGameRules_ChangeLevel; @@ -521,6 +522,106 @@ typedef IHookChainRegistryClass IReGameHookRegistry_CBa typedef IHookChainClass IReGameHook_CBasePlayer_JoiningThink; typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_JoiningThink; +// FreeGameRules hook +typedef IHookChain IReGameHook_FreeGameRules; +typedef IHookChainRegistry IReGameHookRegistry_FreeGameRules; + +// PM_LadderMove hook +typedef IHookChain IReGameHook_PM_LadderMove; +typedef IHookChainRegistry IReGameHookRegistry_PM_LadderMove; + +// PM_WaterJump hook +typedef IHookChain IReGameHook_PM_WaterJump; +typedef IHookChainRegistry IReGameHookRegistry_PM_WaterJump; + +// PM_CheckWaterJump hook +typedef IHookChain IReGameHook_PM_CheckWaterJump; +typedef IHookChainRegistry IReGameHookRegistry_PM_CheckWaterJump; + +// PM_Jump hook +typedef IHookChain IReGameHook_PM_Jump; +typedef IHookChainRegistry IReGameHookRegistry_PM_Jump; + +// PM_Duck hook +typedef IHookChain IReGameHook_PM_Duck; +typedef IHookChainRegistry IReGameHookRegistry_PM_Duck; + +// PM_UnDuck hook +typedef IHookChain IReGameHook_PM_UnDuck; +typedef IHookChainRegistry IReGameHookRegistry_PM_UnDuck; + +// PM_PlayStepSound hook +typedef IHookChain IReGameHook_PM_PlayStepSound; +typedef IHookChainRegistry IReGameHookRegistry_PM_PlayStepSound; + +// PM_AirAccelerate hook +typedef IHookChain IReGameHook_PM_AirAccelerate; +typedef IHookChainRegistry IReGameHookRegistry_PM_AirAccelerate; + +// ClearMultiDamage hook +typedef IHookChain IReGameHook_ClearMultiDamage; +typedef IHookChainRegistry IReGameHookRegistry_ClearMultiDamage; + +// AddMultiDamage hook +typedef IHookChain IReGameHook_AddMultiDamage; +typedef IHookChainRegistry IReGameHookRegistry_AddMultiDamage; + +// ApplyMultiDamage hook +typedef IHookChain IReGameHook_ApplyMultiDamage; +typedef IHookChainRegistry IReGameHookRegistry_ApplyMultiDamage; + +// BuyItem hook +typedef IHookChain IReGameHook_BuyItem; +typedef IHookChainRegistry IReGameHookRegistry_BuyItem; + +// CHalfLifeMultiplay::Think hook +typedef IHookChain IReGameHook_CSGameRules_Think; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_Think; + +// CHalfLifeMultiplay::TeamFull hook +typedef IHookChain IReGameHook_CSGameRules_TeamFull; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_TeamFull; + +// CHalfLifeMultiplay::TeamStacked hook +typedef IHookChain IReGameHook_CSGameRules_TeamStacked; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_TeamStacked; + +// CHalfLifeMultiplay::PlayerGotWeapon hook +typedef IHookChain IReGameHook_CSGameRules_PlayerGotWeapon; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_PlayerGotWeapon; + +// CBotManager::OnEvent hook +typedef IHookChain IReGameHook_CBotManager_OnEvent; +typedef IHookChainRegistry IReGameHookRegistry_CBotManager_OnEvent; + +// CBasePlayer::CheckTimeBasedDamage hook +typedef IHookChainClass IReGameHook_CBasePlayer_CheckTimeBasedDamage; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_CheckTimeBasedDamage; + +// CBasePlayer::EntSelectSpawnPoint hook +typedef IHookChainClass IReGameHook_CBasePlayer_EntSelectSpawnPoint; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_EntSelectSpawnPoint; + +// CBasePlayerWeapon::ItemPostFrame hook +typedef IHookChainClass IReGameHook_CBasePlayerWeapon_ItemPostFrame; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayerWeapon_ItemPostFrame; + +// CBasePlayerWeapon::KickBack hook +typedef IHookChainClass IReGameHook_CBasePlayerWeapon_KickBack; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayerWeapon_KickBack; + +// CBasePlayerWeapon::SendWeaponAnim hook +typedef IHookChainClass IReGameHook_CBasePlayerWeapon_SendWeaponAnim; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayerWeapon_SendWeaponAnim; + +// CHalfLifeMultiplay::SendDeathMessage hook +typedef IHookChain IReGameHook_CSGameRules_SendDeathMessage; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_SendDeathMessage; + +// CBasePlayer::PlayerDeathThink hook +typedef IHookChainClass IReGameHook_CBasePlayer_PlayerDeathThink; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_PlayerDeathThink; + class IReGameHookchains { public: virtual ~IReGameHookchains() {} @@ -654,6 +755,33 @@ class IReGameHookchains { virtual IReGameHookRegistry_CBasePlayer_Pain *CBasePlayer_Pain() = 0; virtual IReGameHookRegistry_CBasePlayer_DeathSound *CBasePlayer_DeathSound() = 0; virtual IReGameHookRegistry_CBasePlayer_JoiningThink *CBasePlayer_JoiningThink() = 0; + + virtual IReGameHookRegistry_FreeGameRules *FreeGameRules() = 0; + virtual IReGameHookRegistry_PM_LadderMove *PM_LadderMove() = 0; + virtual IReGameHookRegistry_PM_WaterJump *PM_WaterJump() = 0; + virtual IReGameHookRegistry_PM_CheckWaterJump *PM_CheckWaterJump() = 0; + virtual IReGameHookRegistry_PM_Jump *PM_Jump() = 0; + virtual IReGameHookRegistry_PM_Duck *PM_Duck() = 0; + virtual IReGameHookRegistry_PM_UnDuck *PM_UnDuck() = 0; + virtual IReGameHookRegistry_PM_PlayStepSound *PM_PlayStepSound() = 0; + virtual IReGameHookRegistry_PM_AirAccelerate *PM_AirAccelerate() = 0; + virtual IReGameHookRegistry_ClearMultiDamage *ClearMultiDamage() = 0; + virtual IReGameHookRegistry_AddMultiDamage *AddMultiDamage() = 0; + virtual IReGameHookRegistry_ApplyMultiDamage *ApplyMultiDamage() = 0; + virtual IReGameHookRegistry_BuyItem *BuyItem() = 0; + virtual IReGameHookRegistry_CSGameRules_Think *CSGameRules_Think() = 0; + virtual IReGameHookRegistry_CSGameRules_TeamFull *CSGameRules_TeamFull() = 0; + virtual IReGameHookRegistry_CSGameRules_TeamStacked *CSGameRules_TeamStacked() = 0; + virtual IReGameHookRegistry_CSGameRules_PlayerGotWeapon *CSGameRules_PlayerGotWeapon() = 0; + virtual IReGameHookRegistry_CBotManager_OnEvent *CBotManager_OnEvent() = 0; + virtual IReGameHookRegistry_CBasePlayer_CheckTimeBasedDamage *CBasePlayer_CheckTimeBasedDamage() = 0; + virtual IReGameHookRegistry_CBasePlayer_EntSelectSpawnPoint *CBasePlayer_EntSelectSpawnPoint() = 0; + virtual IReGameHookRegistry_CBasePlayerWeapon_ItemPostFrame *CBasePlayerWeapon_ItemPostFrame() = 0; + virtual IReGameHookRegistry_CBasePlayerWeapon_KickBack *CBasePlayerWeapon_KickBack() = 0; + virtual IReGameHookRegistry_CBasePlayerWeapon_SendWeaponAnim *CBasePlayerWeapon_SendWeaponAnim() = 0; + virtual IReGameHookRegistry_CSGameRules_SendDeathMessage *CSGameRules_SendDeathMessage() = 0; + + virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink() = 0; }; struct ReGameFuncs_t { @@ -671,6 +799,15 @@ struct ReGameFuncs_t { class CGrenade *(*PlantBomb)(entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity); class CGib *(*SpawnHeadGib)(entvars_t *pevVictim); void (*SpawnRandomGibs)(entvars_t *pevVictim, int cGibs, int human); + void (*UTIL_RestartOther)(const char *szClassname); + void (*UTIL_ResetEntities)(); + void (*UTIL_RemoveOther)(const char *szClassname, int nCount); + void (*UTIL_DecalTrace)(TraceResult *pTrace, int decalNumber); + void (*UTIL_Remove)(CBaseEntity *pEntity); + int (*AddAmmoNameToAmmoRegistry)(const char *szAmmoname); + void (*TextureTypePlaySound)(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType); + class CWeaponBox *(*CreateWeaponBox)(CBasePlayerItem *pItem, CBasePlayer *pPlayerOwner, const char *modelName, Vector &origin, Vector &angles, Vector &velocity, float lifeTime, bool packAmmo); + class CGrenade *(*SpawnGrenade)(WeaponIdType weaponId, entvars_t *pevOwner, Vector &vecSrc, Vector &vecThrow, float time, int iTeam, unsigned short usEvent); }; class IReGameApi { diff --git a/reapi/include/cssdk/dlls/weapons.h b/reapi/include/cssdk/dlls/weapons.h index 609ea915..14f6df48 100644 --- a/reapi/include/cssdk/dlls/weapons.h +++ b/reapi/include/cssdk/dlls/weapons.h @@ -623,6 +623,7 @@ class CKnife: public CBasePlayerWeapon float m_flSwingBaseDamage_Fast; float m_flStabDistance; float m_flSwingDistance; + float m_flBackStabMultiplier; }; class CM249: public CBasePlayerWeapon diff --git a/reapi/include/cssdk/engine/rehlds_api.h b/reapi/include/cssdk/engine/rehlds_api.h index ab1cd9e2..3e2b4ecc 100644 --- a/reapi/include/cssdk/engine/rehlds_api.h +++ b/reapi/include/cssdk/engine/rehlds_api.h @@ -36,7 +36,7 @@ #include "pr_dlls.h" #define REHLDS_API_VERSION_MAJOR 3 -#define REHLDS_API_VERSION_MINOR 11 +#define REHLDS_API_VERSION_MINOR 13 //Steam_NotifyClientConnect hook typedef IHookChain IRehldsHook_Steam_NotifyClientConnect; @@ -226,6 +226,38 @@ typedef IVoidHookChainRegistry IRehldsHookRegistry_ED_Free; typedef IHookChain IRehldsHook_Con_Printf; typedef IHookChainRegistry IRehldsHookRegistry_Con_Printf; +//SV_CheckUserInfo hook +typedef IHookChain IRehldsHook_SV_CheckUserInfo; +typedef IHookChainRegistry IRehldsHookRegistry_SV_CheckUserInfo; + +//PF_precache_generic_I hook +typedef IHookChain IRehldsHook_PF_precache_generic_I; +typedef IHookChainRegistry IRehldsHookRegistry_PF_precache_generic_I; + +//PF_precache_model_I hook +typedef IHookChain IRehldsHook_PF_precache_model_I; +typedef IHookChainRegistry IRehldsHookRegistry_PF_precache_model_I; + +//PF_precache_sound_I hook +typedef IHookChain IRehldsHook_PF_precache_sound_I; +typedef IHookChainRegistry IRehldsHookRegistry_PF_precache_sound_I; + +//EV_Precache hook +typedef IHookChain IRehldsHook_EV_Precache; +typedef IHookChainRegistry IRehldsHookRegistry_EV_Precache; + +//SV_AddResource hook +typedef IVoidHookChain IRehldsHook_SV_AddResource; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_AddResource; + +//SV_ClientPrintf hook +typedef IVoidHookChain IRehldsHook_SV_ClientPrintf; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_ClientPrintf; + +//SV_AllowPhysent hook +typedef IHookChain IRehldsHook_SV_AllowPhysent; +typedef IHookChainRegistry IRehldsHookRegistry_SV_AllowPhysent; + class IRehldsHookchains { public: virtual ~IRehldsHookchains() { } @@ -277,6 +309,14 @@ class IRehldsHookchains { virtual IRehldsHookRegistry_ED_Alloc* ED_Alloc() = 0; virtual IRehldsHookRegistry_ED_Free* ED_Free() = 0; virtual IRehldsHookRegistry_Con_Printf* Con_Printf() = 0; + virtual IRehldsHookRegistry_SV_CheckUserInfo* SV_CheckUserInfo() = 0; + virtual IRehldsHookRegistry_PF_precache_generic_I* PF_precache_generic_I() = 0; + virtual IRehldsHookRegistry_PF_precache_model_I* PF_precache_model_I() = 0; + virtual IRehldsHookRegistry_PF_precache_sound_I* PF_precache_sound_I() = 0; + virtual IRehldsHookRegistry_EV_Precache* EV_Precache() = 0; + virtual IRehldsHookRegistry_SV_AddResource* SV_AddResource() = 0; + virtual IRehldsHookRegistry_SV_ClientPrintf* SV_ClientPrintf() = 0; + virtual IRehldsHookRegistry_SV_AllowPhysent* SV_AllowPhysent() = 0; }; struct RehldsFuncs_t { diff --git a/reapi/include/cssdk/public/interface.cpp b/reapi/include/cssdk/public/interface.cpp index e6de1bef..de0a1848 100644 --- a/reapi/include/cssdk/public/interface.cpp +++ b/reapi/include/cssdk/public/interface.cpp @@ -121,6 +121,14 @@ void *Sys_GetProcAddress(void *pModuleHandle, const char *pName) return GetProcAddress((HMODULE)pModuleHandle, pName); } +// Purpose: Returns a module handle by its name. +// Input : pModuleName - module name +// Output : the module handle or NULL in case of an error +CSysModule *Sys_GetModuleHandle(const char *pModuleName) +{ + return reinterpret_cast(GetModuleHandle(pModuleName)); +} + // Purpose: Loads a DLL/component from disk and returns a handle to it // Input : *pModuleName - filename of the component // Output : opaque handle to the module (hides system dependency) diff --git a/reapi/include/cssdk/public/interface.h b/reapi/include/cssdk/public/interface.h index 0aeaca48..abe45b54 100644 --- a/reapi/include/cssdk/public/interface.h +++ b/reapi/include/cssdk/public/interface.h @@ -114,6 +114,8 @@ extern CreateInterfaceFn Sys_GetFactory(const char *pModuleName); // load/unload components class CSysModule; +extern CSysModule *Sys_GetModuleHandle(const char *pModuleName); + // Load & Unload should be called in exactly one place for each module // The factory for that module should be passed on to dependent components for // proper versioning. diff --git a/reapi/include/cssdk/public/utlarray.h b/reapi/include/cssdk/public/utlarray.h new file mode 100644 index 00000000..6bdb4136 --- /dev/null +++ b/reapi/include/cssdk/public/utlarray.h @@ -0,0 +1,235 @@ +/* +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +*/ + +#pragma once + +// A growable array class that maintains a free list and keeps elements +// in the same location +#include "tier0/platform.h" +#include "tier0/dbg.h" + +#define FOR_EACH_ARRAY(vecName, iteratorName)\ + for (int iteratorName = 0; (vecName).IsUtlArray && iteratorName < (vecName).Count(); iteratorName++) + +#define FOR_EACH_ARRAY_BACK(vecName, iteratorName)\ + for (int iteratorName = (vecName).Count() - 1; (vecName).IsUtlArray && iteratorName >= 0; iteratorName--) + +template +class CUtlArray +{ +public: + typedef T ElemType_t; + enum { IsUtlArray = true }; // Used to match this at compiletime + + CUtlArray(); + CUtlArray(T *pMemory, size_t count); + ~CUtlArray(); + + CUtlArray &operator=(const CUtlArray &other); + CUtlArray(CUtlArray const &vec); + + // element access + T &operator[](int i); + const T &operator[](int i) const; + T &Element(int i); + const T &Element(int i) const; + T &Random(); + const T &Random() const; + + T *Base(); + const T *Base() const; + + // Returns the number of elements in the array, NumAllocated() is included for consistency with UtlVector + int Count() const; + int NumAllocated() const; + + // Is element index valid? + bool IsValidIndex(int i) const; + static int InvalidIndex(); + + void CopyArray(const T *pArray, size_t count); + + void Clear(); + void RemoveAll(); + void Swap(CUtlArray< T, MAX_SIZE> &vec); + + // Finds an element (element needs operator== defined) + int Find(const T &src) const; + void FillWithValue(const T &src); + + bool HasElement(const T &src) const; + +protected: + T m_Memory[MAX_SIZE]; +}; + +// Constructor +template +inline CUtlArray::CUtlArray() +{ +} + +template +inline CUtlArray::CUtlArray(T *pMemory, size_t count) +{ + CopyArray(pMemory, count); +} + +// Destructor +template +inline CUtlArray::~CUtlArray() +{ +} + +template +inline CUtlArray &CUtlArray::operator=(const CUtlArray &other) +{ + if (this != &other) + { + for (size_t n = 0; n < MAX_SIZE; n++) + m_Memory[n] = other.m_Memory[n]; + } + + return *this; +} + +template +inline CUtlArray::CUtlArray(CUtlArray const &vec) +{ + for (size_t n = 0; n < MAX_SIZE; n++) + m_Memory[n] = vec.m_Memory[n]; +} + +template +inline T *CUtlArray::Base() +{ + return &m_Memory[0]; +} + +template +inline const T *CUtlArray::Base() const +{ + return &m_Memory[0]; +} + +// Element access +template +inline T &CUtlArray::operator[](int i) +{ + Assert(IsValidIndex(i)); + return m_Memory[i]; +} + +template +inline const T &CUtlArray::operator[](int i) const +{ + Assert(IsValidIndex(i)); + return m_Memory[i]; +} + +template +inline T &CUtlArray::Element(int i) +{ + Assert(IsValidIndex(i)); + return m_Memory[i]; +} + +template +inline const T &CUtlArray::Element(int i) const +{ + Assert(IsValidIndex(i)); + return m_Memory[i]; +} + +// Count +template +inline int CUtlArray::Count() const +{ + return (int)MAX_SIZE; +} + +template +inline int CUtlArray::NumAllocated() const +{ + return (int)MAX_SIZE; +} + +// Is element index valid? +template +inline bool CUtlArray::IsValidIndex(int i) const +{ + return (i >= 0) && (i < MAX_SIZE); +} + +// Returns in invalid index +template +inline int CUtlArray::InvalidIndex() +{ + return -1; +} + +template +void CUtlArray::CopyArray(const T *pArray, size_t count) +{ + Assert(count < MAX_SIZE); + + for (size_t n = 0; n < count; n++) + m_Memory[n] = pArray[n]; +} + +template +void CUtlArray::Clear() +{ + Q_memset(m_Memory, 0, MAX_SIZE * sizeof(T)); +} + +template +void CUtlArray::RemoveAll() +{ + Clear(); +} + +template +void CUtlArray::Swap(CUtlArray< T, MAX_SIZE> &vec) +{ + for (size_t n = 0; n < MAX_SIZE; n++) + SWAP(m_Memory[n], vec.m_Memory[n]); +} + +// Finds an element (element needs operator== defined) +template +int CUtlArray::Find(const T &src) const +{ + for (int i = 0; i < Count(); i++) + { + if (Element(i) == src) + return i; + } + + return -1; +} + +template +void CUtlArray::FillWithValue(const T &src) +{ + for (int i = 0; i < Count(); i++) + Element(i) = src; +} + +template +bool CUtlArray::HasElement(const T &src) const +{ + return (Find(src) >= 0); +} diff --git a/reapi/msvc/reapi.vcxproj b/reapi/msvc/reapi.vcxproj index 5fdef54e..41b87982 100644 --- a/reapi/msvc/reapi.vcxproj +++ b/reapi/msvc/reapi.vcxproj @@ -190,6 +190,7 @@ + @@ -210,7 +211,7 @@ - + @@ -255,7 +256,7 @@ - + diff --git a/reapi/msvc/reapi.vcxproj.filters b/reapi/msvc/reapi.vcxproj.filters index 99cf6ff6..501a60fc 100644 --- a/reapi/msvc/reapi.vcxproj.filters +++ b/reapi/msvc/reapi.vcxproj.filters @@ -582,6 +582,9 @@ include\cssdk\public + + include\cssdk\public + include\cssdk\public @@ -699,7 +702,7 @@ common - + src @@ -821,7 +824,7 @@ common - + src diff --git a/reapi/src/amx_hook.h b/reapi/src/amx_hook.h index 8b84a356..68e7c6ed 100644 --- a/reapi/src/amx_hook.h +++ b/reapi/src/amx_hook.h @@ -29,29 +29,3 @@ class CAmxxHookBase fwdstate m_state; AMX *m_amx; }; - -template -class CAmxxHookUnique: public CAmxxHookBase -{ -public: - ~CAmxxHookUnique() - { - if (m_uniqueData) - { - delete m_uniqueData; - m_uniqueData = nullptr; - } - } - - CAmxxHookUnique(AMX *amx, const char *funcname, int index, T *data = nullptr) : - CAmxxHookBase(amx, funcname, index, -1), - m_uniqueData(data) - { - - } - - T *GetUnique() const { return m_uniqueData; } - -private: - T *m_uniqueData; -}; diff --git a/reapi/src/entity_callback.cpp b/reapi/src/entity_callback.cpp deleted file mode 100644 index a11b59d3..00000000 --- a/reapi/src/entity_callback.cpp +++ /dev/null @@ -1,179 +0,0 @@ -#include "precompiled.h" - -CEntityCallback g_entCallback; - -void CEntityCallback::PurgeCallbacks(CBaseEntity *pEntity, CallbackType_e type) -{ - auto it = m_callbacks.begin(); - while (it != m_callbacks.end()) - { - eCallback_t *pUnique = (*it)->GetUnique(); - - // this callback was already sets, need to unregister the current forward - if (pUnique->m_callbackType == type && pUnique->m_entity == pEntity) { - delete (*it); - it = m_callbacks.erase(it); - } else { - it++; - } - } -} - -void CEntityCallback::Clear(CBaseEntity *pEntity) -{ - if (pEntity) - { - auto it = m_callbacks.begin(); - while (it != m_callbacks.end()) - { - eCallback_t *pUnique = (*it)->GetUnique(); - if (pUnique->m_entity == pEntity) { - delete (*it); - it = m_callbacks.erase(it); - } else { - it++; - } - } - } - else - { - for (auto h : m_callbacks) { - delete h; - } - - m_callbacks.clear(); - } -} - -bool CEntityCallback::SetThink(AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen) -{ - PurgeCallbacks(pEntity, CType_Think); - - int fwdid; - if (iParamsLen > 0) { - fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_ARRAY, FP_DONE); - } else { - fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_DONE); - } - - if (fwdid == -1) { - AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: failed to register forward.", __FUNCTION__); - return false; - } - - m_callbacks.push_back(new CAmxxHookUnique(amx, pszCallback, fwdid, new eCallback_t(pEntity, pParams, iParamsLen, CType_Think))); - pEntity->SetThink(&CBaseEntity::SUB_Think); - return true; -} - -bool CEntityCallback::SetTouch(AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen) -{ - PurgeCallbacks(pEntity, CType_Touch); - - int fwdid; - if (iParamsLen > 0) { - fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_CELL, FP_ARRAY, FP_DONE); - } else { - fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_CELL, FP_DONE); - } - - if (fwdid == -1) { - AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: failed to register forward.", __FUNCTION__); - return false; - } - - m_callbacks.push_back(new CAmxxHookUnique(amx, pszCallback, fwdid, new eCallback_t(pEntity, pParams, iParamsLen, CType_Touch))); - pEntity->SetTouch(&CBaseEntity::SUB_Touch); - return true; -} - -bool CEntityCallback::SetUse(AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen) -{ - PurgeCallbacks(pEntity, CType_Use); - - int fwdid; - if (iParamsLen > 0) { - fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_FLOAT, FP_ARRAY, FP_DONE); - } else { - fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_FLOAT, FP_DONE); - } - - if (fwdid == -1) { - AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: failed to register forward.", __FUNCTION__); - return false; - } - - m_callbacks.push_back(new CAmxxHookUnique(amx, pszCallback, fwdid, new eCallback_t(pEntity, pParams, iParamsLen, CType_Use))); - pEntity->SetUse(&CBaseEntity::SUB_Use); - return true; -} - -bool CEntityCallback::SetBlocked(AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen) -{ - PurgeCallbacks(pEntity, CType_Blocked); - - int fwdid; - if (iParamsLen > 0) { - fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_CELL, FP_ARRAY, FP_DONE); - } else { - fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_CELL, FP_DONE); - } - - if (fwdid == -1) { - AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: failed to register forward.", __FUNCTION__); - return false; - } - - m_callbacks.push_back(new CAmxxHookUnique(amx, pszCallback, fwdid, new eCallback_t(pEntity, pParams, iParamsLen, CType_Blocked))); - pEntity->SetBlocked(&CBaseEntity::SUB_Blocked); - return true; -} - -bool CEntityCallback::SetMoveDone(AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen) -{ - PurgeCallbacks(pEntity, CType_MoveDone); - - int fwdid; - if (iParamsLen > 0) { - fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_ARRAY, FP_DONE); - } else { - fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_DONE); - } - - if (fwdid == -1) { - AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: failed to register forward.", __FUNCTION__); - return false; - } - - m_callbacks.push_back(new CAmxxHookUnique(amx, pszCallback, fwdid, new eCallback_t(pEntity, pParams, iParamsLen, CType_MoveDone))); - - // TODO: Make sure that the entity actually inherited from CBaseToggle - ((CBaseToggle *)pEntity)->SetMoveDone(&CBaseToggle::SUB_MoveDone); - return true; -} - -// Fundamental callbacks -void CBaseEntity::SUB_Think() -{ - g_entCallback.FireCallbacks(this, CEntityCallback::CType_Think, indexOfEdict(pev)); -} - -void CBaseEntity::SUB_Touch(CBaseEntity *pOther) -{ - g_entCallback.FireCallbacks(this, CEntityCallback::CType_Touch, indexOfEdict(pev), indexOfEdict(pOther->pev)); -} - -void CBaseEntity::SUB_Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) -{ - g_entCallback.FireCallbacks(this, CEntityCallback::CType_Use, indexOfEdict(pev), indexOfEdict(pActivator->pev), indexOfEdict(pCaller->pev), useType, value); -} - -void CBaseEntity::SUB_Blocked(CBaseEntity *pOther) -{ - g_entCallback.FireCallbacks(this, CEntityCallback::CType_Blocked, indexOfEdict(pev), indexOfEdict(pOther->pev)); -} - -void CBaseToggle::SUB_MoveDone() -{ - g_entCallback.FireCallbacks(this, CEntityCallback::CType_MoveDone, indexOfEdict(pev)); -} diff --git a/reapi/src/entity_callback.h b/reapi/src/entity_callback.h deleted file mode 100644 index 62202591..00000000 --- a/reapi/src/entity_callback.h +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include "amx_hook.h" - -class CEntityCallback -{ -public: - void Clear(CBaseEntity *pEntity = nullptr); - - bool SetThink (AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen); - bool SetTouch (AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen); - bool SetUse (AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen); - bool SetBlocked (AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen); - bool SetMoveDone(AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen); - - enum CallbackType_e - { - CType_Think, - CType_Touch, - CType_Use, - CType_Blocked, - CType_MoveDone, - }; - - template - void FireCallbacks(CBaseEntity *pEntity, CallbackType_e type, volatile f_args... args) - { - for (auto fwd : m_callbacks) { - auto data = fwd->GetUnique(); - if (data->m_entity == pEntity && data->m_callbackType == type) - { - if (data->m_iParamLen > 0) { - g_amxxapi.ExecuteForward(fwd->GetFwdIndex(), args..., g_amxxapi.PrepareCellArrayA(data->m_pParams, data->m_iParamLen, true)); - } else { - g_amxxapi.ExecuteForward(fwd->GetFwdIndex(), args...); - } - } - } - } - -private: - void PurgeCallbacks(CBaseEntity *pEntity, CallbackType_e type); - struct eCallback_t - { - eCallback_t(CBaseEntity *pEntity, const cell *pParams, size_t iParamsLen, CallbackType_e type) : - m_entity(pEntity), m_callbackType(type) - { - if (iParamsLen > 0) { - m_iParamLen = iParamsLen + 1; - m_pParams = new cell[m_iParamLen]; - Q_memcpy(m_pParams, pParams, sizeof(cell) * iParamsLen); - m_pParams[iParamsLen] = 0; - } else { - m_iParamLen = 0; - m_pParams = nullptr; - } - }; - - ~eCallback_t() - { - if (m_pParams) { - delete[] m_pParams; - m_pParams = nullptr; - } - - m_iParamLen = 0; - } - - CBaseEntity *m_entity; - CallbackType_e m_callbackType; - cell *m_pParams; - size_t m_iParamLen; - }; - - std::vector *> m_callbacks; -}; - -extern CEntityCallback g_entCallback; diff --git a/reapi/src/entity_callback_dispatcher.cpp b/reapi/src/entity_callback_dispatcher.cpp new file mode 100644 index 00000000..71279336 --- /dev/null +++ b/reapi/src/entity_callback_dispatcher.cpp @@ -0,0 +1,232 @@ +#include "precompiled.h" + +// Deletes all registered callbacks for the specified entity, or all entities if pEntity is nullptr +void CEntityCallbackDispatcher::DeleteExistingCallbacks(CBaseEntity *pEntity, CallbackType type) +{ + for (std::list::const_iterator it = m_callbacks.begin(); + it != m_callbacks.end(); ) + { + EntityCallback *callback = (*it); + + // This callback was already sets, need to unregister the current forward + if (!pEntity || (callback->m_pEntity == pEntity && (callback->m_callbackType == type || None == type))) + { + // Are we in the middle of processing callbacks? + if (IsProcessingCallbacks()) + { + // Sets the mark for the object to be deleted later + const std::list::const_iterator callbackIt = + std::find(m_callbacksMarkForDeletion.begin(), m_callbacksMarkForDeletion.end(), callback); + + if (callbackIt == m_callbacksMarkForDeletion.end()) + m_callbacksMarkForDeletion.push_back(callback); + + it++; + } + else + { + it = m_callbacks.erase(it); + delete callback; + } + } + else + { + it++; + } + } + + if (!pEntity && !IsProcessingCallbacks()) + m_callbacks.clear(); +} + +// Deletes all registered callbacks +void CEntityCallbackDispatcher::DeleteAllCallbacks() +{ + DeleteExistingCallbacks(nullptr); +} + +bool CEntityCallbackDispatcher::SetThink(AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen) +{ + DeleteExistingCallbacks(pEntity, Think); + + int fwdid; + if (iParamsLen > 0) + fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_ARRAY, FP_DONE); + else + fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_DONE); + + if (fwdid == -1) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: failed to register forward.", __FUNCTION__); + return false; + } + + m_callbacks.push_back(new EntityCallback(amx, pszCallback, fwdid, pEntity, pParams, iParamsLen, Think)); + pEntity->SetThink(&CBaseEntity::SUB_Think); + return true; +} + +bool CEntityCallbackDispatcher::SetTouch(AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen) +{ + DeleteExistingCallbacks(pEntity, Touch); + + int fwdid; + if (iParamsLen > 0) + fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_CELL, FP_ARRAY, FP_DONE); + else + fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_CELL, FP_DONE); + + if (fwdid == -1) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: failed to register forward.", __FUNCTION__); + return false; + } + + m_callbacks.push_back(new EntityCallback(amx, pszCallback, fwdid, pEntity, pParams, iParamsLen, Touch)); + pEntity->SetTouch(&CBaseEntity::SUB_Touch); + return true; +} + +bool CEntityCallbackDispatcher::SetUse(AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen) +{ + DeleteExistingCallbacks(pEntity, Use); + + int fwdid; + if (iParamsLen > 0) + fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_FLOAT, FP_ARRAY, FP_DONE); + else + fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_FLOAT, FP_DONE); + + if (fwdid == -1) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: failed to register forward.", __FUNCTION__); + return false; + } + + m_callbacks.push_back(new EntityCallback(amx, pszCallback, fwdid, pEntity, pParams, iParamsLen, Use)); + pEntity->SetUse(&CBaseEntity::SUB_Use); + return true; +} + +bool CEntityCallbackDispatcher::SetBlocked(AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen) +{ + DeleteExistingCallbacks(pEntity, Blocked); + + int fwdid; + if (iParamsLen > 0) + fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_CELL, FP_ARRAY, FP_DONE); + else + fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_CELL, FP_DONE); + + if (fwdid == -1) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: failed to register forward.", __FUNCTION__); + return false; + } + + m_callbacks.push_back(new EntityCallback(amx, pszCallback, fwdid, pEntity, pParams, iParamsLen, Blocked)); + pEntity->SetBlocked(&CBaseEntity::SUB_Blocked); + return true; +} + +bool CEntityCallbackDispatcher::SetMoveDone(AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen) +{ + DeleteExistingCallbacks(pEntity, MoveDone); + + int fwdid; + if (iParamsLen > 0) + fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_ARRAY, FP_DONE); + else + fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_DONE); + + if (fwdid == -1) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: failed to register forward.", __FUNCTION__); + return false; + } + + // Make sure that the entity actually inherited from CBaseToggle + CBaseToggle *pEntityToggle = dynamic_cast(pEntity); + if (!pEntityToggle) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: '%s' has no refs to the base class of an entity 'CBaseToggle'", __FUNCTION__, STRING(pEntity->pev->classname)); + return false; + } + + m_callbacks.push_back(new EntityCallback(amx, pszCallback, fwdid, pEntity, pParams, iParamsLen, MoveDone)); + pEntityToggle->SetMoveDone(&CBaseToggle::SUB_MoveDone); + return true; +} + +void CEntityCallbackDispatcher::UnsetThink(AMX *amx, CBaseEntity *pEntity) +{ + pEntity->SetThink(nullptr); + DeleteExistingCallbacks(pEntity, Think); +} + +void CEntityCallbackDispatcher::UnsetTouch(AMX *amx, CBaseEntity *pEntity) +{ + pEntity->SetTouch(nullptr); + DeleteExistingCallbacks(pEntity, Touch); +} + +void CEntityCallbackDispatcher::UnsetUse(AMX *amx, CBaseEntity *pEntity) +{ + pEntity->SetUse(nullptr); + DeleteExistingCallbacks(pEntity, Use); +} + +void CEntityCallbackDispatcher::UnsetBlocked(AMX *amx, CBaseEntity *pEntity) +{ + pEntity->SetBlocked(nullptr); + DeleteExistingCallbacks(pEntity, Blocked); +} + +void CEntityCallbackDispatcher::UnsetMoveDone(AMX *amx, CBaseEntity *pEntity) +{ + // Make sure that the entity actually inherited from CBaseToggle + CBaseToggle *pEntityToggle = dynamic_cast(pEntity); + if (!pEntityToggle) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: '%s' has no refs to the base class of an entity 'CBaseToggle'", __FUNCTION__, STRING(pEntity->pev->classname)); + return; + } + + pEntityToggle->SetMoveDone(nullptr); + DeleteExistingCallbacks(pEntity, MoveDone); +} + +// Fundamental callbacks +void CBaseEntity::SUB_Think() +{ + EntityCallbackDispatcher().DispatchCallbacks(this, CEntityCallbackDispatcher::Think, indexOfEdict(pev)); +} + +void CBaseEntity::SUB_Touch(CBaseEntity *pOther) +{ + EntityCallbackDispatcher().DispatchCallbacks(this, CEntityCallbackDispatcher::Touch, indexOfEdict(pev), indexOfEdict(pOther->pev)); +} + +void CBaseEntity::SUB_Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) +{ + EntityCallbackDispatcher().DispatchCallbacks(this, CEntityCallbackDispatcher::Use, indexOfEdict(pev), indexOfEdict(pActivator->pev), indexOfEdict(pCaller->pev), useType, value); +} + +void CBaseEntity::SUB_Blocked(CBaseEntity *pOther) +{ + EntityCallbackDispatcher().DispatchCallbacks(this, CEntityCallbackDispatcher::Blocked, indexOfEdict(pev), indexOfEdict(pOther->pev)); +} + +void CBaseToggle::SUB_MoveDone() +{ + EntityCallbackDispatcher().DispatchCallbacks(this, CEntityCallbackDispatcher::MoveDone, indexOfEdict(pev)); +} + +// Instance of the callback dispatcher +static CEntityCallbackDispatcher s_EntityCallbackDispatcher = {}; + +// Returns the instance of the callback dispatcher +CEntityCallbackDispatcher &EntityCallbackDispatcher() +{ + return s_EntityCallbackDispatcher; +} diff --git a/reapi/src/entity_callback_dispatcher.h b/reapi/src/entity_callback_dispatcher.h new file mode 100644 index 00000000..7a701392 --- /dev/null +++ b/reapi/src/entity_callback_dispatcher.h @@ -0,0 +1,172 @@ +#pragma once + +#include "amx_hook.h" + +// Manages entity member functions such as (m_pfnThink, m_pfnTouch, m_pfnUse) and dispatches callbacks to AMXX plugins +class CEntityCallbackDispatcher +{ +public: + bool SetThink (AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen); + bool SetTouch (AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen); + bool SetUse (AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen); + bool SetBlocked (AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen); + bool SetMoveDone (AMX *amx, CBaseEntity *pEntity, const char *pszCallback, const cell *pParams, size_t iParamsLen); + + void UnsetThink (AMX *amx, CBaseEntity *pEntity); + void UnsetTouch (AMX *amx, CBaseEntity *pEntity); + void UnsetUse (AMX *amx, CBaseEntity *pEntity); + void UnsetBlocked (AMX *amx, CBaseEntity *pEntity); + void UnsetMoveDone(AMX *amx, CBaseEntity *pEntity); + + // Enumeration of possible callback types for entity events + enum CallbackType + { + None, // No specific callback type, means unset + Think, + Touch, + Use, + Blocked, + MoveDone, + }; + + // + // @brief Deletes all registered callbacks + void DeleteAllCallbacks(); + + // + // @brief Deletes existing callbacks of the specified type associated with the given entity + // + // @param pEntity Pointer to the entity for which callbacks should be deleted. + // @param type Type of callback to delete (default:None to delete all types) + // + void DeleteExistingCallbacks(CBaseEntity *pEntity, CallbackType type = None); + + // Are we in the middle of processing callbacks? + bool IsProcessingCallbacks() const { return m_bIsProcessingCallbacks; } + + // + // @brief Dispatches callbacks associated with the specified entity and callback type + // + // This function iterates through registered callbacks and executes them for the + // given entity and callback type + // + // + // @param pEntity Pointer to the entity for which callbacks should be dispatched + // @param type Type of callback to dispatch + // @param args Arguments to pass to the callbacks + // + template + void DispatchCallbacks(CBaseEntity *pEntity, CallbackType type, volatile f_args... args) + { + // Flag to indicate that callback processing is currently active. + // This flag is set to true while callback processing to prevent immediate deletion + // of registered callbacks that may be involved in caused AMXX plugin callbacks + // Callbacks marked for deletion are prune after callback processing is complete + m_bIsProcessingCallbacks = true; + + // Iterate through the list of registered callbacks + for (std::list::const_iterator it = m_callbacks.begin(); + it != m_callbacks.end(); it++) + { + const EntityCallback *callback = (*it); + + // Check if the callback is associated with the specified entity and callback type + if (callback->m_pEntity == pEntity && callback->m_callbackType == type) + { + // Check if user parameters provided for this callback + if (callback->m_nUserParamBlockSize > 0) + { + // Execute the callback with the provided arguments and user parameters + g_amxxapi.ExecuteForward(callback->GetFwdIndex(), args..., g_amxxapi.PrepareCellArrayA(callback->m_pUserParams, callback->m_nUserParamBlockSize, true)); + } + else + { + // Execute the callback with the provided arguments + g_amxxapi.ExecuteForward(callback->GetFwdIndex(), args...); + } + } + } + + // Reset the flag to indicate that callback processing has concluded + // From this point onward, entity callbacks will be immediately deleted on the spot as it is, + // without any deferred removals or processing + m_bIsProcessingCallbacks = false; + + // Is there at least one candidate marked for deletion? + if (!m_callbacksMarkForDeletion.empty()) + { + for (std::list::const_iterator it = m_callbacksMarkForDeletion.begin(); + it != m_callbacksMarkForDeletion.end(); it++) + { + const EntityCallback *toDelete = (*it); + + const std::list::const_iterator callbackIt = + std::find(m_callbacks.begin(), m_callbacks.end(), toDelete); + + // Check if the marked for deletion callback + // was found in the list of registered callbacks + if (callbackIt != m_callbacks.end()) + { + m_callbacks.erase(callbackIt); + delete toDelete; + } + } + + m_callbacksMarkForDeletion.clear(); + } + } + +private: + // EntityCallback - a class representing a registered callback for an entity + class EntityCallback: public CAmxxHookBase + { + public: + EntityCallback(AMX *amx, const char *funcname, int index, + CBaseEntity *pEntity, const cell *pParams, size_t iParamsLen, CallbackType type + ) : + CAmxxHookBase(amx, funcname, index, -1), + m_pEntity(pEntity), m_callbackType(type) + { + if (iParamsLen > 0) { + m_nUserParamBlockSize = iParamsLen + 1; + m_pUserParams = new cell[m_nUserParamBlockSize]; + Q_memcpy(m_pUserParams, pParams, sizeof(cell) * iParamsLen); + m_pUserParams[iParamsLen] = 0; + } else { + m_nUserParamBlockSize = 0; + m_pUserParams = nullptr; + } + } + + ~EntityCallback() + { + if (m_pUserParams) + delete[] m_pUserParams; + m_pUserParams = nullptr; + m_nUserParamBlockSize = 0; + } + + // Pointer to the entity for which the callback is registered + CBaseEntity *m_pEntity; + + // Type of the callback (e.g., Think, Touch, Use, and so on) + CallbackType m_callbackType; + + // User-provided data to be passed to their callback function + cell *m_pUserParams; + + // The length of user-provided parameters to be passed to their callback function + size_t m_nUserParamBlockSize; + }; + + // Flag indicating that callback processing is currently in progress + bool m_bIsProcessingCallbacks; + + // List of registered callbacks + std::list m_callbacks; + + // List of callbacks marked for deletion after dispatching callbacks is complete + std::list m_callbacksMarkForDeletion; +}; + +CEntityCallbackDispatcher &EntityCallbackDispatcher(); diff --git a/reapi/src/hook_callback.cpp b/reapi/src/hook_callback.cpp index 78b3a5c4..5962a26b 100644 --- a/reapi/src/hook_callback.cpp +++ b/reapi/src/hook_callback.cpp @@ -115,7 +115,6 @@ void SV_EmitPings_AMXX(SV_EmitPings_t* data, IGameClient* cl) void SV_EmitPings(IRehldsHook_SV_EmitPings *chain, IGameClient *cl, sizebuf_t *msg) { - SV_EmitPings_args_t args(cl, msg); SV_EmitPings_t data(chain, args); SV_EmitPings_AMXX(&data, cl); @@ -141,6 +140,108 @@ void ED_Free(IRehldsHook_ED_Free* chain, edict_t *entity) callVoidForward(RH_ED_Free, original, indexOfEdict(entity)); } +bool SV_AllowPhysent(IRehldsHook_SV_AllowPhysent* chain, edict_t* check, edict_t* sv_player) +{ + auto original = [chain](int _check, int _sv_player) + { + return chain->callNext(edictByIndexAmx(_check), edictByIndexAmx(_sv_player)); + }; + + return callForward(RH_SV_AllowPhysent, original, indexOfEdict(check), indexOfEdict(sv_player)); +} + +BOOL SV_CheckUserInfo_AMXX(IRehldsHook_SV_CheckUserInfo *chain, netadr_t *adr, size_t userinfo, qboolean bIsReconnecting, int iReconnectSlot, char *name) +{ + auto original = [chain](netadr_t *_adr, cell _userinfo, qboolean _bIsReconnecting, int _iReconnectSlot, char *_name) + { + return chain->callNext(_adr, (char *)_userinfo, _bIsReconnecting, _iReconnectSlot, _name); + }; + + return callForward(RH_SV_CheckUserInfo, original, adr, userinfo, bIsReconnecting, iReconnectSlot, name); +} + +BOOL SV_CheckUserInfo(IRehldsHook_SV_CheckUserInfo *chain, netadr_t *adr, char *userinfo, qboolean bIsReconnecting, int iReconnectSlot, char *name) +{ + return SV_CheckUserInfo_AMXX(chain, adr, (size_t)userinfo, bIsReconnecting, iReconnectSlot, name); +} + +int PF_precache_generic_I(IRehldsHook_PF_precache_generic_I *chain, const char *s) +{ + auto original = [chain](const char *_s) + { + return chain->callNext(_s); + }; + + return callForward(RH_PF_precache_generic_I, original, s); +} + +int PF_precache_model_I(IRehldsHook_PF_precache_model_I *chain, char *s) +{ + auto original = [chain](char *_s) + { + return chain->callNext(_s); + }; + + return callForward(RH_PF_precache_model_I, original, s); +} + +int PF_precache_sound_I(IRehldsHook_PF_precache_sound_I *chain, const char *s) +{ + auto original = [chain](const char *_s) + { + return chain->callNext(_s); + }; + + return callForward(RH_PF_precache_sound_I, original, s); +} + +unsigned short EV_Precache_AMXX(EventPrecache_t *data, const char *psz) +{ + auto original = [data](const char *_psz) + { + return data->m_chain->callNext(data->m_args.type, _psz); + }; + + return callForward(RH_EV_Precache, original, psz); +} + +unsigned short EV_Precache(IRehldsHook_EV_Precache *chain, int type, const char *psz) +{ + EventPrecache_args_t args(type); + EventPrecache_t data(chain, args); + return EV_Precache_AMXX(&data, psz); +} + +void SV_AddResource(IRehldsHook_SV_AddResource *chain, resourcetype_t type, const char *name, int size, unsigned char flags, int index) +{ + auto original = [chain](resourcetype_t _type, const char *_name, int _size, unsigned char _flags, int _index) + { + chain->callNext(_type, _name, _size, _flags, _index); + }; + + callVoidForward(RH_SV_AddResource, original, type, name, size, flags, index); +} + +void SV_ClientPrintf(IRehldsHook_SV_ClientPrintf *chain, const char *string) +{ + auto original = [chain](const char *_string) + { + chain->callNext(_string); + }; + + callVoidForward(RH_SV_ClientPrintf, original, string); +} + +void ExecuteServerStringCmd(IRehldsHook_ExecuteServerStringCmd* chain, const char* cmdName, cmd_source_t cmdSrc, IGameClient* cl) +{ + auto original = [chain](const char* _cmdName, cmd_source_t _cmdSrc, int client) + { + chain->callNext(_cmdName, _cmdSrc, _cmdSrc == src_client ? g_RehldsSvs->GetClient(client) - 1 : 0); + }; + + callVoidForward(RH_ExecuteServerStringCmd, original, cmdName, cmdSrc, cmdSrc == src_client ? cl->GetId() + 1 : 0); +} + /* * ReGameDLL functions */ @@ -376,16 +477,6 @@ CBasePlayer *CBasePlayer_Observer_IsValidTarget(IReGameHook_CBasePlayer_Observer return getPrivate(callForward(RG_CBasePlayer_Observer_IsValidTarget, original, indexOfEdict(pthis->pev), iPlayerIndex, bSameTeam)); } -void CBasePlayer_Observer_FindNextPlayer(IReGameHook_CBasePlayer_Observer_FindNextPlayer *chain, CBasePlayer *pthis, bool bReverse, const char *name) -{ - auto original = [chain](int _pthis, bool _bReverse, const char *_name) - { - chain->callNext(getPrivate(_pthis), _bReverse, _name); - }; - - callVoidForward(RG_CBasePlayer_Observer_FindNextPlayer, original, indexOfEdict(pthis->pev), bReverse, name); -} - void CBasePlayer_SetAnimation(IReGameHook_CBasePlayer_SetAnimation *chain, CBasePlayer *pthis, PLAYER_ANIM playerAnim) { auto original = [chain](int _pthis, PLAYER_ANIM _playerAnim) @@ -558,326 +649,224 @@ bool CBasePlayer_GetIntoGame(IReGameHook_CBasePlayer_GetIntoGame *chain, CBasePl return callForward(RG_CBasePlayer_GetIntoGame, original, indexOfEdict(pthis->pev)); } -void CBasePlayer_StartDeathCam(IReGameHook_CBasePlayer_StartDeathCam *chain, CBasePlayer *pthis) +void CBaseAnimating_ResetSequenceInfo(IReGameHook_CBaseAnimating_ResetSequenceInfo *chain, CBaseAnimating *pthis) { auto original = [chain](int _pthis) { - return chain->callNext(getPrivate(_pthis)); + chain->callNext(getPrivate(_pthis)); }; - callVoidForward(RG_CBasePlayer_StartDeathCam, original, indexOfEdict(pthis->pev)); + callVoidForward(RG_CBaseAnimating_ResetSequenceInfo, original, indexOfEdict(pthis->pev)); } -void CBasePlayer_SwitchTeam(IReGameHook_CBasePlayer_SwitchTeam *chain, CBasePlayer *pthis) +int GetForceCamera(IReGameHook_GetForceCamera *chain, CBasePlayer *pObserver) { - auto original = [chain](int _pthis) + auto original = [chain](int _pObserver) { - chain->callNext(getPrivate(_pthis)); + return chain->callNext(getPrivate(_pObserver)); }; - callVoidForward(RG_CBasePlayer_CanSwitchTeam, original, indexOfEdict(pthis->pev)); + return callForward(RG_GetForceCamera, original, indexOfEdict(pObserver->pev)); } -bool CBasePlayer_CanSwitchTeam(IReGameHook_CBasePlayer_CanSwitchTeam *chain, CBasePlayer *pthis, TeamName teamToSwap) +void PlayerBlind(IReGameHook_PlayerBlind *chain, CBasePlayer *pPlayer, entvars_t *pevInflictor, entvars_t *pevAttacker, float fadeTime, float fadeHold, int alpha, Vector& color) { - auto original = [chain](int _pthis, TeamName _teamToSwap) + Vector colorCopy(color); + + auto original = [chain, &colorCopy](int _pPlayer, int _pevInflictor, int _pevAttacker, float _fadeTime, float _fadeHold, int _alpha, cell _color) { - return chain->callNext(getPrivate(_pthis), _teamToSwap); + chain->callNext(getPrivate(_pPlayer), PEV(_pevInflictor), PEV(_pevAttacker), _fadeTime, _fadeHold, _alpha, colorCopy); }; - return callForward(RG_CBasePlayer_CanSwitchTeam, original, indexOfEdict(pthis->pev), teamToSwap); + callVoidForward(RG_PlayerBlind, original, indexOfEdict(pPlayer->pev), indexOfEdict(pevInflictor), indexOfEdict(pevAttacker), fadeTime, fadeHold, alpha, getAmxVector(colorCopy)); } -CGrenade *CBasePlayer_ThrowGrenade(IReGameHook_CBasePlayer_ThrowGrenade *chain, CBasePlayer *pthis, CBasePlayerWeapon *pWeapon, Vector &vecSrc, Vector &vecThrow, float time, unsigned short usEvent) +void RadiusFlash_TraceLine(IReGameHook_RadiusFlash_TraceLine *chain, CBasePlayer *pPlayer, entvars_t *pevInflictor, entvars_t *pevAttacker, Vector& vecSrc, Vector& vecSpot, TraceResult *ptr) { - Vector vecSrcCopy(vecSrc), vecThrowCopy(vecThrow); + Vector vecSrcCopy(vecSrc), vecSpotCopy(vecSpot); - auto original = [chain, &vecSrcCopy, &vecThrowCopy](int _pthis, int _pWeapon, cell _vecSrc, cell _vecThrow, float _time, unsigned short _usEvent) + auto original = [chain, &vecSrcCopy, &vecSpotCopy](int _pPlayer, int _pevInflictor, int _pevAttacker, cell _vecSrc, cell _vecSpot, TraceResult *_ptr) { - return indexOfPDataAmx(chain->callNext(getPrivate(_pthis), getPrivate(_pWeapon), vecSrcCopy, vecThrowCopy, _time, _usEvent)); + chain->callNext(getPrivate(_pPlayer), PEV(_pevInflictor), PEV(_pevAttacker), vecSrcCopy, vecSpotCopy, _ptr); }; - return getPrivate(callForward(RG_CBasePlayer_ThrowGrenade, original, indexOfEdict(pthis->pev), indexOfEdict(pWeapon->pev), getAmxVector(vecSrcCopy), getAmxVector(vecThrowCopy), time, usEvent)); + callVoidForward(RG_RadiusFlash_TraceLine, original, indexOfEdict(pPlayer->pev), indexOfEdict(pevInflictor), indexOfEdict(pevAttacker), getAmxVector(vecSrcCopy), getAmxVector(vecSpotCopy), ptr); } -void CBasePlayer_SetSpawnProtection(IReGameHook_CBasePlayer_SetSpawnProtection *chain, CBasePlayer *pthis, float flProtectionTime) +bool RoundEnd(IReGameHook_RoundEnd *chain, int winStatus, ScenarioEventEndRound event, float tmDelay) { - auto original = [chain](int _pthis, float _flProtectionTime) + auto original = [chain](int _winStatus, ScenarioEventEndRound _event, float _tmDelay) { - return chain->callNext(getPrivate(_pthis), _flProtectionTime); + return chain->callNext(_winStatus, _event, _tmDelay); }; - callVoidForward(RG_CBasePlayer_SetSpawnProtection, original, indexOfEdict(pthis->pev), flProtectionTime); + return callForward(RG_RoundEnd, original, winStatus, event, tmDelay); } -void CBasePlayer_RemoveSpawnProtection(IReGameHook_CBasePlayer_RemoveSpawnProtection *chain, CBasePlayer *pthis) +void PM_Move_AMXX(Move_t *data, int playerIndex) { - auto original = [chain](int _pthis) + auto original = [data](int _playerIndex) { - return chain->callNext(getPrivate(_pthis)); + data->m_chain->callNext(data->m_args.ppmove, data->m_args.server); }; - callVoidForward(RG_CBasePlayer_RemoveSpawnProtection, original, indexOfEdict(pthis->pev)); + callVoidForward(RG_PM_Move, original, playerIndex); } -bool CBasePlayer_HintMessageEx(IReGameHook_CBasePlayer_HintMessageEx *chain, CBasePlayer *pthis, const char *pMessage, float duration, bool bDisplayIfPlayerDead, bool bOverride) +void PM_Move(IReGameHook_PM_Move *chain, playermove_t *ppmove, int server) { - auto original = [chain](int _pthis, const char *_pMessage, float _duration, bool _bDisplayIfPlayerDead, bool _bOverride) - { - return chain->callNext(getPrivate(_pthis), _pMessage, _duration, _bDisplayIfPlayerDead, _bOverride); - }; + g_pMove = ppmove; - return callForward(RG_CBasePlayer_HintMessageEx, original, indexOfEdict(pthis->pev), pMessage, duration, bDisplayIfPlayerDead, bOverride); + Move_args_t args(ppmove, server); + Move_t data(chain, args); + PM_Move_AMXX(&data, ppmove->player_index + 1); } -void CBasePlayer_UseEmpty(IReGameHook_CBasePlayer_UseEmpty *chain, CBasePlayer *pthis) +void PM_AirMove(IReGameHook_PM_AirMove *chain, int playerIndex) { - auto original = [chain](int _pthis) + auto original = [chain](int _playerIndex) { - return chain->callNext(getPrivate(_pthis)); + chain->callNext(_playerIndex); }; - callVoidForward(RG_CBasePlayer_UseEmpty, original, indexOfEdict(pthis->pev)); + callVoidForward(RG_PM_AirMove, original, playerIndex); } -void CBasePlayer_DropIdlePlayer(IReGameHook_CBasePlayer_DropIdlePlayer *chain, CBasePlayer *pthis, const char *reason) +void HandleMenu_ChooseAppearance(IReGameHook_HandleMenu_ChooseAppearance *chain, CBasePlayer *pPlayer, int slot) { - auto original = [chain](int _pthis, const char *_reason) + auto original = [chain](int _pPlayer, int _slot) { - return chain->callNext(getPrivate(_pthis), _reason); + chain->callNext(getPrivate(_pPlayer), _slot); }; - callVoidForward(RG_CBasePlayer_DropIdlePlayer, original, indexOfEdict(pthis->pev), reason); + callVoidForward(RG_HandleMenu_ChooseAppearance, original, indexOfEdict(pPlayer->pev), slot); } -void CBasePlayer_Pain(IReGameHook_CBasePlayer_Pain *chain, CBasePlayer *pthis, int iLastHitGroup, bool bHasArmour) +BOOL HandleMenu_ChooseTeam(IReGameHook_HandleMenu_ChooseTeam *chain, CBasePlayer *pPlayer, int slot) { - auto original = [chain](int _pthis, int _iLastHitGroup, bool _bHasArmour) + auto original = [chain](int _pPlayer, int _slot) { - return chain->callNext(getPrivate(_pthis), _iLastHitGroup, _bHasArmour); + return chain->callNext(getPrivate(_pPlayer), _slot); }; - callVoidForward(RG_CBasePlayer_Pain, original, indexOfEdict(pthis->pev), iLastHitGroup, bHasArmour); + return callForward(RG_HandleMenu_ChooseTeam, original, indexOfEdict(pPlayer->pev), slot); } -void CBasePlayer_DeathSound(IReGameHook_CBasePlayer_DeathSound *chain, CBasePlayer *pthis) +void ShowMenu(IReGameHook_ShowMenu *chain, CBasePlayer *pPlayer, int bitsValidSlots, int nDisplayTime, BOOL fNeedMore, char *pszText) { - auto original = [chain](int _pthis) + auto original = [chain](int _pPlayer, int _bitsValidSlots, int _nDisplayTime, BOOL _fNeedMore, char *_pszText) { - return chain->callNext(getPrivate(_pthis)); + chain->callNext(getPrivate(_pPlayer), _bitsValidSlots, _nDisplayTime, _fNeedMore, _pszText); }; - callVoidForward(RG_CBasePlayer_DeathSound, original, indexOfEdict(pthis->pev)); + callVoidForward(RG_ShowMenu, original, indexOfEdict(pPlayer->pev), bitsValidSlots, nDisplayTime, fNeedMore, pszText); } -void CBasePlayer_JoiningThink(IReGameHook_CBasePlayer_JoiningThink *chain, CBasePlayer *pthis) +void ShowVGUIMenu(IReGameHook_ShowVGUIMenu *chain, CBasePlayer *pPlayer, int MenuType, int BitMask, char *szOldMenu) { - auto original = [chain](int _pthis) + auto original = [chain](int _pPlayer, int _MenuType, int _BitMask, char *_szOldMenu) { - return chain->callNext(getPrivate(_pthis)); + chain->callNext(getPrivate(_pPlayer), _MenuType, _BitMask, _szOldMenu); }; - callVoidForward(RG_CBasePlayer_JoiningThink, original, indexOfEdict(pthis->pev)); + callVoidForward(RG_ShowVGUIMenu, original, indexOfEdict(pPlayer->pev), MenuType, BitMask, szOldMenu); } -void CBaseAnimating_ResetSequenceInfo(IReGameHook_CBaseAnimating_ResetSequenceInfo *chain, CBaseAnimating *pthis) +bool BuyGunAmmo(IReGameHook_BuyGunAmmo *chain, CBasePlayer *player, CBasePlayerItem *weapon, bool bBlinkMoney) { - auto original = [chain](int _pthis) + auto original = [chain](int _player, int _weapon, bool _bBlinkMoney) { - chain->callNext(getPrivate(_pthis)); + return chain->callNext(getPrivate(_player), getPrivate(_weapon), _bBlinkMoney); }; - callVoidForward(RG_CBaseAnimating_ResetSequenceInfo, original, indexOfEdict(pthis->pev)); + return callForward(RG_BuyGunAmmo, original, indexOfEdict(player->pev), indexOfEdict(weapon->pev), bBlinkMoney); } -BOOL CBasePlayerWeapon_CanDeploy(IReGameHook_CBasePlayerWeapon_CanDeploy *chain, CBasePlayerWeapon *pthis) +CBaseEntity *BuyWeaponByWeaponID(IReGameHook_BuyWeaponByWeaponID *chain, CBasePlayer *pPlayer, WeaponIdType weaponID) { - auto original = [chain](int _pthis) + auto original = [chain](int _pPlayer, WeaponIdType _weaponID) { - return chain->callNext(getPrivate(_pthis)); + return indexOfPDataAmx(chain->callNext(getPrivate(_pPlayer), _weaponID)); }; - return callForward(RG_CBasePlayerWeapon_CanDeploy, original, indexOfEdict(pthis->pev)); + return getPrivate(callForward(RG_BuyWeaponByWeaponID, original, indexOfEdict(pPlayer->pev), weaponID)); } -BOOL CBasePlayerWeapon_DefaultDeploy(IReGameHook_CBasePlayerWeapon_DefaultDeploy *chain, CBasePlayerWeapon *pthis, char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal) +BOOL CSGameRules_FShouldSwitchWeapon(IReGameHook_CSGameRules_FShouldSwitchWeapon *chain, CBasePlayer *pPlayer, CBasePlayerItem *pWeapon) { - auto original = [chain](int _pthis, char *_szViewModel, char *_szWeaponModel, int _iAnim, char *_szAnimExt, int _skiplocal) + auto original = [chain](int _pPlayer, int _pWeapon) { - return chain->callNext(getPrivate(_pthis), _szViewModel, _szWeaponModel, _iAnim, _szAnimExt, _skiplocal); + return chain->callNext(getPrivate(_pPlayer), getPrivate(_pWeapon)); }; - return callForward(RG_CBasePlayerWeapon_DefaultDeploy, original, indexOfEdict(pthis->pev), szViewModel, szWeaponModel, iAnim, szAnimExt, skiplocal); + return callForward(RG_CSGameRules_FShouldSwitchWeapon, original, indexOfEdict(pPlayer->pev), indexOfEdict(pWeapon->pev)); } -int CBasePlayerWeapon_DefaultReload(IReGameHook_CBasePlayerWeapon_DefaultReload *chain, CBasePlayerWeapon *pthis, int iClipSize, int iAnim, float fDelay) +BOOL CSGameRules_GetNextBestWeapon(IReGameHook_CSGameRules_GetNextBestWeapon *chain, CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon) { - auto original = [chain](int _pthis, int _iClipSize, int _iAnim, float _fDelay) + auto original = [chain](int _pPlayer, int _pCurrentWeapon) { - return chain->callNext(getPrivate(_pthis), _iClipSize, _iAnim, _fDelay); + return chain->callNext(getPrivate(_pPlayer), getPrivate(_pCurrentWeapon)); }; - return callForward(RG_CBasePlayerWeapon_DefaultReload, original, indexOfEdict(pthis->pev), iClipSize, iAnim, fDelay); + return callForward(RG_CSGameRules_GetNextBestWeapon, original, indexOfEdict(pPlayer->pev), indexOfEdict(pCurrentWeapon->pev)); } -bool CBasePlayerWeapon_DefaultShotgunReload(IReGameHook_CBasePlayerWeapon_DefaultShotgunReload *chain, CBasePlayerWeapon *pthis, int iAnim, int iStartAnim, float fDelay, float fStartDelay, const char *pszReloadSound1, const char *pszReloadSound2) +float CSGameRules_FlPlayerFallDamage(IReGameHook_CSGameRules_FlPlayerFallDamage *chain, CBasePlayer *pPlayer) { - auto original = [chain](int _pthis, int _iAnim, int _iStartAnim, float _fDelay, float _fStartDelay, const char *_pszReloadSound1, const char *_pszReloadSound2) + auto original = [chain](int _pPlayer) { - return chain->callNext(getPrivate(_pthis), _iAnim, _iStartAnim, _fDelay, _fStartDelay, _pszReloadSound1, _pszReloadSound2); + return chain->callNext(getPrivate(_pPlayer)); }; - return callForward(RG_CBasePlayerWeapon_DefaultShotgunReload, original, indexOfEdict(pthis->pev), iAnim, iStartAnim, fDelay, fStartDelay, pszReloadSound1, pszReloadSound2); + return callForward(RG_CSGameRules_FlPlayerFallDamage, original, indexOfEdict(pPlayer->pev)); } -int GetForceCamera(IReGameHook_GetForceCamera *chain, CBasePlayer *pObserver) +BOOL CSGameRules_FPlayerCanTakeDamage(IReGameHook_CSGameRules_FPlayerCanTakeDamage *chain, CBasePlayer *pPlayer, CBaseEntity *pAttacker) { - auto original = [chain](int _pObserver) + auto original = [chain](int _pPlayer, int _pAttacker) { - return chain->callNext(getPrivate(_pObserver)); + return chain->callNext(getPrivate(_pPlayer), getPrivate(_pAttacker)); }; - return callForward(RG_GetForceCamera, original, indexOfEdict(pObserver->pev)); + return callForward(RG_CSGameRules_FPlayerCanTakeDamage, original, indexOfEdict(pPlayer->pev), indexOfEdict(pAttacker->pev)); } -void PlayerBlind(IReGameHook_PlayerBlind *chain, CBasePlayer *pPlayer, entvars_t *pevInflictor, entvars_t *pevAttacker, float fadeTime, float fadeHold, int alpha, Vector& color) +void CSGameRules_PlayerSpawn(IReGameHook_CSGameRules_PlayerSpawn *chain, CBasePlayer *pPlayer) { - Vector colorCopy(color); - - auto original = [chain, &colorCopy](int _pPlayer, int _pevInflictor, int _pevAttacker, float _fadeTime, float _fadeHold, int _alpha, cell _color) + auto original = [chain](int _pPlayer) { - chain->callNext(getPrivate(_pPlayer), PEV(_pevInflictor), PEV(_pevAttacker), _fadeTime, _fadeHold, _alpha, colorCopy); + chain->callNext(getPrivate(_pPlayer)); }; - callVoidForward(RG_PlayerBlind, original, indexOfEdict(pPlayer->pev), indexOfEdict(pevInflictor), indexOfEdict(pevAttacker), fadeTime, fadeHold, alpha, getAmxVector(colorCopy)); + callVoidForward(RG_CSGameRules_PlayerSpawn, original, indexOfEdict(pPlayer->pev)); } -void RadiusFlash_TraceLine(IReGameHook_RadiusFlash_TraceLine *chain, CBasePlayer *pPlayer, entvars_t *pevInflictor, entvars_t *pevAttacker, Vector& vecSrc, Vector& vecSpot, TraceResult *ptr) +BOOL CSGameRules_FPlayerCanRespawn(IReGameHook_CSGameRules_FPlayerCanRespawn *chain, CBasePlayer *pPlayer) { - Vector vecSrcCopy(vecSrc), vecSpotCopy(vecSpot); - - auto original = [chain, &vecSrcCopy, &vecSpotCopy](int _pPlayer, int _pevInflictor, int _pevAttacker, cell _vecSrc, cell _vecSpot, TraceResult *_ptr) + auto original = [chain](int _pPlayer) { - chain->callNext(getPrivate(_pPlayer), PEV(_pevInflictor), PEV(_pevAttacker), vecSrcCopy, vecSpotCopy, _ptr); + return chain->callNext(getPrivate(_pPlayer)); }; - callVoidForward(RG_RadiusFlash_TraceLine, original, indexOfEdict(pPlayer->pev), indexOfEdict(pevInflictor), indexOfEdict(pevAttacker), getAmxVector(vecSrcCopy), getAmxVector(vecSpotCopy), ptr); + return callForward(RG_CSGameRules_FPlayerCanRespawn, original, indexOfEdict(pPlayer->pev)); } -bool RoundEnd(IReGameHook_RoundEnd *chain, int winStatus, ScenarioEventEndRound event, float tmDelay) +edict_t *CSGameRules_GetPlayerSpawnSpot(IReGameHook_CSGameRules_GetPlayerSpawnSpot *chain, CBasePlayer *pPlayer) { - auto original = [chain](int _winStatus, ScenarioEventEndRound _event, float _tmDelay) + auto original = [chain](int _pPlayer) { - return chain->callNext(_winStatus, _event, _tmDelay); + return indexOfEdict(chain->callNext(getPrivate(_pPlayer))); }; - return callForward(RG_RoundEnd, original, winStatus, event, tmDelay); + return edictByIndexAmx(callForward(RG_CSGameRules_GetPlayerSpawnSpot, original, indexOfEdict(pPlayer->pev))); } -void PM_Move_AMXX(Move_t *data, int playerIndex) +void CSGameRules_ClientUserInfoChanged(IReGameHook_CSGameRules_ClientUserInfoChanged *chain, CBasePlayer *pPlayer, char *infobuffer) { - auto original = [data](int _playerIndex) + auto original = [chain](int _pPlayer, char *_infobuffer) { - data->m_chain->callNext(data->m_args.ppmove, data->m_args.server); - }; - - callVoidForward(RG_PM_Move, original, playerIndex); -} - -void PM_Move(IReGameHook_PM_Move *chain, playermove_t *ppmove, int server) -{ - g_pMove = ppmove; - - Move_args_t args(ppmove, server); - Move_t data(chain, args); - PM_Move_AMXX(&data, ppmove->player_index + 1); -} - -void PM_AirMove(IReGameHook_PM_AirMove *chain, int playerIndex) -{ - auto original = [chain](int _playerIndex) - { - chain->callNext(_playerIndex); - }; - - callVoidForward(RG_PM_AirMove, original, playerIndex); -} - -BOOL CSGameRules_FShouldSwitchWeapon(IReGameHook_CSGameRules_FShouldSwitchWeapon *chain, CBasePlayer *pPlayer, CBasePlayerItem *pWeapon) -{ - auto original = [chain](int _pPlayer, int _pWeapon) - { - return chain->callNext(getPrivate(_pPlayer), getPrivate(_pWeapon)); - }; - - return callForward(RG_CSGameRules_FShouldSwitchWeapon, original, indexOfEdict(pPlayer->pev), indexOfEdict(pWeapon->pev)); -} - -BOOL CSGameRules_GetNextBestWeapon(IReGameHook_CSGameRules_GetNextBestWeapon *chain, CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon) -{ - auto original = [chain](int _pPlayer, int _pCurrentWeapon) - { - return chain->callNext(getPrivate(_pPlayer), getPrivate(_pCurrentWeapon)); - }; - - return callForward(RG_CSGameRules_GetNextBestWeapon, original, indexOfEdict(pPlayer->pev), indexOfEdict(pCurrentWeapon->pev)); -} - -float CSGameRules_FlPlayerFallDamage(IReGameHook_CSGameRules_FlPlayerFallDamage *chain, CBasePlayer *pPlayer) -{ - auto original = [chain](int _pPlayer) - { - return chain->callNext(getPrivate(_pPlayer)); - }; - - return callForward(RG_CSGameRules_FlPlayerFallDamage, original, indexOfEdict(pPlayer->pev)); -} - -BOOL CSGameRules_FPlayerCanTakeDamage(IReGameHook_CSGameRules_FPlayerCanTakeDamage *chain, CBasePlayer *pPlayer, CBaseEntity *pAttacker) -{ - auto original = [chain](int _pPlayer, int _pAttacker) - { - return chain->callNext(getPrivate(_pPlayer), getPrivate(_pAttacker)); - }; - - return callForward(RG_CSGameRules_FPlayerCanTakeDamage, original, indexOfEdict(pPlayer->pev), indexOfEdict(pAttacker->pev)); -} - -void CSGameRules_PlayerSpawn(IReGameHook_CSGameRules_PlayerSpawn *chain, CBasePlayer *pPlayer) -{ - auto original = [chain](int _pPlayer) - { - chain->callNext(getPrivate(_pPlayer)); - }; - - callVoidForward(RG_CSGameRules_PlayerSpawn, original, indexOfEdict(pPlayer->pev)); -} - -BOOL CSGameRules_FPlayerCanRespawn(IReGameHook_CSGameRules_FPlayerCanRespawn *chain, CBasePlayer *pPlayer) -{ - auto original = [chain](int _pPlayer) - { - return chain->callNext(getPrivate(_pPlayer)); - }; - - return callForward(RG_CSGameRules_FPlayerCanRespawn, original, indexOfEdict(pPlayer->pev)); -} - -edict_t *CSGameRules_GetPlayerSpawnSpot(IReGameHook_CSGameRules_GetPlayerSpawnSpot *chain, CBasePlayer *pPlayer) -{ - auto original = [chain](int _pPlayer) - { - return indexOfEdict(chain->callNext(getPrivate(_pPlayer))); - }; - - return edictByIndexAmx(callForward(RG_CSGameRules_GetPlayerSpawnSpot, original, indexOfEdict(pPlayer->pev))); -} - -void CSGameRules_ClientUserInfoChanged(IReGameHook_CSGameRules_ClientUserInfoChanged *chain, CBasePlayer *pPlayer, char *infobuffer) -{ - auto original = [chain](int _pPlayer, char *_infobuffer) - { - chain->callNext(getPrivate(_pPlayer), _infobuffer); + chain->callNext(getPrivate(_pPlayer), _infobuffer); }; callVoidForward(RG_CSGameRules_ClientUserInfoChanged, original, indexOfEdict(pPlayer->pev), infobuffer); @@ -983,14 +972,14 @@ void CSGameRules_RemoveGuns(IReGameHook_CSGameRules_RemoveGuns *chain) callVoidForward(RG_CSGameRules_RemoveGuns, original); } -void CSGameRules_GiveC4(IReGameHook_CSGameRules_GiveC4 *chain) +CBasePlayer *CSGameRules_GiveC4(IReGameHook_CSGameRules_GiveC4 *chain) { auto original = [chain]() { - chain->callNext(); + return indexOfPDataAmx(chain->callNext()); }; - callVoidForward(RG_CSGameRules_GiveC4, original); + return getPrivate(callForward(RG_CSGameRules_GiveC4, original)); } void CSGameRules_ChangeLevel(IReGameHook_CSGameRules_ChangeLevel *chain) @@ -1033,6 +1022,48 @@ void CSGameRules_OnRoundFreezeEnd(IReGameHook_CSGameRules_OnRoundFreezeEnd *chai callVoidForward(RG_CSGameRules_OnRoundFreezeEnd, original); } +void CBasePlayer_StartDeathCam(IReGameHook_CBasePlayer_StartDeathCam *chain, CBasePlayer *pthis) +{ + auto original = [chain](int _pthis) + { + return chain->callNext(getPrivate(_pthis)); + }; + + callVoidForward(RG_CBasePlayer_StartDeathCam, original, indexOfEdict(pthis->pev)); +} + +void CBasePlayer_SwitchTeam(IReGameHook_CBasePlayer_SwitchTeam *chain, CBasePlayer *pthis) +{ + auto original = [chain](int _pthis) + { + chain->callNext(getPrivate(_pthis)); + }; + + callVoidForward(RG_CBasePlayer_SwitchTeam, original, indexOfEdict(pthis->pev)); +} + +bool CBasePlayer_CanSwitchTeam(IReGameHook_CBasePlayer_CanSwitchTeam *chain, CBasePlayer *pthis, TeamName teamToSwap) +{ + auto original = [chain](int _pthis, TeamName _teamToSwap) + { + return chain->callNext(getPrivate(_pthis), _teamToSwap); + }; + + return callForward(RG_CBasePlayer_CanSwitchTeam, original, indexOfEdict(pthis->pev), teamToSwap); +} + +CGrenade *CBasePlayer_ThrowGrenade(IReGameHook_CBasePlayer_ThrowGrenade *chain, CBasePlayer *pthis, CBasePlayerWeapon *pWeapon, Vector &vecSrc, Vector &vecThrow, float time, unsigned short usEvent) +{ + Vector vecSrcCopy(vecSrc), vecThrowCopy(vecThrow); + + auto original = [chain, &vecSrcCopy, &vecThrowCopy](int _pthis, int _pWeapon, cell _vecSrc, cell _vecThrow, float _time, unsigned short _usEvent) + { + return indexOfPDataAmx(chain->callNext(getPrivate(_pthis), getPrivate(_pWeapon), vecSrcCopy, vecThrowCopy, _time, _usEvent)); + }; + + return getPrivate(callForward(RG_CBasePlayer_ThrowGrenade, original, indexOfEdict(pthis->pev), indexOfEdict(pWeapon->pev), getAmxVector(vecSrcCopy), getAmxVector(vecThrowCopy), time, usEvent)); +} + bool CSGameRules_CanPlayerHearPlayer(IReGameHook_CSGameRules_CanPlayerHearPlayer *chain, CBasePlayer *pListener, CBasePlayer *pSender) { auto original = [chain](int _pListener, int _pSender) @@ -1113,124 +1144,166 @@ void CGrenade_ExplodeBomb(IReGameHook_CGrenade_ExplodeBomb *chain, CGrenade *pth callVoidForward(RG_CGrenade_ExplodeBomb, original, indexOfEdict(pthis->pev), ptr, bitsDamageType); } -void HandleMenu_ChooseAppearance(IReGameHook_HandleMenu_ChooseAppearance *chain, CBasePlayer *pPlayer, int slot) +CGrenade *ThrowHeGrenade(IReGameHook_ThrowHeGrenade *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity, float time, int iTeam, unsigned short usEvent) { - auto original = [chain](int _pPlayer, int _slot) + Vector vecStartCopy(vecStart), vecVelocityCopy(vecVelocity); + + auto original = [chain, &vecStartCopy, &vecVelocityCopy](int _pevOwner, cell _vecStart, cell _vecVelocity, float _time, int _iTeam, unsigned short _usEvent) { - chain->callNext(getPrivate(_pPlayer), _slot); + return indexOfPDataAmx(chain->callNext(PEV(_pevOwner), vecStartCopy, vecVelocityCopy, _time, _iTeam, _usEvent)); }; - callVoidForward(RG_HandleMenu_ChooseAppearance, original, indexOfEdict(pPlayer->pev), slot); + return getPrivate(callForward(RG_ThrowHeGrenade, original, indexOfEdict(pevOwner), getAmxVector(vecStartCopy), getAmxVector(vecVelocityCopy), time, iTeam, usEvent)); } -BOOL HandleMenu_ChooseTeam(IReGameHook_HandleMenu_ChooseTeam *chain, CBasePlayer *pPlayer, int slot) +CGrenade *ThrowFlashbang(IReGameHook_ThrowFlashbang *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity, float time) { - auto original = [chain](int _pPlayer, int _slot) + Vector vecStartCopy(vecStart), vecVelocityCopy(vecVelocity); + + auto original = [chain, &vecStartCopy, &vecVelocityCopy](int _pevOwner, cell _vecStart, cell _vecVelocity, float _time) { - return chain->callNext(getPrivate(_pPlayer), _slot); + return indexOfPDataAmx(chain->callNext(PEV(_pevOwner), vecStartCopy, vecVelocityCopy, _time)); }; - return callForward(RG_HandleMenu_ChooseTeam, original, indexOfEdict(pPlayer->pev), slot); + return getPrivate(callForward(RG_ThrowFlashbang, original, indexOfEdict(pevOwner), getAmxVector(vecStartCopy), getAmxVector(vecVelocityCopy), time)); } -void ShowMenu(IReGameHook_ShowMenu *chain, CBasePlayer *pPlayer, int bitsValidSlots, int nDisplayTime, BOOL fNeedMore, char *pszText) +CGrenade *ThrowSmokeGrenade(IReGameHook_ThrowSmokeGrenade *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity, float time, unsigned short usEvent) { - auto original = [chain](int _pPlayer, int _bitsValidSlots, int _nDisplayTime, BOOL _fNeedMore, char *_pszText) + Vector vecStartCopy(vecStart), vecVelocityCopy(vecVelocity); + + auto original = [chain, &vecStartCopy, &vecVelocityCopy](int _pevOwner, cell _vecStart, cell _vecVelocity, float _time, unsigned short _usEvent) { - chain->callNext(getPrivate(_pPlayer), _bitsValidSlots, _nDisplayTime, _fNeedMore, _pszText); + return indexOfPDataAmx(chain->callNext(PEV(_pevOwner), vecStartCopy, vecVelocityCopy, _time, _usEvent)); }; - callVoidForward(RG_ShowMenu, original, indexOfEdict(pPlayer->pev), bitsValidSlots, nDisplayTime, fNeedMore, pszText); + return getPrivate(callForward(RG_ThrowSmokeGrenade, original, indexOfEdict(pevOwner), getAmxVector(vecStartCopy), getAmxVector(vecVelocityCopy), time, usEvent)); } -void ShowVGUIMenu(IReGameHook_ShowVGUIMenu *chain, CBasePlayer *pPlayer, int MenuType, int BitMask, char *szOldMenu) +CGrenade *PlantBomb(IReGameHook_PlantBomb *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity) { - auto original = [chain](int _pPlayer, int _MenuType, int _BitMask, char *_szOldMenu) + Vector vecStartCopy(vecStart), vecVelocityCopy(vecVelocity); + + auto original = [chain, &vecStartCopy, &vecVelocityCopy](int _pevOwner, cell _vecStart, cell _vecVelocity) { - chain->callNext(getPrivate(_pPlayer), _MenuType, _BitMask, _szOldMenu); + return indexOfPDataAmx(chain->callNext(PEV(_pevOwner), vecStartCopy, vecVelocityCopy)); }; - callVoidForward(RG_ShowVGUIMenu, original, indexOfEdict(pPlayer->pev), MenuType, BitMask, szOldMenu); + return getPrivate(callForward(RG_PlantBomb, original, indexOfEdictAmx(pevOwner), getAmxVector(vecStartCopy), getAmxVector(vecVelocityCopy))); } -bool BuyGunAmmo(IReGameHook_BuyGunAmmo *chain, CBasePlayer *player, CBasePlayerItem *weapon, bool bBlinkMoney) +void CBasePlayer_RemoveSpawnProtection(IReGameHook_CBasePlayer_RemoveSpawnProtection *chain, CBasePlayer *pthis) { - auto original = [chain](int _player, int _weapon, bool _bBlinkMoney) + auto original = [chain](int _pthis) { - return chain->callNext(getPrivate(_player), getPrivate(_weapon), _bBlinkMoney); + return chain->callNext(getPrivate(_pthis)); }; - return callForward(RG_BuyGunAmmo, original, indexOfEdict(player->pev), indexOfEdict(weapon->pev), bBlinkMoney); + callVoidForward(RG_CBasePlayer_RemoveSpawnProtection, original, indexOfEdict(pthis->pev)); } -CBaseEntity *BuyWeaponByWeaponID(IReGameHook_BuyWeaponByWeaponID *chain, CBasePlayer *pPlayer, WeaponIdType weaponID) +void CBasePlayer_SetSpawnProtection(IReGameHook_CBasePlayer_SetSpawnProtection *chain, CBasePlayer *pthis, float flProtectionTime) { - auto original = [chain](int _pPlayer, WeaponIdType _weaponID) + auto original = [chain](int _pthis, float _flProtectionTime) { - return indexOfPDataAmx(chain->callNext(getPrivate(_pPlayer), _weaponID)); + return chain->callNext(getPrivate(_pthis), _flProtectionTime); }; - return getPrivate(callForward(RG_BuyWeaponByWeaponID, original, indexOfEdict(pPlayer->pev), weaponID)); + callVoidForward(RG_CBasePlayer_SetSpawnProtection, original, indexOfEdict(pthis->pev), flProtectionTime); } -CGrenade *ThrowHeGrenade(IReGameHook_ThrowHeGrenade *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity, float time, int iTeam, unsigned short usEvent) +bool IsPenetrableEntity(IReGameHook_IsPenetrableEntity *chain, Vector &vecSrc, Vector &vecEnd, entvars_t *pevAttacker, edict_t *pHit) { - Vector vecStartCopy(vecStart), vecVelocityCopy(vecVelocity); + Vector vecSrcCopy(vecSrc), vecEndCopy(vecEnd); - auto original = [chain, &vecStartCopy, &vecVelocityCopy](int _pevOwner, cell _vecStart, cell _vecVelocity, float _time, int _iTeam, unsigned short _usEvent) + auto original = [chain, &vecSrcCopy, &vecEndCopy](cell _vecSrc, cell _vecEnd, int _pevAttacker, int _pHit) { - return indexOfPDataAmx(chain->callNext(PEV(_pevOwner), vecStartCopy, vecVelocityCopy, _time, _iTeam, _usEvent)); + return chain->callNext(vecSrcCopy, vecEndCopy, PEV(_pevAttacker), edictByIndexAmx(_pHit)); }; - return getPrivate(callForward(RG_ThrowHeGrenade, original, indexOfEdict(pevOwner), getAmxVector(vecStartCopy), getAmxVector(vecVelocityCopy), time, iTeam, usEvent)); + return callForward(RG_IsPenetrableEntity, original, getAmxVector(vecSrcCopy), getAmxVector(vecEndCopy), indexOfEdict(pevAttacker), indexOfEdict(pHit)); } -CGrenade *ThrowFlashbang(IReGameHook_ThrowFlashbang *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity, float time) +bool CBasePlayer_HintMessageEx(IReGameHook_CBasePlayer_HintMessageEx *chain, CBasePlayer *pthis, const char *pMessage, float duration, bool bDisplayIfPlayerDead, bool bOverride) { - Vector vecStartCopy(vecStart), vecVelocityCopy(vecVelocity); + auto original = [chain](int _pthis, const char *_pMessage, float _duration, bool _bDisplayIfPlayerDead, bool _bOverride) + { + return chain->callNext(getPrivate(_pthis), _pMessage, _duration, _bDisplayIfPlayerDead, _bOverride); + }; - auto original = [chain, &vecStartCopy, &vecVelocityCopy](int _pevOwner, cell _vecStart, cell _vecVelocity, float _time) + return callForward(RG_CBasePlayer_HintMessageEx, original, indexOfEdict(pthis->pev), pMessage, duration, bDisplayIfPlayerDead, bOverride); +} + +void CBasePlayer_UseEmpty(IReGameHook_CBasePlayer_UseEmpty *chain, CBasePlayer *pthis) +{ + auto original = [chain](int _pthis) { - return indexOfPDataAmx(chain->callNext(PEV(_pevOwner), vecStartCopy, vecVelocityCopy, _time)); + return chain->callNext(getPrivate(_pthis)); }; - return getPrivate(callForward(RG_ThrowFlashbang, original, indexOfEdict(pevOwner), getAmxVector(vecStartCopy), getAmxVector(vecVelocityCopy), time)); + callVoidForward(RG_CBasePlayer_UseEmpty, original, indexOfEdict(pthis->pev)); } -CGrenade *ThrowSmokeGrenade(IReGameHook_ThrowSmokeGrenade *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity, float time, unsigned short usEvent) +BOOL CBasePlayerWeapon_CanDeploy(IReGameHook_CBasePlayerWeapon_CanDeploy *chain, CBasePlayerWeapon *pthis) { - Vector vecStartCopy(vecStart), vecVelocityCopy(vecVelocity); + auto original = [chain](int _pthis) + { + return chain->callNext(getPrivate(_pthis)); + }; - auto original = [chain, &vecStartCopy, &vecVelocityCopy](int _pevOwner, cell _vecStart, cell _vecVelocity, float _time, unsigned short _usEvent) + return callForward(RG_CBasePlayerWeapon_CanDeploy, original, indexOfEdict(pthis->pev)); +} + +BOOL CBasePlayerWeapon_DefaultDeploy(IReGameHook_CBasePlayerWeapon_DefaultDeploy *chain, CBasePlayerWeapon *pthis, char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal) +{ + auto original = [chain](int _pthis, char *_szViewModel, char *_szWeaponModel, int _iAnim, char *_szAnimExt, int _skiplocal) { - return indexOfPDataAmx(chain->callNext(PEV(_pevOwner), vecStartCopy, vecVelocityCopy, _time, _usEvent)); + return chain->callNext(getPrivate(_pthis), _szViewModel, _szWeaponModel, _iAnim, _szAnimExt, _skiplocal); }; - return getPrivate(callForward(RG_ThrowSmokeGrenade, original, indexOfEdict(pevOwner), getAmxVector(vecStartCopy), getAmxVector(vecVelocityCopy), time, usEvent)); + return callForward(RG_CBasePlayerWeapon_DefaultDeploy, original, indexOfEdict(pthis->pev), szViewModel, szWeaponModel, iAnim, szAnimExt, skiplocal); } -CGrenade *PlantBomb(IReGameHook_PlantBomb *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity) +int CBasePlayerWeapon_DefaultReload(IReGameHook_CBasePlayerWeapon_DefaultReload *chain, CBasePlayerWeapon *pthis, int iClipSize, int iAnim, float fDelay) { - Vector vecStartCopy(vecStart), vecVelocityCopy(vecVelocity); + auto original = [chain](int _pthis, int _iClipSize, int _iAnim, float _fDelay) + { + return chain->callNext(getPrivate(_pthis), _iClipSize, _iAnim, _fDelay); + }; - auto original = [chain, &vecStartCopy, &vecVelocityCopy](int _pevOwner, cell _vecStart, cell _vecVelocity) + return callForward(RG_CBasePlayerWeapon_DefaultReload, original, indexOfEdict(pthis->pev), iClipSize, iAnim, fDelay); +} + +bool CBasePlayerWeapon_DefaultShotgunReload(IReGameHook_CBasePlayerWeapon_DefaultShotgunReload *chain, CBasePlayerWeapon *pthis, int iAnim, int iStartAnim, float fDelay, float fStartDelay, const char *pszReloadSound1, const char *pszReloadSound2) +{ + auto original = [chain](int _pthis, int _iAnim, int _iStartAnim, float _fDelay, float _fStartDelay, const char *_pszReloadSound1, const char *_pszReloadSound2) { - return indexOfPDataAmx(chain->callNext(PEV(_pevOwner), vecStartCopy, vecVelocityCopy)); + return chain->callNext(getPrivate(_pthis), _iAnim, _iStartAnim, _fDelay, _fStartDelay, _pszReloadSound1, _pszReloadSound2); }; - return getPrivate(callForward(RG_PlantBomb, original, indexOfEdictAmx(pevOwner), getAmxVector(vecStartCopy), getAmxVector(vecVelocityCopy))); + return callForward(RG_CBasePlayerWeapon_DefaultShotgunReload, original, indexOfEdict(pthis->pev), iAnim, iStartAnim, fDelay, fStartDelay, pszReloadSound1, pszReloadSound2); } -bool IsPenetrableEntity(IReGameHook_IsPenetrableEntity *chain, Vector &vecSrc, Vector &vecEnd, entvars_t *pevAttacker, edict_t *pHit) +void CBasePlayer_DropIdlePlayer(IReGameHook_CBasePlayer_DropIdlePlayer *chain, CBasePlayer *pthis, const char *reason) { - Vector vecSrcCopy(vecSrc), vecEndCopy(vecEnd); + auto original = [chain](int _pthis, const char *_reason) + { + return chain->callNext(getPrivate(_pthis), _reason); + }; - auto original = [chain, &vecSrcCopy, &vecEndCopy](cell _vecSrc, cell _vecEnd, int _pevAttacker, int _pHit) + callVoidForward(RG_CBasePlayer_DropIdlePlayer, original, indexOfEdict(pthis->pev), reason); +} + +CWeaponBox *CreateWeaponBox(IReGameHook_CreateWeaponBox *chain, CBasePlayerItem *pItem, CBasePlayer *pPlayerOwner, const char *modelName, Vector &origin, Vector &angles, Vector &velocity, float lifeTime, bool packAmmo) +{ + Vector vecOriginCopy(origin), vecAnglesCopy(angles), vecVelocityCopy(velocity); + + auto original = [chain, &vecOriginCopy, &vecAnglesCopy, &vecVelocityCopy](int _pItem, int _pPlayerOwner, const char *_modelName, cell _origin, cell _angles, cell _velocity, float _lifeTime, bool _packAmmo) { - return chain->callNext(vecSrcCopy, vecEndCopy, PEV(_pevAttacker), edictByIndexAmx(_pHit)); + return indexOfPDataAmx(chain->callNext(getPrivate(_pItem), getPrivate(_pPlayerOwner), _modelName, vecOriginCopy, vecAnglesCopy, vecVelocityCopy, _lifeTime, _packAmmo)); }; - return callForward(RG_IsPenetrableEntity, original, getAmxVector(vecSrcCopy), getAmxVector(vecEndCopy), indexOfEdict(pevAttacker), indexOfEdict(pHit)); + return getPrivate(callForward(RG_CreateWeaponBox, original, indexOfEdictAmx(pItem->pev), indexOfEdictAmx(pPlayerOwner->pev), modelName, getAmxVector(vecOriginCopy), getAmxVector(vecAnglesCopy), getAmxVector(vecVelocityCopy), lifeTime, packAmmo)); } CGib *SpawnHeadGib(IReGameHook_SpawnHeadGib *chain, entvars_t *pevVictim) @@ -1335,6 +1408,312 @@ void CBasePlayer_Observer_SetMode(IReGameHook_CBasePlayer_Observer_SetMode *chai callVoidForward(RG_CBasePlayer_Observer_SetMode, original, indexOfEdict(pthis->pev), iMode); } +void CBasePlayer_Observer_FindNextPlayer(IReGameHook_CBasePlayer_Observer_FindNextPlayer *chain, CBasePlayer *pthis, bool bReverse, const char *name) +{ + auto original = [chain](int _pthis, bool _bReverse, const char *_name) + { + chain->callNext(getPrivate(_pthis), _bReverse, _name); + }; + + callVoidForward(RG_CBasePlayer_Observer_FindNextPlayer, original, indexOfEdict(pthis->pev), bReverse, name); +} + +void CBasePlayer_Pain(IReGameHook_CBasePlayer_Pain *chain, CBasePlayer *pthis, int iLastHitGroup, bool bHasArmour) +{ + auto original = [chain](int _pthis, int _iLastHitGroup, bool _bHasArmour) + { + return chain->callNext(getPrivate(_pthis), _iLastHitGroup, _bHasArmour); + }; + + callVoidForward(RG_CBasePlayer_Pain, original, indexOfEdict(pthis->pev), iLastHitGroup, bHasArmour); +} + +void CBasePlayer_DeathSound(IReGameHook_CBasePlayer_DeathSound *chain, CBasePlayer *pthis) +{ + auto original = [chain](int _pthis) + { + return chain->callNext(getPrivate(_pthis)); + }; + + callVoidForward(RG_CBasePlayer_DeathSound, original, indexOfEdict(pthis->pev)); +} + +void CBasePlayer_JoiningThink(IReGameHook_CBasePlayer_JoiningThink *chain, CBasePlayer *pthis) +{ + auto original = [chain](int _pthis) + { + return chain->callNext(getPrivate(_pthis)); + }; + + callVoidForward(RG_CBasePlayer_JoiningThink, original, indexOfEdict(pthis->pev)); +} + +void PM_LadderMove_AMXX(IReGameHook_PM_LadderMove *chain, physent_t *pLadder, int playerIndex) +{ + auto original = [chain](physent_t *_pLadder, int _playerIndex) + { + chain->callNext(_pLadder); + }; + + callVoidForward(RG_PM_LadderMove, original, pLadder, playerIndex); +} + +void PM_LadderMove(IReGameHook_PM_LadderMove *chain, physent_t *pLadder) +{ + PM_LadderMove_AMXX(chain, pLadder, pLadder->player + 1); +} + +void PM_WaterJump_AMXX(IReGameHook_PM_WaterJump *chain, int playerIndex) +{ + auto original = [chain](int _playerIndex) + { + chain->callNext(); + }; + + callVoidForward(RG_PM_WaterJump, original, playerIndex); +} + +void PM_WaterJump(IReGameHook_PM_WaterJump *chain) +{ + PM_WaterJump_AMXX(chain, g_pMove->player_index + 1); +} + +void PM_CheckWaterJump_AMXX(IReGameHook_PM_CheckWaterJump *chain, int playerIndex) +{ + auto original = [chain](int _playerIndex) + { + chain->callNext(); + }; + + callVoidForward(RG_PM_CheckWaterJump, original, playerIndex); +} + +void PM_CheckWaterJump(IReGameHook_PM_CheckWaterJump *chain) +{ + PM_CheckWaterJump_AMXX(chain, g_pMove->player_index + 1); +} + +void PM_Jump_AMXX(IReGameHook_PM_Jump *chain, int playerIndex) +{ + auto original = [chain](int _playerIndex) + { + chain->callNext(); + }; + + callVoidForward(RG_PM_Jump, original, playerIndex); +} + +void PM_Jump(IReGameHook_PM_Jump *chain) +{ + PM_Jump_AMXX(chain, g_pMove->player_index + 1); +} + +void PM_Duck_AMXX(IReGameHook_PM_Duck *chain, int playerIndex) +{ + auto original = [chain](int _playerIndex) + { + chain->callNext(); + }; + + callVoidForward(RG_PM_Duck, original, playerIndex); +} + +void PM_Duck(IReGameHook_PM_Duck *chain) +{ + PM_Duck_AMXX(chain, g_pMove->player_index + 1); +} + +void PM_UnDuck_AMXX(IReGameHook_PM_UnDuck *chain, int playerIndex) +{ + auto original = [chain](int _playerIndex) + { + chain->callNext(); + }; + + callVoidForward(RG_PM_UnDuck, original, playerIndex); +} + +void PM_UnDuck(IReGameHook_PM_UnDuck *chain) +{ + PM_UnDuck_AMXX(chain, g_pMove->player_index + 1); +} + +void PM_PlayStepSound_AMXX(IReGameHook_PM_PlayStepSound *chain, int step, float fvol, int playerIndex) +{ + auto original = [chain](int _step, float _fvol, int _playerIndex) + { + chain->callNext(_step, _fvol); + }; + + callVoidForward(RG_PM_PlayStepSound, original, step, fvol, playerIndex); +} + +void PM_PlayStepSound(IReGameHook_PM_PlayStepSound *chain, int step, float fvol) +{ + PM_PlayStepSound_AMXX(chain, step, fvol, g_pMove->player_index + 1); +} + +void PM_AirAccelerate_AMXX(IReGameHook_PM_AirAccelerate *chain, vec_t *wishdir, float wishspeed, float accel, int playerIndex) +{ + Vector wishdirCopy(wishdir); + + auto original = [chain, &wishdirCopy](cell _wishdir, float _wishspeed, float _accel, int _playerIndex) + { + chain->callNext(wishdirCopy, _wishspeed, _accel); + }; + + callVoidForward(RG_PM_AirAccelerate, original, getAmxVector(wishdirCopy), wishspeed, accel, playerIndex); +} + +void PM_AirAccelerate(IReGameHook_PM_AirAccelerate *chain, vec_t *wishdir, float wishspeed, float accel) +{ + PM_AirAccelerate_AMXX(chain, wishdir, wishspeed, accel, g_pMove->player_index + 1); +} + +void ClearMultiDamage(IReGameHook_ClearMultiDamage *chain) +{ + auto original = [chain]() + { + chain->callNext(); + }; + + callVoidForward(RG_ClearMultiDamage, original); +} + +void AddMultiDamage(IReGameHook_AddMultiDamage *chain, entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType) +{ + auto original = [chain](int _pevInflictor, int _pEntity, float _flDamage, int _bitsDamageType) + { + chain->callNext(PEV(_pevInflictor), getPrivate(_pEntity), _flDamage, _bitsDamageType); + }; + + callVoidForward(RG_AddMultiDamage, original, indexOfEdict(pevInflictor), indexOfEdict(pEntity->pev), flDamage, bitsDamageType); +} + +void ApplyMultiDamage(IReGameHook_ApplyMultiDamage *chain, entvars_t *pevInflictor, entvars_t *pevAttacker) +{ + auto original = [chain](int _pevInflictor, int _pevAttacker) + { + chain->callNext(PEV(_pevInflictor), PEV(_pevAttacker)); + }; + + callVoidForward(RG_ApplyMultiDamage, original, indexOfEdict(pevInflictor), indexOfEdict(pevAttacker)); +} + +void BuyItem(IReGameHook_BuyItem *chain, CBasePlayer *pPlayer, int iSlot) +{ + auto original = [chain](int _pPlayer, int _iSlot) + { + chain->callNext(getPrivate(_pPlayer), _iSlot); + }; + + callVoidForward(RG_AddMultiDamage, original, indexOfEdict(pPlayer->pev), iSlot); +} + +void CSGameRules_Think(IReGameHook_CSGameRules_Think *chain) +{ + auto original = [chain]() + { + chain->callNext(); + }; + + callVoidForward(RG_CSGameRules_Think, original); +} + +BOOL CSGameRules_TeamFull(IReGameHook_CSGameRules_TeamFull *chain, int team_id) +{ + auto original = [chain](int _team_id) + { + return chain->callNext(_team_id); + }; + + return callForward(RG_CSGameRules_TeamFull, original, team_id); +} + +BOOL CSGameRules_TeamStacked(IReGameHook_CSGameRules_TeamStacked *chain, int newTeam_id, int curTeam_id) +{ + auto original = [chain](int _newTeam_id, int _curTeam_id) + { + return chain->callNext(_newTeam_id, _curTeam_id); + }; + + return callForward(RG_CSGameRules_TeamStacked, original, newTeam_id, curTeam_id); +} + +void CSGameRules_PlayerGotWeapon(IReGameHook_CSGameRules_PlayerGotWeapon *chain, CBasePlayer *pPlayer, CBasePlayerItem *pWeapon) +{ + auto original = [chain](int _pPlayer, int _pWeapon) + { + chain->callNext(getPrivate(_pPlayer), getPrivate(_pWeapon)); + }; + + callVoidForward(RG_CSGameRules_PlayerGotWeapon, original, indexOfEdict(pPlayer->pev), indexOfEdict(pWeapon->pev)); +} + +void CBotManager_OnEvent(IReGameHook_CBotManager_OnEvent *chain, GameEventType event, CBaseEntity* pEntity, CBaseEntity* pOther) +{ + auto original = [chain](GameEventType _event, int _pEntity, int _pOther) + { + chain->callNext(_event, getPrivate(_pEntity), getPrivate(_pOther)); + }; + + callVoidForward(RG_CBotManager_OnEvent, original, event, indexOfEdict(pEntity->pev), indexOfEdict(pOther->pev)); +} + +void CBasePlayer_CheckTimeBasedDamage(IReGameHook_CBasePlayer_CheckTimeBasedDamage *chain, CBasePlayer *pthis) +{ + auto original = [chain](int _pthis) + { + chain->callNext(getPrivate(_pthis)); + }; + + callVoidForward(RG_CBasePlayer_CheckTimeBasedDamage, original, indexOfEdict(pthis->pev)); +} + +edict_t *CBasePlayer_EntSelectSpawnPoint(IReGameHook_CBasePlayer_EntSelectSpawnPoint *chain, CBasePlayer *pthis) +{ + auto original = [chain](int _pthis) + { + return indexOfEdict(chain->callNext(getPrivate(_pthis))); + }; + + return edictByIndexAmx(callForward(RG_CBasePlayer_EntSelectSpawnPoint, original, indexOfEdict(pthis->pev))); +} + +void CBasePlayerWeapon_ItemPostFrame(IReGameHook_CBasePlayerWeapon_ItemPostFrame *chain, CBasePlayerWeapon *pthis) +{ + auto original = [chain](int _pthis) + { + chain->callNext(getPrivate(_pthis)); + }; + + callVoidForward(RG_CBasePlayerWeapon_ItemPostFrame, original, indexOfEdict(pthis->pev)); +} + +void CBasePlayerWeapon_KickBack(IReGameHook_CBasePlayerWeapon_KickBack *chain, CBasePlayerWeapon *pthis, float up_base, float lateral_base, float up_modifier, float lateral_modifier, float up_max, float lateral_max, int direction_change) +{ + auto original = [chain](int _pthis, float _up_base, float _lateral_base, float _up_modifier, float _lateral_modifier, float _up_max, float _lateral_max, int _direction_change) + { + chain->callNext(getPrivate(_pthis), _up_base, _lateral_base, _up_modifier, _lateral_modifier, _up_max, _lateral_max, _direction_change); + }; + + callVoidForward(RG_CBasePlayerWeapon_KickBack, original, indexOfEdict(pthis->pev), up_base, lateral_base, up_modifier, lateral_modifier, up_max, lateral_max, direction_change); +} + +void CBasePlayerWeapon_SendWeaponAnim(IReGameHook_CBasePlayerWeapon_SendWeaponAnim *chain, CBasePlayerWeapon *pthis, int iAnim, int skiplocal) +{ + auto original = [chain](int _pthis, int _iAnim, int _skiplocal) + { + chain->callNext(getPrivate(_pthis), _iAnim, _skiplocal); + }; + + callVoidForward(RG_CBasePlayerWeapon_SendWeaponAnim, original, indexOfEdict(pthis->pev), iAnim, skiplocal); +} + + +/* +* VTC functions +*/ int g_iClientStartSpeak, g_iClientStopSpeak; void OnClientStartSpeak(size_t clientIndex) @@ -1401,3 +1780,4 @@ void CmdExec(IRecheckerHook_CmdExec *chain, IGameClient *cl, IResourceBuffer *re CmdExec_t data(chain, res); CmdExec_AMXX(&data, cl, res->GetFileName(), cmdExec, responseHash); } + diff --git a/reapi/src/hook_callback.h b/reapi/src/hook_callback.h index 9925b729..af39e6ad 100644 --- a/reapi/src/hook_callback.h +++ b/reapi/src/hook_callback.h @@ -21,7 +21,8 @@ enum AType : uint8 ATYPE_EDICT, ATYPE_EVARS, ATYPE_BOOL, - ATYPE_VECTOR + ATYPE_VECTOR, + ATYPE_TRACE }; struct retval_t @@ -53,6 +54,7 @@ inline AType getApiType(entvars_t *) { return ATYPE_EVARS; } inline AType getApiType(bool) { return ATYPE_BOOL; } inline AType getApiType(Vector) { return ATYPE_VECTOR; } inline AType getApiType(ENTITYINIT) { return ATYPE_INTEGER; } +inline AType getApiType(TraceResult*) { return ATYPE_TRACE; } template inline AType getApiType(T *) { return ATYPE_INTEGER; } @@ -327,13 +329,17 @@ struct hookdata_t A m_args; }; -// rehlds functions +/* +* ReHLDS functions +*/ void SV_StartSound(IRehldsHook_SV_StartSound *chain, int recipients, edict_t *entity, int channel, const char *sample, int volume, float attenuation, int fFlags, int pitch); void SV_DropClient(IRehldsHook_SV_DropClient *chain, IGameClient *cl, bool crash, const char *fmt); void SV_ActivateServer(IRehldsHook_SV_ActivateServer *chain, int runPhysics); void Cvar_DirectSet(IRehldsHook_Cvar_DirectSet *chain, cvar_t *var, const char *value); void ClientConnected(IRehldsHook_ClientConnected* chain, IGameClient* cl); void SV_ConnectClient(IRehldsHook_SV_ConnectClient* chain); +BOOL SV_CheckUserInfo(IRehldsHook_SV_CheckUserInfo *chain, netadr_t *adr, char *userinfo, qboolean bIsReconnecting, int iReconnectSlot, char *name); +BOOL SV_CheckUserInfo_AMXX(IRehldsHook_SV_CheckUserInfo *chain, netadr_t *adr, size_t userinfo, qboolean bIsReconnecting, int iReconnectSlot, char *name); struct SV_WriteFullClientUpdate_args_t { @@ -347,6 +353,7 @@ using SV_WriteFullClientUpdate_t = hookdata_t; -void PM_Move_AMXX(Move_t *data, int playerIndex); -void PM_Move(IReGameHook_PM_Move *chain, playermove_t *ppmove, int server); - -void PM_AirMove(IReGameHook_PM_AirMove *chain, int playerIndex); -void HandleMenu_ChooseAppearance(IReGameHook_HandleMenu_ChooseAppearance *chain, CBasePlayer *pPlayer, int slot); -BOOL HandleMenu_ChooseTeam(IReGameHook_HandleMenu_ChooseTeam *chain, CBasePlayer *pPlayer, int slot); -void ShowMenu(IReGameHook_ShowMenu *chain, CBasePlayer *pPlayer, int bitsValidSlots, int nDisplayTime, BOOL fNeedMore, char *pszText); -void ShowVGUIMenu(IReGameHook_ShowVGUIMenu *chain, CBasePlayer *pPlayer, int MenuType, int BitMask, char *szOldMenu); -bool BuyGunAmmo(IReGameHook_BuyGunAmmo *chain, CBasePlayer *player, CBasePlayerItem *weapon, bool bBlinkMoney); -CBaseEntity *BuyWeaponByWeaponID(IReGameHook_BuyWeaponByWeaponID *chain, CBasePlayer *pPlayer, WeaponIdType weaponID); -CGrenade *ThrowHeGrenade(IReGameHook_ThrowHeGrenade *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity, float time, int iTeam, unsigned short usEvent); -CGrenade *ThrowFlashbang(IReGameHook_ThrowFlashbang *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity, float time); -CGrenade *ThrowSmokeGrenade(IReGameHook_ThrowSmokeGrenade *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity, float time, unsigned short usEvent); -CGrenade *PlantBomb(IReGameHook_PlantBomb *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity); -bool IsPenetrableEntity(IReGameHook_IsPenetrableEntity *chain, Vector &vecSrc, Vector &vecEnd, entvars_t *pevAttacker, edict_t *pHit); -CGib *SpawnHeadGib(IReGameHook_SpawnHeadGib *chain, entvars_t *pevVictim); -void SpawnRandomGibs(IReGameHook_SpawnRandomGibs *chain, entvars_t *pevVictim, int cGibs, int human); +using EventPrecache_t = hookdata_t; +unsigned short EV_Precache_AMXX(EventPrecache_t *data, const char *psz); +unsigned short EV_Precache(IRehldsHook_EV_Precache *chain, int type, const char *psz); +void SV_AddResource(IRehldsHook_SV_AddResource *chain, resourcetype_t type, const char *name, int size, unsigned char flags, int index); +edict_t *ED_Alloc(IRehldsHook_ED_Alloc* chain); +void ED_Free(IRehldsHook_ED_Free* chain, edict_t *entity); +void SV_ClientPrintf(IRehldsHook_SV_ClientPrintf* chain, const char *string); +bool SV_AllowPhysent(IRehldsHook_SV_AllowPhysent* chain, edict_t* check, edict_t* sv_player); -// regamedll functions - player +/* +* ReGameDLL functions +*/ void CBasePlayer_Spawn(IReGameHook_CBasePlayer_Spawn *chain, CBasePlayer *pthis); void CBasePlayer_Precache(IReGameHook_CBasePlayer_Precache *chain, CBasePlayer *pthis); int CBasePlayer_ObjectCaps(IReGameHook_CBasePlayer_ObjectCaps *chain, CBasePlayer *pthis); @@ -422,7 +413,6 @@ void CBasePlayer_RoundRespawn(IReGameHook_CBasePlayer_RoundRespawn *chain, CBase void CBasePlayer_Blind(IReGameHook_CBasePlayer_Blind *chain, CBasePlayer *pthis, float flUntilTime, float flHoldTime, float flFadeTime, int iAlpha); CBasePlayer *CBasePlayer_Observer_IsValidTarget(IReGameHook_CBasePlayer_Observer_IsValidTarget *chain, CBasePlayer *pthis, int iPlayerIndex, bool bSameTeam); -void CBasePlayer_Observer_FindNextPlayer(IReGameHook_CBasePlayer_Observer_FindNextPlayer *chain, CBasePlayer *pthis, bool bReverse, const char *name); void CBasePlayer_SetAnimation(IReGameHook_CBasePlayer_SetAnimation *chain, CBasePlayer *pthis, PLAYER_ANIM playerAnim); void CBasePlayer_GiveDefaultItems(IReGameHook_CBasePlayer_GiveDefaultItems *chain, CBasePlayer *pthis); CBaseEntity *CBasePlayer_GiveNamedItem(IReGameHook_CBasePlayer_GiveNamedItem *chain, CBasePlayer *pthis, const char *pszName); @@ -440,26 +430,33 @@ void CBasePlayer_MakeVIP(IReGameHook_CBasePlayer_MakeVIP *chain, CBasePlayer *pt bool CBasePlayer_MakeBomber(IReGameHook_CBasePlayer_MakeBomber *chain, CBasePlayer *pthis); void CBasePlayer_StartObserver(IReGameHook_CBasePlayer_StartObserver *chain, CBasePlayer *pthis, Vector &vecPosition, Vector &vecViewAngle); bool CBasePlayer_GetIntoGame(IReGameHook_CBasePlayer_GetIntoGame *chain, CBasePlayer *pthis); -void CBasePlayer_StartDeathCam(IReGameHook_CBasePlayer_StartDeathCam *chain, CBasePlayer *pthis); -void CBasePlayer_SwitchTeam(IReGameHook_CBasePlayer_SwitchTeam *chain, CBasePlayer *pthis); -bool CBasePlayer_CanSwitchTeam(IReGameHook_CBasePlayer_CanSwitchTeam *chain, CBasePlayer *pthis, TeamName teamToSwap); -CGrenade *CBasePlayer_ThrowGrenade(IReGameHook_CBasePlayer_ThrowGrenade *chain, CBasePlayer *pthis, CBasePlayerWeapon *pWeapon, Vector &vecSrc, Vector &vecThrow, float time, unsigned short usEvent); -void CBasePlayer_SetSpawnProtection(IReGameHook_CBasePlayer_SetSpawnProtection *chain, CBasePlayer *pthis, float flProtectionTime); -void CBasePlayer_RemoveSpawnProtection(IReGameHook_CBasePlayer_RemoveSpawnProtection *chain, CBasePlayer *pthis); -bool CBasePlayer_HintMessageEx(IReGameHook_CBasePlayer_HintMessageEx *chain, CBasePlayer *pthis, const char *pMessage, float duration, bool bDisplayIfPlayerDead, bool bOverride); -void CBasePlayer_UseEmpty(IReGameHook_CBasePlayer_UseEmpty *chain, CBasePlayer *pthis); -void CBasePlayer_DropIdlePlayer(IReGameHook_CBasePlayer_DropIdlePlayer *chain, CBasePlayer *pthis, const char *reason); -void CBasePlayer_Observer_SetMode(IReGameHook_CBasePlayer_Observer_SetMode *chain, CBasePlayer *pthis, int iMode); -void CBasePlayer_Pain(IReGameHook_CBasePlayer_Pain *chain, CBasePlayer *pthis, int iLastHitGroup, bool bHasArmour); -void CBasePlayer_DeathSound(IReGameHook_CBasePlayer_DeathSound *chain, CBasePlayer *pthis); -void CBasePlayer_JoiningThink(IReGameHook_CBasePlayer_JoiningThink *chain, CBasePlayer *pthis); void CBaseAnimating_ResetSequenceInfo(IReGameHook_CBaseAnimating_ResetSequenceInfo *chain, CBaseAnimating *pthis); -BOOL CBasePlayerWeapon_CanDeploy(IReGameHook_CBasePlayerWeapon_CanDeploy *chain, CBasePlayerWeapon *pthis); -BOOL CBasePlayerWeapon_DefaultDeploy(IReGameHook_CBasePlayerWeapon_DefaultDeploy *chain, CBasePlayerWeapon *pthis, char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal); -int CBasePlayerWeapon_DefaultReload(IReGameHook_CBasePlayerWeapon_DefaultReload *chain, CBasePlayerWeapon *pthis, int iClipSize, int iAnim, float fDelay); -bool CBasePlayerWeapon_DefaultShotgunReload(IReGameHook_CBasePlayerWeapon_DefaultShotgunReload *chain, CBasePlayerWeapon *pthis, int iAnim, int iStartAnim, float fDelay, float fStartDelay, const char *pszReloadSound1, const char *pszReloadSound2); +int GetForceCamera(IReGameHook_GetForceCamera *chain, CBasePlayer *pObserver); +void PlayerBlind(IReGameHook_PlayerBlind *chain, CBasePlayer *pPlayer, entvars_t *pevInflictor, entvars_t *pevAttacker, float fadeTime, float fadeHold, int alpha, Vector& color); +void RadiusFlash_TraceLine(IReGameHook_RadiusFlash_TraceLine *chain, CBasePlayer *pPlayer, entvars_t *pevInflictor, entvars_t *pevAttacker, Vector& vecSrc, Vector& vecSpot, TraceResult *ptr); +bool RoundEnd(IReGameHook_RoundEnd *chain, int winStatus, ScenarioEventEndRound event, float tmDelay); +// TODO: pending InstallGameRules +// TODO: pending PM_Init +struct Move_args_t +{ + Move_args_t(playermove_t *_ppmove, int _server) : ppmove(_ppmove), server(_server) {} + + playermove_t *ppmove; + int server; +}; +using Move_t = hookdata_t; +void PM_Move_AMXX(Move_t *data, int playerIndex); +void PM_Move(IReGameHook_PM_Move *chain, playermove_t *ppmove, int server); +void PM_AirMove(IReGameHook_PM_AirMove *chain, int playerIndex); +void HandleMenu_ChooseAppearance(IReGameHook_HandleMenu_ChooseAppearance *chain, CBasePlayer *pPlayer, int slot); +BOOL HandleMenu_ChooseTeam(IReGameHook_HandleMenu_ChooseTeam *chain, CBasePlayer *pPlayer, int slot); +void ShowMenu(IReGameHook_ShowMenu *chain, CBasePlayer *pPlayer, int bitsValidSlots, int nDisplayTime, BOOL fNeedMore, char *pszText); +void ShowVGUIMenu(IReGameHook_ShowVGUIMenu *chain, CBasePlayer *pPlayer, int MenuType, int BitMask, char *szOldMenu); +bool BuyGunAmmo(IReGameHook_BuyGunAmmo *chain, CBasePlayer *player, CBasePlayerItem *weapon, bool bBlinkMoney); +CBaseEntity *BuyWeaponByWeaponID(IReGameHook_BuyWeaponByWeaponID *chain, CBasePlayer *pPlayer, WeaponIdType weaponID); +// TODO: pending InternalCommand BOOL CSGameRules_FShouldSwitchWeapon(IReGameHook_CSGameRules_FShouldSwitchWeapon *chain, CBasePlayer *pPlayer, CBasePlayerItem *pWeapon); BOOL CSGameRules_GetNextBestWeapon(IReGameHook_CSGameRules_GetNextBestWeapon *chain, CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon); @@ -479,38 +476,102 @@ void CSGameRules_CleanUpMap(IReGameHook_CSGameRules_CleanUpMap *chain); void CSGameRules_RestartRound(IReGameHook_CSGameRules_RestartRound *chain); void CSGameRules_CheckWinConditions(IReGameHook_CSGameRules_CheckWinConditions *chain); void CSGameRules_RemoveGuns(IReGameHook_CSGameRules_RemoveGuns *chain); -void CSGameRules_GiveC4(IReGameHook_CSGameRules_GiveC4 *chain); +CBasePlayer *CSGameRules_GiveC4(IReGameHook_CSGameRules_GiveC4 *chain); void CSGameRules_ChangeLevel(IReGameHook_CSGameRules_ChangeLevel *chain); void CSGameRules_GoToIntermission(IReGameHook_CSGameRules_GoToIntermission *chain); void CSGameRules_BalanceTeams(IReGameHook_CSGameRules_BalanceTeams *chain); void CSGameRules_OnRoundFreezeEnd(IReGameHook_CSGameRules_OnRoundFreezeEnd *chain); +// TODO: pending PM_UpdateStepSound +void CBasePlayer_StartDeathCam(IReGameHook_CBasePlayer_StartDeathCam *chain, CBasePlayer *pthis); +void CBasePlayer_SwitchTeam(IReGameHook_CBasePlayer_SwitchTeam *chain, CBasePlayer *pthis); +bool CBasePlayer_CanSwitchTeam(IReGameHook_CBasePlayer_CanSwitchTeam *chain, CBasePlayer *pthis, TeamName teamToSwap); +CGrenade *CBasePlayer_ThrowGrenade(IReGameHook_CBasePlayer_ThrowGrenade *chain, CBasePlayer *pthis, CBasePlayerWeapon *pWeapon, Vector &vecSrc, Vector &vecThrow, float time, unsigned short usEvent); bool CSGameRules_CanPlayerHearPlayer(IReGameHook_CSGameRules_CanPlayerHearPlayer *chain, CBasePlayer *pListener, CBasePlayer *pSender); - void CWeaponBox_SetModel(IReGameHook_CWeaponBox_SetModel *chain, CWeaponBox *pthis, const char *pszModelName); - void CGrenade_DefuseBombStart(IReGameHook_CGrenade_DefuseBombStart *chain, CGrenade *pthis, CBasePlayer *pPlayer); void CGrenade_DefuseBombEnd(IReGameHook_CGrenade_DefuseBombEnd *chain, CGrenade *pthis, CBasePlayer *pPlayer, bool bDefused); void CGrenade_ExplodeHeGrenade(IReGameHook_CGrenade_ExplodeHeGrenade *chain, CGrenade *pthis, TraceResult *ptr, int bitsDamageType); void CGrenade_ExplodeFlashbang(IReGameHook_CGrenade_ExplodeFlashbang *chain, CGrenade *pthis, TraceResult *ptr, int bitsDamageType); void CGrenade_ExplodeSmokeGrenade(IReGameHook_CGrenade_ExplodeSmokeGrenade *chain, CGrenade *pthis); void CGrenade_ExplodeBomb(IReGameHook_CGrenade_ExplodeBomb *chain, CGrenade *pthis, TraceResult *ptr, int bitsDamageType); +CGrenade *ThrowHeGrenade(IReGameHook_ThrowHeGrenade *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity, float time, int iTeam, unsigned short usEvent); +CGrenade *ThrowFlashbang(IReGameHook_ThrowFlashbang *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity, float time); +CGrenade *ThrowSmokeGrenade(IReGameHook_ThrowSmokeGrenade *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity, float time, unsigned short usEvent); +CGrenade *PlantBomb(IReGameHook_PlantBomb *chain, entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity); +void CBasePlayer_RemoveSpawnProtection(IReGameHook_CBasePlayer_RemoveSpawnProtection *chain, CBasePlayer *pthis); +void CBasePlayer_SetSpawnProtection(IReGameHook_CBasePlayer_SetSpawnProtection *chain, CBasePlayer *pthis, float flProtectionTime); +bool IsPenetrableEntity(IReGameHook_IsPenetrableEntity *chain, Vector &vecSrc, Vector &vecEnd, entvars_t *pevAttacker, edict_t *pHit); +bool CBasePlayer_HintMessageEx(IReGameHook_CBasePlayer_HintMessageEx *chain, CBasePlayer *pthis, const char *pMessage, float duration, bool bDisplayIfPlayerDead, bool bOverride); +void CBasePlayer_UseEmpty(IReGameHook_CBasePlayer_UseEmpty *chain, CBasePlayer *pthis); +BOOL CBasePlayerWeapon_CanDeploy(IReGameHook_CBasePlayerWeapon_CanDeploy *chain, CBasePlayerWeapon *pthis); +BOOL CBasePlayerWeapon_DefaultDeploy(IReGameHook_CBasePlayerWeapon_DefaultDeploy *chain, CBasePlayerWeapon *pthis, char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal); +int CBasePlayerWeapon_DefaultReload(IReGameHook_CBasePlayerWeapon_DefaultReload *chain, CBasePlayerWeapon *pthis, int iClipSize, int iAnim, float fDelay); +bool CBasePlayerWeapon_DefaultShotgunReload(IReGameHook_CBasePlayerWeapon_DefaultShotgunReload *chain, CBasePlayerWeapon *pthis, int iAnim, int iStartAnim, float fDelay, float fStartDelay, const char *pszReloadSound1, const char *pszReloadSound2); +void CBasePlayer_DropIdlePlayer(IReGameHook_CBasePlayer_DropIdlePlayer *chain, CBasePlayer *pthis, const char *reason); +CWeaponBox *CreateWeaponBox(IReGameHook_CreateWeaponBox *chain, CBasePlayerItem *pItem, CBasePlayer *pPlayerOwner, const char *modelName, Vector &origin, Vector &angles, Vector &velocity, float lifeTime, bool packAmmo); -// regamedll functions - gib +CGib *SpawnHeadGib(IReGameHook_SpawnHeadGib *chain, entvars_t *pevVictim); +void SpawnRandomGibs(IReGameHook_SpawnRandomGibs *chain, entvars_t *pevVictim, int cGibs, int human); void CGib_Spawn(IReGameHook_CGib_Spawn *chain, CGib *pthis, const char *szGibModel); void CGib_BounceGibTouch(IReGameHook_CGib_BounceGibTouch *chain, CGib *pthis, CBaseEntity *pOther); void CGib_WaitTillLand(IReGameHook_CGib_WaitTillLand *chain, CGib *pthis); -// regamedll functions - cbaseentity void CBaseEntity_FireBullets(IReGameHook_CBaseEntity_FireBullets *chain, CBaseEntity *pEntity, ULONG cShots, Vector &vecSrc, Vector &vecDirShooting, Vector &vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker); void CBaseEntity_FireBuckshots(IReGameHook_CBaseEntity_FireBuckshots *chain, CBaseEntity *pEntity, ULONG cShots, Vector &vecSrc, Vector &vecDirShooting, Vector &vecSpread, float flDistance, int iTracerFreq, int iDamage, entvars_t *pevAttacker); Vector &CBaseEntity_FireBullets3(IReGameHook_CBaseEntity_FireBullets3 *chain, CBaseEntity *pEntity, Vector &vecSrc, Vector &vecDirShooting, float vecSpread, float flDistance, int iPenetration, int iBulletType, int iDamage, float flRangeModifier, entvars_t *pevAttacker, bool bPistol, int shared_rand); +void CBasePlayer_Observer_SetMode(IReGameHook_CBasePlayer_Observer_SetMode *chain, CBasePlayer *pthis, int iMode); +void CBasePlayer_Observer_FindNextPlayer(IReGameHook_CBasePlayer_Observer_FindNextPlayer *chain, CBasePlayer *pthis, bool bReverse, const char *name); + +void CBasePlayer_Pain(IReGameHook_CBasePlayer_Pain *chain, CBasePlayer *pthis, int iLastHitGroup, bool bHasArmour); +void CBasePlayer_DeathSound(IReGameHook_CBasePlayer_DeathSound *chain, CBasePlayer *pthis); +void CBasePlayer_JoiningThink(IReGameHook_CBasePlayer_JoiningThink *chain, CBasePlayer *pthis); + +// TODO: pending FreeGameRules +void PM_LadderMove_AMXX(IReGameHook_PM_LadderMove *chain, physent_t *pLadder, int playerIndex); +void PM_LadderMove(IReGameHook_PM_LadderMove *chain, physent_t *pLadder); +void PM_WaterJump_AMXX(IReGameHook_PM_WaterJump *chain, int playerIndex); +void PM_WaterJump(IReGameHook_PM_WaterJump *chain); +void PM_CheckWaterJump_AMXX(IReGameHook_PM_CheckWaterJump *chain, int playerIndex); +void PM_CheckWaterJump(IReGameHook_PM_CheckWaterJump *chain); +void PM_Jump_AMXX(IReGameHook_PM_Jump *chain, int playerIndex); +void PM_Jump(IReGameHook_PM_Jump *chain); +void PM_Duck_AMXX(IReGameHook_PM_Duck *chain, int playerIndex); +void PM_Duck(IReGameHook_PM_Duck *chain); +void PM_UnDuck_AMXX(IReGameHook_PM_UnDuck *chain, int playerIndex); +void PM_UnDuck(IReGameHook_PM_UnDuck *chain); +void PM_PlayStepSound_AMXX(IReGameHook_PM_PlayStepSound *chain, int step, float fvol, int playerIndex); +void PM_PlayStepSound(IReGameHook_PM_PlayStepSound *chain, int step, float fvol); +void PM_AirAccelerate_AMXX(IReGameHook_PM_AirAccelerate *chain, vec_t *wishdir, float wishspeed, float accel, int playerIndex); +void PM_AirAccelerate(IReGameHook_PM_AirAccelerate *chain, vec_t *wishdir, float wishspeed, float accel); +void ClearMultiDamage(IReGameHook_ClearMultiDamage *chain); +void AddMultiDamage(IReGameHook_AddMultiDamage *chain, entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType); +void ApplyMultiDamage(IReGameHook_ApplyMultiDamage *chain, entvars_t *pevInflictor, entvars_t *pevAttacker); +void BuyItem(IReGameHook_BuyItem *chain, CBasePlayer *pPlayer, int iSlot); +void CSGameRules_Think(IReGameHook_CSGameRules_Think *chain); +BOOL CSGameRules_TeamFull(IReGameHook_CSGameRules_TeamFull *chain, int team_id); +BOOL CSGameRules_TeamStacked(IReGameHook_CSGameRules_TeamStacked *chain, int newTeam_id, int curTeam_id); +void CSGameRules_PlayerGotWeapon(IReGameHook_CSGameRules_PlayerGotWeapon *chain, CBasePlayer *pPlayer, CBasePlayerItem *pWeapon); +void CBotManager_OnEvent(IReGameHook_CBotManager_OnEvent *chain, GameEventType event, CBaseEntity* pEntity, CBaseEntity* pOther); +void CBasePlayer_CheckTimeBasedDamage(IReGameHook_CBasePlayer_CheckTimeBasedDamage *chain, CBasePlayer *pthis); +edict_t *CBasePlayer_EntSelectSpawnPoint(IReGameHook_CBasePlayer_EntSelectSpawnPoint *chain, CBasePlayer *pthis); +void CBasePlayerWeapon_ItemPostFrame(IReGameHook_CBasePlayerWeapon_ItemPostFrame *chain, CBasePlayerWeapon *pthis); +void CBasePlayerWeapon_KickBack(IReGameHook_CBasePlayerWeapon_KickBack *chain, CBasePlayerWeapon *pthis, float up_base, float lateral_base, float up_modifier, float lateral_modifier, float up_max, float lateral_max, int direction_change); +void CBasePlayerWeapon_SendWeaponAnim(IReGameHook_CBasePlayerWeapon_SendWeaponAnim *chain, CBasePlayerWeapon *pthis, int iAnim, int skiplocal); + +/* +* VTC functions +*/ extern int g_iClientStartSpeak; extern int g_iClientStopSpeak; void OnClientStartSpeak(size_t clientIndex); void OnClientStopSpeak(size_t clientIndex); +/* +* ReChecker functions +*/ + using CmdExec_t = hookdata_t; void CmdExec_AMXX(CmdExec_t *chain, IGameClient *cl, const char *filename, char *cmd, uint32 responseHash); void CmdExec(IRecheckerHook_CmdExec *chain, IGameClient *cl, IResourceBuffer *res, char *cmd, uint32 responseHash); @@ -520,3 +581,4 @@ void FileConsistencyProcess_AMXX(FileConsistencyProcess_t *data, IGameClient *cl void FileConsistencyProcess(IRecheckerHook_FileConsistencyProcess *chain, IGameClient *cl, IResourceBuffer *res, ResourceType_e typeFind, uint32 responseHash); void FileConsistencyFinal(IRecheckerHook_FileConsistencyFinal *chain, IGameClient *cl); + diff --git a/reapi/src/hook_list.cpp b/reapi/src/hook_list.cpp index 2b9df5cb..870c95c1 100644 --- a/reapi/src/hook_list.cpp +++ b/reapi/src/hook_list.cpp @@ -20,6 +20,11 @@ inline size_t getFwdParamType(void(*)(float&)) { return FP_FLOA inline size_t getFwdParamType(void(*)(const char *)) { return FP_STRING; } inline size_t getFwdParamType(void(*)(char *)) { return FP_STRING; } inline size_t getFwdParamType(void(*)(IResourceBuffer*)) { return FP_CELL; } +inline size_t getFwdParamType(void(*)(unsigned char)) { return FP_CELL; } +inline size_t getFwdParamType(void(*)(resourcetype_t)) { return FP_CELL; } +inline size_t getFwdParamType(void(*)(cmd_source_t)) { return FP_CELL; } +inline size_t getFwdParamType(void(*)(GameEventType)) { return FP_CELL; } +inline size_t getFwdParamType(void(*)(float*)) { return FP_ARRAY; } template inline size_t getFwdParamType(void(*)(T *)) { return FP_CELL; } @@ -94,6 +99,16 @@ hook_t hooklist_engine[] = { ENG(ED_Alloc), ENG(ED_Free), ENG(Con_Printf), + ENG(SV_CheckUserInfo, _AMXX), + ENG(PF_precache_generic_I), + ENG(PF_precache_model_I), + ENG(PF_precache_sound_I), + ENG(EV_Precache, _AMXX), + ENG(SV_AddResource), + ENG(SV_ClientPrintf), + ENG(SV_AllowPhysent), + ENG(ExecuteServerStringCmd), + }; #define DLL(h,...) { {}, {}, #h, "ReGameDLL", [](){ return api_cfg.hasReGameDLL(); }, ((!(RG_##h & (MAX_REGION_RANGE - 1)) ? regfunc::current_cell = 1, true : false) || (RG_##h & (MAX_REGION_RANGE - 1)) == regfunc::current_cell++) ? regfunc(h##__VA_ARGS__) : regfunc(#h#__VA_ARGS__), [](){ g_ReGameHookchains->h()->registerHook(&h); }, [](){ g_ReGameHookchains->h()->unregisterHook(&h); }, false} @@ -117,6 +132,19 @@ hook_t hooklist_gamedll[] = { DLL(IsPenetrableEntity), DLL(SpawnHeadGib), DLL(SpawnRandomGibs), + DLL(CreateWeaponBox), + DLL(PM_LadderMove, _AMXX), + DLL(PM_WaterJump, _AMXX), + DLL(PM_CheckWaterJump, _AMXX), + DLL(PM_Jump, _AMXX), + DLL(PM_Duck, _AMXX), + DLL(PM_UnDuck, _AMXX), + DLL(PM_PlayStepSound, _AMXX), + DLL(PM_AirAccelerate, _AMXX), + DLL(ClearMultiDamage), + DLL(AddMultiDamage), + DLL(ApplyMultiDamage), + DLL(BuyItem), }; hook_t hooklist_animating[] = { @@ -181,6 +209,9 @@ hook_t hooklist_player[] = { DLL(CBasePlayer_Pain), DLL(CBasePlayer_DeathSound), DLL(CBasePlayer_JoiningThink), + + DLL(CBasePlayer_CheckTimeBasedDamage), + DLL(CBasePlayer_EntSelectSpawnPoint), }; hook_t hooklist_gamerules[] = { @@ -208,6 +239,10 @@ hook_t hooklist_gamerules[] = { DLL(CSGameRules_BalanceTeams), DLL(CSGameRules_OnRoundFreezeEnd), DLL(CSGameRules_CanPlayerHearPlayer), + DLL(CSGameRules_Think), + DLL(CSGameRules_TeamFull), + DLL(CSGameRules_TeamStacked), + DLL(CSGameRules_PlayerGotWeapon), }; hook_t hooklist_grenade[] = { @@ -228,6 +263,9 @@ hook_t hooklist_weapon[] = { DLL(CBasePlayerWeapon_DefaultDeploy), DLL(CBasePlayerWeapon_DefaultReload), DLL(CBasePlayerWeapon_DefaultShotgunReload), + DLL(CBasePlayerWeapon_ItemPostFrame), + DLL(CBasePlayerWeapon_KickBack), + DLL(CBasePlayerWeapon_SendWeaponAnim), }; hook_t hooklist_gib[] = { @@ -242,6 +280,10 @@ hook_t hooklist_cbaseentity[] = { DLL(CBaseEntity_FireBullets3), }; +hook_t hooklist_botmanager[] = { + DLL(CBotManager_OnEvent), +}; + #define RCHECK(h,...) { {}, {}, #h, "ReChecker", [](){ return api_cfg.hasRechecker(); }, ((!(RC_##h & (MAX_REGION_RANGE - 1)) ? regfunc::current_cell = 1, true : false) || (RC_##h & (MAX_REGION_RANGE - 1)) == regfunc::current_cell++) ? regfunc(h##__VA_ARGS__) : regfunc(#h#__VA_ARGS__), [](){ g_RecheckerHookchains->h()->registerHook(&h); }, [](){ g_RecheckerHookchains->h()->unregisterHook(&h); }, false} hook_t hooklist_rechecker[] = { RCHECK(FileConsistencyProcess, _AMXX), @@ -268,6 +310,7 @@ hook_t* hooklist_t::getHookSafe(size_t hook) CASE(weapon) CASE(gib) CASE(cbaseentity) + CASE(botmanager) } return nullptr; @@ -288,6 +331,7 @@ void hooklist_t::clear() FOREACH_CLEAR(weapon); FOREACH_CLEAR(gib); FOREACH_CLEAR(cbaseentity); + FOREACH_CLEAR(botmanager); } void hook_t::clear() diff --git a/reapi/src/hook_list.h b/reapi/src/hook_list.h index bf798827..18483eb2 100644 --- a/reapi/src/hook_list.h +++ b/reapi/src/hook_list.h @@ -38,6 +38,7 @@ extern hook_t hooklist_weaponbox[]; extern hook_t hooklist_weapon[]; extern hook_t hooklist_gib[]; extern hook_t hooklist_cbaseentity[]; +extern hook_t hooklist_botmanager[]; enum { @@ -65,6 +66,7 @@ struct hooklist_t CASE(weapon) CASE(gib) CASE(cbaseentity) + CASE(botmanager) } #undef CASE @@ -88,6 +90,7 @@ struct hooklist_t ht_weapon, ht_gib, ht_cbaseentity, + ht_botmanager, }; }; @@ -105,7 +108,16 @@ enum EngineFunc RH_ED_Alloc, RH_ED_Free, RH_Con_Printf, - + RH_SV_CheckUserInfo, + RH_PF_precache_generic_I, + RH_PF_precache_model_I, + RH_PF_precache_sound_I, + RH_EV_Precache, + RH_SV_AddResource, + RH_SV_ClientPrintf, + RH_SV_AllowPhysent, + RH_ExecuteServerStringCmd, + // [...] }; @@ -135,6 +147,20 @@ enum GamedllFunc RG_SpawnHeadGib, RG_SpawnRandomGibs, + RG_CreateWeaponBox, + RG_PM_LadderMove, + RG_PM_WaterJump, + RG_PM_CheckWaterJump, + RG_PM_Jump, + RG_PM_Duck, + RG_PM_UnDuck, + RG_PM_PlayStepSound, + RG_PM_AirAccelerate, + RG_ClearMultiDamage, + RG_AddMultiDamage, + RG_ApplyMultiDamage, + RG_BuyItem, + // [...] }; @@ -207,6 +233,9 @@ enum GamedllFunc_CBasePlayer RG_CBasePlayer_DeathSound, RG_CBasePlayer_JoiningThink, + RG_CBasePlayer_CheckTimeBasedDamage, + RG_CBasePlayer_EntSelectSpawnPoint, + // [...] }; @@ -235,6 +264,9 @@ enum GamedllFunc_CBasePlayerWeapon RG_CBasePlayerWeapon_DefaultDeploy, RG_CBasePlayerWeapon_DefaultReload, RG_CBasePlayerWeapon_DefaultShotgunReload, + RG_CBasePlayerWeapon_ItemPostFrame, + RG_CBasePlayerWeapon_KickBack, + RG_CBasePlayerWeapon_SendWeaponAnim, // [...] }; @@ -266,6 +298,10 @@ enum GamedllFunc_CSGameRules RG_CSGameRules_BalanceTeams, RG_CSGameRules_OnRoundFreezeEnd, RG_CSGameRules_CanPlayerHearPlayer, + RG_CSGameRules_Think, + RG_CSGameRules_TeamFull, + RG_CSGameRules_TeamStacked, + RG_CSGameRules_PlayerGotWeapon, // [...] }; @@ -288,6 +324,13 @@ enum GamedllFunc_CBaseEntity // [...] }; +enum GamedllFunc_CBotManager +{ + RG_CBotManager_OnEvent = BEGIN_FUNC_REGION(botmanager), + + // [...] +}; + enum ReCheckerFunc { RC_FileConsistencyProcess = BEGIN_FUNC_REGION(rechecker), diff --git a/reapi/src/main.cpp b/reapi/src/main.cpp index 263786b6..d82b4252 100644 --- a/reapi/src/main.cpp +++ b/reapi/src/main.cpp @@ -69,7 +69,7 @@ void ServerDeactivate_Post() api_cfg.ServerDeactivate(); g_hookManager.Clear(); g_queryFileManager.Clear(); - g_entCallback.Clear(); + EntityCallbackDispatcher().DeleteAllCallbacks(); g_pFunctionTable->pfnSpawn = DispatchSpawn; g_pFunctionTable->pfnKeyValue = KeyValue; @@ -140,6 +140,6 @@ void OnFreeEntPrivateData(edict_t *pEdict) return; } - g_entCallback.Clear(pEntity); + EntityCallbackDispatcher().DeleteExistingCallbacks(pEntity); SET_META_RESULT(MRES_IGNORED); } diff --git a/reapi/src/member_list.cpp b/reapi/src/member_list.cpp index 7bfca903..bf3a90d3 100644 --- a/reapi/src/member_list.cpp +++ b/reapi/src/member_list.cpp @@ -30,6 +30,7 @@ #define MOVEVAR_MEMBERS(mx) STRUCT_MEMBERS(movevars_t, mx, mv_##mx) #define UCMD_MEMBERS(mx) STRUCT_MEMBERS(usercmd_s, mx, ucmd_##mx) #define PMTRACE_MEMBERS(mx) STRUCT_MEMBERS(pmtrace_s, mx, pmt_##mx) +#define NETADR_MEMBERS(mx) STRUCT_MEMBERS(netadr_t, mx, netadr_##mx) #define CSPL_MEMBERS(mx) CLASS_MEMBERS(CCSPlayer, mx, mx) #define BASEITEM_MEMBERS(mx) CLASS_MEMBERS(CBasePlayerItem, mx, mx) #define BASEWPN_MEMBERS(mx) CLASS_MEMBERS_PREF(CBasePlayerWeapon, mx, m_Weapon_##mx, m_) @@ -69,6 +70,7 @@ #define MAPINFO_MEMBERS(mx) CLASS_MEMBERS_PREF(CMapInfo, mx, m_MapInfo_##mx, m_) #define CSPLWPN_MEMBERS(mx) CLASS_MEMBERS_PREF(CCSPlayerWeapon, mx, m_Weapon_##mx, m_) #define GIB_MEMBERS(mx) CLASS_MEMBERS_PREF(CGib, mx, m_Gib_##mx, m_) +#define CSENT_MEMBERS(mx) CLASS_MEMBERS(CCSEntity, mx, mx) inline MType getMemberType(float*) { return MEMBER_FLOAT; } inline MType getMemberType(float) { return MEMBER_FLOAT; } @@ -111,6 +113,8 @@ inline MType getMemberType(MONSTERSTATE) { return MEMBER_INTEGER; } inline MType getMemberType(ArmorType) { return MEMBER_INTEGER; } inline MType getMemberType(ArmouryItemPack) { return MEMBER_INTEGER; } inline MType getMemberType(InfoMapBuyParam) { return MEMBER_INTEGER; } +inline MType getMemberType(SecondaryAtkState) { return MEMBER_INTEGER; } +inline MType getMemberType(netadrtype_t) { return MEMBER_INTEGER; } inline MType getMemberType(TraceResult) { return MEMBER_TRACERESULT; } @@ -118,6 +122,7 @@ inline MType getMemberType(short) { return MEMBER_SHORT; } inline MType getMemberType(unsigned short) { return MEMBER_SHORT; } inline MType getMemberType(bool) { return MEMBER_BOOL; } +inline MType getMemberType(bool*) { return MEMBER_BOOL; } inline MType getMemberType(CUnifiedSignals) { return MEMBER_SIGNALS; } inline MType getMemberType(RebuyStruct) { return MEBMER_REBUYSTRUCT; } @@ -760,6 +765,14 @@ member_t memberlist_csplayer[] = { CSPL_MEMBERS(m_bGameForcingRespawn), CSPL_MEMBERS(m_bAutoBunnyHopping), CSPL_MEMBERS(m_bMegaBunnyJumping), + CSPL_MEMBERS(m_bPlantC4Anywhere), + CSPL_MEMBERS(m_bSpawnProtectionEffects), + CSPL_MEMBERS(m_flJumpHeight), + CSPL_MEMBERS(m_flLongJumpHeight), + CSPL_MEMBERS(m_flLongJumpForce), + CSPL_MEMBERS(m_flDuckSpeedMultiplier), + CSPL_MEMBERS(m_iNumKilledByUnanswered), + CSPL_MEMBERS(m_bPlayerDominated), }; member_t memberlist_baseitem[] = { @@ -1002,6 +1015,7 @@ member_t memberlist_knife[] = { KNIFE_MEMBERS(flSwingBaseDamage_Fast), KNIFE_MEMBERS(flStabDistance), KNIFE_MEMBERS(flSwingDistance), + KNIFE_MEMBERS(flBackStabMultiplier), }; member_t memberlist_p90[] = { @@ -1034,7 +1048,7 @@ member_t memberlist_mapinfo[] = { }; member_t memberlist_csplayerweapon[] = { - CSPLWPN_MEMBERS(bHasSecondaryAttack), + CSPLWPN_MEMBERS(iStateSecondaryAttack), CSPLWPN_MEMBERS(flBaseDamage), }; @@ -1045,6 +1059,17 @@ member_t memberlist_gib[] = { GIB_MEMBERS(lifeTime), }; +member_t memberlist_netadr[] = { + NETADR_MEMBERS(type), + NETADR_MEMBERS(ip), + NETADR_MEMBERS(port) +}; + +member_t memberlist_csentity[] = { + CSENT_MEMBERS(m_ucDmgPenetrationLevel), + CSENT_MEMBERS(m_pevLastInflictor), +}; + #ifdef __GNUC__ #pragma GCC diagnostic pop #endif // #ifdef __GNUC__ @@ -1108,6 +1133,8 @@ member_t *memberlist_t::operator[](size_t members) const CASE(mapinfo) CASE(csplayerweapon) CASE(gib) + CASE(netadr) + CASE(csentity) } #undef CASE diff --git a/reapi/src/member_list.h b/reapi/src/member_list.h index b2947853..58969330 100644 --- a/reapi/src/member_list.h +++ b/reapi/src/member_list.h @@ -83,6 +83,8 @@ struct memberlist_t mt_mapinfo, mt_csplayerweapon, mt_gib, + mt_netadr, + mt_csentity }; }; @@ -735,6 +737,13 @@ enum PMTrace pmt_hitgroup }; +enum NetAdr +{ + netadr_type = BEGIN_MEMBER_REGION(netadr), + netadr_ip, + netadr_port +}; + // CCSPlayer enum CSPlayer_Members { @@ -749,6 +758,14 @@ enum CSPlayer_Members m_bGameForcingRespawn, m_bAutoBunnyHopping, m_bMegaBunnyJumping, + m_bPlantC4Anywhere, + m_bSpawnProtectionEffects, + m_flJumpHeight, + m_flLongJumpHeight, + m_flLongJumpForce, + m_flDuckSpeedMultiplier, + m_iNumKilledByUnanswered, + m_bPlayerDominated, }; enum CBasePlayerItem_Members @@ -1023,6 +1040,7 @@ enum CKnife_Members m_Knife_flSwingBaseDamage_Fast, m_Knife_flStabDistance, m_Knife_flSwingDistance, + m_Knife_flBackStabMultiplier, }; enum CP90_Members @@ -1060,7 +1078,7 @@ enum MapInfo_Members enum CSPlayerWeapon_Members { - m_Weapon_bHasSecondaryAttack = BEGIN_MEMBER_REGION(csplayerweapon), + m_Weapon_iStateSecondaryAttack = BEGIN_MEMBER_REGION(csplayerweapon), m_Weapon_flBaseDamage, }; @@ -1071,3 +1089,9 @@ enum CGib_Members m_Gib_material, m_Gib_lifeTime, }; + +enum CSEntity_Members +{ + m_ucDmgPenetrationLevel = BEGIN_MEMBER_REGION(csentity), + m_pevLastInflictor, +}; diff --git a/reapi/src/mods/mod_regamedll_api.cpp b/reapi/src/mods/mod_regamedll_api.cpp index c7810f78..22dfcbd4 100644 --- a/reapi/src/mods/mod_regamedll_api.cpp +++ b/reapi/src/mods/mod_regamedll_api.cpp @@ -11,7 +11,7 @@ bool RegamedllApi_Init() if (!szGameDLLModule) return false; - CSysModule *gameModule = Sys_LoadModule(szGameDLLModule); + CSysModule *gameModule = Sys_GetModuleHandle(szGameDLLModule); if (!gameModule) return false; @@ -62,6 +62,12 @@ bool RegamedllApi_Init() if (!g_ReGameApi->BGetICSEntity(CSENTITY_API_INTERFACE_VERSION)) { UTIL_ServerPrint("[%s]: Interface CCSEntity API version '%s' not found.\n", Plugin_info.logtag, CSENTITY_API_INTERFACE_VERSION); + + if (g_ReGameApi->BGetICSEntity("CSENTITY_API_INTERFACE_VERSION002")) + UTIL_ServerPrint("[%s]: Please update ReGameDLL to the latest version.\n", Plugin_info.logtag); + else + UTIL_ServerPrint("[%s]: Please update ReAPI to the latest version.\n", Plugin_info.logtag); + return false; } diff --git a/reapi/src/mods/mod_rehlds_api.cpp b/reapi/src/mods/mod_rehlds_api.cpp index 7dedb302..109c582f 100644 --- a/reapi/src/mods/mod_rehlds_api.cpp +++ b/reapi/src/mods/mod_rehlds_api.cpp @@ -8,15 +8,24 @@ IRehldsServerStatic* g_RehldsSvs; bool RehldsApi_Init() { - if (!IS_DEDICATED_SERVER()) +#ifdef WIN32 + // Find the most appropriate module handle from a list of DLL candidates + // Notes: + // - "swds.dll" is the library Dedicated Server + // + // Let's also attempt to locate the ReHLDS API in the client's library + // - "sw.dll" is the client library for Software render, with a built-in listenserver + // - "hw.dll" is the client library for Hardware render, with a built-in listenserver + const char *dllNames[] = { "swds.dll", "sw.dll", "hw.dll" }; // List of DLL candidates to lookup for the ReHLDS API + CSysModule *engineModule = NULL; // The module handle of the selected DLL + for (const char *dllName : dllNames) { - return false; + if (engineModule = Sys_GetModuleHandle(dllName)) + break; // gotcha } -#ifdef WIN32 - CSysModule* engineModule = Sys_LoadModule("swds.dll"); #else - CSysModule* engineModule = Sys_LoadModule("engine_i486.so"); + CSysModule *engineModule = Sys_GetModuleHandle("engine_i486.so"); #endif if (!engineModule) diff --git a/reapi/src/natives/natives_common.cpp b/reapi/src/natives/natives_common.cpp index 6315653c..416521a7 100644 --- a/reapi/src/natives/natives_common.cpp +++ b/reapi/src/natives/natives_common.cpp @@ -113,6 +113,61 @@ cell AMX_NATIVE_CALL amx_get_viewent(AMX *amx, cell *params) return indexOfEdictAmx(pClient->pViewEntity); } +/* +* Sets value string to entire buffer +* +* @param buffer Pointer to buffer +* @param value Value to set +* @param maxlen Maximum size of the value buffer to set, -1 means copy all characters +* +* @return 1 on success, 0 otherwise +* +* native set_key_value_buffer(const pbuffer, const value[], const maxlen = -1); +*/ +cell AMX_NATIVE_CALL amx_set_key_value_buffer(AMX *amx, cell *params) +{ + enum args_e { arg_count, arg_buffer, arg_value, arg_maxlen }; + + char *buffer = reinterpret_cast(params[arg_buffer]); + if (!buffer) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: Invalid buffer", __FUNCTION__); + return FALSE; + } + + size_t maxlen = (params[arg_maxlen] > 0) ? min(params[arg_maxlen], MAX_INFO_STRING) : MAX_INFO_STRING; + char infobuf[MAX_INFO_STRING]; + const char *value = getAmxString(amx, params[arg_value], infobuf); + size_t len = min(Q_strlen(value) + 1, maxlen); + Q_strnlcpy(buffer, value, len); + return TRUE; +} + +/* +* Gets an AMXX string buffer from a infobuffer pointer +* +* @param buffer Info string pointer +* @param value String to copy value to +* @param maxlen Maximum size of the output buffer +* +* @return Returns a string buffer on infobuffer pointer +* +* native get_key_value_buffer(const pbuffer, const output[], const maxlen); +*/ +cell AMX_NATIVE_CALL amx_get_key_value_buffer(AMX *amx, cell *params) +{ + enum args_e { arg_count, arg_buffer, arg_output, arg_maxlen }; + + char *buffer = reinterpret_cast(params[arg_buffer]); + if (!buffer) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: Invalid buffer", __FUNCTION__); + return FALSE; + } + + return g_amxxapi.SetAmxString(amx, params[arg_output], buffer, params[arg_maxlen]); +} + /* * Gets value for key in buffer * @@ -236,7 +291,7 @@ cell AMX_NATIVE_CALL amx_GetBonePosition(AMX *amx, cell *params) */ cell AMX_NATIVE_CALL amx_GetAttachment(AMX *amx, cell *params) { - enum args_e { arg_count, arg_index, arg_bone, arg_attachment, arg_angles }; + enum args_e { arg_count, arg_index, arg_attachment, arg_origin, arg_angles }; CHECK_ISENTITY(arg_index); @@ -251,12 +306,113 @@ cell AMX_NATIVE_CALL amx_GetAttachment(AMX *amx, cell *params) return FALSE; } - Vector *pVecOrigin = (Vector *)getAmxAddr(amx, params[arg_attachment]); + Vector *pVecOrigin = (Vector *)getAmxAddr(amx, params[arg_origin]); Vector *pVecAngles = (PARAMS_COUNT == 4) ? (Vector *)getAmxAddr(amx, params[arg_angles]) : nullptr; - GetAttachment(pEntity, params[arg_bone], pVecOrigin, pVecAngles); + GetAttachment(pEntity, params[arg_attachment], pVecOrigin, pVecAngles); 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 * @@ -287,7 +443,7 @@ cell AMX_NATIVE_CALL amx_SetThink(AMX *amx, cell *params) char namebuf[256]; const char *funcname = getAmxString(amx, params[arg_handler], namebuf); if (unlikely(funcname == nullptr || funcname[0] == '\0')) { - pEntity->SetThink(nullptr); + EntityCallbackDispatcher().UnsetThink(amx, pEntity); return TRUE; } @@ -298,7 +454,7 @@ cell AMX_NATIVE_CALL amx_SetThink(AMX *amx, cell *params) } cell *pParams = (PARAMS_COUNT >= 3) ? getAmxAddr(amx, params[arg_params]) : nullptr; - return (cell)g_entCallback.SetThink(amx, pEntity, funcname, pParams, params[arg_len]); + return (cell)EntityCallbackDispatcher().SetThink(amx, pEntity, funcname, pParams, params[arg_len]); } /* @@ -331,7 +487,7 @@ cell AMX_NATIVE_CALL amx_SetTouch(AMX *amx, cell *params) char namebuf[256]; const char *funcname = getAmxString(amx, params[arg_handler], namebuf); if (unlikely(funcname == nullptr || funcname[0] == '\0')) { - pEntity->SetTouch(nullptr); + EntityCallbackDispatcher().UnsetTouch(amx, pEntity); return TRUE; } @@ -342,7 +498,7 @@ cell AMX_NATIVE_CALL amx_SetTouch(AMX *amx, cell *params) } cell *pParams = (PARAMS_COUNT >= 3) ? getAmxAddr(amx, params[arg_params]) : nullptr; - return (cell)g_entCallback.SetTouch(amx, pEntity, funcname, pParams, params[arg_len]); + return (cell)EntityCallbackDispatcher().SetTouch(amx, pEntity, funcname, pParams, params[arg_len]); } /* @@ -375,7 +531,7 @@ cell AMX_NATIVE_CALL amx_SetUse(AMX *amx, cell *params) char namebuf[256]; const char *funcname = getAmxString(amx, params[arg_handler], namebuf); if (unlikely(funcname == nullptr || funcname[0] == '\0')) { - pEntity->SetUse(nullptr); + EntityCallbackDispatcher().UnsetUse(amx, pEntity); return TRUE; } @@ -386,7 +542,7 @@ cell AMX_NATIVE_CALL amx_SetUse(AMX *amx, cell *params) } cell *pParams = (PARAMS_COUNT >= 3) ? getAmxAddr(amx, params[arg_params]) : nullptr; - return (cell)g_entCallback.SetUse(amx, pEntity, funcname, pParams, params[arg_len]); + return (cell)EntityCallbackDispatcher().SetUse(amx, pEntity, funcname, pParams, params[arg_len]); } /* @@ -419,7 +575,7 @@ cell AMX_NATIVE_CALL amx_SetBlocked(AMX *amx, cell *params) char namebuf[256]; const char *funcname = getAmxString(amx, params[arg_handler], namebuf); if (unlikely(funcname == nullptr || funcname[0] == '\0')) { - pEntity->SetBlocked(nullptr); + EntityCallbackDispatcher().UnsetBlocked(amx, pEntity); return TRUE; } @@ -430,7 +586,7 @@ cell AMX_NATIVE_CALL amx_SetBlocked(AMX *amx, cell *params) } cell *pParams = (PARAMS_COUNT >= 3) ? getAmxAddr(amx, params[arg_params]) : nullptr; - return (cell)g_entCallback.SetBlocked(amx, pEntity, funcname, pParams, params[arg_len]); + return (cell)EntityCallbackDispatcher().SetBlocked(amx, pEntity, funcname, pParams, params[arg_len]); } /* @@ -464,7 +620,7 @@ cell AMX_NATIVE_CALL amx_SetMoveDone(AMX *amx, cell *params) char namebuf[256]; const char *funcname = getAmxString(amx, params[arg_handler], namebuf); if (unlikely(funcname == nullptr || funcname[0] == '\0')) { - ((CBaseToggle *)pEntity)->SetMoveDone(nullptr); + EntityCallbackDispatcher().UnsetMoveDone(amx, pEntity); return TRUE; } @@ -475,24 +631,29 @@ cell AMX_NATIVE_CALL amx_SetMoveDone(AMX *amx, cell *params) } cell *pParams = (PARAMS_COUNT >= 3) ? getAmxAddr(amx, params[arg_params]) : nullptr; - return (cell)g_entCallback.SetMoveDone(amx, pEntity, funcname, pParams, params[arg_len]); + return (cell)EntityCallbackDispatcher().SetMoveDone(amx, pEntity, funcname, pParams, params[arg_len]); } AMX_NATIVE_INFO Natives_Common[] = { - { "FClassnameIs", amx_FClassnameIs }, - { "GetGrenadeType", amx_GetGrenadeType }, - { "engset_view", amx_engset_view }, - { "get_viewent", amx_get_viewent }, - { "get_key_value", amx_get_key_value }, - { "set_key_value", amx_set_key_value }, - { "GetBonePosition", amx_GetBonePosition }, - { "GetAttachment", amx_GetAttachment }, - { "SetThink", amx_SetThink }, - { "SetTouch", amx_SetTouch }, - { "SetUse", amx_SetUse }, - { "SetBlocked", amx_SetBlocked }, - { "SetMoveDone", amx_SetMoveDone }, + { "FClassnameIs", amx_FClassnameIs }, + { "GetGrenadeType", amx_GetGrenadeType }, + { "engset_view", amx_engset_view }, + { "get_viewent", amx_get_viewent }, + { "get_key_value", amx_get_key_value }, + { "set_key_value", amx_set_key_value }, + { "get_key_value_buffer", amx_get_key_value_buffer }, + { "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 }, + { "SetBlocked", amx_SetBlocked }, + { "SetMoveDone", amx_SetMoveDone }, { nullptr, nullptr } }; diff --git a/reapi/src/natives/natives_helper.h b/reapi/src/natives/natives_helper.h index f1cb1621..6ec6b5ea 100644 --- a/reapi/src/natives/natives_helper.h +++ b/reapi/src/natives/natives_helper.h @@ -40,6 +40,10 @@ class CAmxArg { return m_value != 0; } + operator unsigned short() const + { + return (unsigned short)m_value; + } operator CBaseEntity*() const { if (m_value < 0) @@ -78,6 +82,14 @@ class CAmxArg { return static_cast(m_value); } + operator WeaponIdType() const + { + return static_cast(m_value); + } + operator TraceResult *() const + { + return reinterpret_cast(m_value); + } Vector& vector() const { return operator Vector&(); diff --git a/reapi/src/natives/natives_hookchains.cpp b/reapi/src/natives/natives_hookchains.cpp index e0a1d9c9..87c8c0f0 100644 --- a/reapi/src/natives/natives_hookchains.cpp +++ b/reapi/src/natives/natives_hookchains.cpp @@ -322,6 +322,11 @@ cell AMX_NATIVE_CALL SetHookChainArg(AMX *amx, cell *params) case ATYPE_EVARS: *(entvars_t **)destAddr = PEV(*srcAddr); break; + case ATYPE_TRACE: + **(TraceResult **)destAddr = *(TraceResult *)(*srcAddr); + break; + default: + return FALSE; } return TRUE; diff --git a/reapi/src/natives/natives_members.cpp b/reapi/src/natives/natives_members.cpp index a356f8a6..54ba699c 100644 --- a/reapi/src/natives/natives_members.cpp +++ b/reapi/src/natives/natives_members.cpp @@ -667,6 +667,96 @@ cell AMX_NATIVE_CALL get_pmtrace(AMX *amx, cell *params) return get_member(tr, member, dest, element); } +/* +* Sets a NetAdr var. +* +* @param var The specified mvar, look at the enum NetAdrVars +* +* @return 1 on success. +* +* native set_netadr(const adr, const NetAdrVars:var, any:...); +*/ +cell AMX_NATIVE_CALL set_netadr(AMX *amx, cell *params) +{ + enum args_e { arg_count, arg_adr, arg_var, arg_value }; + member_t *member = memberlist[params[arg_var]]; + + if (unlikely(member == nullptr)) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: unknown member id %i", __FUNCTION__, params[arg_var]); + return FALSE; + } + + netadr_t *adr = (netadr_t *)params[arg_adr]; + if (unlikely(adr == nullptr)) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: Invalid network address", __FUNCTION__); + return FALSE; + } + + switch (params[arg_var]) + { + case netadr_type: + adr->type = (netadrtype_t)params[arg_value]; + break; + case netadr_port: + adr->port = ntohs(params[arg_value] & 0xFFFF); // cap short + break; + case netadr_ip: + *(size_t *)adr->ip = htonl(params[arg_value] & 0xFFFFFFFF); // cap int + break; + default: + return FALSE; + } + + return TRUE; +} + +/* +* Returns a NetAdr var +* +* @param var The specified mvar, look at the enum NetAdrVars +* +* @return If an integer or boolean or one byte, array or everything else is passed via the 3rd argument and more, look at the argument list for the specified mvar +* +* native any:get_netadr(const adr, const NetAdrVars:var, any:...); +*/ +cell AMX_NATIVE_CALL get_netadr(AMX *amx, cell *params) +{ + enum args_e { arg_count, arg_adr, arg_var, arg_3, arg_4 }; + member_t *member = memberlist[params[arg_var]]; + + if (unlikely(member == nullptr)) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: unknown member id %i", __FUNCTION__, params[arg_var]); + return FALSE; + } + + netadr_t *adr = (netadr_t *)params[arg_adr]; + if (unlikely(adr == nullptr)) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: Invalid network address", __FUNCTION__); + return FALSE; + } + + switch (params[arg_var]) + { + case netadr_type: return adr->type; + case netadr_port: return ntohs(adr->port); + case netadr_ip: + { + if (PARAMS_COUNT == 4) + { + cell *dest = getAmxAddr(amx, params[arg_3]); + size_t length = *getAmxAddr(amx, params[arg_4]); + setAmxString(dest, NET_AdrToString(*adr, true /*no port*/), length); + } + + return htonl(*(size_t *)adr->ip); + } + default: + break; + } + + return FALSE; +} + /* * Sets a RebuyStruct member. * @@ -757,6 +847,9 @@ AMX_NATIVE_INFO ReGameVars_Natives[] = { "set_pmtrace", set_pmtrace }, { "get_pmtrace", get_pmtrace }, + { "set_netadr", set_netadr }, + { "get_netadr", get_netadr }, + { nullptr, nullptr } }; @@ -1029,6 +1122,7 @@ void *get_pdata_custom(CBaseEntity *pEntity, cell member) { const auto table = memberlist_t::members_tables_e(member / MAX_REGION_RANGE); switch (table) { + case memberlist_t::mt_csentity: case memberlist_t::mt_csplayer: case memberlist_t::mt_csplayerweapon: { if (unlikely(pEntity->m_pEntity == nullptr)) { diff --git a/reapi/src/natives/natives_misc.cpp b/reapi/src/natives/natives_misc.cpp index d06a1224..4aa53b4d 100644 --- a/reapi/src/natives/natives_misc.cpp +++ b/reapi/src/natives/natives_misc.cpp @@ -542,8 +542,9 @@ cell AMX_NATIVE_CALL rg_update_teamscores(AMX *amx, cell *params) * * @param classname Entity classname * @param useHashTable Use this only for known game entities -* -* @note: Do not use this if you use a custom classname +* @note: Do not use this if you plan to change custom classname an entity after creation, +* otherwise it will never be release from hash table even if an entity was destroyed, +* and that to lead table to inflate/memory leaks * * @return Index of the created entity or 0 otherwise * @@ -752,6 +753,8 @@ cell AMX_NATIVE_CALL rg_has_item_by_name(AMX *amx, cell *params) * @param weapon name or id Weapon id, see WEAPON_* constants, WeaponIdType or weapon_* name * @param WpnInfo:type Info type, see WI_* constants * +* @note weapon_* name can only be used to get WI_ID +* * @return Weapon information * @error If weapon_id or type are out of bounds, an error will be thrown * @@ -902,58 +905,35 @@ cell AMX_NATIVE_CALL rg_set_weapon_info(AMX *amx, cell *params) /* * Remove all the player's stuff in a specific slot. * -* @param index Client index -* @param slot The slot that will be emptied +* @param index Client index +* @param slot The slot that will be emptied +* @param removeAmmo Remove ammunition * -* @return 1 on success, 0 otherwise +* @return 1 - successful removal of all items in the slot or the slot is empty +* 0 - if at least one item failed to remove * -* native rg_remove_items_by_slot(const index, const InventorySlotType:slot); +* native rg_remove_items_by_slot(const index, const InventorySlotType:slot, const bool:removeAmmo = true); */ cell AMX_NATIVE_CALL rg_remove_items_by_slot(AMX *amx, cell *params) { - enum args_e { arg_count, arg_index, arg_slot }; + enum args_e { arg_count, arg_index, arg_slot, arg_remammo }; CHECK_ISPLAYER(arg_index); CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_index]); CHECK_CONNECTED(pPlayer, arg_index); - if (params[arg_slot] == C4_SLOT) - { - pPlayer->CSPlayer()->RemovePlayerItemEx("weapon_c4", true); - } - else - { - pPlayer->ForEachItem(params[arg_slot], [pPlayer](CBasePlayerItem *pItem) - { - if (pItem->IsWeapon()) { - if (pItem == pPlayer->m_pActiveItem) { - ((CBasePlayerWeapon *)pItem)->RetireWeapon(); - } - - pPlayer->m_rgAmmo[ pItem->PrimaryAmmoIndex() ] = 0; - } - - if (pPlayer->RemovePlayerItem(pItem)) { - pPlayer->pev->weapons &= ~(1 << pItem->m_iId); - - // No more weapon - if ((pPlayer->pev->weapons & ~(1 << WEAPON_SUIT)) == 0) { - pPlayer->m_iHideHUD |= HIDEHUD_WEAPONS; - } - - pItem->Kill(); - } - - return false; - }); + bool success = true; - if (!pPlayer->m_rgpPlayerItems[PRIMARY_WEAPON_SLOT]) { - pPlayer->m_bHasPrimary = false; - } - } + pPlayer->ForEachItem(params[arg_slot], [&](CBasePlayerItem *pItem) + { + // Compatible with older versions of the plugin, + // which still only pass two parameters + success &= pPlayer->CSPlayer()->RemovePlayerItemEx(STRING(pItem->pev->classname), (PARAMS_COUNT < 3 || params[arg_remammo] != 0)) ? true : false; + return false; + }); - return TRUE; + return success ? TRUE : FALSE; } /* @@ -962,7 +942,8 @@ cell AMX_NATIVE_CALL rg_remove_items_by_slot(AMX *amx, cell *params) * @param index Client index * @param slot Specific slot for remove of each item. * -* @return 1 on success, 0 otherwise +* @return 1 - successful drop of all items in the slot or the slot is empty +* 0 - if at least one item failed to drop * * native rg_drop_items_by_slot(const index, const InventorySlotType:slot); */ @@ -975,12 +956,14 @@ cell AMX_NATIVE_CALL rg_drop_items_by_slot(AMX *amx, cell *params) CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_index]); CHECK_CONNECTED(pPlayer, arg_index); - pPlayer->ForEachItem(params[arg_slot], [pPlayer](CBasePlayerItem *pItem) { - pPlayer->CSPlayer()->DropPlayerItem(STRING(pItem->pev->classname)); + bool success = true; + + pPlayer->ForEachItem(params[arg_slot], [&](CBasePlayerItem *pItem) { + success &= pPlayer->CSPlayer()->DropPlayerItem(STRING(pItem->pev->classname)) ? true : false; return false; }); - return TRUE; + return success ? TRUE : FALSE; } /* @@ -1010,9 +993,9 @@ cell AMX_NATIVE_CALL rg_remove_all_items(AMX *amx, cell *params) * Forces the player to drop the specified item classname. * * @param index Client index -* @param item_name Item classname +* @param item_name Item classname, if no name, the active item classname * -* @return 1 on success, 0 otherwise +* @return Entity index of weaponbox, AMX_NULLENT (-1) otherwise * * native rg_drop_item(const index, const item_name[]); */ @@ -1026,8 +1009,12 @@ cell AMX_NATIVE_CALL rg_drop_item(AMX *amx, cell *params) CHECK_CONNECTED(pPlayer, arg_index); char item[256]; - pPlayer->CSPlayer()->DropPlayerItem(getAmxString(amx, params[arg_item_name], item)); - return TRUE; + auto pEntity = pPlayer->CSPlayer()->DropPlayerItem(getAmxString(amx, params[arg_item_name], item)); + + if (pEntity) + return indexOfPDataAmx(pEntity); + + return AMX_NULLENT; } /* @@ -1258,6 +1245,10 @@ cell AMX_NATIVE_CALL rg_give_defusekit(AMX *amx, cell *params) return FALSE; } + if (pPlayer->m_iTeam != CT) { + return FALSE; + } + pPlayer->m_bHasDefuser = params[arg_def] ? true : false; pPlayer->pev->body = params[arg_def] ? 1 : 0; @@ -1584,10 +1575,11 @@ cell AMX_NATIVE_CALL rg_get_user_footsteps(AMX *amx, cell *params) * @param index Client index * @param receiver Receiver index, if 0 it will transfer to a random player * -* @return 1 on success, 0 otherwise +* @return Index of player entity if successfull, 0 otherwise * * native rg_transfer_c4(const index, const receiver = 0); */ + cell AMX_NATIVE_CALL rg_transfer_c4(AMX *amx, cell *params) { enum args_e { arg_count, arg_index, arg_receiver }; @@ -1598,29 +1590,50 @@ cell AMX_NATIVE_CALL rg_transfer_c4(AMX *amx, cell *params) CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_index]); CHECK_CONNECTED(pPlayer, arg_index); - if (!pPlayer->m_bHasC4 || !pPlayer->CSPlayer()->RemovePlayerItem("weapon_c4")) + if (!pPlayer->m_bHasC4) { return FALSE; + } - pPlayer->pev->body = 0; - pPlayer->m_bHasC4 = false; - pPlayer->CSPlayer()->SetBombIcon(); - pPlayer->CSPlayer()->SetProgressBarTime(0); + CBasePlayer *pReceiver = nullptr; - if (params[arg_receiver] != 0 && params[arg_receiver] <= gpGlobals->maxClients) { - CBasePlayer *pReceiver = UTIL_PlayerByIndex(params[arg_receiver]); + if (params[arg_receiver] > 0 && params[arg_receiver] <= gpGlobals->maxClients) { + pReceiver = UTIL_PlayerByIndex(params[arg_receiver]); CHECK_CONNECTED(pReceiver, arg_receiver); - if (!pReceiver->CSPlayer()->MakeBomber()) + if (!pPlayer->CSPlayer()->RemovePlayerItemEx("weapon_c4", true)) { return FALSE; + } + + if (!pReceiver->CSPlayer()->MakeBomber()) { + return FALSE; + } + } + else { + int NumDeadCT, NumDeadTerrorist, NumAliveTerrorist, NumAliveCT; + CSGameRules()->InitializePlayerCounts(NumAliveTerrorist, NumAliveCT, NumDeadTerrorist, NumDeadCT); + + if (pPlayer->m_iTeam == CT && NumAliveTerrorist < 1) { + return FALSE; + } + + if (pPlayer->m_iTeam == TERRORIST && NumAliveTerrorist < 2) { + return FALSE; + } + + if (!pPlayer->CSPlayer()->RemovePlayerItemEx("weapon_c4", true)) { + return FALSE; + } - } else { auto flags = pPlayer->pev->flags; pPlayer->pev->flags |= FL_DORMANT; - CSGameRules()->GiveC4(); + pReceiver = CSGameRules()->GiveC4(); pPlayer->pev->flags = flags; } - return TRUE; + if (pReceiver) + return indexOfPDataAmx(pReceiver); + + return FALSE; } /* @@ -2023,7 +2036,7 @@ cell AMX_NATIVE_CALL rg_send_bartime(AMX *amx, cell *params) * * @noreturn * -* native rg_send_bartime2(const index, const duration, const startPercent, const bool:observer = true); +* native rg_send_bartime2(const index, const duration, const Float:startPercent, const bool:observer = true); */ cell AMX_NATIVE_CALL rg_send_bartime2(AMX *amx, cell *params) { @@ -2033,15 +2046,16 @@ cell AMX_NATIVE_CALL rg_send_bartime2(AMX *amx, cell *params) CHECK_CONNECTED(pPlayer, arg_index); CAmxArgs args(amx, params); + float startPercent = args[arg_start_percent]; if (!args[arg_observer]) { EMESSAGE_BEGIN(MSG_ONE_UNRELIABLE, gmsgBarTime2, nullptr, pPlayer->edict()); EWRITE_SHORT(args[arg_time]); - EWRITE_SHORT(args[arg_start_percent]); + EWRITE_SHORT(startPercent); EMESSAGE_END(); return TRUE; } - pPlayer->CSPlayer()->SetProgressBarTime2(args[arg_time], args[arg_start_percent]); + pPlayer->CSPlayer()->SetProgressBarTime2(args[arg_time], startPercent); return TRUE; } @@ -2237,6 +2251,136 @@ cell AMX_NATIVE_CALL rg_get_iteminfo(AMX *amx, cell *params) return TRUE; } +/** +* Sets a parameter of the global CBasePlayerItem::m_ItemInfoArray array +* @note To have effect on client side (i.g. ammo size on HUD) you should +* alter this value BEFORE WeaponList message is sent to client, or +* force it's alteration by sending again to the specific client. +* Hooking WeaponList message with AMXX's register_message is a choice. +* +* @param weapon_id Weapon id, see WEAPON_* constants +* @param type Item info type. See ItemInfo constants. +* +* native rg_set_global_iteminfo(const {WeaponIdType,_}:weapon_id, ItemInfo:type, any:...); +*/ +cell AMX_NATIVE_CALL rg_set_global_iteminfo(AMX *amx, cell *params) +{ + enum args_e { arg_count, arg_weapon_id, arg_type, arg_value }; + + WeaponIdType weaponId = static_cast(params[arg_weapon_id]); + if (!GetWeaponInfoRange(weaponId, false)) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid weapon id %i", __FUNCTION__, weaponId); + return FALSE; + } + + ItemInfo* II = g_ReGameApi->GetItemInfo(weaponId); + + char itembuf[256]; + cell *ptr = getAmxAddr(amx, params[arg_value]); + + ItemInfo_e type = static_cast(params[arg_type]); + switch (type) + { + case ItemInfo_iSlot: II->iSlot = *ptr; break; + case ItemInfo_iPosition: II->iPosition = *ptr; break; + case ItemInfo_iMaxAmmo1: II->iMaxAmmo1 = *ptr; break; + case ItemInfo_iMaxAmmo2: II->iMaxAmmo2 = *ptr; break; + case ItemInfo_iMaxClip: II->iMaxClip = *ptr; break; + case ItemInfo_iId: II->iId = *ptr; break; + case ItemInfo_iFlags: II->iFlags = *ptr; break; + case ItemInfo_iWeight: II->iWeight = *ptr; break; + case ItemInfo_pszAmmo1: II->pszAmmo1 = STRING(getAmxStringAlloc(amx, params[arg_value], itembuf)); break; + case ItemInfo_pszAmmo2: II->pszAmmo2 = STRING(getAmxStringAlloc(amx, params[arg_value], itembuf)); break; + case ItemInfo_pszName: II->pszName = STRING(getAmxStringAlloc(amx, params[arg_value], itembuf)); break; + + default: + AMXX_LogError(amx, AMX_ERR_NATIVE, "Unknown ItemInfo type %d", type); + return FALSE; + } + + return TRUE; +} + +/** +* Gets a parameter of the global CBasePlayerItem::m_ItemInfoArray array +* +* @param weapon_id Weapon id, see WEAPON_* constants +* @param type Item info type. See ItemInfo constants. +* +* native rg_get_global_iteminfo(const {WeaponIdType,_}:weapon_id, ItemInfo:type, any:...); +*/ +cell AMX_NATIVE_CALL rg_get_global_iteminfo(AMX *amx, cell *params) +{ + enum args_e { arg_count, arg_weapon_id, arg_type, arg_output, arg_length }; + + WeaponIdType weaponId = static_cast(params[arg_weapon_id]); + if (!GetWeaponInfoRange(weaponId, false)) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid weapon id %i", __FUNCTION__, weaponId); + return FALSE; + } + + ItemInfo_e type = static_cast(params[arg_type]); + if ((type == ItemInfo_pszAmmo1 || type == ItemInfo_pszAmmo2 || type == ItemInfo_pszName) && PARAMS_COUNT != 4) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "Bad arg count. Expected %d, got %d.", 4, PARAMS_COUNT); + return FALSE; + } + + ItemInfo* II = g_ReGameApi->GetItemInfo(weaponId); + + cell *dest = getAmxAddr(amx, params[arg_output]); + size_t length = (PARAMS_COUNT == 4) ? *getAmxAddr(amx, params[arg_length]) : 0; + + switch (type) + { + case ItemInfo_iSlot: return II->iSlot; + case ItemInfo_iPosition: return II->iPosition; + case ItemInfo_iMaxAmmo1: return II->iMaxAmmo1; + case ItemInfo_iMaxAmmo2: return II->iMaxAmmo2; + case ItemInfo_iMaxClip: return II->iMaxClip; + case ItemInfo_iId: return II->iId; + case ItemInfo_iFlags: return II->iFlags; + case ItemInfo_iWeight: return II->iWeight; + case ItemInfo_pszAmmo1: + { + if (II->pszAmmo1 == nullptr) { + setAmxString(dest, "", 1); + break; + } + + setAmxString(dest, II->pszAmmo1, length); + break; + } + case ItemInfo_pszAmmo2: + { + if (II->pszAmmo2 == nullptr) { + setAmxString(dest, "", 1); + break; + } + + setAmxString(dest, II->pszAmmo2, length); + break; + } + case ItemInfo_pszName: + { + if (II->pszName == nullptr) { + setAmxString(dest, "", 1); + break; + } + + setAmxString(dest, II->pszName, length); + break; + } + default: + AMXX_LogError(amx, AMX_ERR_NATIVE, "Unknown ItemInfo type %d", type); + return FALSE; + } + + return TRUE; +} + /* * Adds hint message to the queue. * @@ -2468,99 +2612,728 @@ cell AMX_NATIVE_CALL rg_spawn_random_gibs(AMX* amx, cell* params) return TRUE; } -AMX_NATIVE_INFO Misc_Natives_RG[] = +/* +* Spawn a grenade (HEGrenade, Flashbang, SmokeGrenade, or C4) +* +* @param weaponId WEAPON_HEGRENADE, WEAPON_SMOKEGRENADE, WEAPON_FLASHBANG or WEAPON_C4 +* @param pevOwner Grenade owner +* @param vecSrc Grenade spawn position +* @param vecThrow Grenade velocity vector +* @param time Grenade explosion time +* @param iTeam Grenade team, see TEAM_* constants +* @param usEvent Event index related to grenade (returned value of precache_event) +* +* @return Entity index on success, AMX_NULLENT (-1) otherwise +*/ +cell AMX_NATIVE_CALL rg_spawn_grenade(AMX* amx, cell* params) { - { "rg_set_animation", rg_set_animation }, - { "rg_add_account", rg_add_account }, - { "rg_give_item", rg_give_item }, - { "rg_give_custom_item", rg_give_custom_item }, - { "rg_give_default_items", rg_give_default_items }, - { "rg_give_shield", rg_give_shield }, - - { "rg_dmg_radius", rg_dmg_radius }, - { "rg_multidmg_clear", rg_multidmg_clear }, - { "rg_multidmg_apply", rg_multidmg_apply }, - { "rg_multidmg_add", rg_multidmg_add }, + enum args_e { arg_count, arg_weapon_id, arg_index, arg_origin, arg_velocity, arg_time, arg_team, arg_event }; - { "rg_fire_bullets", rg_fire_bullets }, - { "rg_fire_buckshots", rg_fire_buckshots }, - { "rg_fire_bullets3", rg_fire_bullets3 }, + CHECK_ISPLAYER(arg_index); - { "rg_round_end", rg_round_end }, - { "rg_update_teamscores", rg_update_teamscores }, + CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_index]); + CHECK_CONNECTED(pPlayer, arg_index); - { "rg_create_entity", rg_create_entity }, - { "rg_find_ent_by_class", rg_find_ent_by_class }, - { "rg_find_ent_by_owner", rg_find_ent_by_owner }, - { "rg_find_weapon_bpack_by_name", rg_find_weapon_bpack_by_name }, - { "rg_has_item_by_name", rg_has_item_by_name }, + CAmxArgs args(amx, params); - { "rg_get_weapon_info", rg_get_weapon_info }, - { "rg_set_weapon_info", rg_set_weapon_info }, + CGrenade *pBomb = g_ReGameFuncs->SpawnGrenade(args[arg_weapon_id], + pPlayer->pev, + args[arg_origin], + args[arg_velocity], + args[arg_time], + args[arg_team], + args[arg_event]); - { "rg_remove_items_by_slot", rg_remove_items_by_slot }, - { "rg_drop_items_by_slot", rg_drop_items_by_slot }, + // Sanity check anyway + if (pBomb) + return indexOfPDataAmx(pBomb); - { "rg_remove_all_items", rg_remove_all_items }, - { "rg_remove_item", rg_remove_item }, - { "rg_drop_item", rg_drop_item }, - { "rg_internal_cmd", rg_internal_cmd }, + return AMX_NULLENT; +} - { "rg_give_defusekit", rg_give_defusekit }, +/* +* Spawn a weaponbox entity with its properties +* +* @param pItem Weapon entity index to attach +* @param pPlayerOwner Player index to remove pItem entity (0 = no weapon owner) +* @param modelName Model name ("models/w_*.mdl") +* @param origin Weaponbox origin position +* @param angles Weaponbox angles +* @param velocity Weaponbox initial velocity vector +* @param lifeTime Time to stay in world (< 0.0 = use mp_item_staytime cvar value) +* @param packAmmo Set if ammo should be removed from weapon owner +* +* @return Weaponbox ent index on success, AMX_NULLENT (-1) otherwise +*/ +cell AMX_NATIVE_CALL rg_create_weaponbox(AMX* amx, cell* params) +{ + enum args_e { arg_count, arg_item, arg_player, arg_modelname, arg_origin, arg_angles, arg_velocity, arg_lifetime, arg_packammo }; - { "rg_set_user_bpammo", rg_set_user_bpammo }, - { "rg_get_user_bpammo", rg_get_user_bpammo }, - { "rg_set_user_ammo", rg_set_user_ammo }, - { "rg_get_user_ammo", rg_get_user_ammo }, + CHECK_ISENTITY(arg_item); - { "rg_get_user_armor", rg_get_user_armor }, - { "rg_set_user_armor", rg_set_user_armor }, - { "rg_set_user_team", rg_set_user_team }, - { "rg_set_user_model", rg_set_user_model }, - { "rg_reset_user_model", rg_reset_user_model }, + CBasePlayerItem *pItem = getPrivate(params[arg_item]); + if (unlikely(pItem == nullptr)) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__); + return FALSE; + } + + CBasePlayer *pPlayer = nullptr; - { "rg_set_user_footsteps", rg_set_user_footsteps }, - { "rg_get_user_footsteps", rg_get_user_footsteps }, + if (params[arg_player] != 0) + { + CHECK_ISPLAYER(arg_player); - { "rg_transfer_c4", rg_transfer_c4 }, - { "rg_instant_reload_weapons", rg_instant_reload_weapons }, - { "rg_plant_bomb", rg_plant_bomb }, + pPlayer = getPrivate(params[arg_player]); + CHECK_CONNECTED(pPlayer, arg_player); + } - { "rg_set_account_rules", rg_set_account_rules }, - { "rg_get_account_rules", rg_get_account_rules }, + CAmxArgs args(amx, params); - { "rg_is_bomb_planted", rg_is_bomb_planted }, - { "rg_join_team", rg_join_team }, - { "rg_balance_teams", rg_balance_teams }, - { "rg_swap_all_players", rg_swap_all_players }, - { "rg_switch_team", rg_switch_team }, - { "rg_switch_weapon", rg_switch_weapon }, - { "rg_get_join_team_priority", rg_get_join_team_priority }, - { "rg_is_player_can_takedamage", rg_is_player_can_takedamage }, - { "rg_is_player_can_respawn", rg_is_player_can_respawn }, - { "rg_get_weaponbox_id", rg_get_weaponbox_id }, - { "rg_round_respawn", rg_round_respawn }, - { "rg_reset_maxspeed", rg_reset_maxspeed }, + char modelStr[MAX_PATH]; + const char *modelName = getAmxString(amx, params[arg_modelname], modelStr); + CWeaponBox *pBox = g_ReGameFuncs->CreateWeaponBox(pItem, pPlayer, modelName, args[arg_origin], args[arg_angles], args[arg_velocity], args[arg_lifetime], args[arg_packammo]); - { "rg_send_bartime", rg_send_bartime }, - { "rg_send_bartime2", rg_send_bartime2 }, - { "rg_send_audio", rg_send_audio }, + if (pBox) + return indexOfPDataAmx(pBox); - { "rg_set_iteminfo", rg_set_iteminfo }, - { "rg_get_iteminfo", rg_get_iteminfo }, + return AMX_NULLENT; +} - { "rg_hint_message", rg_hint_message }, +/* +* Removes an entity using gamedll's UTIL_Remove function, which sets a frame delay to ensure its removal. +* +* @param pEntity Entity index to remove +* +* @return 1 on success, 0 otherwise +*/ +cell AMX_NATIVE_CALL rg_remove_entity(AMX* amx, cell* params) +{ + enum args_e { arg_count, arg_entity }; - { "rg_restart_round", rg_restart_round }, - { "rg_check_win_conditions", rg_check_win_conditions }, - { "rg_initialize_player_counts", rg_initialize_player_counts }, + CHECK_ISENTITY(arg_entity); - { "rg_reset_can_hear_player", rg_reset_can_hear_player }, - { "rg_set_can_hear_player", rg_set_can_hear_player }, - { "rg_get_can_hear_player", rg_get_can_hear_player }, + auto pEntity = getPrivate(params[arg_entity]); + if (!pEntity || (pEntity->pev->flags & FL_KILLME) != 0) + { + return FALSE; + } - { "rg_spawn_head_gib", rg_spawn_head_gib }, - { "rg_spawn_random_gibs", rg_spawn_random_gibs }, + g_ReGameFuncs->UTIL_Remove(pEntity); + + if ((pEntity->pev->flags & FL_KILLME) != 0) + { + return TRUE; + } + + return FALSE; +} + +/* +* Creates a Decal in world based on a traceresult. +* +* @param ptr Traceresult pointer, use Fakemeta's create_tr2 to instantiate one +* @param decalNumber Number of decal to spray, see DECAL_ constants on cssdk_const.inc +* +* @noreturn +*/ +cell AMX_NATIVE_CALL rg_decal_trace(AMX* amx, cell* params) +{ + enum args_e { arg_count, arg_trace, arg_decal }; + + CAmxArgs args(amx, params); + g_ReGameFuncs->UTIL_DecalTrace(args[arg_trace], args[arg_decal]); + return TRUE; +} + +/* +* Emits a sound based on a traceresult simulating a bullet hit (metal, wood, concrete, etc.). +* @note Used mostly on trace attacks (bullets, knife). +* +* @param ptr Traceresult pointer, use Fakemeta's create_tr2 to instantiate one +* @param vecSrc Start position +* @param vecEnd End position, must match ptr's vecEndPos member +* @param iBulletType Bullet type, see BULLET_* constants in cssdk_const.inc +* +* @noreturn +*/ +cell AMX_NATIVE_CALL rg_emit_texture_sound(AMX* amx, cell* params) +{ + enum args_e { arg_count, arg_trace, arg_start, arg_end, arg_bullet_type }; + + CAmxArgs args(amx, params); + g_ReGameFuncs->TextureTypePlaySound(args[arg_trace], args[arg_start], args[arg_end], args[arg_bullet_type]); + return TRUE; +} + +/* +* Generates an ammo slot in game's logic +* @note To see a visual effect, WeaponList message should be sent using the custom ammo name, +* where ammo icon HUD will be the one listed in "sprites/weapon_.txt" file. +* +* @param szAmmoname Ammo name to create. +* +* @note Maximum ammo index is 31, after that every ammo instantiation will start from 1 overriding existing ones. +* @return New ammo index. If name already exists, will return the matched index from memory. +*/ +cell AMX_NATIVE_CALL rg_add_ammo_registry(AMX* amx, cell* params) +{ + enum args_e { arg_count, arg_ammoname }; + + char ammonamebuf[190]; + string_t ammoname = getAmxStringAlloc(amx, params[arg_ammoname], ammonamebuf); + + if (!ammonamebuf || ammonamebuf[0] == '\0') + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: empty ammo name", __FUNCTION__); + return FALSE; + } + + return (cell)g_ReGameFuncs->AddAmmoNameToAmmoRegistry(STRING(ammoname)); +} + +/* +* Deploys a weapon attached to a player using the CBasePlayerWeapon::DefaultDeploy function. +* +* @param entity Weapon to deploy. Must be attached to a player. +* @param szViewModel Weapon view model name ("models/v_*.mdl") +* @param szWeaponModel Weapon world model bame ("models/p_*.mdl") +* @param iAnim Weapon view model animation to play (often "deploy", use HLMV to see anim index) +* @param szAnimExt Player anim extension name to assign. Examples: "carbine", "shotgun", "knife", etc. +* Use HLMV on a player model to see animext names. +* @param skiplocal If 0, weapon animation will be forced to play on client ignoring active client prediction. +* +* @return 1 on successful weapon deploy, 0 otherwise. +*/ +cell AMX_NATIVE_CALL rg_weapon_deploy(AMX* amx, cell* params) +{ + enum args_e { arg_count, arg_weapon, arg_viewmodel, arg_weaponmodel, arg_anim, arg_animextension, arg_skiplocal }; + + CHECK_ISENTITY(arg_weapon); + CBasePlayerWeapon *pWeapon = getPrivate(params[arg_weapon]); + + if (unlikely(pWeapon == nullptr)) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__); + return FALSE; + } + + if (!pWeapon->IsWeapon()) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); + return FALSE; + } + + CCSPlayerWeapon *pCSWeapon = pWeapon->CSPlayerWeapon(); + if (unlikely(pCSWeapon == nullptr)) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized m_pEntity.", __FUNCTION__); + return FALSE; + } + + char viewmodelbuffer[MAX_PATH], weaponmodelbuffer[MAX_PATH], animextbuffer[32]; + getAmxString(amx, params[arg_viewmodel], viewmodelbuffer); + getAmxString(amx, params[arg_weaponmodel], weaponmodelbuffer); + getAmxString(amx, params[arg_animextension], animextbuffer); + + return pCSWeapon->DefaultDeploy(viewmodelbuffer, weaponmodelbuffer, (int)params[arg_anim], animextbuffer, (int)params[arg_skiplocal]) ? TRUE : FALSE; +} + +/* +* Reloads a weapon or a player's active weapon using the CBasePlayerWeapon::DefaultReload function. +* +* @param entity Weapon to reload (> MaxPlayers) OR player index to reload his current active weapon (>= 1 & <= MaxPlayers). +* @param iClipSize Weapon max clip to check. 0 = weapon max clip stored in ItemInfo +* @param iAnim Weapon view model animation to play (often "reload", use HLMV to see anim index) +* @param fDelay Player reload duration before clip refill. +* +* @return 1 on successful weapon reload, 0 otherwise. +*/ +cell AMX_NATIVE_CALL rg_weapon_reload(AMX* amx, cell* params) +{ + enum args_e { arg_count, arg_weapon, arg_clipsize, arg_anim, arg_delay }; + + CBasePlayerWeapon *pWeapon; + + if (params[arg_weapon] > 0 && params[arg_weapon] <= gpGlobals->maxClients) + { + CHECK_ISPLAYER(arg_weapon); + CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_weapon]); + CHECK_CONNECTED(pPlayer, arg_weapon); + + if (!pPlayer->IsAlive()) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %d not alive", __FUNCTION__, params[arg_weapon]); + return FALSE; + } + + pWeapon = static_cast(pPlayer->m_pActiveItem); + } + else + { + CHECK_ISENTITY(arg_weapon); + + pWeapon = getPrivate(params[arg_weapon]); + } + + if (unlikely(pWeapon == nullptr)) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__); + return FALSE; + } + + if (!pWeapon->IsWeapon()) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); + return FALSE; + } + + CCSPlayerWeapon *pCSWeapon = pWeapon->CSPlayerWeapon(); + if (unlikely(pCSWeapon == nullptr)) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized m_pEntity.", __FUNCTION__); + return FALSE; + } + + CAmxArgs args(amx, params); + + int clipsize = args[arg_clipsize]; + + if (clipsize <= 0) + clipsize = pWeapon->CSPlayerItem()->m_ItemInfo.iMaxClip; + + return pCSWeapon->DefaultReload(clipsize, args[arg_anim], args[arg_delay]) ? TRUE : FALSE; +} + +/* +* Forces shotgun reload thinking on a weapon or a player's active weapon using the CBasePlayerWeapon::DefaultShotgunReload function. +* +* @param entity Weapon to reload (> MaxClients) OR player index to reload his current active weapon (>= 1 & <= MaxClients). +* @param iAnim Weapon view model "insert" animation to play (use HLMV to see anim index) +* @param iStartAnim Weapon view model "start reload" animation to play (use HLMV to see anim index) +* @param fDelay Delay between each buckshot inserted +* @param fStartDelay Delay before buckshots insertion starts +* @param pszReloadSound1 Sound to play on every insertion +* @param pszReloadSound2 Another sound to play on every insertion +* +* @note This is used inside weapon's Reload function and is often called every frame player is pressing IN_RELOAD button. +* @return 1 while weapon not in delay and with ammo remaining to load, 0 otherwise. +*/ +cell AMX_NATIVE_CALL rg_weapon_shotgun_reload(AMX* amx, cell* params) +{ + enum args_e { arg_count, arg_weapon, arg_anim, arg_startanim, arg_delay, arg_startdelay, arg_reloadsound1, arg_reloadsound2 }; + + CBasePlayerWeapon *pWeapon; + + if (params[arg_weapon] > 0 && params[arg_weapon] <= gpGlobals->maxClients) + { + CHECK_ISPLAYER(arg_weapon); + CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_weapon]); + CHECK_CONNECTED(pPlayer, arg_weapon); + + if (!pPlayer->IsAlive()) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %d not alive", __FUNCTION__, params[arg_weapon]); + return FALSE; + } + + pWeapon = static_cast(pPlayer->m_pActiveItem); + } + else + { + CHECK_ISENTITY(arg_weapon); + + pWeapon = getPrivate(params[arg_weapon]); + } + + if (unlikely(pWeapon == nullptr)) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__); + return FALSE; + } + + if (!pWeapon->IsWeapon()) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); + return FALSE; + } + + CCSPlayerWeapon *pCSWeapon = pWeapon->CSPlayerWeapon(); + if (unlikely(pCSWeapon == nullptr)) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized m_pEntity.", __FUNCTION__); + return FALSE; + } + + CAmxArgs args(amx, params); + + char sound1buffer[MAX_PATH], sound2buffer[MAX_PATH]; + const char *reloadsound1 = getAmxString(amx, params[arg_reloadsound1], sound1buffer); + const char *reloadsound2 = getAmxString(amx, params[arg_reloadsound2], sound2buffer); + + return pCSWeapon->DefaultShotgunReload(args[arg_anim], args[arg_startanim], args[arg_delay], args[arg_startdelay], reloadsound1, reloadsound2) ? TRUE : FALSE; +} + +/* +* Sends a weapon animation using the CBasePlayerWeapon::SendWeaponAnim function. +* +* @param entity Weapon to send animation on owner (> MaxClients) OR player index to send animation (>= 1 & <= MaxClients). +* @param iAnim Weapon view model animation to play (use HLMV to see anim index) +* @param skiplocal If 0, weapon animation will be forced to play on client ignoring active client prediction. +* +* @noreturn +*/ +cell AMX_NATIVE_CALL rg_weapon_send_animation(AMX* amx, cell* params) +{ + enum args_e { arg_count, arg_weapon, arg_anim, arg_skiplocal }; + + CBasePlayerWeapon *pWeapon; + + if (params[arg_weapon] > 0 && params[arg_weapon] <= gpGlobals->maxClients) + { + CHECK_ISPLAYER(arg_weapon); + CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_weapon]); + CHECK_CONNECTED(pPlayer, arg_weapon); + + if (!pPlayer->IsAlive()) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %d not alive", __FUNCTION__, params[arg_weapon]); + return FALSE; + } + + pWeapon = static_cast(pPlayer->m_pActiveItem); + } + else + { + CHECK_ISENTITY(arg_weapon); + + pWeapon = getPrivate(params[arg_weapon]); + } + + if (unlikely(pWeapon == nullptr)) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__); + return FALSE; + } + + if (!pWeapon->IsWeapon()) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); + return FALSE; + } + + CCSPlayerWeapon *pCSWeapon = pWeapon->CSPlayerWeapon(); + if (unlikely(pCSWeapon == nullptr)) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized m_pEntity.", __FUNCTION__); + return FALSE; + } + + CAmxArgs args(amx, params); + + pCSWeapon->SendWeaponAnim(args[arg_anim], args[arg_skiplocal]); + return TRUE; +} + +/* +* Emits a "recoil" effect on weapon's player using the CBasePlayerWeapon::KickBack function. +* +* @param entity Weapon to reload (> MaxClients) OR player index to reload his current active weapon (>= 1 & <= MaxClients). +* @param up_base Minimum vertical punchangle +* @param lateral_base Minimum horizontal punchangle +* @param up_modifier Vertical punchangle units to multiply to m_iShotsFired member +* @param lateral_modifier Horizontal punchangle units to multiply to m_iShotsFired member +* @param up_max Maximum vertical punchangle +* @param lateral_max Maximum horizontal punchangle +* @param direction_change Probability to change punchangle orientation (positive or negative). 0 = 100% (1/1), 1 = 50% (1/2), 2 = 33.3% (1/3), ... +* +* @noreturn +*/ +cell AMX_NATIVE_CALL rg_weapon_kickback(AMX* amx, cell* params) +{ + enum args_e { arg_count, arg_weapon, arg_up_base, arg_lateral_base, arg_up_modifier, arg_lateral_modifier, arg_up_max, arg_lateral_max, arg_direction_change }; + + CBasePlayerWeapon *pWeapon; + + if (params[arg_weapon] > 0 && params[arg_weapon] <= gpGlobals->maxClients) + { + CHECK_ISPLAYER(arg_weapon); + CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_weapon]); + CHECK_CONNECTED(pPlayer, arg_weapon); + + if (!pPlayer->IsAlive()) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %d not alive", __FUNCTION__, params[arg_weapon]); + return FALSE; + } + + pWeapon = static_cast(pPlayer->m_pActiveItem); + } + else + { + CHECK_ISENTITY(arg_weapon); + + pWeapon = getPrivate(params[arg_weapon]); + } + + if (unlikely(pWeapon == nullptr)) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__); + return FALSE; + } + + if (!pWeapon->IsWeapon()) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); + return FALSE; + } + + CCSPlayerWeapon *pCSWeapon = pWeapon->CSPlayerWeapon(); + if (unlikely(pCSWeapon == nullptr)) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized m_pEntity.", __FUNCTION__); + return FALSE; + } + + CAmxArgs args(amx, params); + + pCSWeapon->KickBack(args[arg_up_base], args[arg_lateral_base], args[arg_up_modifier], args[arg_lateral_modifier], args[arg_up_max], args[arg_lateral_max], args[arg_direction_change]); + return TRUE; +} + +/* +* Switches player current weapon into the best one on its inventory using the CHalfLifeMultiplay::GetNextBestWeapon function. +* +* @param player Player index. +* @param currentWeapon Current player active weapon. 0 = retrieve from m_pActiveItem member +* +* @note Weapon selection is based on weapon's Weight attribute from ItemInfo structure. +* @return 1 if weapon was found and switched to, 0 otherwise +*/ +cell AMX_NATIVE_CALL rg_switch_best_weapon(AMX* amx, cell* params) +{ + enum args_e { arg_count, arg_index, arg_weapon }; + + CHECK_GAMERULES(); + + CHECK_ISPLAYER(arg_index); + + CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_index]); + CHECK_CONNECTED(pPlayer, arg_index); + + if (!pPlayer->IsAlive()) + return FALSE; + + CBasePlayerWeapon *pWeapon; + + if (params[arg_weapon] != 0) + { + CHECK_ISENTITY(arg_weapon); + + pWeapon = getPrivate(params[arg_weapon]); + + if (unlikely(pWeapon == nullptr)) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__); + return FALSE; + } + + if (!pWeapon->IsWeapon()) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: #%d entity is not a weapon.", __FUNCTION__, indexOfEdict(pWeapon->pev)); + return FALSE; + } + } + else + { + pWeapon = static_cast(pPlayer->m_pActiveItem); + + if (unlikely(pWeapon == nullptr)) { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %d has invalid m_pActiveItem", __FUNCTION__, params[arg_index]); + return FALSE; + } + } + + return CSGameRules()->GetNextBestWeapon(pPlayer, pWeapon); +} + +/* +* Disappear a player from the world. Used when VIP reaches escape zone. Basically a silent kill. +* +* @param player Player index. +* +* @noreturn +*/ +cell AMX_NATIVE_CALL rg_disappear(AMX* amx, cell* params) +{ + enum args_e { arg_count, arg_index }; + + CHECK_ISPLAYER(arg_index) + + CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_index]); + CHECK_CONNECTED(pPlayer, arg_index); + + pPlayer->CSPlayer()->Disappear(); + return TRUE; +} + +/* +* Sets player current Observer mode. +* @note Player must be a valid observer (m_afPhysicsFlags & PFLAG_OBSERVER). +* +* @param player Player index. +* @param mode Observer mode, see OBS_* constants in cssdk_const.inc +* +* @noreturn +*/ +cell AMX_NATIVE_CALL rg_set_observer_mode(AMX* amx, cell* params) +{ + enum args_e { arg_count, arg_index, arg_mode }; + + CHECK_ISPLAYER(arg_index) + + CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_index]); + CHECK_CONNECTED(pPlayer, arg_index); + + pPlayer->CSPlayer()->Observer_SetMode((int)params[arg_mode]); + return TRUE; +} + +/* +* Emits a death notice (logs, DeathMsg event, win conditions check) +* +* @param pVictim Player index. +* @param pKiller Killer entity. +* @param pevInflictor Inflictor entity. 0 = world +* +* @noreturn +*/ +cell AMX_NATIVE_CALL rg_death_notice(AMX* amx, cell* params) +{ + enum args_e { arg_count, arg_victim, arg_killer, arg_inflictor }; + + CHECK_GAMERULES(); + + CHECK_ISPLAYER(arg_victim) + + CBasePlayer *pPlayer = UTIL_PlayerByIndex(params[arg_victim]); + CHECK_CONNECTED(pPlayer, arg_victim); + + CHECK_ISENTITY(arg_killer) + + CAmxArgs args(amx, params); + CSGameRules()->DeathNotice(pPlayer, args[arg_killer], args[arg_inflictor]); + return TRUE; +} + +AMX_NATIVE_INFO Misc_Natives_RG[] = +{ + { "rg_set_animation", rg_set_animation }, + { "rg_add_account", rg_add_account }, + { "rg_give_item", rg_give_item }, + { "rg_give_custom_item", rg_give_custom_item }, + { "rg_give_default_items", rg_give_default_items }, + { "rg_give_shield", rg_give_shield }, + + { "rg_dmg_radius", rg_dmg_radius }, + { "rg_multidmg_clear", rg_multidmg_clear }, + { "rg_multidmg_apply", rg_multidmg_apply }, + { "rg_multidmg_add", rg_multidmg_add }, + + { "rg_fire_bullets", rg_fire_bullets }, + { "rg_fire_buckshots", rg_fire_buckshots }, + { "rg_fire_bullets3", rg_fire_bullets3 }, + + { "rg_round_end", rg_round_end }, + { "rg_update_teamscores", rg_update_teamscores }, + + { "rg_create_entity", rg_create_entity }, + { "rg_find_ent_by_class", rg_find_ent_by_class }, + { "rg_find_ent_by_owner", rg_find_ent_by_owner }, + { "rg_find_weapon_bpack_by_name", rg_find_weapon_bpack_by_name }, + { "rg_has_item_by_name", rg_has_item_by_name }, + + { "rg_get_weapon_info", rg_get_weapon_info }, + { "rg_set_weapon_info", rg_set_weapon_info }, + + { "rg_remove_items_by_slot", rg_remove_items_by_slot }, + { "rg_drop_items_by_slot", rg_drop_items_by_slot }, + + { "rg_remove_all_items", rg_remove_all_items }, + { "rg_remove_item", rg_remove_item }, + { "rg_drop_item", rg_drop_item }, + { "rg_internal_cmd", rg_internal_cmd }, + + { "rg_give_defusekit", rg_give_defusekit }, + + { "rg_set_user_bpammo", rg_set_user_bpammo }, + { "rg_get_user_bpammo", rg_get_user_bpammo }, + { "rg_set_user_ammo", rg_set_user_ammo }, + { "rg_get_user_ammo", rg_get_user_ammo }, + + { "rg_get_user_armor", rg_get_user_armor }, + { "rg_set_user_armor", rg_set_user_armor }, + { "rg_set_user_team", rg_set_user_team }, + { "rg_set_user_model", rg_set_user_model }, + { "rg_reset_user_model", rg_reset_user_model }, + + { "rg_set_user_footsteps", rg_set_user_footsteps }, + { "rg_get_user_footsteps", rg_get_user_footsteps }, + + { "rg_transfer_c4", rg_transfer_c4 }, + { "rg_instant_reload_weapons", rg_instant_reload_weapons }, + { "rg_plant_bomb", rg_plant_bomb }, + + { "rg_set_account_rules", rg_set_account_rules }, + { "rg_get_account_rules", rg_get_account_rules }, + + { "rg_is_bomb_planted", rg_is_bomb_planted }, + { "rg_join_team", rg_join_team }, + { "rg_balance_teams", rg_balance_teams }, + { "rg_swap_all_players", rg_swap_all_players }, + { "rg_switch_team", rg_switch_team }, + { "rg_switch_weapon", rg_switch_weapon }, + { "rg_get_join_team_priority", rg_get_join_team_priority }, + { "rg_is_player_can_takedamage", rg_is_player_can_takedamage }, + { "rg_is_player_can_respawn", rg_is_player_can_respawn }, + { "rg_get_weaponbox_id", rg_get_weaponbox_id }, + { "rg_round_respawn", rg_round_respawn }, + { "rg_reset_maxspeed", rg_reset_maxspeed }, + + { "rg_send_bartime", rg_send_bartime }, + { "rg_send_bartime2", rg_send_bartime2 }, + { "rg_send_audio", rg_send_audio }, + + { "rg_set_iteminfo", rg_set_iteminfo }, + { "rg_get_iteminfo", rg_get_iteminfo }, + { "rg_set_global_iteminfo", rg_set_global_iteminfo }, + { "rg_get_global_iteminfo", rg_get_global_iteminfo }, + + { "rg_hint_message", rg_hint_message }, + + { "rg_restart_round", rg_restart_round }, + { "rg_check_win_conditions", rg_check_win_conditions }, + { "rg_initialize_player_counts", rg_initialize_player_counts }, + + { "rg_reset_can_hear_player", rg_reset_can_hear_player }, + { "rg_set_can_hear_player", rg_set_can_hear_player }, + { "rg_get_can_hear_player", rg_get_can_hear_player }, + + { "rg_spawn_head_gib", rg_spawn_head_gib }, + { "rg_spawn_random_gibs", rg_spawn_random_gibs }, + + { "rg_spawn_grenade", rg_spawn_grenade }, + { "rg_create_weaponbox", rg_create_weaponbox }, + { "rg_remove_entity", rg_remove_entity }, + { "rg_decal_trace", rg_decal_trace }, + { "rg_emit_texture_sound", rg_emit_texture_sound }, + { "rg_add_ammo_registry", rg_add_ammo_registry }, + { "rg_weapon_deploy", rg_weapon_deploy }, + { "rg_weapon_reload", rg_weapon_reload }, + { "rg_weapon_shotgun_reload", rg_weapon_shotgun_reload }, + { "rg_weapon_send_animation", rg_weapon_send_animation }, + { "rg_weapon_kickback", rg_weapon_kickback }, + { "rg_switch_best_weapon", rg_switch_best_weapon }, + { "rg_disappear", rg_disappear }, + { "rg_set_observer_mode", rg_set_observer_mode }, + { "rg_death_notice", rg_death_notice }, { nullptr, nullptr } }; @@ -2728,7 +3501,7 @@ cell AMX_NATIVE_CALL rh_drop_client(AMX *amx, cell *params) * * @param output Buffer to copy the ip address * @param len Maximum buffer size -* +* * @noreturn * * native rh_get_net_from(output[], len); @@ -2738,13 +3511,38 @@ cell AMX_NATIVE_CALL rh_get_net_from(AMX* amx, cell* params) enum args_e { arg_count, arg_output, arg_maxlen }; cell *dest = getAmxAddr(amx, params[arg_output]); - char *addr = NET_AdrToString(*g_RehldsData->GetNetFrom()); + const char *addr = NET_AdrToString(*g_RehldsData->GetNetFrom()); setAmxString(dest, addr, params[arg_maxlen]); - + return TRUE; } +/* +* Returns client's netchan playing time in seconds. +* +* @param index Client index +* +* @return Netchan connection time in seconds or 0 if client index is invalid or client is not connected +* +* native rh_get_client_connect_time(const index); +*/ +cell AMX_NATIVE_CALL rh_get_client_connect_time(AMX *amx, cell *params) +{ + enum args_e { arg_count, arg_index }; + + CHECK_ISPLAYER(arg_index); + + client_t *pClient = clientOfIndex(params[arg_index]); + if (unlikely(pClient == nullptr || !(pClient->active | pClient->spawned | pClient->connected))) + { + AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %i is not connected", __FUNCTION__, params[arg_index]); + return FALSE; + } + + return (cell)(g_RehldsFuncs->GetRealTime() - pClient->netchan.connect_time); +} + AMX_NATIVE_INFO Misc_Natives_RH[] = { { "rh_set_mapname", rh_set_mapname }, @@ -2755,6 +3553,8 @@ AMX_NATIVE_INFO Misc_Natives_RH[] = { "rh_drop_client", rh_drop_client }, { "rh_get_net_from", rh_get_net_from }, + { "rh_get_client_connect_time", rh_get_client_connect_time }, + { nullptr, nullptr } }; diff --git a/reapi/src/natives/natives_reunion.cpp b/reapi/src/natives/natives_reunion.cpp index 3437b4aa..4dad5789 100644 --- a/reapi/src/natives/natives_reunion.cpp +++ b/reapi/src/natives/natives_reunion.cpp @@ -36,6 +36,36 @@ cell AMX_NATIVE_CALL REU_GetAuthtype(AMX *amx, cell *params) return g_ReunionApi->GetClientAuthtype(params[arg_index] - 1); } +/* +* Get client authkey +* +* @param index Client index +* @param index Buffer to copy the authkey +* @param index Maximum buffer size +* +* @return Number of cells copied to buffer +* +* native REU_GetAuthKey(const index, dest[], maxlen); +*/ +cell AMX_NATIVE_CALL REU_GetAuthKey(AMX *amx, cell *params) +{ + enum args_e { arg_count, arg_index, arg_output, arg_maxlen }; + + CHECK_ISPLAYER(arg_index); + + int clientId = params[arg_index] - 1; + + char buffer[256]; + size_t size = g_ReunionApi->GetClientAuthdata(clientId, buffer, sizeof buffer); + if (size <= 0) + return 0; + + size_t numToCopy = min(size, params[arg_maxlen]); + cell *dest = getAmxAddr(amx, params[arg_output]); + setAmxString(dest, buffer, numToCopy); + return numToCopy; +} + /* * Check if the client is running RevEmu with limited user rights. * @@ -70,6 +100,7 @@ AMX_NATIVE_INFO Reunion_Natives[] = { { "REU_GetProtocol", REU_GetProtocol }, { "REU_GetAuthtype", REU_GetAuthtype }, + { "REU_GetAuthKey", REU_GetAuthKey }, { "REU_IsRevemuWithoutAdminRights", REU_IsRevemuWithoutAdminRights }, { nullptr, nullptr } diff --git a/reapi/src/precompiled.h b/reapi/src/precompiled.h index 742ef8c9..e9a4ae4d 100644 --- a/reapi/src/precompiled.h +++ b/reapi/src/precompiled.h @@ -9,6 +9,7 @@ // C++ #include // std::vector +#include // std::list // platform defs #include "platform.h" @@ -60,7 +61,7 @@ #include "api_config.h" #include "hook_manager.h" #include "hook_callback.h" -#include "entity_callback.h" +#include "entity_callback_dispatcher.h" #include "member_list.h" // natives diff --git a/reapi/src/reapi_utils.cpp b/reapi/src/reapi_utils.cpp index 2d30416e..ade7779a 100644 --- a/reapi/src/reapi_utils.cpp +++ b/reapi/src/reapi_utils.cpp @@ -97,7 +97,7 @@ CBaseEntity *GiveNamedItemInternal(AMX *amx, CBasePlayer *pPlayer, const char *p return pEntity; } -void StudioFrameAdvanceEnt(edict_t *pEdict) +void StudioFrameAdvanceEnt(studiohdr_t *pstudiohdr, edict_t *pEdict) { float flInterval = gpGlobals->time - pEdict->v.animtime; if (flInterval <= 0.001f) { @@ -109,10 +109,8 @@ void StudioFrameAdvanceEnt(edict_t *pEdict) flInterval = 0.0f; } - studiohdr_t *pstudiohdr = static_cast(GET_MODEL_PTR(pEdict)); - if (!pstudiohdr) { + if (!pstudiohdr) return; - } if (pEdict->v.sequence >= pstudiohdr->numseq || pEdict->v.sequence < 0) { return; @@ -160,14 +158,25 @@ void GetBonePosition(CBaseEntity *pEntity, int iBone, Vector *pVecOrigin, Vector Vector vecOrigin, vecAngles; edict_t *pEdict = pEntity->edict(); + if (pVecOrigin) *pVecOrigin = Vector(0, 0, 0); + if (pVecAngles) *pVecAngles = Vector(0, 0, 0); + + studiohdr_t *pstudiohdr = static_cast(GET_MODEL_PTR(pEdict)); + if (!pstudiohdr) + return; + + if (iBone < 0 || iBone >= pstudiohdr->numbones) + return; // invalid bone + // force to update frame - StudioFrameAdvanceEnt(pEdict); + StudioFrameAdvanceEnt(pstudiohdr, pEdict); pEntity->pev->angles.x = -pEntity->pev->angles.x; GET_BONE_POSITION(pEdict, iBone, vecOrigin, vecAngles); pEntity->pev->angles.x = -pEntity->pev->angles.x; - if (!pEntity->IsPlayer()) { + // ReGameDLL already have fixes angles for non-players entities + if (!g_ReGameApi && !pEntity->IsPlayer()) { FixupAngles(pEdict, vecOrigin); } @@ -180,17 +189,28 @@ void GetBonePosition(CBaseEntity *pEntity, int iBone, Vector *pVecOrigin, Vector } } -void GetAttachment(CBaseEntity *pEntity, int iBone, Vector *pVecOrigin, Vector *pVecAngles) +void GetAttachment(CBaseEntity *pEntity, int iAttachment, Vector *pVecOrigin, Vector *pVecAngles) { Vector vecOrigin, vecAngles; edict_t *pEdict = pEntity->edict(); + if (pVecOrigin) *pVecOrigin = Vector(0, 0, 0); + if (pVecAngles) *pVecAngles = Vector(0, 0, 0); + + studiohdr_t *pstudiohdr = static_cast(GET_MODEL_PTR(pEdict)); + if (!pstudiohdr) + return; + + if (iAttachment < 0 || iAttachment >= pstudiohdr->numattachments) + return; // invalid attachment + // force to update frame - StudioFrameAdvanceEnt(pEdict); + StudioFrameAdvanceEnt(pstudiohdr, pEdict); - GET_ATTACHMENT(pEdict, iBone, vecOrigin, vecAngles); + GET_ATTACHMENT(pEdict, iAttachment, vecOrigin, vecAngles); - if (!pEntity->IsPlayer()) { + // ReGameDLL already have fixes angles for non-players entities + if (!g_ReGameApi && !pEntity->IsPlayer()) { FixupAngles(pEdict, vecOrigin); } @@ -203,6 +223,74 @@ void GetAttachment(CBaseEntity *pEntity, int iBone, Vector *pVecOrigin, Vector * } } +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) @@ -232,7 +320,8 @@ const char *getATypeStr(AType type) "ATYPE_EDICT", "ATYPE_EVARS", "ATYPE_BOOL", - "ATYPE_VECTOR" + "ATYPE_VECTOR", + "ATYPE_TRACE" }; if (type >= arraysize(s_ATypes)) @@ -241,7 +330,7 @@ const char *getATypeStr(AType type) return s_ATypes[type]; } -char* NET_AdrToString(const netadr_t& a) +const char *NET_AdrToString(const netadr_t &a, bool onlyBase) { static char s[64]; @@ -249,8 +338,14 @@ char* NET_AdrToString(const netadr_t& a) if (a.type == NA_LOOPBACK) Q_snprintf(s, sizeof(s), "loopback"); + else if (a.type == NA_IP) - Q_snprintf(s, sizeof(s), "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port)); + { + if (onlyBase) + Q_snprintf(s, sizeof(s), "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]); + else + Q_snprintf(s, sizeof(s), "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port)); + } #ifdef _WIN32 else // NA_IPX Q_snprintf(s, sizeof(s), "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%i", a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], ntohs(a.port)); diff --git a/reapi/src/reapi_utils.h b/reapi/src/reapi_utils.h index 994864c3..b8d3a4c0 100644 --- a/reapi/src/reapi_utils.h +++ b/reapi/src/reapi_utils.h @@ -53,12 +53,15 @@ ModelName GetModelAuto(TeamName team); void UTIL_ServerPrint(const char *fmt, ...); CBaseEntity *GiveNamedItemInternal(AMX *amx, CBasePlayer *pPlayer, const char *pszItemName, const size_t uid = 0); -void GetBonePosition(CBaseEntity *pEntity, int iBone, Vector *vecOrigin, Vector *vecAngles); -void GetAttachment(CBaseEntity *pEntity, int iBone, Vector *pVecOrigin, Vector *pVecAngles); +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); -char *NET_AdrToString(const netadr_t& a); +const char *NET_AdrToString(const netadr_t &a, bool onlyBase = false); extern void NORETURN UTIL_SysError(const char *fmt, ...); diff --git a/reapi/version/version.h b/reapi/version/version.h index ba22bb75..721f2b48 100644 --- a/reapi/version/version.h +++ b/reapi/version/version.h @@ -6,5 +6,5 @@ #pragma once #define VERSION_MAJOR 5 -#define VERSION_MINOR 21 +#define VERSION_MINOR 24 #define VERSION_MAINTENANCE 0