目录
- 概述
- 定义
- 核心机制
- 1. SpellScript 系统
- 2. 可用的事件类型
- 注册方式
- 1. 基础注册
- 2. 在脚本加载器中注册
- 使用场景
- 1. BOSS 战机制
- 2. NPC 行为控制
- 3. 传送门功能
- 4. 通用功能
- 代码示例
- 示例 1: 基本 BOSS 机制
- 示例 2: 通用法术 - 食尸
- 示例 3: 目标选择 + DUMMY 效果
- 示例 4: BOSS 技能 - 孢子召唤者
- 示例 5: 实体消失
- 最佳实践
- 1. 空值检查
- 2. 使用正确的效果索引
- 3. 选择合适的事件
- 4. 代码组织
- 5. 性能考虑
- 注意事项
- 1. 脚本注册
- 2. 调试技巧
- 3. 多线程安全
- 4. 性能影响
- 总结
概述
SPELL_EFFECT_DUMMY是 TrinityCore 中的一种特殊法术效果,主要用于作为脚本触发器使用。它本身不提供任何内置的游戏逻辑,而是允许通过脚本系统实现自定义的游戏机制。
定义
SPELL_EFFECT_DUMMY在SharedDefines.h中定义为SpellEffectName枚举的第 3 个值:
核心机制
1. SpellScript 系统
DUMMY 效果通过SpellScript类和SpellEffectFn宏实现:
classspell_custom_spell:publicSpellScript{PrepareSpellScript(spell_custom_spell);voidHandleHit(SpellEffIndex effIndex){// 自定义逻辑}voidRegister()override{OnEffectHitTarget+=SpellEffectFn(spell_custom_spell::HandleHit,EFFECT_0,SPELL_EFFECT_DUMMY);}};2. 可用的事件类型
DUMMY 效果可以绑定到以下事件:
OnEffectHitTarget- 效果命中目标时触发OnEffectHit- 效果命中时触发OnObjectAreaTargetSelect- 区域目标选择时触发OnEffectLaunchTarget- 效果发射到目标时触发
注册方式
1. 基础注册
voidRegister()override{OnEffectHitTarget+=SpellEffectFn(spell_custom::HandleHit,EFFECT_0,SPELL_EFFECT_DUMMY);}2. 在脚本加载器中注册
voidAddSC_boss_example(){RegisterSpellScript(spell_custom_spell);}使用场景
1. BOSS 战机制
最常见的使用场景,用于实现复杂的 BOSS 战斗机制:
- 阶段转换
- 特殊技能触发
- 团队光环效果
- 事件序列控制
2. NPC 行为控制
- 对话触发
- 特定行为激活
- 状态机转换
3. 传送门功能
- 传送门激活
- 目标选择逻辑
- 传送条件判断
4. 通用功能
- 法术增强
- 自定义效果叠加
- 复杂的条件判断
代码示例
示例 1: 基本 BOSS 机制
来自boss_elder_leaxa.cpp:
classspell_sanguine_feast_selector:publicSpellScript{PrepareSpellScript(spell_sanguine_feast_selector);voidHandleHit(SpellEffIndex/*effIndex*/){Unit*caster=GetCaster();Unit*target=GetHitUnit();if(!caster||!target)return;// 自定义逻辑:选择目标并执行特殊效果if(caster->GetTypeId()==TYPEID_UNIT)caster->CastSpell(target,SPELL_SANGUINE_FEAST_DMG,true);}voidRegister()override{OnEffectHitTarget+=SpellEffectFn(spell_sanguine_feast_selector::HandleHit,EFFECT_0,SPELL_EFFECT_DUMMY);}};示例 2: 通用法术 - 食尸
来自spell_generic.cpp:
classspell_gen_cannibalize:publicSpellScript{PrepareSpellScript(spell_gen_cannibalize);voidHandleDummy(SpellEffIndex/*effIndex*/){Unit*caster=GetCaster();if(!caster)return;// 自定义逻辑:食尸效果caster->CastSpell(caster,SPELL_CANNIBALIZE_TRIGGERED,true);}voidRegister()override{OnEffectHitTarget+=SpellEffectFn(spell_gen_cannibalize::HandleDummy,EFFECT_0,SPELL_EFFECT_DUMMY);}};示例 3: 目标选择 + DUMMY 效果
来自boss_priestess_alun_za.cpp:
classspell_reanimated_ritualist_bolt:publicSpellScript{PrepareSpellScript(spell_reanimated_ritualist_bolt);voidFilterTargets(std::list<WorldObject*>&targets){// 自定义目标选择逻辑targets.remove_if([](WorldObject*obj){Unit*unit=obj->ToUnit();return!unit||!unit->IsPlayer();});}voidHandleHit(SpellEffIndex/*effIndex*/){// 命中目标后的处理Unit*target=GetHitUnit();if(target)GetCaster()->CastSpell(target,SPELL_BOSS_ABILITY,true);}voidRegister()override{OnObjectAreaTargetSelect+=SpellObjectAreaTargetSelectFn(spell_reanimated_ritualist_bolt::FilterTargets,EFFECT_0,TARGET_UNIT_DEST_AREA_ENEMY);OnEffectHitTarget+=SpellEffectFn(spell_reanimated_ritualist_bolt::HandleHit,EFFECT_0,SPELL_EFFECT_DUMMY);}};示例 4: BOSS 技能 - 孢子召唤者
来自boss_sporecaller_zancha.cpp:
classspell_zancha_shocking_claw:publicSpellScript{PrepareSpellScript(spell_zancha_shocking_claw);voidHandleHit(SpellEffIndex/*effIndex*/){Unit*caster=GetCaster();Unit*target=GetHitUnit();if(!caster||!target)return;// 自定义逻辑:BOSS 特殊技能if(caster->GetEntry()==NPC_SPORECALLER_ZANCHA)caster->CastSpell(target,SPELL_SHOCKING_CLAW_DMG,true);}voidRegister()override{OnEffectHitTarget+=SpellEffectFn(spell_zancha_shocking_claw::HandleHit,EFFECT_0,SPELL_EFFECT_DUMMY);}};示例 5: 实体消失
来自spell_generic.cpp:
classspell_gen_despawn_self:publicSpellScript{PrepareSpellScript(spell_gen_despawn_self);voidHandleDummy(SpellEffIndex/*effIndex*/){Unit*caster=GetCaster();if(!caster)return;// 自定义逻辑:实体消失if(Creature*creature=caster->ToCreature())creature->DespawnOrUnsummon();}voidRegister()override{OnEffectHit+=SpellEffectFn(spell_gen_despawn_self::HandleDummy,EFFECT_0,SPELL_EFFECT_DUMMY);}};最佳实践
1. 空值检查
始终检查关键指针:
voidHandleHit(SpellEffIndex/*effIndex*/){Unit*caster=GetCaster();Unit*target=GetHitUnit();if(!caster||!target)return;// 安全的逻辑代码}2. 使用正确的效果索引
根据需要选择EFFECT_0、EFFECT_1或EFFECT_2:
// 单效果法术OnEffectHitTarget+=SpellEffectFn(spell_custom::HandleHit,EFFECT_0,SPELL_EFFECT_DUMMY);// 多效果法术OnEffectHitTarget+=SpellEffectFn(spell_custom::HandleEffect0,EFFECT_0,SPELL_EFFECT_DUMMY);OnEffectHitTarget+=SpellEffectFn(spell_custom::HandleEffect1,EFFECT_1,SPELL_EFFECT_DUMMY);3. 选择合适的事件
根据需求选择正确的事件类型:
OnEffectHitTarget- 需要目标信息时使用OnEffectHit- 不需要目标信息时使用OnObjectAreaTargetSelect- 需要自定义目标选择时使用
4. 代码组织
保持代码清晰和模块化:
classspell_custom_effect:publicSpellScript{PrepareSpellScript(spell_custom_effect);// 辅助函数boolIsValidTarget(Unit*target){returntarget&&target->IsAlive();}voidHandleHit(SpellEffIndex/*effIndex*/){Unit*target=GetHitUnit();if(!IsValidTarget(target))return;// 主要逻辑}voidRegister()override{OnEffectHitTarget+=SpellEffectFn(spell_custom_effect::HandleHit,EFFECT_0,SPELL_EFFECT_DUMMY);}};5. 性能考虑
避免在 DUMMY 效果处理函数中执行过于复杂的计算:
voidHandleHit(SpellEffIndex/*effIndex*/){// 快速处理if(!GetCaster()||!GetHitUnit())return;// 执行必要的逻辑GetCaster()->CastSpell(GetHitUnit(),SOME_SPELL,true);}注意事项
1. 脚本注册
不要忘记在脚本加载器中注册:
voidAddSC_your_script(){RegisterSpellScript(spell_custom_effect);}2. 调试技巧
使用日志输出帮助调试:
voidHandleHit(SpellEffIndex/*effIndex*/){LOG_DEBUG("scripts","DUMMY effect hit: Caster {}, Target {}",GetCaster()?GetCaster()->GetEntry():0,GetHitUnit()?GetHitUnit()->GetEntry():0);}3. 多线程安全
注意 TrinityCore 是多线程的,确保代码是线程安全的:
- 避免静态变量
- 使用线程安全的数据结构
- 注意对象生命周期
4. 性能影响
DUMMY 效果会频繁触发,特别是在多人战斗中:
- 保持处理逻辑简洁
- 避免数据库查询
- 减少不必要的计算
- 使用缓存
总结
SPELL_EFFECT_DUMMY是 TrinityCore 脚本系统中最强大和灵活的工具之一。通过它,可以实现几乎任何自定义的游戏机制。正确理解和使用 DUMMY 效果对于创建高质量的服务器脚本至关重要。
关键要点:
- DUMMY 效果作为脚本触发器,不提供内置逻辑
- 通过
SpellScript和SpellEffectFn宏实现自定义逻辑 - 广泛应用于 BOSS 战、NPC 行为等场景
- 遵循最佳实践确保代码质量和性能
- 注意脚本注册的完整性