Форумы на Наша-Life
Home user CP  
Календарь событий Найти других пользователей Часто задаваемые Вопросы Поиск  
Автор
Тема
Создать Новую Тему    Ответить
6apMaJIeu'
(Member)

Зарегистрирован: Jul 2012
Проживает: Россия/Санкт-Петербург
Написал: 41 сообщений

Оценка: 0 Votes

Раздаём оружие игрока для npc
Сообщение #1104507
Всем привет!
В данной теме предлагаю решать вопросы раздачи оружия для npc, которого они изначально не имеют, так как похожей темы не нашёл.
Например: почему в hl2 никто, кроме игрока, не стреляет из арбалета, магнума, или гранатой из автомата? Анимаций-то для этого вроде сделано предостаточно, ну или их на крайняк можно спереть от другого оружия. Магнумы так вообще везде почти валяются, но их никто не использует...

Посему вот пара туторов для того, чтобы немного разнообразить снаряжение некоторых npc:


1. Итак, делаем так, чтобы, имея smg1, солдат Альянса стрелял подствольными гранатами, а не кидал ручные.

npc_combine.cpp

добавляем в начале: #include "grenade_ar2.h"

Далее ищем
Activity CNPC_Combine::NPC_TranslateActivity( Activity eNewActivity )
Находим условие
else if ( enewActivity == ACT_RANGE_ATTACK2 )
В нём меняем оружие "weapon_grenadelauncher" на "weapon_smg1"

Далее находим описание события в анимации
case COMBINE_AE_GREN_LAUNCH
и переделываем его след. образом:
code:
case COMBINE_AE_GREN_LAUNCH:
{
EmitSound( "NPC_Combine.GrenadeLaunch" );

Vector vecThrow = m_vecTossVelocity;

CGrenadeAR2 *pGrenade = (CGrenadeAR2*)Create( "grenade_ar2", Weapon_ShootPosition(), vec3_angle, this );
pGrenade->SetAbsVelocity( vecThrow );

//CBaseEntity *pGrenade = CreateNoSpawn( "npc_contactgrenade", Weapon_ShootPosition(), vec3_angle, this );
//pGrenade->KeyValue( "velocity", m_vecTossVelocity );
//pGrenade->Spawn( );

m_iNumGrenades--;

if ( g_pGameRules->IsSkillLevel(SKILL_HARD) )
m_flNextGrenadeCheck = gpGlobals->curtime + random->RandomFloat( 2, 5 );// wait a random amount of time before shooting again
else
m_flNextGrenadeCheck = gpGlobals->curtime + 6;// wait six seconds before even looking again to see if a grenade can be thrown.
}
handledEvent = true;
break;


В
void CNPC_Combine::Precache()
добавляем
PrecacheModel("models/Weapons/ar2_grenade.mdl");

Компилируем server.dll

Теперь этот anim event надо добавить в исходник модельки.

SourceSDK пожопился и не дал нам его, так что будем делать по-кривому.

Декомпилируем combine_soldier.mdl и combine_soldier_anims.mdl
Лучше брать последние версии моделей.
combine_soldier_anims лучше декомпилировать именно CannonFodder's MDL Decompiler'ом, т.к. он хотябы некоторые анимации не испортит при декомпиляции.

Из декомпилированного кала combine_soldier_anims, уж извините по другому не назовёшь, берём shootAR2g.smd (мне она показалась самой подходящей), переименовываем в grenLaunch.smd и переносим его в директорию декомпилированного combine_soldier.

Открываем qc-файл от combine_soldier и дописываем после

$sequence ragdoll "ragdoll" ACT_DIERAGDOLL 1 fps 30.00

нашу анимацию и event

$sequence grenLaunch "grenLaunch" ACT_COMBINE_LAUNCH_GRENADE 1 { event 8 16 "" } fps 30.00

Компилируем.

Аналогичные вещи проделываем с combine_soldier_prisonguard.

