Stat ( goldsrc map sources ), pcs.
weapon_sniperrifle с оптическим прицелом
Исходный код снайперки
weapon_sniperrifle с оптическим прицелом
Author/s of tutorial : Ku2zoff Views : 2300 ( +1 ) Downloads : 0 Uploader : Streit Created : 04/07/2011 8:43:22 PM Source : http://www.hlfx.ru/forum Rating : ( 3.67 ) Share :
Following translations are available : |
russian |
Как я и обещал, я выложил снайперку (weapon_sniperrifle) с оптическим прицелом. Вот она: Добавим в проект файл rifle.cpp
/***
*
* 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.
*
*
*
*
* This weapon written by Ku2zoff
*
*
****/
#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD )
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "weapons.h"
#include "monsters.h"
#include "player.h"
#include "gamerules.h"
#include "shake.h"
#include "nodes.h"
#include "soundent.h"
enum sniperrifle_e {
SNIPERRIFLE_DRAW = 0,
SNIPERRIFLE_SLOWIDLE,
SNIPERRIFLE_FIRE1,
SNIPERRIFLE_FIRELASTROUND,
SNIPERRIFLE_RELOAD,
SNIPERRIFLE_RELOAD2,
SNIPERRIFLE_SLOWIDLEEMPTY,
SNIPERRIFLE_HOLSTER,
};
LINK_ENTITY_TO_CLASS( weapon_sniperrifle, CSniperrifle );
int CSniperrifle::GetItemInfo(ItemInfo *p)
{
p->pszName = STRING(pev->classname);
p->pszAmmo1 = "338";
p->iMaxAmmo1 = _338_MAX_CARRY;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = SNIPERRIFLE_MAX_CLIP;
p->iFlags = 0;
p->iSlot = 2;
p->iPosition = 3;
p->iId = m_iId = WEAPON_SNIPERRIFLE;
p->iWeight = SNIPERRIFLE_WEIGHT;
return 1;
}
int CSniperrifle::AddToPlayer( CBasePlayer *pPlayer )
{
if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) )
{
MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev );
WRITE_BYTE( m_iId );
MESSAGE_END();
return TRUE;
}
return FALSE;
}
void CSniperrifle::Spawn( )
{
pev->classname = MAKE_STRING("weapon_sniperrifle"); // hack to allow for old names
Precache( );
m_iId = WEAPON_SNIPERRIFLE;
SET_MODEL(ENT(pev), "models/w_sniper.mdl");
m_iDefaultAmmo = SNIPERRIFLE_DEFAULT_GIVE;
FallInit();// get ready to fall down.
}
void CSniperrifle::Precache( void )
{
PRECACHE_MODEL("models/v_sniper.mdl");
PRECACHE_MODEL("models/w_sniper.mdl");
PRECACHE_MODEL("models/p_sniper.mdl");
PRECACHE_MODEL("models/w_sniper_clip.mdl");
PRECACHE_SOUND("items/9mmclip1.wav");
PRECACHE_SOUND ("weapons/sniper_cock1.wav");
PRECACHE_SOUND ("weapons/sniper_fire1.wav");
PRECACHE_SOUND ("weapons/sniper_zoomout.wav");
PRECACHE_SOUND ("weapons/sniper_zoomin.wav");
m_usFireSniper = PRECACHE_EVENT( 1, "events/sniper.sc" );
}
BOOL CSniperrifle::Deploy( )
{
return DefaultDeploy( "models/v_sniper.mdl", "models/p_sniper.mdl", SNIPERRIFLE_DRAW, "bow", UseDecrement() );
}
void CSniperrifle::Holster( int skiplocal /* = 0 */ )
{
m_fInReload = FALSE;// cancel any reload in progress.
if ( m_fInZoom )
{
SecondaryAttack();
}
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0;
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
SendWeaponAnim( SNIPERRIFLE_HOLSTER );
}
void CSniperrifle::SecondaryAttack( void )
{
if ( m_pPlayer->pev->fov != 0 )
{
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov
m_fInZoom = 0;
#ifndef CLIENT_DLL
UTIL_ScreenFade( m_pPlayer, Vector(0,0,0), 0.5, 0.25, 255, FFADE_IN );
#endif
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/sniper_zoomout.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0xF));
}
else if ( m_pPlayer->pev->fov != 15 )
{
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 15;
m_fInZoom = 1;
#ifndef CLIENT_DLL
UTIL_ScreenFade( m_pPlayer, Vector(0,0,0), 0.5, 0.25, 255, FFADE_IN );
#endif
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/sniper_zoomin.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0xF));
}
pev->nextthink = UTIL_WeaponTimeBase() + 0.1;
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0;
}
void CSniperrifle::PrimaryAttack( void )
{
Shoot( 0.0001, 1.5, TRUE );
}
void CSniperrifle::Shoot( float flSpread , float flCycleTime, BOOL fUseAutoAim )
{
if (m_pPlayer->pev->waterlevel == 3)
{
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/sniper_cock1.wav", 0.8, ATTN_NORM);
m_flNextPrimaryAttack = 0.15;
return;
}
if (m_iClip <= 0)
{
if (m_fFireOnEmpty)
{
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/sniper_cock1.wav", 0.8, ATTN_NORM);
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2;
}
return;
}
m_iClip--;
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
int flags;
#if defined( CLIENT_WEAPONS )
flags = FEV_NOTHOST;
#else
flags = 0;
#endif
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
Vector vecSrc = m_pPlayer->GetGunPosition( );
Vector vecAiming;
if ( fUseAutoAim )
{
vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );
}
else
{
vecAiming = gpGlobals->v_forward;
}
Vector vecDir;
vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_338, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed );
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), fUseAutoAim ? m_usFireSniper : m_usFireSniper, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 );
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + flCycleTime;
if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
void CSniperrifle::Reload( void )
{
if ( m_fInZoom )
{
SecondaryAttack();
}
if ( m_pPlayer->ammo_338 <= 0 )
return;
if ( m_pPlayer->pev->fov != 0 )
{
m_fInZoom = FALSE;
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov
}
if (m_iClip == 0)
DefaultReload( 10, SNIPERRIFLE_RELOAD, 3.9 );
else
DefaultReload( 10, SNIPERRIFLE_RELOAD2, 2.7 );
}
void CSniperrifle::WeaponIdle( void )
{
m_pPlayer->GetAutoaimVector( AUTOAIM_2DEGREES ); // get the autoaim vector but ignore it; used for autoaim crosshair in DM
if ( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() )
{
float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 );
if (flRand <= 0.75)
{
if (m_iClip)
{
SendWeaponAnim( SNIPERRIFLE_SLOWIDLE );
}
else
{
SendWeaponAnim( SNIPERRIFLE_SLOWIDLEEMPTY );
}
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 60.0 / 12.0;
}
}
}
class CSniperrifleAmmo : public CBasePlayerAmmo
{
void Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_sniper_clip.mdl");
CBasePlayerAmmo::Spawn( );
}
void Precache( void )
{
PRECACHE_MODEL ("models/w_sniper_clip.mdl");
PRECACHE_SOUND("items/9mmclip1.wav");
}
BOOL AddAmmo( CBaseEntity *pOther )
{
if (pOther->GiveAmmo( AMMO_SNIPERRIFLECLIP_GIVE, "338", _338_MAX_CARRY ) != -1)
{
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM);
return TRUE;
}
return FALSE;
}
};
LINK_ENTITY_TO_CLASS( ammo_338, CSniperrifleAmmo );
#endif
Потом открываем game.cpp и аналогично, как было с ножом, добавляем в него:
// Rifle
cvar_t sk_plr_snpr_bullet1 = {"sk_plr_snpr_bullet1","0"};
cvar_t sk_plr_snpr_bullet2 = {"sk_plr_snpr_bullet2","0"};
cvar_t sk_plr_snpr_bullet3 = {"sk_plr_snpr_bullet3","0"};
Затем спускаемся ниже и добавляем:
// Rifle
CVAR_REGISTER ( &sk_plr_snpr_bullet1 );// {"sk_plr_bullet1","0"};
CVAR_REGISTER ( &sk_plr_snpr_bullet2 );// {"sk_plr_bullet2","0"};
CVAR_REGISTER ( &sk_plr_snpr_bullet3 );// {"sk_plr_bullet3","0"};
После этого открываем gamerules.cpp и дописываем:
// Rifle
gSkillData.plrDmgSniper = GetSkillCvar( "sk_plr_snpr_bullet");
Потом в multiplay_gamerules.cpp добавляем:
// Rifle
gSkillData.plrDmgSniper = 100;//значения могут быть любыми, это убойная сила винтовки в мультиплеере
Если вы хотите, чтобы винтовку можно было получить с помощью команды impulse 101, то откройте player.cpp и сделайте следующее:
case 101:
gEvilImpulse101 = TRUE;
GiveNamedItem( "item_suit" );
GiveNamedItem( "item_battery" );
GiveNamedItem( "weapon_crowbar" );
GiveNamedItem( "weapon_9mmhandgun" );
GiveNamedItem( "ammo_9mmclip" );
GiveNamedItem( "weapon_shotgun" );
GiveNamedItem( "ammo_buckshot" );
GiveNamedItem( "weapon_9mmAR" );
GiveNamedItem( "ammo_9mmAR" );
GiveNamedItem( "ammo_ARgrenades" );
GiveNamedItem( "weapon_handgrenade" );
GiveNamedItem( "weapon_tripmine" );
GiveNamedItem( "weapon_knife" );
GiveNamedItem( "weapon_sniperrifle" );//новая строчка
#ifndef OEM_BUILD
Затем в файле skill.h добавьте:
После в weapons.cpp в функцию void W_Precache(void) добавьте
// Rifle
UTIL_PrecacheOtherWeapon( "weapon_sniperrifle" );
UTIL_PrecacheOther( "ammo_338" );
Потом надо добавить новые значения в weapons.h:
#define WEAPON_SNARK 15
#define WEAPON_KNIFE 16
#define WEAPON_SNIPERRIFLE 17//Новая строчка
#define SNARK_WEIGHT -10
#define KNIFE_WEIGHT 10
#define SNIPERRIFLE_WEIGHT 10//Новая строчка
#define TRIPMINE_MAX_CARRY 8
#define SNARK_MAX_CARRY 15
#define HORNET_MAX_CARRY 10
#define M203_GRENADE_MAX_CARRY 10
#define _338_MAX_CARRY 30//Максимум патронов для винтовки
#define SATCHEL_MAX_CLIP WEAPON_NOCLIP
#define TRIPMINE_MAX_CLIP WEAPON_NOCLIP
#define SNARK_MAX_CLIP WEAPON_NOCLIP
#define SNIPERRIFLE_MAX_CLIP 10//Количество патронов в магазине у винтовки
#define TRIPMINE_DEFAULT_GIVE 1
#define SNARK_DEFAULT_GIVE 5
#define HIVEHAND_DEFAULT_GIVE 10
#define SNIPERRIFLE_DEFAULT_GIVE 10//Патроны в магазине только что поднятой винтовки
Далее, разумеется, ещё ниже:
#define AMMO_RPGCLIP_GIVE RPG_MAX_CLIP
#define AMMO_URANIUMBOX_GIVE 20
#define AMMO_SNARKBOX_GIVE 5
#define AMMO_SNIPERRIFLECLIP_GIVE SNIPERRIFLE_MAX_CLIP//Сколько патронов в только что поднятой обойме
И, наконец в самом низу файла нужно вставить вот это:
class CSniperrifle : public CBasePlayerWeapon
{
public:
void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 2; }
int GetItemInfo(ItemInfo *p);
int AddToPlayer( CBasePlayer *pPlayer );
void PrimaryAttack( void );
void SecondaryAttack( void );
BOOL Deploy( void );
void Holster( int skiplocal = 0 );
void Reload( void );
void WeaponIdle( void );
void Shoot( float flSpread, float flCycleTime, BOOL fUseAutoAim );
float m_flSoundDelay;
BOOL m_fInZoom;// don't save this.
virtual BOOL UseDecrement( void )
{
#if defined( CLIENT_WEAPONS )
return TRUE;
#else
return FALSE;
#endif
}
private:
unsigned short m_usFireSniper;
};
Так как винтовка это огнестрельное оружие, надо провести ещё несколько операций, для полной её работоспособности:
Открывем файл cbase.h и добавляем:
int ammo_9mm;
int ammo_357;
int ammo_bolts;
int ammo_buckshot;
int ammo_rockets;
int ammo_uranium;
int ammo_hornets;
int ammo_argrens;
int ammo_338;//Если мы создали для винтовки новые патроны, то придётся повозиться, иначе будут косяки с перезарядкой
После идём в client.cpp и в функции void UpdateClientData делаем так:
cd->ammo_rockets = pl->ammo_rockets;
cd->ammo_cells = pl->ammo_uranium;
cd->vuser2.x = pl->ammo_hornets;
cd->vuser2.y = pl->ammo_338;//Если это не сделать то время от времени у винтовки не будет рисоваться анимация перезарядки
!!!Внимание!!! параметр cd→vuser2.y обязательно должен отличаться от уже имеющихся cd→ammo_rockets, cd→vuser2.x и других подобных им
После этого идём в combat.cpp и добавляем в функцию Vector CBaseEntity::FireBulletsPlayer вот это:
case BULLET_PLAYER_BUCKSHOT:
// make distance based!
pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgBuckshot, vecDir, &tr, DMG_BULLET);
break;
case BULLET_PLAYER_357:
pEntity->TraceAttack(pevAttacker, gSkillData.plrDmg357, vecDir, &tr, DMG_BULLET);
break;
case BULLET_PLAYER_338:
pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgSniper, vecDir, &tr, DMG_BULLET); //Вот она, убойная сила винтовки
break;
После этого открываем player.cpp и дописываем в функцию void CBasePlayer::TabulateAmmo() это:
ammo_rockets = AmmoInventory( GetAmmoIndex( "rockets" ) );
ammo_uranium = AmmoInventory( GetAmmoIndex( "uranium" ) );
ammo_hornets = AmmoInventory( GetAmmoIndex( "Hornets" ) );
ammo_338 = AmmoInventory( GetAmmoIndex( "338" ) );//Патроны снайперки
После спускаемся к коду impulse 101 и дописываем:
#ifndef OEM_BUILD
GiveNamedItem( "weapon_357" );
GiveNamedItem( "ammo_357" );
GiveNamedItem( "weapon_crossbow" );
GiveNamedItem( "ammo_crossbow" );
GiveNamedItem( "weapon_egon" );
GiveNamedItem( "weapon_gauss" );
GiveNamedItem( "ammo_gaussclip" );
GiveNamedItem( "weapon_rpg" );
GiveNamedItem( "ammo_rpgclip" );
GiveNamedItem( "weapon_satchel" );
GiveNamedItem( "weapon_snark" );
GiveNamedItem( "weapon_hornetgun" );
GiveNamedItem( "ammo_338" );//Получаем патроны для винтовки при повторном вводе impulse 101
#endif
После этого нам надо вернуться в weapons.h и добавить:
typedef enum
{
BULLET_NONE = 0,
BULLET_PLAYER_9MM, // glock
BULLET_PLAYER_MP5, // mp5
BULLET_PLAYER_357, // python
BULLET_PLAYER_BUCKSHOT, // shotgun
BULLET_PLAYER_CROWBAR, // crowbar swipe
BULLET_PLAYER_338,//Для винтовки
BULLET_MONSTER_9MM,
BULLET_MONSTER_MP5,
BULLET_MONSTER_12MM,
} Bullet;
С сервером всё, переходим на клиентскую сторону. Примечание редактора: не забудьте и на клиент, в папку хл, добавить файл rifle.cpp пунктом Add Files to Folder… в контекстном меню. В ev_hldm.cpp добавляем:
void EV_EgonStop( struct event_args_s *args );
void EV_HornetGunFire( struct event_args_s *args );
void EV_TripmineFire( struct event_args_s *args );
void EV_SnarkFire( struct event_args_s *args );
void EV_Knife( struct event_args_s *args );
void EV_FireSniper( struct event_args_s *args );//Новая строчка
Потом спускаемся вниз и добавляем новый event:
//======================
// RIFLE START
//======================
enum sniperrifle_e {
SNIPERRIFLE_DRAW = 0,
SNIPERRIFLE_SLOWIDLE,
SNIPERRIFLE_FIRE1,
SNIPERRIFLE_FIRELASTROUND,
SNIPERRIFLE_RELOAD,
SNIPERRIFLE_RELOAD2,
SNIPERRIFLE_SLOWIDLEEMPTY,
SNIPERRIFLE_HOLSTER,
};
void EV_FireSniper( event_args_t *args )
{
int idx;
int empty;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
vec3_t vecSrc, vecAiming;
vec3_t up, right, forward;
float flSpread = 0.01;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
empty = args->bparam1;
AngleVectors( angles, forward, right, up );
if ( EV_IsLocal( idx ) )
{
// Add muzzle flash to current weapon model
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( empty ? SNIPERRIFLE_FIRELASTROUND : SNIPERRIFLE_FIRE1, 2 );
V_PunchAxis( 0, -20.0 );
}
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/sniper_fire1.wav", gEngfuncs.pfnRandomFloat(0.8, 0.9), ATTN_NORM, 0, PITCH_NORM );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_338, 0, 0, args->fparam1, args->fparam2 );
}
//======================
// RIFLE END
//======================
Потом идём в файл view.cpp
{ "models/p_shotgun.mdl", "models/v_shotgun.mdl" },
{ "models/p_squeak.mdl", "models/v_squeak.mdl" },
{ "models/p_tripmine.mdl", "models/v_tripmine.mdl" },
{ "models/p_satchel_radio.mdl", "models/v_satchel_radio.mdl" },
{ "models/p_satchel.mdl", "models/v_satchel.mdl" },
{ "models/p_knife.mdl", "models/v_knife.mdl" },
{ "models/p_sniper.mdl", "models/v_sniper.mdl" },//Новая строчка
После открываем hl_events.cpp
void EV_HornetGunFire( struct event_args_s *args );
void EV_TripmineFire( struct event_args_s *args );
void EV_SnarkFire( struct event_args_s *args );
void EV_Knife( struct event_args_s *args );
void EV_FireSniper( struct event_args_s *args );//Новая строчка
gEngfuncs.pfnHookEvent( "events/firehornet.sc", EV_HornetGunFire );
gEngfuncs.pfnHookEvent( "events/tripfire.sc", EV_TripmineFire );
gEngfuncs.pfnHookEvent( "events/snarkfire.sc", EV_SnarkFire );
gEngfuncs.pfnHookEvent( "events/knife.sc", EV_Knife );
gEngfuncs.pfnHookEvent( "events/sniper.sc", EV_FireSniper );//Новая строчка
И последний файл клиента hl_weapons.cpp
CHgun g_HGun;
CHandGrenade g_HandGren;
CSatchel g_Satchel;
CTripmine g_Tripmine;
CSqueak g_Snark;
CKnife g_Knife;
CSniperrifle g_Sniperrifle;//Новая строчка
Затем ниже в функции void HUD_InitClientWeapons( void )
HUD_PrepEntity( &g_HGun , &player );
HUD_PrepEntity( &g_HandGren , &player );
HUD_PrepEntity( &g_Satchel , &player );
HUD_PrepEntity( &g_Tripmine , &player );
HUD_PrepEntity( &g_Snark , &player );
HUD_PrepEntity( &g_Knife , &player );
HUD_PrepEntity( &g_Sniperrifle , &player );//Новая строчка
Ещё ниже к подобным параметрам пишем:
case WEAPON_SNIPERRIFLE:
pWeapon = &g_Sniperrifle;
break;
На этом кодинг винтовки закончен. Начинаем работу с оптическим прицелом. Добавляем в клиент zoom.cpp
#include "hud.h"
#include "cl_util.h"
#include "parsemsg.h"
#include "hud_servers.h"
#include "vgui_int.h"
#include "vgui_TeamFortressViewport.h"
#include "triangleapi.h"
#include "r_studioint.h"
#include "com_model.h"
#include
#include
extern engine_studio_api_t IEngineStudio;
void DrawQuad(float xmin, float ymin, float xmax, float ymax)
{
//top left
gEngfuncs.pTriAPI->TexCoord2f(0,0);
gEngfuncs.pTriAPI->Vertex3f(xmin, ymin, 0);
//bottom left
gEngfuncs.pTriAPI->TexCoord2f(0,1);
gEngfuncs.pTriAPI->Vertex3f(xmin, ymax, 0);
//bottom right
gEngfuncs.pTriAPI->TexCoord2f(1,1);
gEngfuncs.pTriAPI->Vertex3f(xmax, ymax, 0);
//top right
gEngfuncs.pTriAPI->TexCoord2f(1,0);
gEngfuncs.pTriAPI->Vertex3f(xmax, ymin, 0);
}
DECLARE_MESSAGE(m_Zoom, ZoomHUD)
int CHudZoom::Init()
{
m_iHudMode = 0;
HOOK_MESSAGE(ZoomHUD);
m_iFlags |= HUD_ACTIVE;
gHUD.AddHudElem(this);
return 1;
}
int CHudZoom::VidInit()
{
m_hBottom_Left = SPR_Load("sprites/weapon_sniperrifle/sniper_bottom_left.spr");
m_hBottom_Right = SPR_Load("sprites/weapon_sniperrifle/sniper_bottom_right.spr");
m_hTop_Left = SPR_Load("sprites/weapon_sniperrifle/sniper_top_left.spr");
m_hTop_Right = SPR_Load("sprites/weapon_sniperrifle/sniper_top_right.spr");
m_hBlack = SPR_Load("sprites/weapon_sniperrifle/sniper_black.spr");
m_iHudMode = 0;
return 1;
}
int CHudZoom::MsgFunc_ZoomHUD (const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
m_iHudMode = READ_BYTE();
return 1;
}
int CHudZoom::Draw(float flTime)
{
if(!IEngineStudio.IsHardware() || !m_hBottom_Left || !m_hBottom_Right || !m_hTop_Left || !m_hTop_Right ) return 0;
if(!m_iHudMode) return 0;//draw scope
gEngfuncs.pTriAPI->RenderMode(kRenderTransColor);
gEngfuncs.pTriAPI->Brightness(1.0);
gEngfuncs.pTriAPI->Color4ub(255, 255, 255, 255);
gEngfuncs.pTriAPI->CullFace(TRI_NONE);
float left = (ScreenWidth - ScreenHeight)/2;
float right = left + ScreenHeight;
float centerx = ScreenWidth/2;
float centery = ScreenHeight/2;
gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer( m_hTop_Left ), 0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS);
DrawQuad(left, 0, centerx, centery);
gEngfuncs.pTriAPI->End();
gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer( m_hTop_Right ), 0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS);
DrawQuad(centerx, 0, right, centery);
gEngfuncs.pTriAPI->End();
gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer( m_hBottom_Right ), 0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS);
DrawQuad(centerx, centery, right, ScreenHeight);
gEngfuncs.pTriAPI->End();
gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer( m_hBottom_Left ), 0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS);
DrawQuad(left, centery, centerx, ScreenHeight);
gEngfuncs.pTriAPI->End();
gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer( m_hBlack ), 0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS);
DrawQuad(0, 0, (left + 1), ScreenHeight);
gEngfuncs.pTriAPI->End();
gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer( m_hBlack ), 0);
gEngfuncs.pTriAPI->Begin(TRI_QUADS);
DrawQuad((right - 1), 0, ScreenWidth, ScreenHeight);
gEngfuncs.pTriAPI->End();
return 1;
}
В файле hud.cpp в функцию void CHud
Init( void ) добавляем:
m_StatusBar.Init();
m_DeathNotice.Init();
m_AmmoSecondary.Init();
m_TextMessage.Init();
m_StatusIcons.Init();
m_Zoom.Init();//новая строчка
GetClientVoiceMgr()->Init(&g_VoiceStatusHelper, (vgui:anel**)&gViewPort);
Потом, по такому же принципу в функцию void CHud
VidInit( void ) добавляем:
m_Menu.VidInit();
m_AmmoSecondary.VidInit();
m_TextMessage.VidInit();
m_StatusIcons.VidInit();
m_Zoom.VidInit();//Новая строчка
GetClientVoiceMgr()->VidInit();
После этого в hud.h создаём новый класс:
class CHudZoom: public CHudBase
{
public:
int Init( void );
int VidInit( void );
int Draw(float flTime);
int MsgFunc_ZoomHUD(const char *pszName, int iSize, void *pbuf );
int m_iHudMode;
private:
HSPRITE m_hBottom_Left;
HSPRITE m_hBottom_Right;
HSPRITE m_hTop_Left;
HSPRITE m_hTop_Right;
HSPRITE m_hBlack;
};
Ниже в описании самого класса CHud добавляем:
CHudSayText m_SayText;
CHudMenu m_Menu;
CHudAmmoSecondary m_AmmoSecondary;
CHudTextMessage m_TextMessage;
CHudStatusIcons m_StatusIcons;
CHudZoom m_Zoom;//новая строчка
Затем открываем hud_redraw.cpp и в функции int CHud
Redraw после
if (m_flShotTime && m_flShotTime < flTime)
{
gEngfuncs.pfnClientCmd("snapshot\n");
m_flShotTime = 0;
}
m_iIntermission = intermission;
if(m_Zoom.m_iHudMode > 0)
{
m_Zoom.Draw( flTime );
return 1;
}
Потом идём в ev_hldm.h и там аналогично добавляем:
BULLET_PLAYER_BUCKSHOT, // shotgun
BULLET_PLAYER_CROWBAR, // crowbar swipe
BULLET_PLAYER_338, //добавляем наши патроны
С клиентом всё, идём на серверную сторону.
Открываем player.cpp и пишем:
extern void CopyToBodyQue(entvars_t* pev);
extern void respawn(entvars_t *pev, BOOL fCopyCorpse);
extern Vector VecBModelOrigin(entvars_t *pevBModel );
extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer );
extern int gmsgZoom;//Новая строчка
int gmsgTextMsg = 0;
int gmsgSetFOV = 0;
int gmsgShowMenu = 0;
int gmsgGeigerRange = 0;
int gmsgTeamNames = 0;
int gmsgZoom = 0;//Новая строчка
gmsgAmmoX = REG_USER_MSG("AmmoX", 2);
gmsgTeamNames = REG_USER_MSG( "TeamNames", -1 );
gmsgStatusText = REG_USER_MSG("StatusText", -1);
gmsgStatusValue = REG_USER_MSG("StatusValue", 3);
gmsgZoom = REG_USER_MSG( "ZoomHud", 1);//Новая строчка
Теперь нам надо задать условие, при котором на экране будет отображаться оптический прицел. Прокрутим вниз до функции void CBasePlayer :: UpdateClientData( void )
if ( m_iFOV != 0 && m_iFOV != 20 && m_iFOV != 40 )
{
MESSAGE_BEGIN( MSG_ONE, gmsgZoom, NULL, pev );
WRITE_BYTE(1);
MESSAGE_END();
}
Если вы хотите, чтобы оптический прицел рисовался не только у снайперки, но и у арбалета и револьвера, то уберите условия m_iFOV != 20 и m_iFOV != 40 (20 это арбалет, а 40 это револьвер) И не забывайте стирать лишние &&
В этой же функции замените условие
if ( m_iFOV != m_iClientFOV )
{
MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev );
WRITE_BYTE( m_iFOV );
MESSAGE_END();
// cache FOV change at end of function, so weapon updates can see that FOV has changed
}
if ( m_iFOV != m_iClientFOV )
{
MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev );
WRITE_BYTE( m_iFOV );
MESSAGE_END();
MESSAGE_BEGIN( MSG_ONE, gmsgZoom, NULL, pev );
WRITE_BYTE(0);
MESSAGE_END();
// cache FOV change at end of function, so weapon updates can see that FOV has changed
}
Нам ведь нужно чтобы оптический прицел отключался.
В конец файла skill.cfg добавьте
sk_plr_snpr_bullet1 "100"
sk_plr_snpr_bullet2 "100"
sk_plr_snpr_bullet3 "100"
На этом всё, не забудте создать файл sniper.sc в папке events вашего мода.
P.S. Спасибо, Дядя Миша, за тутор по оптическому прицелу
Similar 1. И снова наследование классов :) - Казалось бы тема наследования классов давно избита, ан нет всё ещё существуют вопросы, правда про чуть боле сложное наследование. 2. Динамическое освещение - этой статье будет описан способ добавления динамических вспышек света, которые можно использовать для еффекта молнии 3. Замедление игрока - Довольно забавно наблюдать, как игрок одинаково быстро бегает как с монтировкой в руках, так и с тяжелой базукой, хотя логичнее, что держа в руках сей девайс, он будет бегать медленнее 4. Создание кооперативного прохождения - Данный тутор покажет как сделать в вашем моде кооператив.
3037 06/24/2018, 11:25:31 AM commented :
#1 у меня вылетает игра после того как взял в руки оружие
You cannot comment, because you are not logged-in.