Сегодня я расскажу вам как сделать простой Ak 47 с подробным описанием его функций и опций :) хз как вам на понятном языке обьяснить сложные термены C++ Итак приступим... Для того чтобы внедрить такое орудие убийства в ваш мод вам потребуется минимум знать как компилить проэкт в C++ И как туда добовлять cpp файл :) Нус обьяснение самого тутора будет на примере кода. И так для начала зайдём в Visual Studio и добавим в ваш проэкт с++ файл. добавим его в Server.dll в src/dlls/hl2_dll. Что бы добавить в сервер weapon_ak47.cpр надо нажать на него правой кнопкой и выбрать вкладочку add/add new item... а там уже выбрать формат .cрp и внизу написать название, в нашем случае это weapon_ak47, потом нажать open и вписать этот код. // 15.02.06 // Кто кодил? Кодил Lolmen // Как кодил? Сам! :D // Весь код принадлежит протасову виталию и отправлен на изучение // людьми сообщества Nashalife :) // Вам разрешается его использовать по полной программе :) #include "cbase.h" // засунем базу без неё никуда #include "basehlcombatweapon.h" // определим какие свойства юзать бум юзать #include "NPCevent.h" // для NPC #include "basecombatcharacter.h" // для игрока #include "AI_BaseNPC.h" // для AI #include "player.h" // сам игрок #include "game.h" // игра #include "in_buttons.h" // для кнопок мыши #include "AI_Memory.h" // для AI память #include "soundent.h" // хз вродь звуки или чёто такое // Обозначили все в своём классе // Класс оружиеАк47 юзаем для него класс Автоматов :) class CWeaponAK47 : public CHLSelectFireMachineGun { DECLARE_DATADESC(); public: DECLARE_CLASS( CWeaponAK47, CHLSelectFireMachineGun ); CWeaponAK47(); DECLARE_SERVERCLASS(); void Precache( void ); // подгрузка void AddViewKick( void ); // как нас будет трясти при стрельбе void SecondaryAttack( void ); // вторичная атака void ItemPostFrame( void ); // оружие на каждый кадр int GetMinBurst() { return 2; } // взять минимальный разброс int GetMaxBurst() { return 6; } // взять максимальный разброс virtual void Equip( CBaseCombatCharacter *pOwner ); // когда NPC снабжен пушкой bool Reload( void ); // обозначим тип BOOL переключатель для перезарядки float GetFireRate( void ) { return 0.1f; } // скорость стрельбы int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; } virtual const Vector& GetBulletSpread( void ) // берем конус разброса { static const Vector cone = VECTOR_CONE_5DEGREES; // конус разброса от дула return cone; } const WeaponProficiencyInfo_t *GetProficiencyValues(); // приоритеты void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ) { switch( pEvent->event ) { case EVENT_WEAPON_SMG1: // Дает понять что мы юзаем опции SMG1 для NPC { Vector vecShootOrigin, vecShootDir; // дадим названия вкторам QAngle angDiscard; if ((pEvent->options == NULL) || (pEvent->options[0] == '\0') || (!pOperator->GetAttachment(pEvent->options, vecShootOrigin, angDiscard))) { vecShootOrigin = pOperator->Weapon_ShootPosition(); // позиция откуда вылетают пули } CAI_BaseNPC *npc = pOperator->MyNPCPointer(); // найдём NPC ASSERT( npc != NULL ); // если NPC нету то ждём его vecShootDir = npc->GetActualShootTrajectory( vecShootOrigin ); // куда NPC стрелять WeaponSoundRealtime( SINGLE_NPC ); // звук для NPC CSoundEnt::InsertSound( SOUND_COMBAT, pOperator->GetAbsOrigin(), SOUNDENT_VOLUME_MACHINEGUN, 0.2, pOperator ); // параметры звука pOperator->FireBullets( 1, vecShootOrigin, vecShootDir, VECTOR_CONE_PRECALCULATED, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 2, entindex(), 0 ); //чем будет NPC стрелять pOperator->DoMuzzleFlash(); // Будет мерцать Вспышка от выстрелов m_iClip1 = m_iClip1 - 1; // сколько патронов займем за один выстрел } break; default: BaseClass::Operator_HandleAnimEvent( pEvent, pOperator ); break; } } DECLARE_ACTTABLE(); }; // начали использовать функции из класса IMPLEMENT_SERVERCLASS_ST(CWeaponAK47, DT_WeaponAK47) END_SEND_TABLE() LINK_ENTITY_TO_CLASS( weapon_ak47, CWeaponAK47 ); PRECACHE_WEAPON_REGISTER(weapon_ak47); BEGIN_DATADESC( CWeaponAK47 ) END_DATADESC() acttable_t CWeaponAK47::m_acttable[] = // Активности (Анимации для NPC) { { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SMG1, true }, // Скажем NPC что ему при выстреле нужно юзать анимку от SMG1 }; IMPLEMENT_ACTTABLE(CWeaponAK47); //========================================================= CWeaponAK47::CWeaponAK47( ) { // Конструктор для калаша m_fMinRange1 = 64;// нет минимальной дальности полёта пули. m_fMaxRange1 = 1400; // максимальная дальность полёта пули; } //----------------------------------------------------------------------------- // Что делаем? : Подгружаем //----------------------------------------------------------------------------- void CWeaponAK47::Precache( void ) { // что подгружаем? ничего просто инициализируем подгрузку // но ниче не грузим :) BaseClass::Precache(); } //----------------------------------------------------------------------------- // Что делаем? : даем NPC более длинный маштаб полета пули. //----------------------------------------------------------------------------- void CWeaponAK47::Equip( CBaseCombatCharacter *pOwner ) { if( pOwner->Classify() == CLASS_PLAYER_ALLY ) // если пушка у игрока то { m_fMaxRange1 = 3000; // максммальный полёт пули } else // потому что пока она не у игрока полёт пули равен { m_fMaxRange1 = 1400; // равен 1400 } BaseClass::Equip( pOwner ); } //----------------------------------------------------------------------------- // Что делаем? Делаем все для перезарядки //----------------------------------------------------------------------------- bool CWeaponAK47::Reload( void ) { bool fRet; // переключатель float fCacheTime = m_flNextSecondaryAttack; // время для перезарядки fRet = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD ); // что перезаряжаем? обойму 1 обойму 2 и юзаем анимку перезарядки ACT_VM_RELOAD if ( fRet ) // если переключатель fRet включён , то { // Перекрываем доступ к вторичной атаке чтобы небыло багов // Неразрешено стрелять когда мы перезаряжаемся m_flNextSecondaryAttack = GetOwner()->m_flNextAttack = fCacheTime; WeaponSound( RELOAD ); // звук из скрипта проиграем RELOAD } return fRet; // возратим fRet } //----------------------------------------------------------------------------- // Что делаем? Добовляем потясывание экрана при стрельбе //----------------------------------------------------------------------------- void CWeaponAK47::AddViewKick( void ) { #define EASY_DAMPEN 0.5f // легкое подергивание #define MAX_VERTICAL_KICK 15.0f //макс вертикальный наклон в градусах #define SLIDE_LIMIT 3.0f // всю эту батву будем делать за столько то секунд //Кого трясти будем? CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); // игрока :D if ( pPlayer == NULL ) return; // если игрока у нас нету то и трясти не будем! DoMachineGunKick( pPlayer, EASY_DAMPEN, MAX_VERTICAL_KICK, m_fFireDuration, SLIDE_LIMIT ); // а вот это уже инициализирует все что мы набрали } //----------------------------------------------------------------- // Че делаем? Проверяем не нажали ли геймер по кнопке мыши :) // Первичный огонь у пушки вызывается по дефолту его не трогаем // А вот что делать, если мы нажали по правой мыше, // которая у нас стоит в настройках как вторичная атака? //----------------------------------------------------------------- void CWeaponAK47::ItemPostFrame( void ) { // Если геймер есть то все ока :) CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); // Если геймера нету то пипец ниче не делаем :) if ( pOwner == NULL ) return; // Если геймер нажал кнопку ATTACK2(подефолту правая кнопка мыши) // то время вторичной атаки меньше либо равно текущему времени if ( pOwner->m_nButtons & IN_ATTACK2 ) { if (m_flNextSecondaryAttack <= gpGlobals->curtime) { SecondaryAttack(); // и тут мы вызовем функцию вторичной стрельбы оружия pOwner->m_nButtons &= ~IN_ATTACK2; // а вот если ненажал кнопку ATTACK2 return;// то будем ждать пока нажмет :) } } BaseClass::ItemPostFrame(); // используем и базовый класс тоже } //----------------------------------------------------------------------------- // Что делаем? определяем что у нас будет вторичной Атакой :) //----------------------------------------------------------------------------- void CWeaponAK47::SecondaryAttack( void ) { // А вот тут пока пусто сюда мы можем сделать : // Приближение,Выстрел из подстволки,Удар штыком и тд } //------------------------------------------------------------------ // Что делаем? Опа самая непонятная чать "приоритеты оружия" // Короче это определяет насколько крут наш ствол // Если например в пистолете закончились патроны на что же сменить оружие // В первую очередь? На самый крутой ствол :) // Наш ствол будет покруче чем SMG :) //----------------------------------------------------------------- const WeaponProficiencyInfo_t *CWeaponAK47::GetProficiencyValues() { static WeaponProficiencyInfo_t proficiencyTable[] = { { 8.0, 0.75 }, { 6.00, 0.75 }, { 10.0/2.0, 0.75 }, { 5.0/3.0, 0.75 }, { 2.00, 1.0 }, }; COMPILE_TIME_ASSERT( ARRAYSIZE(proficiencyTable) == WEAPON_PROFICIENCY_PERFECT + 1); // а это нам сократит время компила пушки :) return proficiencyTable; } Теперь зайдем в X:\папку с вашим проэктом \src\cl_dll\hl2_hud\c_weapon__stubs_hl2.cpp Откроем этот файлец и добавим туда строку после: STUB_WEAPON_CLASS( weapon_smg1, WeaponSMG1, C_HLSelectFireMachineGun ); вот эту STUB_WEAPON_CLASS( weapon_ak47, WeaponAK47, C_HLSelectFireMachineGun ); Теперь компельнём проэкт :) теперь самя малось осталось написать скрипт. Скрипт напишем следующим образом зайдем в папку с стимом там в SteamApps\SourceMods\папка с вашим модом\scripts и создадим там текстовик c именем weapon_ak47 след содержания : // Small Machine Gun 1 WeaponData { // Weapon data is loaded by both the Game and Client DLLs. "printname" "AK47" "viewmodel" "models/weapons/v_smg1.mdl" // Замените модельку на вашу "playermodel" "models/weapons/w_smg1.mdl" //Замените модельку на вашу "anim_prefix" "smg2" "bucket" "2" "bucket_position" "9" "clip_size" "39" "default_clip" "30" "primary_ammo" "SMG1" "secondary_ammo" "None" "weight" "3" "item_flags" "0" // Sounds for the weapon. There is a max of 16 sounds per category (i.e. max 16 "single_shot" sounds) SoundData { "reload" "Weapon_SMG1.Reload" "reload_npc" "Weapon_SMG1.NPC_Reload" "empty" "Weapon_SMG1.Empty" "single_shot" "Weapon_SMG1.Single" "single_shot_npc" "Weapon_SMG1.NPC_Single" "special1" "Weapon_SMG1.Special1" "special2" "Weapon_SMG1.Special2" "double_shot" "Weapon_SMG1.Double" "burst" "Weapon_SMG1.Burst" } // Weapon Sprite data is loaded by the Client DLL. TextureData { "weapon" { "font" "WeaponIcons" "character" "a" } "weapon_s" { "font" "WeaponIconsSelected" "character" "a" } "ammo" { "font" "WeaponIcons" "character" "r" } "ammo2" { "font" "WeaponIcons" "character" "t" } "crosshair" { "font" "Crosshairs" "character" "Q" } "autoaim" { "file" "sprites/crosshairs" "x" "0" "y" "48" "width" "24" "height" "24" } } } Затем запускаем ваш мод... В игре прописываем give weapon_ak47 и наблюдаем за тем как это дело работает.
Источник: http://source-inside.ru/index.php?id=79 |