(Конечно анимации должны по идее содержаться в combine_soldier_anims, но у меня не получилось его нормально декомпилировать. Так что могу предложить только такой способ.)

Важно обратить внимание на движок игры при компиляции:
- для старых версий, 2003 - 2005, используйте конфигурацию ер1.
- для новых - с 2007-го - orangebox.

отличаются они расположением файла studiomdl.exe:
В первом случае: ...Source SDK/bin/ep1/bin
Во втором: ...Source SDK/bin/orangebox/bin

Если скомпилировать не на том движке - могут глючить анимации.

Теперь заменяем скомпилированные phy-файлы на оригинальные.
Это нужно, чтобы не было багов с ragdoll'ом модельки.

Всё. Теперь солдат будет стрелять гранатами из автомата так же, как игрок.

2. Даём ГО-шнику револьвер "Магнум 357":

Прежде всего: убираем нафиг оригинальную модельку и вставляем в директорию ../models/weapons ту, что я прикрепил к этому сообщению.
Привязки и физика теперь впорядке, единственное - на оригинальных картах может лежать не совсем в тех же местах, т. к. в idle анимации оригинальной модельки ствол почему-то лежал на боку...

Кодируем weapon_357.cpp:
после всех #includ'оф в начале файла дописываем данные, предназначенные для персонажей:

code:
//-----------------------------------------------------------------------------
// CWeapon357
//-----------------------------------------------------------------------------

class CWeapon357 : public CBaseHLCombatWeapon
{
DECLARE_DATADESC();

public:
DECLARE_CLASS( CWeapon357, CBaseHLCombatWeapon );

CWeapon357(void);

DECLARE_SERVERCLASS();

void Precache( void );
void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
void PrimaryAttack( void );

int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; }

virtual void Equip( CBaseCombatCharacter *pOwner );

virtual const Vector& GetBulletSpread( void )
{
// Handle NPCs first
static Vector npcCone = VECTOR_CONE_5DEGREES;
if ( GetOwner() && GetOwner()->IsNPC() )
return npcCone;

static Vector cone;

cone = VECTOR_CONE_4DEGREES;

return cone;
}
virtual int GetMinBurst()
{
return 1;
}

virtual int GetMaxBurst()
{
return 2;
}

virtual float GetFireRate( void )
{
return 1.5f;
}

DECLARE_ACTTABLE();
};

IMPLEMENT_SERVERCLASS_ST(CWeapon357, DT_Weapon357)
END_SEND_TABLE()

LINK_ENTITY_TO_CLASS( weapon_357, CWeapon357 );
PRECACHE_WEAPON_REGISTER( weapon_357 );

BEGIN_DATADESC( CWeapon357 )
END_DATADESC()

acttable_t CWeapon357::m_acttable[] =
{
{ ACT_IDLE, ACT_IDLE_PISTOL, true },
{ ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_PISTOL, true },
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_PISTOL, true },
{ ACT_RELOAD, ACT_RELOAD_SMG1, true },
{ ACT_WALK_AIM, ACT_WALK_AIM_PISTOL, true },
{ ACT_RUN_AIM, ACT_RUN_AIM_PISTOL, true },
{ ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_PISTOL,true },
{ ACT_RELOAD_LOW, ACT_RELOAD_SMG1_LOW, false },
{ ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_PISTOL_LOW, false },
{ ACT_COVER_LOW, ACT_COVER_PISTOL_LOW, false },
{ ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_PISTOL_LOW, false },
{ ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, false },
};

