#include #include #include #include #define PLUGIN_NAME "Throw grenade camera" #define PLUGIN_VERSION "1.0" #define PLUGIN_AUTHOR "Denzer" new const THROW_GRENADE_CAMERA_MODEL[] = "models/rpgrocket.mdl"; new const THROW_GRENADE_CAMERA_CLASSNAME[] = "throw_grenade_camera"; enum _:ThrowData_s { THROW_ENTITY_ID, bool:THROW_CAMERA_ON }; new g_eThrowData[MAX_PLAYERS + 1][ThrowData_s]; new g_iFollowPlayer[33] public plugin_precache() { precache_model(THROW_GRENADE_CAMERA_MODEL); } public plugin_init() { register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR); register_clcmd("+follow", "followGrenade") register_impulse(100, "followGrenade") RegisterHookChain(RG_RoundEnd, "RoundEnd_Post", true); RegisterHookChain(RG_CBasePlayer_ThrowGrenade, "CBasePlayer_ThrowGrenade_Post", true); RegisterHookChain(RG_CGrenade_ExplodeHeGrenade, "CGrenade_Explode_Post", true); RegisterHookChain(RG_CGrenade_ExplodeFlashbang, "CGrenade_Explode_Post", true); RegisterHookChain(RG_CGrenade_ExplodeSmokeGrenade, "CGrenade_Explode_Post", true); RegisterHookChain(RG_CBasePlayer_Observer_IsValidTarget, "CBasePlayer_Observer_IsValidTarget_Pre", false); CreateCams(); } public client_putinserver(id) { g_eThrowData[id][THROW_CAMERA_ON] = false; g_iFollowPlayer[id] = 0 } public followGrenade(id) { if((get_user_team(id) >= 3) && (get_user_flags(id) & ADMIN_KICK) && g_iFollowPlayer[id]) { SetCamThrow(id, g_iFollowPlayer[id]); g_iFollowPlayer[id] = 0 } } CreateCams() { for (new i = 1; i <= MaxClients; i++) { // https://github.com/alliedmodders/amxmodx/blob/9bcabfeb1f774439475313c30fb3fe256870268f/modules/engine/engine.cpp#L495-L515 new iEnt = g_eThrowData[i][THROW_ENTITY_ID] = rg_create_entity("info_target"); if (is_nullent(iEnt)) { continue; } engfunc(EngFunc_SetModel, iEnt, THROW_GRENADE_CAMERA_MODEL); set_entvar(iEnt, var_classname, THROW_GRENADE_CAMERA_CLASSNAME); set_entvar(iEnt, var_rendermode, kRenderTransColor); set_entvar(iEnt, var_renderamt, 0); set_entvar(iEnt, var_renderfx, kRenderFxNone); set_entvar(iEnt, var_solid, SOLID_NOT); set_entvar(iEnt, var_movetype, MOVETYPE_NOCLIP); } } public RoundEnd_Post() { for (new i = 1; i <= MaxClients; i++) { new iEnt = g_eThrowData[i][THROW_ENTITY_ID]; ResetCamThrow(i, iEnt); } } public CBasePlayer_ThrowGrenade_Post(const index) { new this = GetHookChainReturn(ATYPE_INTEGER); for (new i = 1; i <= MaxClients; i++) { if (i == index) { continue; } if (!is_user_connected(i)) { continue; } if((get_entvar(i, var_iuser2) != index) || !(get_user_flags(i) & ADMIN_KICK)) continue; g_iFollowPlayer[i] = this } } public CGrenade_Explode_Post(this) { new iEnt = MaxClients+1; while ((iEnt = rg_find_ent_by_class(iEnt, THROW_GRENADE_CAMERA_CLASSNAME))) { if (get_entvar(iEnt, var_owner) == this) { new id = get_entvar(iEnt, var_chain); ResetCamThrow(id, iEnt); } } } public CBasePlayer_Observer_IsValidTarget_Pre(const this, iPlayerIndex, bool:bSameTeam) { if (g_eThrowData[this][THROW_CAMERA_ON]) { SetHookChainArg(2, ATYPE_INTEGER, 0); } return HC_CONTINUE; } SetCamThrow(id, grenade) { if (g_eThrowData[id][THROW_CAMERA_ON]) { return; } new iEnt = g_eThrowData[id][THROW_ENTITY_ID]; g_eThrowData[id][THROW_CAMERA_ON] = true; set_entvar(iEnt, var_owner, grenade); set_entvar(iEnt, var_chain, id); set_entvar(iEnt, var_nextthink, get_gametime() + 0.01); SetThink(iEnt, "ThinkThrowCamera"); attach_view(id, iEnt); } public ThinkThrowCamera(iEnt) { if (is_nullent(iEnt)) { return; } new this = get_entvar(iEnt, var_owner); if (is_nullent(this)) { return; } new Float:flOrigin[3]; get_entvar(this, var_origin, flOrigin); new Float:flViewOfs[3]; get_entvar(this, var_view_ofs, flViewOfs); flOrigin[2] += flViewOfs[2]; new Float:flAngles[3]; get_entvar(this, var_angles, flAngles); flAngles[0] = 45.0; new Float:flVector[3]; angle_vector(flAngles, ANGLEVECTOR_FORWARD, flVector); new Float:flCameraOrigin[3]; flCameraOrigin[0] = flOrigin[0] + (-flVector[0] * 100.0); flCameraOrigin[1] = flOrigin[1] + (-flVector[1] * 100.0); flCameraOrigin[2] = flOrigin[2] + (-flVector[2] * 100.0); engfunc(EngFunc_SetOrigin, iEnt, flCameraOrigin); set_entvar(iEnt, var_angles, flAngles) set_entvar(iEnt, var_nextthink, get_gametime() + 0.01); } ResetCamThrow(id, iEnt) { if (is_user_connected(id)) { engset_view(id, id); } g_eThrowData[id][THROW_CAMERA_ON] = false; set_entvar(iEnt, var_nextthink, get_gametime()); SetThink(iEnt, ""); } /* public camera_follow_grenade(id, grenade) { new Float:origin[3]; new Float:spec_origin[3]; new Float:velocity[3]; new Float:angles[3]; entity_get_vector(grenade, EV_VEC_origin, origin); entity_get_vector(grenade, EV_VEC_velocity, velocity); new Float:speed = xs_vec_len(velocity); if (speed < 5.0) { return PLUGIN_CONTINUE; } xs_vec_copy(origin, spec_origin); xs_vec_div_scalar(velocity, speed, velocity); // https://github.com/s1lentq/ReGameDLL_CS/blob/f57d28fe721ea4d57d10c010d15d45f05f2f5bad/regamedll/dlls/wpn_shared/wpn_flashbang.cpp#L191 // Max grenade speed should be 750 speed = 100 + 0.2 * speed; xs_vec_add_scaled(spec_origin, velocity, -1.0 * speed, spec_origin); spec_origin[2] += 10.0; new trace; new Float:fraction; engfunc(EngFunc_TraceLine, origin, spec_origin, IGNORE_MONSTERS, 0, trace); get_tr2(trace, TR_flFraction, fraction); if (fraction < 1.0) { spec_origin[0] += velocity[0] * speed * (1 - (fraction * 0.8)); spec_origin[1] += velocity[1] * speed * (1 - (fraction * 0.8)); spec_origin[2] += velocity[2] * speed * (1 - (fraction * 0.8)); } new Float:dir[3]; xs_vec_sub(origin, spec_origin, dir); vector_to_angle(dir, angles); angles[0] *= -1.0; observer_set_mode(id, OBS_ROAMING); entity_set_origin(id, spec_origin); entity_set_vector(id, EV_VEC_angles, angles); entity_set_vector(id, EV_VEC_v_angle, angles); entity_set_vector(id, EV_VEC_punchangle, zeros); entity_set_int(id, EV_INT_fixangle, 1); return PLUGIN_HANDLED; } */