Stat overall size ( ALL )
Создание нового ствола с новыми патронами
Создание нового ствола
Создание нового ствола с новыми патронами
Author/s of tutorial : Ghoul [BB] Views : 1844 ( +1 ) Downloads : 0 Uploader : Streit Created : 04/07/2011 8:38:50 PM Source : http://www.half-life.ru/forum Rating : ( 0 ) Share :
Following translations are available : |
russian |
По многочисленным просьбам, как пришедшим на мой адрес, так и на этом форуме: "А как тебе удалось сделать стока стволов, да и
как вообще можно проделать такое и т.д." я подробно опишу, как добавить новое оружие, с новым типом боеприпаса к нему.
Будут затронуты как клиентная, так и серверная части..
Проверено на СДК 2.2, на коем и базируется мой мод. Я не гарантирую работу и 100% совместимость данного тутора на какой-либо другой модификации,
в особенности это касается системы Spirit, со всеми ее эдишнами и билдами!
Итак, приступим. Серверная часть.
func_break.cpp, в классе *CBreakable:SpawnObjects[] добавляем под аналогичными образцами строку:
Это дает нам выпадение оружия при разбивании ящиков на карте, если установлено число, соотв. позиции оружия в этом листе.. (для мапперов)
weapons.cpp, функция W_Precache(void)
Прекэшим наше оружие.
UTIL_PrecacheOtherWeapon( "weapon_awp" );
Далее переходим в weapons.h, к аналогичным функциям стандартного оружия:
#define WEAPON_awp 16 //(ваш порядковый номер, у меня он 16)
Чуть ниже, среди похожих функций другого оружия:
class Cawp : public CBasePlayerWeapon
{
public:
void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 0; }
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 );
int m_iShell;
BOOL m_fInZoom;
virtual BOOL UseDecrement( void )
{
#if defined( CLIENT_WEAPONS )
return TRUE;
#else
return FALSE;
#endif
}
private:
unsigned short m_usawp;
};
Здесь мы обозначили все действия, которые оружие должно совершать. Они содержатся в самом файле оружия.
С сервером все, переходим к клиенту.
Находим hl_events.cpp, и регистрируем там используемый оружием эвент:
в самом верху, под аналогичными функциями
void EV_Fireawp( struct event_args_s *args );
gEngfuncs.pfnHookEvent( "events/awp.sc", EV_Fireawp );
Тут все. Переходим к hl_weapons.cpp.
Под CMP5 g_Mp5;
ставим
Спускаемся ниже, ищем HUD_PrepEntity( &g_Mp5, &player );
и ставим ниже
HUD_PrepEntity( &g_awp, &player );
case WEAPON_MP5:
pWeapon = &g_Mp5;
break;
case WEAPON_awp:
pWeapon = &g_awp;
break;
Фуух, вроде все!
Перейдем к ev_hldm.cpp, где создадим само оружие (вернее, его эффекты - анимация, вспышка, вытряхивание гильз)
Найдем похожий случай для МП5:
void EV_FireMP5( struct event_args_s *args );
void EV_Fireawp( struct event_args_s *args );
Далее ищем void EV_FireMP5( event_args_t *args )
И под этим, после строк коммента
//======================
// MP5 END
//======================
//======================
// AWP START
//======================
enum awp_e
{
AWP_DRAW,
AWP_IDLE1,
AWP_FIRE1,
AWP_FIRE2,
AWP_RELOAD1,
AWP_RELOAD2,
AWP_RELOAD3,
AWP_IDLE2,
AWP_HOLSTER
};
void EV_Fireawp( event_args_t *args )
{
int idx;
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 );
AngleVectors( angles, forward, right, up );
dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight (0);
dl->origin.x = origin.x;
dl->origin.y = origin.y;
dl->origin.z = origin.z;
dl->radius = gEngfuncs.pfnRandomFloat( 330, 370 );
dl->color.r = 210;
dl->color.g = 200;
dl->color.b = 60;
dl->die = gEngfuncs.GetClientTime() + 0.06;
if ( EV_IsLocal( idx ) )
{
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( AWP_FIRE1 + gEngfuncs.pfnRandomLong(0,1), 2 );
V_PunchAxis( 0, -10.0 );
}
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/awp1.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) );//звук выстрела
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_338Magnum, 1, &tracerCount[idx-1], args->fparam1, args->fparam2 );//вылет пули
}
//======================
// AWP END
//======================
Ну вот и все. Не забываем добавить на сервере в проект wpn_awp.cpp. Но! Мы ж еще хотим, чтобы для нового оружия были новые боеприпасы,
со своим уроном и т.п. Исправим!
Создание нового типа патронов.
На сервере.
Откроем cbase.h, и под int ammo_9mm;
поставим
Потом откроем client.cpp, под строкой
cd->vuser1.x = pl->ammo_9mm;
cd->vuser1.y = pl->ammo_338Magnum;
Потом в player.cpp, в void CBasePlayer::TabulateAmmo()
{
поставим
ammo_338Magnum = AmmoInventory( GetAmmoIndex( "338Magnum" ) );
Новый тип пуль делается по аналогии…
Примечание редактора: на этом заканчивался оригинальный текст данного тутора, но поскольку в коде оружия использованы пули BULLET_PLAYER_338Magnum которых нет в обычном хл, я написал продолжение к этому тутору которое добавляет этот тип пуль.
case BULLET_PLAYER_BUCKSHOT:
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_338Magnum: //Новые строчки
pEntity->TraceAttack(pevAttacker, gSkillData.plrDmg358Magnum, vecDir, &tr, DMG_BULLET);
break;
case BULLET_PLAYER_BUCKSHOT:
case BULLET_PLAYER_357:
case BULLET_PLAYER_338Magnum: //Новая строка
BULLET_PLAYER_BUCKSHOT, // shotgun
BULLET_PLAYER_CROWBAR, // crowbar swipe
BULLET_PLAYER_338Magnum, //Новая строка
float plrDmgSatchel;
float plrDmgTripmine;
float plrDmg358Magnum; //Новая строка
// Tripmine
cvar_t sk_plr_tripmine1 = {"sk_plr_tripmine1","0"};
cvar_t sk_plr_tripmine2 = {"sk_plr_tripmine2","0"};
cvar_t sk_plr_tripmine3 = {"sk_plr_tripmine3","0"};
//Новые строки
cvar_t sk_plr_358Magnum1 = {"sk_plr_358Magnum1","0"};
cvar_t sk_plr_358Magnum2 = {"sk_plr_358Magnum2","0"};
cvar_t sk_plr_358Magnum3 = {"sk_plr_358Magnum3","0"};
// Tripmine
CVAR_REGISTER ( &sk_plr_tripmine1 );// {"sk_plr_tripmine1","0"};
CVAR_REGISTER ( &sk_plr_tripmine2 );// {"sk_plr_tripmine2","0"};
CVAR_REGISTER ( &sk_plr_tripmine3 );// {"sk_plr_tripmine3","0"};
// Новые строчки
CVAR_REGISTER ( &sk_plr_358Magnum1 );
CVAR_REGISTER ( &sk_plr_358Magnum2 );
CVAR_REGISTER ( &sk_plr_358Magnum3 );
// Tripmine
gSkillData.plrDmgTripmine = GetSkillCvar( "sk_plr_tripmine");
// Новые строчки
gSkillData.plrDmg358Magnum = GetSkillCvar( "sk_plr_358Magnum");
Теперь переходим на клиент
case BULLET_PLAYER_BUCKSHOT:
case BULLET_PLAYER_357:
case BULLET_PLAYER_338Magnum://новая строка
case BULLET_PLAYER_357:
EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType );
EV_HLDM_DecalGunshot( &tr, iBulletType );
break;
case BULLET_PLAYER_338Magnum://новые строки
EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType );
EV_HLDM_DecalGunshot( &tr, iBulletType );
break;
BULLET_PLAYER_BUCKSHOT, // shotgun
BULLET_PLAYER_CROWBAR, // crowbar swipe
BULLET_PLAYER_338Magnum,//новая строка
Теперь в skill.cfg вставляем в самый конец:
sk_plr_358Magnum1 "100"
sk_plr_358Magnum2 "100"
sk_plr_358Magnum3 "100"
Не забудьте создать файл awp.sc в папке events (содержимое можно скопировать из mp5.sc)
Сам исходник Слонобоя (этот файл нужно добавить на сервер и на клиент) :
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
#include "soundent.h"
#include "gamerules.h"
enum awp_e
{
AWP_DRAW,
AWP_IDLE1,
AWP_FIRE1,
AWP_FIRE2,
AWP_RELOAD1,
AWP_RELOAD2,
AWP_RELOAD3,
AWP_IDLE2,
AWP_HOLSTER
};
LINK_ENTITY_TO_CLASS( weapon_awp, Cawp );
void Cawp::Spawn( )
{
pev->classname = MAKE_STRING("weapon_awp");
Precache( );
SET_MODEL(ENT(pev), "models/w_awp.mdl");
m_iId = WEAPON_awp;
m_iDefaultAmmo = 10;
FallInit();
}
void Cawp::Precache( void )
{
PRECACHE_MODEL("models/v_awp.mdl");
PRECACHE_MODEL("models/p_awp.mdl");
PRECACHE_MODEL("models/w_awp.mdl");
PRECACHE_SOUND ("weapons/awp1.wav");
PRECACHE_SOUND ("weapons/zoom.wav");
m_usawp = PRECACHE_EVENT( 1, "events/awp.sc" );
}
int Cawp::GetItemInfo(ItemInfo *p)
{
p->pszName = STRING(pev->classname);
p->pszAmmo1 = "338Magnum";
p->iMaxAmmo1 = 30;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = 10;
p->iSlot = 0;
p->iPosition = 1;
p->iFlags = 0;
p->iId = m_iId = WEAPON_awp;
p->iWeight = 20;
return 1;
}
int Cawp::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;
}
BOOL Cawp::Deploy( )
{
return DefaultDeploy( "models/v_awp.mdl", "models/p_awp.mdl", AWP_DRAW, "mp5" );
}
void Cawp::PrimaryAttack()
{
if (m_pPlayer->pev->waterlevel == 3)
{
PlayEmptySound( );
m_flNextPrimaryAttack = 0.15;
return;
}
if (m_iClip <= 0)
{
PlayEmptySound();
m_flNextPrimaryAttack = 0.15;
return;
}
m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
m_iClip--;
int flags;
#if defined( CLIENT_WEAPONS )
flags = FEV_NOTHOST;
#else
flags = 0;
#endif
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
Vector vecSrc = m_pPlayer->GetGunPosition( );
Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
Vector vecDir;
vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, Vector( 0.00001, 0.00001, 0.00001 ), 8192, BULLET_PLAYER_338Magnum, 1, 0, m_pPlayer->pev, m_pPlayer->random_seed );
#if defined( CLIENT_WEAPONS )
flags = FEV_NOTHOST;
#else
flags = 0;
#endif
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usawp, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 );
if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.8;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
void Cawp::SecondaryAttack( void )
{
if ( m_pPlayer->pev->fov ==8 )
{
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0;
m_fInZoom = 0;
}
else if ( m_pPlayer->pev->fov == 40 )
{
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 8;
m_fInZoom = 1;
}
else if ( m_pPlayer->pev->fov == 0 )
{
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 40;
m_fInZoom = 2;
}
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5;
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/zoom.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0xF));//проиграть звук
}
void Cawp::Holster( int skiplocal )
{
m_fInReload = FALSE;
if (m_pPlayer->pev->fov != 0 )
{
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0;
m_fInZoom = 0;
}
SendWeaponAnim(AWP_HOLSTER);
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0;
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
void Cawp::Reload( void )
{
if (m_pPlayer->pev->fov != 0 )
{
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0;
m_fInZoom = 0;
}
DefaultReload( 10, AWP_RELOAD1, 2.8 );
}
void Cawp::WeaponIdle( void )
{
m_pPlayer->UpdateClientData();
ResetEmptySound( );
m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
return;
int iAnim;
switch ( RANDOM_LONG( 0, 1 ) )
{
case 0:
iAnim = AWP_IDLE1;
break;
default:
case 1:
iAnim = AWP_IDLE2;
break;
}
SendWeaponAnim( iAnim );
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
class CawpAmmoClip : public CBasePlayerAmmo
{
void Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/w_chainammo.mdl");
CBasePlayerAmmo::Spawn( );
}
void Precache( void )
{
PRECACHE_MODEL ("models/w_chainammo.mdl");
PRECACHE_SOUND("items/9mmclip1.wav");
}
BOOL AddAmmo( CBaseEntity *pOther )
{
int bResult = (pOther->GiveAmmo( 10, "338Magnum", 30) != -1);
if (bResult)
{
EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM);
}
return bResult;
}
};
LINK_ENTITY_TO_CLASS( ammo_338Magnum, CawpAmmoClip );
Спрайты, модели и звуки файле .
Примечание редактора: в исходном коде данного тутора содержались логические глюки, которые не удалось исправить не переписав весь код тутора, по этому использовать этот тутор рекомендуется только в целях обучения кодингу, но не использования в моде.
Similar 1. Добавление ножа из Op4 - Добавление ножа из Op4 2. Разбираемся в коде пушки МР5 - По просьбам трудящихся коментирую код МР5 3. Исходный код снайперки - weapon_sniperrifle с оптическим прицелом 4. Замедление игрока - Довольно забавно наблюдать, как игрок одинаково быстро бегает как с монтировкой в руках, так и с тяжелой базукой, хотя логичнее, что держа в руках сей девайс, он будет бегать медленнее 5. Создание кооперативного прохождения - Данный тутор покажет как сделать в вашем моде кооператив. 6. Создание сценариев - Для создания сценариев (aka скриптов) в Half-Life существуют две энтити: scripted_sequence и scripted_sentence. Первая отвечает за движения, выполняемые монстром/персонажем, будь то ходьба, бег, нажатие кнопки, тряска автомата с газировкой или почёсывание подбородка. Вторая служит для того, чтобы персонаж произнес какую-то фразу. При этом его голова повернётся в сторону слушателя, и рот будет открываться в соответствии с амплитудой звука. 7. Звук попадания как в HL2 - Работа на клиенте
You cannot comment, because you are not logged-in.