/* AMX Mod X * Barnacle Grapple. * * http://aghl.ru/forum/ - Russian Half-Life and Adrenaline Gamer Community * * This file is provided as is (no warranties) */ #pragma semicolon 1 #pragma ctrlchar '\' #include #include #include #include #include #define PLUGIN "Barnacle Grapple" #define VERSION "1.1" #define AUTHOR "KORD_12.7" // Weapon settings #define WEAPON_NAME "weapon_grapple" #define WEAPON_SLOT 1 #define WEAPON_POSITION 5 #define WEAPON_PRIMARY_AMMO "" // NULL #define WEAPON_PRIMARY_AMMO_MAX -1 #define WEAPON_SECONDARY_AMMO "" // NULL #define WEAPON_SECONDARY_AMMO_MAX -1 #define WEAPON_MAX_CLIP -1 #define WEAPON_DEFAULT_AMMO -1 #define WEAPON_FLAGS 0 #define WEAPON_WEIGHT 21 // Grapple settings #define GRAPPLE_FLY_VELOCITY 1500 #define GRAPPLE_PULL_VELOCITY 400.0 // Hud #define WEAPON_HUD_TXT "sprites/weapon_grapple.txt" #define WEAPON_HUD_SPR "sprites/weapon_grapple.spr" // Models #define MODEL_VIEW "models/v_bgrap_koshak.mdl" #define MODEL_WORLD "models/w_bgrap.mdl" #define MODEL_PLAYER "models/p_bgrap.mdl" #define MODEL_TONGUE_TIP "models/shock_effect.mdl" // Sprites #define SPRITE_TONGUE "sprites/tongue.spr" // Sounds #define SOUND_DRAW "weapons/alienweap_draw.wav" #define SOUND_WAIT "weapons/bgrapple_wait.wav" #define SOUND_PULL "weapons/bgrapple_pull.wav" #define SOUND_FIRE "weapons/bgrapple_fire.wav" #define SOUND_COUGH "weapons/bgrapple_cough.wav" #define SOUND_CHEW_1 "barnacle/bcl_chew1.wav" #define SOUND_CHEW_2 "barnacle/bcl_chew2.wav" #define SOUND_CHEW_3 "barnacle/bcl_chew3.wav" #define SOUND_IMPACT "weapons/bgrapple_impact.wav" #define SOUND_RELEASE "weapons/bgrapple_release.wav" // Animation #define ANIM_EXTENSION "gauss" enum _:GrappleAnim { ANIM_BREATHE = 0, ANIM_LONGIDLE, ANIM_SHORTIDLE, ANIM_COUGH, ANIM_DOWN, ANIM_UP, ANIM_FIRE, ANIM_FIREWAITING, ANIM_FIREREACHED, ANIM_FIRETRAVEL, ANIM_FIRERELEASE }; #define SET_SIZE(%0,%1,%2) engfunc(EngFunc_SetSize,%0,%1,%2) #define SET_ORIGIN(%0,%1) engfunc(EngFunc_SetOrigin,%0,%1) enum { FIRE_OFF, FIRE_CHARGE } #define Offset_iTip Offset_iuser1 #define Offset_iBeam Offset_iuser2 #define Offset_iPull Offset_iuser1 #define Offset_iTarget Offset_iuser2 //********************************************** //* Precache resources * //********************************************** public plugin_precache() { PRECACHE_MODEL(MODEL_VIEW); PRECACHE_MODEL(MODEL_WORLD); PRECACHE_MODEL(MODEL_PLAYER); PRECACHE_MODEL(SPRITE_TONGUE); PRECACHE_MODEL(MODEL_TONGUE_TIP); PRECACHE_SOUND(SOUND_DRAW); PRECACHE_SOUND(SOUND_WAIT); PRECACHE_SOUND(SOUND_PULL); PRECACHE_SOUND(SOUND_FIRE); PRECACHE_SOUND(SOUND_COUGH); PRECACHE_SOUND(SOUND_CHEW_1); PRECACHE_SOUND(SOUND_CHEW_2); PRECACHE_SOUND(SOUND_CHEW_3); PRECACHE_SOUND(SOUND_IMPACT); PRECACHE_SOUND(SOUND_RELEASE); PRECACHE_GENERIC(WEAPON_HUD_TXT); PRECACHE_GENERIC(WEAPON_HUD_SPR); } //********************************************** //* Register weapon. * //********************************************** public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR); new iGrapple = wpnmod_register_weapon ( WEAPON_NAME, WEAPON_SLOT, WEAPON_POSITION, WEAPON_PRIMARY_AMMO, WEAPON_PRIMARY_AMMO_MAX, WEAPON_SECONDARY_AMMO, WEAPON_SECONDARY_AMMO_MAX, WEAPON_MAX_CLIP, WEAPON_FLAGS, WEAPON_WEIGHT ); wpnmod_register_weapon_forward(iGrapple, Fwd_Wpn_Spawn, "Grapple_Spawn"); wpnmod_register_weapon_forward(iGrapple, Fwd_Wpn_Deploy, "Grapple_Deploy"); wpnmod_register_weapon_forward(iGrapple, Fwd_Wpn_PrimaryAttack, "Grapple_PrimaryAttack"); wpnmod_register_weapon_forward(iGrapple, Fwd_Wpn_SecondaryAttack, "Grapple_SecondaryAttack"); wpnmod_register_weapon_forward(iGrapple, Fwd_Wpn_Idle, "Grapple_Idle"); wpnmod_register_weapon_forward(iGrapple, Fwd_Wpn_Holster, "Grapple_Holster"); } //********************************************** //* Weapon spawn. * //********************************************** public Grapple_Spawn(const iItem) { // Setting world model SET_MODEL(iItem, MODEL_WORLD); } //********************************************** //* Deploys the weapon. * //********************************************** public Grapple_Deploy(const iItem) { wpnmod_set_offset_int(iItem, Offset_iFireState, FIRE_OFF); return wpnmod_default_deploy(iItem, MODEL_VIEW, MODEL_PLAYER, ANIM_UP, ANIM_EXTENSION); } //********************************************** //* Called when the weapon is holster. * //********************************************** public Grapple_Holster(const iItem) { Grapple_DestroyEffect(iItem); } //********************************************** //* Displays the idle animation for the weapon.* //********************************************** public Grapple_Idle(const iItem, const iPlayer) { if (wpnmod_get_offset_float(iItem, Offset_flTimeWeaponIdle) > 0.0) { return; } if (wpnmod_get_offset_int(iItem, Offset_iFireState) != FIRE_OFF) { Grapple_EndAttack(iItem, iPlayer); return; } new iAnim; new Float: flRand; new Float: flNextIdle; if ((flRand = random_float(0.0, 1.0)) > 0.5) { if (flRand > 0.95) { iAnim = ANIM_COUGH; flNextIdle = 4.63; } else { iAnim = ANIM_BREATHE; flNextIdle = 2.6; } } else { iAnim = ANIM_LONGIDLE; flNextIdle = 10.03; } wpnmod_send_weapon_anim(iItem, iAnim); wpnmod_set_offset_float(iItem, Offset_flTimeWeaponIdle, flNextIdle); } //********************************************** //* The main attack of a weapon is triggered. * //********************************************** public Grapple_PrimaryAttack(const iItem, const iPlayer) { Grapple_StartAttack(iItem, iPlayer, true); } //********************************************** //* Secondary attack of a weapon is triggered. * //********************************************** public Grapple_SecondaryAttack(const iItem, const iPlayer) { Grapple_StartAttack(iItem, iPlayer, false); } //********************************************** //* Start Grapple attack. * //********************************************** Grapple_StartAttack(const iItem, const iPlayer, const bool: bPull) { static iFireState; static iGrappleTip; static Float: flGameTime; flGameTime = get_gametime(); iFireState = wpnmod_get_offset_int(iItem, Offset_iFireState); iGrappleTip = wpnmod_get_offset_int(iItem, Offset_iTip); wpnmod_set_offset_float(iItem, Offset_flReleaseThrow, bPull ? 0.0 : 1.0); if (iFireState == FIRE_OFF) { set_pev(iPlayer, pev_punchangle, Float: {-2.0, 0.0, 0.0}); wpnmod_send_weapon_anim(iItem, ANIM_FIRE); wpnmod_set_player_anim(iPlayer, PLAYER_ATTACK1); wpnmod_set_offset_int(iItem, Offset_iFireState, FIRE_CHARGE); wpnmod_set_offset_float(iItem, Offset_flTimeWeaponIdle, 0.1); wpnmod_set_offset_float(iItem, Offset_flPumpTime, flGameTime + 0.5); wpnmod_set_offset_float(iItem, Offset_flStartThrow, flGameTime + 0.5); emit_sound(iPlayer, CHAN_WEAPON, SOUND_FIRE, 0.9, ATTN_NORM, 0, PITCH_NORM); } else if (iFireState == FIRE_CHARGE && pev_valid(iGrappleTip)) { if (wpnmod_get_offset_float(iItem, Offset_flStartThrow) < flGameTime) { if (wpnmod_get_offset_int(iGrappleTip, Offset_iPull)) { wpnmod_send_weapon_anim(iItem, ANIM_FIRETRAVEL); wpnmod_set_offset_float(iItem, Offset_flStartThrow, flGameTime + 0.68); } else { wpnmod_send_weapon_anim(iItem, ANIM_FIREWAITING); wpnmod_set_offset_float(iItem, Offset_flStartThrow, flGameTime + 0.24); } } if (wpnmod_get_offset_float(iItem, Offset_flPumpTime) < flGameTime) { emit_sound(iPlayer, CHAN_WEAPON, SOUND_PULL, 0.9, ATTN_NORM, 0, PITCH_NORM); wpnmod_set_offset_float(iItem, Offset_flPumpTime, flGameTime + 0.68); } if (bPull) { Grapple_Stab(iItem, iPlayer); } } Grapple_UpdateEffect(iItem, iPlayer); } //********************************************** //* End Grapple attack. * //********************************************** Grapple_EndAttack(const iItem, const iPlayer) { Grapple_DestroyEffect(iItem); wpnmod_send_weapon_anim(iItem, ANIM_FIRERELEASE); wpnmod_set_offset_int(iItem, Offset_iFireState, FIRE_OFF); wpnmod_set_offset_float(iItem, Offset_flNextPrimaryAttack, 1.0); wpnmod_set_offset_float(iItem, Offset_flNextSecondaryAttack, 1.0); wpnmod_set_offset_float(iItem, Offset_flTimeWeaponIdle, 0.9); emit_sound(iPlayer, CHAN_WEAPON, SOUND_PULL, 0.0, 0.0, SND_STOP, PITCH_NORM); emit_sound(iPlayer, CHAN_WEAPON, SOUND_RELEASE, 0.9, ATTN_NORM, 0, PITCH_NORM); } //********************************************** //* Tongue tip effects. * //********************************************** Grapple_UpdateEffect(const iItem, const iPlayer) { static iTip, iBeam; iTip = wpnmod_get_offset_int(iItem, Offset_iTip); if (!pev_valid(iTip)) { Grapple_CreateEffect(iItem, iPlayer); } iBeam = wpnmod_get_offset_int(iItem, Offset_iBeam); if (pev_valid(iBeam)) { Beam_RelinkBeam(iBeam); } } Grapple_DestroyEffect(const iItem) { new iBeam = wpnmod_get_offset_int(iItem, Offset_iBeam); if (pev_valid(iBeam)) { set_pev(iBeam, pev_flags, FL_KILLME); wpnmod_set_offset_int(iItem, Offset_iBeam, FM_NULLENT); } new iTip = wpnmod_get_offset_int(iItem, Offset_iTip); if (pev_valid(iTip)) { set_pev(iTip, pev_flags, FL_KILLME); wpnmod_set_offset_int(iItem, Offset_iTip, FM_NULLENT); } } Grapple_CreateEffect(const iItem, const iPlayer) { Grapple_DestroyEffect(iItem); new iTip; new iBeam; new Float: vecOrigin[3]; new Float: vecAngles[3]; new Float: vecVelocity[3]; velocity_by_aim(iPlayer, GRAPPLE_FLY_VELOCITY, vecVelocity); wpnmod_get_gun_position(iPlayer, vecOrigin, 16.0, 8.0, -8.0); static iszAllocStringCached; if (iszAllocStringCached || (iszAllocStringCached = engfunc(EngFunc_AllocString, "info_target"))) { iTip = engfunc(EngFunc_CreateNamedEntity, iszAllocStringCached); } if (pev_valid(iTip)) { engfunc(EngFunc_VecToAngles, vecVelocity, vecAngles); set_pev(iTip, pev_classname, "grapple_tip"); set_pev(iTip, pev_solid, SOLID_BBOX); set_pev(iTip, pev_movetype, MOVETYPE_FLY); set_pev(iTip, pev_velocity, vecVelocity); set_pev(iTip, pev_angles, vecAngles); set_pev(iTip, pev_owner, iPlayer); set_pev(iTip, pev_iuser4, iItem); SET_ORIGIN(iTip, vecOrigin); SET_MODEL(iTip, MODEL_TONGUE_TIP); SET_SIZE(iTip, Float: {0.0, 0.0, 0.0}, Float: {0.0, 0.0, 0.0}); wpnmod_set_offset_int(iItem, Offset_iTip, iTip); if (pev_valid((iBeam = Beam_Create(SPRITE_TONGUE, 15.0)))) { set_pev(iBeam, pev_classname, "tongue_beam"); Beam_EntsInit(iBeam, iTip, iPlayer); Beam_SetFlags(iBeam, BEAM_FSOLID); Beam_SetEndAttachment(iBeam, 1); Beam_SetBrightness(iBeam, 100.0); wpnmod_set_offset_int(iItem, Offset_iBeam, iBeam); } wpnmod_set_think(iTip, "GrappleTip_FlyThink"); wpnmod_set_touch(iTip, "GrappleTip_TongueTouch"); set_pev(iTip, pev_nextthink, get_gametime() + 0.1); } } //********************************************** //* Tongue tip think funcs. * //********************************************** public GrappleTip_FlyThink(const iGrappleTip) { static iItem; static iOwner; iItem = pev(iGrappleTip, pev_iuser4); iOwner = pev(iGrappleTip, pev_owner); set_pev(iGrappleTip, pev_nextthink, get_gametime() + 0.1); if (!ExecuteHamB(Ham_IsInWorld, iGrappleTip)) { Grapple_EndAttack(iItem, iOwner); } } public GrappleTip_PullThink(const iGrappleTip) { static iItem; static iOwner; static iTarget; static Float: flDistance; static Float: vecVelocity[3]; static Float: vecPlayerOrigin[3]; static Float: vecGrappleOrigin[3]; iItem = pev(iGrappleTip, pev_iuser4); iOwner = pev(iGrappleTip, pev_owner); iTarget = wpnmod_get_offset_int(iGrappleTip, Offset_iTarget); if (pev_valid(iTarget) && ExecuteHamB(Ham_Classify, iTarget) && !ExecuteHamB(Ham_IsAlive, iTarget)) { Grapple_EndAttack(iItem, iOwner); return; } set_pev(iGrappleTip, pev_nextthink, get_gametime() + 0.1); if (!wpnmod_get_offset_int(iGrappleTip, Offset_iPull) || wpnmod_get_offset_float(iItem, Offset_flReleaseThrow)) { return; } pev(iOwner, pev_origin, vecPlayerOrigin); pev(iGrappleTip, pev_origin, vecGrappleOrigin); flDistance = get_distance_f(vecGrappleOrigin, vecPlayerOrigin); if (flDistance) { xs_vec_sub(vecGrappleOrigin, vecPlayerOrigin, vecGrappleOrigin); xs_vec_mul_scalar(vecGrappleOrigin, GRAPPLE_PULL_VELOCITY / flDistance, vecVelocity); set_pev(iOwner, pev_velocity, vecVelocity); } } //********************************************** //* Tongue tip touch func. * //********************************************** public GrappleTip_TongueTouch(const iGrappleTip, const iOther) { new iHit; new iItem; new iOwner; new szClassName[32]; new szTextureName[13]; new Float: vecOrigin[3]; new Float: vecVelocity[3]; iItem = pev(iGrappleTip, pev_iuser4); iOwner = pev(iGrappleTip, pev_owner); pev(iGrappleTip, pev_origin, vecOrigin); pev(iGrappleTip, pev_velocity, vecVelocity); if (pev(iOther, pev_flags) & (FL_CLIENT | FL_MONSTER)) { iHit = true; set_pev(iGrappleTip, pev_movetype, MOVETYPE_FOLLOW); set_pev(iGrappleTip, pev_skin, iOther); set_pev(iGrappleTip, pev_body, 0); set_pev(iGrappleTip, pev_aiment, iOther); } else { pev(iOther, pev_classname, szClassName, charsmax(szClassName)); if (equali(szClassName, "ammo_spore")) { iHit = true; } else { xs_vec_normalize(vecVelocity, vecVelocity); xs_vec_mul_scalar(vecVelocity, 8.0, vecVelocity); xs_vec_add(vecVelocity, vecOrigin, vecVelocity); engfunc(EngFunc_TraceTexture, iOther, vecOrigin, vecVelocity, szTextureName, charsmax(szTextureName)); if (equali(szTextureName, "xeno_grapple")) { iHit = true; } } } if (!iHit) { Grapple_EndAttack(iItem, iOwner); } else { wpnmod_set_think(iGrappleTip, "GrappleTip_PullThink"); set_pev(iGrappleTip, pev_nextthink, get_gametime() + 0.1); emit_sound(iOwner, CHAN_ITEM, SOUND_IMPACT, 0.9, ATTN_NORM, 0, PITCH_NORM); } set_pev(iGrappleTip, pev_solid, SOLID_NOT); set_pev(iGrappleTip, pev_velocity, Float: {0.0, 0.0, 0.0}); wpnmod_set_offset_int(iGrappleTip, Offset_iPull, iHit); wpnmod_set_offset_int(iGrappleTip, Offset_iTarget, iOther); } //********************************************** //* Make damage to victim. * //********************************************** public Grapple_Stab(const iItem, const iPlayer) { new Float: flDmgTime; new Float: flGameTime = get_gametime(); pev(iItem, pev_dmgtime, flDmgTime); if (flDmgTime > flGameTime) { return; } set_pev(iItem, pev_dmgtime, flGameTime + 0.5); #define Instance(%0) ((%0 == -1) ? 0 : %0) new iTrace; new iTarget; new iEntity; new iGrappleTip; new Float: vecSrc[3]; new Float: vecEnd[3]; new Float: vecAngle[3]; new Float: vecForward[3]; new Float: flFraction; iTrace = create_tr2(); iGrappleTip = wpnmod_get_offset_int(iItem, Offset_iTip); iTarget = wpnmod_get_offset_int(iGrappleTip, Offset_iTarget); pev(iPlayer, pev_origin, vecSrc); pev(iPlayer, pev_v_angle, vecAngle); engfunc(EngFunc_MakeVectors, vecAngle); global_get(glb_v_forward, vecForward); xs_vec_mul_scalar(vecForward, 32.0, vecForward); xs_vec_add(vecForward, vecSrc, vecEnd); engfunc(EngFunc_TraceLine, vecSrc, vecEnd, DONT_IGNORE_MONSTERS, iPlayer, iTrace); get_tr2(iTrace, TR_flFraction, flFraction); if (flFraction >= 1.0) { engfunc(EngFunc_TraceHull, vecSrc, vecEnd, DONT_IGNORE_MONSTERS, HULL_HEAD, iPlayer, iTrace); get_tr2(iTrace, TR_flFraction, flFraction); if (flFraction < 1.0) { new iHit = Instance(get_tr2(iTrace, TR_pHit)); if (!iHit || ExecuteHamB(Ham_IsBSPModel, iHit)) { FindHullIntersection(vecSrc, iTrace, Float: {-16.0, -16.0, -18.0}, Float: {16.0, 16.0, 18.0}, iPlayer); } get_tr2(iTrace, TR_vecEndPos, vecEnd); } } get_tr2(iTrace, TR_flFraction, flFraction); if (flFraction < 1.0) { iEntity = Instance(get_tr2(iTrace, TR_pHit)); if (iEntity && ExecuteHamB(Ham_Classify, iEntity) != CLASS_NONE && iEntity == iTarget) { wpnmod_clear_multi_damage(); pev(iPlayer, pev_v_angle, vecAngle); engfunc(EngFunc_MakeVectors, vecAngle); global_get(glb_v_forward, vecForward); ExecuteHamB(Ham_TraceAttack, iEntity, iPlayer, 50.0, vecForward, iTrace, DMG_SLASH | DMG_ALWAYSGIB); wpnmod_apply_multi_damage(iPlayer, iPlayer); switch (random_num(0, 1)) { case 0: emit_sound(iPlayer, CHAN_ITEM, SOUND_CHEW_1, 1.0, ATTN_NORM, 0, PITCH_NORM); case 1: emit_sound(iPlayer, CHAN_ITEM, SOUND_CHEW_2, 1.0, ATTN_NORM, 0, PITCH_NORM); case 2: emit_sound(iPlayer, CHAN_ITEM, SOUND_CHEW_3, 1.0, ATTN_NORM, 0, PITCH_NORM); } } } free_tr2(iTrace); } //********************************************** //* Some usefull stocks. * //********************************************** stock FindHullIntersection(const Float: vecSrc[3], &iTrace, const Float: vecMins[3], const Float: vecMaxs[3], const iEntity) { new i, j, k; new iTempTrace; new Float: vecEnd[3]; new Float: vecEndPos[3]; new Float: vecHullEnd[3]; new Float: vecMinMaxs[2][3]; new Float: flDistance; new Float: flFraction; new Float: flThisDistance; flDistance = 999999.0; xs_vec_copy(vecMins, vecMinMaxs[0]); xs_vec_copy(vecMaxs, vecMinMaxs[1]); get_tr2(iTrace, TR_vecEndPos, vecHullEnd); xs_vec_sub(vecHullEnd, vecSrc, vecHullEnd); xs_vec_mul_scalar(vecHullEnd, 2.0, vecHullEnd); xs_vec_add(vecHullEnd, vecSrc, vecHullEnd); engfunc(EngFunc_TraceLine, vecSrc, vecHullEnd, DONT_IGNORE_MONSTERS, iEntity, (iTempTrace = create_tr2())); get_tr2(iTempTrace, TR_flFraction, flFraction); if (flFraction < 1.0) { free_tr2(iTrace); iTrace = iTempTrace; return; } for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { for (k = 0; k < 2; k++) { vecEnd[0] = vecHullEnd[0] + vecMinMaxs[i][0]; vecEnd[1] = vecHullEnd[1] + vecMinMaxs[j][1]; vecEnd[2] = vecHullEnd[2] + vecMinMaxs[k][2]; engfunc(EngFunc_TraceLine, vecSrc, vecEnd, DONT_IGNORE_MONSTERS, iEntity, iTempTrace); get_tr2(iTempTrace, TR_flFraction, flFraction); if (flFraction < 1.0) { get_tr2(iTempTrace, TR_vecEndPos, vecEndPos); xs_vec_sub(vecEndPos, vecSrc, vecEndPos); if ((flThisDistance = xs_vec_len(vecEndPos)) < flDistance) { free_tr2(iTrace); iTrace = iTempTrace; flDistance = flThisDistance; } } } } } }