在 Half-Life MOD 中创建自己的武器及弹药
2006-03-12 14:52
471 查看
本文将介绍如何在 Half-Life MOD 中创建自己的武器及弹药, 本文所有源代码全部来自Codename HLDino, 你可以在Codename HLDino 开发者首页下载得到本文提到的源代码.
本文假设您有足够的C++知识及基本的HL MOD开发经验
首先, 在weapons.h中(没有硬性规定, 但是此为HL MOD开发惯例)添加武器类的声明以及一些宏的说明:
然后, 当然是对武器进行编码啦:
关于弹药的说明:
注意这一行:
p->pszAmmo1 = "ak47"; //指定弹药的名称
这一行中指定的就是弹药的名称了.然后要在CBaseEntity中添加声明来存储你的弹药:
int ammo_ak47; //cbase.h - 第350行
并在CBasePlayer::TabulateAmmo()中注册弹药:
ammo_ak47 = AmmoInventory( GetAmmoIndex( "ak47" ) ); //player.cpp - 第1141行
在你的代码中访问m_pPlayer->ammo_ak47即可得到弹药的数量.
弹药类 (CAK47Ammo)产生的实体是在地图中可以捡起的弹药, 如果你不需要这种功能( 如在CS中就没有这种功能 ), 就可以不写弹药类.
如果你想要武器可以打碎物品( 指func_breakable实体 ), 在CBreakable::pSpawnObjects[]数组中加入你的武器的名称:
然后, 在全局函数void W_Precache(void)中初始化你的武器:
这样, 在server端的代码就完成了.
现在, 打开你的client端代码, 并将 ak47.cpp 添加到工程的hl目录中:
在client端的主要任务是对武器击发是产生事件的处理, 注意刚才的server端代码中的这两句:
m_usAK47 = PRECACHE_EVENT( 1, "events/ak47.sc" );
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usAK47, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 );
它们分别初始化事件和触发事件, 在client端中要响应这个事件, 联系它们的纽带就是 "events/ak47.sc" 这个文件, 它可以是空的, 但是必须存在.
在ev_hldm.cpp中声明并完成事件函数:
在hl/hl_weapons.cpp中完成关于HUD的设置:
最后一步, 在hl/hl_events.cpp中给事件挂上钩子:
编译你的MOD, 配置sprite中的文件( sprite/weapon_ak47.txt )指定准星, HUD图标等, 新的武器就完成了.
Copyright © 2000-2005 =M4CS=
ALL RIGHTS RESERVED
本文假设您有足够的C++知识及基本的HL MOD开发经验
首先, 在weapons.h中(没有硬性规定, 但是此为HL MOD开发惯例)添加武器类的声明以及一些宏的说明:
//weapons.h - 第81行 //武器的ID #define WEAPON_AK47 16 //weapons.h - 第98行 //武器的重量(在拣到武器时, 重的武器会被自动切换) #define AK47_WEIGHT 25 //weapons.h - 第114行 //最大载弹量 #define AK47_MAX_CARRY 250 //weapons.h - 第133行 //每个弹匣的最大载弹量 #define AK47_MAX_CLIP 30 //weapons.h - 第150行 //在拣到武器时给予的子弹数目 #define AK47_DEFAULT_GIVE 30 //weapons.h - 第169行 //在拣到弹药时给予的子弹数目 #define AMMO_AK47CLIP_GIVE AK47_MAX_CLIP //weapons.h - 第591行 //武器的类声明 class CAK47 : public CBasePlayerWeapon { public: void Spawn( void ); void Precache( void ); int iItemSlot( void ) { return 3; } int GetItemInfo(ItemInfo *p); int AddToPlayer( CBasePlayer *pPlayer ); void PrimaryAttack( void ); BOOL Deploy( void ); void Reload( void ); void WeaponIdle( void ); float m_flNextAnimTime; int m_iShell; virtual BOOL UseDecrement( void ) { #if defined( CLIENT_WEAPONS ) return TRUE; #else return FALSE; #endif } private: unsigned short m_usAK47; };
然后, 当然是对武器进行编码啦:
/*** * * 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. * ****/ /** * Codename HLDino * Version: Beta 1.0 * Date: Feb 2, 2005 * Author: fiNAL.Y * Description: * The source code for weapon_ak47 * Copyright (C) 2000-2005 =M4CS= Development * Copyright (C) 2000-2005 SoftBoys Entertainment * Copyright (C) 2000-2005 MODChina.com */ #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" //定义武器的动作, 这些动作的顺序和模型(v_ak47.mdl)中是一致的 enum AK47_e { AK47_IDLE1 = 0, AK47_RELOAD, AK47_DRAW, AK47_SHOOT1, AK47_SHOOT2, AK47_SHOOT3, }; //定义武器的伤害值 const int AK47_DAMAGE = 25; //使类与游戏中的实体建立连接 LINK_ENTITY_TO_CLASS( weapon_ak47, CAK47 ); //========================================================= //========================================================= //在武器产生时被调用 void CAK47::Spawn( ) { pev->classname = MAKE_STRING("weapon_ak47"); //指定了武器的名称(最好与实体名称一致) Precache( ); SET_MODEL(ENT(pev), "models/w_ak47.mdl"); m_iId = WEAPON_AK47; m_iDefaultAmmo = AK47_DEFAULT_GIVE; FallInit();// get ready to fall down. } void CAK47::Precache( void ) { //告诉引擎对以下文件进行预缓存 PRECACHE_MODEL("models/v_ak47.mdl"); PRECACHE_MODEL("models/w_ak47.mdl"); PRECACHE_MODEL("models/p_ak47.mdl"); m_iShell = PRECACHE_MODEL ("models/shell.mdl"); PRECACHE_SOUND ("weapons/ak47-1.wav"); PRECACHE_SOUND ("weapons/ak47-2.wav"); PRECACHE_SOUND ("weapons/ak47_clipin.wav"); PRECACHE_SOUND( "weapons/ak47_clipout.wav" ); PRECACHE_SOUND( "weapons/ak47_boltpull.wav" ); m_usAK47 = PRECACHE_EVENT( 1, "events/ak47.sc" ); } int CAK47::GetItemInfo(ItemInfo *p) { p->pszName = STRING(pev->classname); p->pszAmmo1 = "ak47"; //指定弹药的名称 p->iMaxAmmo1 = AK47_MAX_CARRY; p->pszAmmo2 = NULL; p->iMaxAmmo2 = -1; p->iMaxClip = AK47_MAX_CLIP; p->iSlot = 2; p->iPosition = 4; //这两行指定了武器在HUD中的位置, 不要与其他武器重复 p->iFlags = 0; p->iId = m_iId = WEAPON_AK47; p->iWeight = AK47_WEIGHT; return 1; } int CAK47::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 CAK47::Deploy( ) { return DefaultDeploy( "models/v_ak47.mdl", "models/p_ak47.mdl", AK47_DRAW, "AK47" ); } void CAK47::PrimaryAttack() { 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--; m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); Vector vecSrc = m_pPlayer->GetGunPosition( ); Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); Vector vecDir; #ifdef CLIENT_DLL if ( !bIsMultiplayer() ) #else if ( !g_pGameRules->IsMultiplayer() ) #endif { // optimized multiplayer. Widened to make it easier to hit a moving player vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, 8192, BULLET_PLAYER_MP5, 2, AK47_DAMAGE, m_pPlayer->pev, m_pPlayer->random_seed ); } else { // single player spread vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_3DEGREES, 8192, BULLET_PLAYER_MP5, 2, AK47_DAMAGE, m_pPlayer->pev, m_pPlayer->random_seed ); } int flags; #if defined( CLIENT_WEAPONS ) flags = FEV_NOTHOST; #else flags = 0; #endif PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usAK47, 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) // HEV suit - indicate out of ammo condition m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; if ( m_flNextPrimaryAttac 4000 k < UTIL_WeaponTimeBase() ) m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } void CAK47::Reload( void ) { if ( m_pPlayer->ammo_ak47 <= 0 ) return; DefaultReload( AK47_MAX_CLIP, AK47_RELOAD, 1.5 ); } void CAK47::WeaponIdle( void ) { ResetEmptySound( ); if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; SendWeaponAnim( AK47_IDLE1 ); m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } //弹药的类定义 class CAK47Ammo : public CBasePlayerAmmo { void Spawn( void ) { Precache( ); SET_MODEL(ENT(pev), "models/w_9mmARclip.mdl"); CBasePlayerAmmo::Spawn( ); } void Precache( void ) { PRECACHE_MODEL ("models/w_9mmARclip.mdl"); PRECACHE_SOUND("items/9mmclip1.wav"); } BOOL AddAmmo( CBaseEntity *pOther ) { int bResult = (pOther->GiveAmmo( AMMO_AK47CLIP_GIVE, "ak47", AK47_MAX_CARRY) != -1); if (bResult) { EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); } return bResult; } }; LINK_ENTITY_TO_CLASS( ammo_ak47, CAK47Ammo );
关于弹药的说明:
注意这一行:
p->pszAmmo1 = "ak47"; //指定弹药的名称
这一行中指定的就是弹药的名称了.然后要在CBaseEntity中添加声明来存储你的弹药:
int ammo_ak47; //cbase.h - 第350行
并在CBasePlayer::TabulateAmmo()中注册弹药:
ammo_ak47 = AmmoInventory( GetAmmoIndex( "ak47" ) ); //player.cpp - 第1141行
在你的代码中访问m_pPlayer->ammo_ak47即可得到弹药的数量.
弹药类 (CAK47Ammo)产生的实体是在地图中可以捡起的弹药, 如果你不需要这种功能( 如在CS中就没有这种功能 ), 就可以不写弹药类.
如果你想要武器可以打碎物品( 指func_breakable实体 ), 在CBreakable::pSpawnObjects[]数组中加入你的武器的名称:
//func_break.cpp - 第61行 "weapon_ak47", // 22 "ammo_ak47", // 23
然后, 在全局函数void W_Precache(void)中初始化你的武器:
//weapons.cpp - 第337行 // ak47 UTIL_PrecacheOtherWeapon( "weapon_ak47" ); UTIL_PrecacheOther( "ammo_ak47" );
这样, 在server端的代码就完成了.
现在, 打开你的client端代码, 并将 ak47.cpp 添加到工程的hl目录中:
在client端的主要任务是对武器击发是产生事件的处理, 注意刚才的server端代码中的这两句:
m_usAK47 = PRECACHE_EVENT( 1, "events/ak47.sc" );
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usAK47, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 );
它们分别初始化事件和触发事件, 在client端中要响应这个事件, 联系它们的纽带就是 "events/ak47.sc" 这个文件, 它可以是空的, 但是必须存在.
在ev_hldm.cpp中声明并完成事件函数:
//ev_hldm.cpp - 第83行 void EV_AK47Fire( struct event_args_s *args ); //ev_hldm.cpp - 第1604行 void EV_AK47Fire( event_args_t *args ) { //... }
在hl/hl_weapons.cpp中完成关于HUD的设置:
//hl/hl_weapons.cpp - 第69行 CAK47 g_Ak47; //hl/hl_weapons.cpp - 第639行 void HUD_InitClientWeapons( void ) { //... HUD_PrepEntity( &g_Ak47 , &player ); //... } //hl/hl_weapons.cpp - 第757行 void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cmd, double time, unsigned int random_seed ) { //... switch ( from->client.m_iId ) { //... case WEAPON_AK47: pWeapon = &g_Ak47; break; //... } //... }
最后一步, 在hl/hl_events.cpp中给事件挂上钩子:
//hl/hl_events.cpp - 第39行, 与ev_hldm中的声明保持一致 void EV_AK47Fire( struct event_args_s *args ); //hl/hl_events.cpp - 第79行 gEngfuncs.pfnHookEvent( "events/ak47.sc", EV_AK47Fire );
编译你的MOD, 配置sprite中的文件( sprite/weapon_ak47.txt )指定准星, HUD图标等, 新的武器就完成了.
Copyright © 2000-2005 =M4CS=
ALL RIGHTS RESERVED
相关文章推荐
- 使用plugman 创建一个自己的cordova插件
- openerp学习笔记 搜索视图(自己创建的、自己的、本部门的、本部门及下属部门的、今日的、日期从,日期至、多条件模糊搜索、or、and)
- iOS开发之保存照片到自己创建的相簿
- 【docker】创建自己的容器并提交至镜像中心
- 在thinkphp框架既然系统已经有了model为什么还需要创建自己的model
- 创建一个自己的jar包
- MySQL 创建表时,设置时间字段自己主动插入当前时间
- 基础总结篇之八:创建及调用自己的ContentProvider
- 创建自己Stack底层使用链表java版本
- JAVA进阶 面向对象程序设计——第1周 类与对象(自己定义类,然后用自己定义的类来创建对象)
- JavaScript-创建第一个自己的类库
- 提示 #32: 你知道吗... 如何轻松地创建你自己的项目模板?
- wordpress 自己创建插件怎么创建
- 使用method_missing和respond_to?创建自己的动态方法
- 创建一个数组, 实现函数init()初始化数组、 实现empty()清空数组、 实现reverse()函数完成数组元素的逆置。 要求:自己设计函数的参数,返回值
- 自己创建@Resource注解
- oracle创建数据库后创建自己的用户
- 创建自己的yum 仓库
- 自己创建集合
- 创建自己的pk8, x509.pem并给app签名