IMPLEMENT_ACTTABLE( CWeapon357 );

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CWeapon357::CWeapon357( void )
{
m_fMinRange1 = 24;
m_fMaxRange1 = 1500;

m_bReloadsSingly = false;
m_bFiresUnderwater = false;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeapon357::Precache( void )
{
BaseClass::Precache();
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CWeapon357::Equip( CBaseCombatCharacter *pOwner )
{
BaseClass::Equip( pOwner );
}


Далее в том же файле после case event_weapon_reload дописываем ещё два.
code:
case EVENT_WEAPON_HG_RELOAD:
{
CAI_BaseNPC *npc = pOperator->MyNPCPointer();

CEffectData data;

for ( int i = 0; i < 6; i++ )
{
data.m_vOrigin = npc->Weapon_ShootPosition() + RandomVector( -4, 4 );
data.m_vAngles = QAngle( 90, random->RandomInt( 0, 360 ), 0 );
data.m_nEntIndex = entindex();

DispatchEffect( "ShellEject", data );
}
break;
}

case EVENT_WEAPON_PISTOL_FIRE:
{
Vector vecShootOrigin, vecShootDir;
vecShootOrigin = pOperator->Weapon_ShootPosition();

CAI_BaseNPC *npc = pOperator->MyNPCPointer();
ASSERT( npc != NULL );

vecShootDir = npc->GetActualShootTrajectory( vecShootOrigin );

CSoundEnt::InsertSound( SOUND_COMBAT, pOperator->GetAbsOrigin(), SOUNDENT_VOLUME_PISTOL, 0.2, pOperator );

WeaponSound( SINGLE_NPC );
pOperator->FireBullets( 1, vecShootOrigin, vecShootDir, VECTOR_CONE_PRECALCULATED, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 2 );
pOperator->DoMuzzleFlash();

m_iClip1 = m_iClip1 - 1;
}
break;
default:
BaseClass::Operator_HandleAnimEvent( pEvent, pOperator );
break;

Добавляем название "EVENT_WEAPON_HG_RELOAD" в ..game_shared/npcevent.h и ставим ему значение 3019 на всякий случай.

Теперь открываем npc_metropolice.cpp
void CNPC_MetroPolice::Spawn( void )
Здесь под if'ом с пистолетом МОЖНО БЫЛО БЫ дописать:

code:
if( !FClassnameIs( pWeapon, "weapon_357" ) )
{
m_fWeaponDrawn = true;
}


...но тогда этот дурак npc_metropolice перестанет доставать из кабуры и пистолет, и револьвер! Видимо, эта функция может работать только для ОДНОГО оружия, не важно какого. А вот почему - загадка на уровне чудес, которую я так и не раскопал...

В том же файле
void CNPC_MetroPolice::OnUpdateShotRegulator( )
под if'ом с weapon_pistol дописываем:
code:
if( Weapon_OwnsThisType( "weapon_357" ) )
{
if ( m_nBurstMode == BURST_NOT_ACTIVE )
{

GetShotRegulator()->SetBurstShotCountRange(GetActiveWeapon()->GetMinBurst(), GetActiveWeapon()->GetMaxBurst() );
GetShotRegulator()->SetRestInterval( 1.2, 2.0 );
}
}


В том же файле
внутри "Activity CNPC_MetroPolice::NPC_TranslateActivity( Activity newActivity )" дописываем if:
code:
if ( Weapon_OwnsThisType( "weapon_357" ) )
{
if ( newActivity == ACT_RELOAD || CapabilitiesGet() & bits_CAP_DUCK && newActivity == ACT_RELOAD_LOW )
{
//Emit 6 shells for hand gun reloading
animevent_t fakeEvent;
fakeEvent.pSource = this;
fakeEvent.event = EVENT_WEAPON_HG_RELOAD;
GetActiveWeapon()->Operator_HandleAnimEvent( &fakeEvent, this );
}
}


В том же файле
code:
WeaponProficiency_t CNPC_MetroPolice::CalcWeaponProficiency( CBaseCombatWeapon *pWeapon )
{
if( FClassnameIs( pWeapon, "weapon_pistol" ) )
{
return WEAPON_PROFICIENCY_POOR;
}

if( FClassnameIs( pWeapon, "weapon_smg1" ) )
{
return WEAPON_PROFICIENCY_VERY_GOOD;
}

if( FClassnameIs( pWeapon, "weapon_357" ) )
{
return WEAPON_PROFICIENCY_AVERAGE;
}

return BaseClass::CalcWeaponProficiency( pWeapon );
}


Теперь открываем c_te_legacy_tempents.cpp в исходниках для client.dll, в корешке, и дописываем muzzleflash для 357:
code:
case MUZZLEFLASH_357:
if ( firstPerson )
{
MuzzleFlash_357_Player( entityIndex, attachmentIndex );
}
else
{
MuzzleFlash_357_NPC( entityIndex, attachmentIndex );
}
break;


Далее:

code:
case MUZZLEFLASH_357:
if ( firstPerson )
{
MuzzleFlash_357_Player( entityIndex, 1 );
}
else
{
MuzzleFlash_357_NPC( entityIndex, 1 );
}
break;


Далее после "void CTempEnts::MuzzleFlash_357_Player( int entityIndex, int attachmentIndex )" делаем ещё один void:
code:
void CTempEnts::MuzzleFlash_357_NPC( int entityIndex, int attachmentIndex )
{
FX_MuzzleEffectAttached( 0.5f, entityIndex, attachmentIndex, NULL, true );
}


Открываем c_te_legacy_tempents.h
Дописываем под void'ом для игрока void для персонажей:
code:
// 357
void MuzzleFlash_357_Player( int entityIndex, int attachmentIndex );
void MuzzleFlash_357_NPC( int entityIndex, int attachmentIndex );


Компилируем client и server.

Теперь обращаемся к игровым скриптам. Обычно лежат в
..hl2/scripts/

Внутри weapon_357.txt в "SoundData" дописываем:
"single_shot_npc" "Weapon_357.NPC_Single"
"reload_npc" "Weapon_357.NPC_Reload"

Внутри game_sounds_weapons.txt
"Weapon_357.NPC_Single"
{
"channel" "CHAN_WEAPON"
"volume" "0.9"
"soundlevel" "SNDLVL_GUNFIRE"
"pitch" "68,73"

"wave" "^weapons/357_fire2.wav"
}

"Weapon_357.NPC_Reload"
{
"channel" "CHAN_ITEM"
"volume" "0.7"
"soundlevel" "SNDLVL_NORM"

"rndwave"
{
"wave" "weapons/357/357_reload1.wav"
"wave" "weapons/357/357_reload4.wav"
"wave" "weapons/357/357_reload3.wav"
}
}


Пока всё! Используйте наздоровье!

Хочу предупредить: неплохо целятся и больно бьют.

skill.cfg трогать не советую, т.к. на трудном уровне сложности игрок будет наносить такой же урон, как и другие обладатели оружия.
Прикрепленный файл: hl2.rar
Файл был скачан 29 раз(а).

Поправил 6apMaJIeu' 03-10-2015 в 17:27

Old Post 14-05-2015 15:25
6apMaJIeu' отсутствует Посмотреть данные '6apMaJIeu'' Отправить Приватное Сообщение для '6apMaJIeu'' Найти другие сообщения '6apMaJIeu'' Добавить 6apMaJIeu' в Список Друзей
Править/Удалить Сообщение Ответить с Цитированием
Все время в GMT . Сейчас 03:02.
Создать Новую Тему    Ответить

Быстрый ответ
Ваше Имя:
Хотите Зарегистрироваться?
Ваш Пароль:
Забыли свой Пароль?
Вы можете оставлять свои комментарии анонимно, просто введя свои имя и оставив пустым поле пароля.
Ваш ответ:

[проверить размер]
[транслит в win] | [?]
[русская клавиатура]

Дополнительно: Подтверждение по E-Mail


Быстрый переход:
 
Оцените эту Тему:
 

Правила форума:
Создание Тем не разрешено
Создание Сообщений разрешено
Создавать Вложения не разрешено
Редактирование Сообщений не разрешено
Коды HTML запрещены
Коды форума разрешены
Смайлики разрешены
Коды [IMG] запрещены