目录
-
- 概述
- 定义
- 核心机制
-
- [1. 处理函数](#1. 处理函数)
- [2. 相关的召唤效果](#2. 相关的召唤效果)
- 数据库配置
-
- [spell_effect 表 | SpellEffect.db2](#spell_effect 表 | SpellEffect.db2)
- [SummonProperties.db2 配置](#SummonProperties.db2 配置)
- 脚本注册与使用
- 使用场景
-
- [1. BOSS 战机制](#1. BOSS 战机制)
- [2. 职业召唤系统](#2. 职业召唤系统)
- [3. 功能性召唤](#3. 功能性召唤)
- [4. 任务相关召唤](#4. 任务相关召唤)
- 代码示例
-
- [示例 1: Boss 战召唤小怪](#示例 1: Boss 战召唤小怪)
- [示例 2: 战场宠物召唤](#示例 2: 战场宠物召唤)
- [示例 3: 自定义召唤属性](#示例 3: 自定义召唤属性)
- [示例 4: 多目标召唤](#示例 4: 多目标召唤)
- [示例 5: 召唤并绑定 AI](#示例 5: 召唤并绑定 AI)
- 最佳实践
-
- [1. 选择合适的召唤类型](#1. 选择合适的召唤类型)
- [2. 设置合理的持续时间](#2. 设置合理的持续时间)
- [3. 考虑召唤位置](#3. 考虑召唤位置)
- [4. 处理召唤失败](#4. 处理召唤失败)
- [5. 管理召唤物生命周期](#5. 管理召唤物生命周期)
- 调试与故障排除
- 性能考虑
-
- [1. 批量召唤](#1. 批量召唤)
- [2. 内存管理](#2. 内存管理)
- [3. 网络同步](#3. 网络同步)
- [4. AI 负载](#4. AI 负载)
- 扩展与自定义
- 注意事项
-
- [1. 数据库/DB2配置](#1. 数据库/DB2配置)
- [2. 脚本注册](#2. 脚本注册)
- [3. 空值检查](#3. 空值检查)
- [4. 线程安全](#4. 线程安全)
- [5. 性能影响](#5. 性能影响)
- 总结
概述
SPELL_EFFECT_SUMMON 主要用于实现技能召唤功能。当玩家或 NPC 施放具有此效果的技能时,会在指定位置召唤出生物、物体或其他实体。
主要特点:
- 是 TrinityCore 中实现召唤系统的核心
- 召唤生物、守护者、载具、图腾等各种游戏对象,广泛应用于 BOSS 战机制、召唤宠物、临时守卫、载具召唤等
- 支持多种召唤类型和属性配置
定义
SPELL_EFFECT_SUMMON 在 SharedDefines.h 中定义为 SpellEffectName 枚举的第 28 个值
核心机制
1. 处理函数
SPELL_EFFECT_SUMMON 的处理函数在 SpellEffects.cpp 中的 EffectSummonType():
cpp
void Spell::EffectSummonType()
{
if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH)
return;
uint32 entry = effectInfo->MiscValue;
if (!entry)
return;
SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(effectInfo->MiscValueB);
if (!properties)
{
TC_LOG_ERROR("spells", "EffectSummonType: Unhandled summon type {}.", effectInfo->MiscValueB);
return;
}
// 确定召唤者
WorldObject* caster = m_caster;
if (m_originalCaster)
caster = m_originalCaster;
// 计算持续时间
Milliseconds duration = Milliseconds(m_spellInfo->CalcDuration(caster));
// 确定召唤数量
uint32 numSummons;
switch (effectInfo->MiscValueB)
{
case 64: case 61: case 1101: case 66: case 648: case 2301:
case 1061: case 1261: case 629: case 181: case 715:
case 1562: case 833: case 1161: case 713:
numSummons = (damage > 0) ? damage : 1;
break;
default:
numSummons = 1;
break;
}
// 根据召唤类型执行不同的召唤逻辑
switch (properties->Control)
{
case SUMMON_CATEGORY_WILD:
case SUMMON_CATEGORY_ALLY:
SummonGuardian(effectInfo, entry, properties, numSummons, privateObjectOwner);
break;
case SUMMON_CATEGORY_VEHICLE:
summon = unitCaster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, unitCaster, m_spellInfo->Id);
break;
// ... 其他情况处理
}
}
2. 相关的召唤效果
TrinityCore 中还有其他相关的召唤效果:
| 效果名称 | 值 | 用途 |
|---|---|---|
SPELL_EFFECT_SUMMON |
28 | 通用召唤 |
SPELL_EFFECT_SUMMON_PET |
56 | 召唤宠物 |
SPELL_EFFECT_SUMMON_OBJECT_WILD |
76 | 召唤野生物体 |
SPELL_EFFECT_SUMMON_PLAYER |
85 | 召唤玩家 |
SPELL_EFFECT_SUMMON_OBJECT_SLOT1 |
104 | 槽位 1 物体召唤 |
SPELL_EFFECT_SUMMON_PERSONAL_GAMEOBJECT |
171 | 个人游戏对象召唤 |
数据库配置
spell_effect 表 | SpellEffect.db2
要使用 SPELL_EFFECT_SUMMON,需要在 spell_effect 表或 SpellEffect.db2中配置以下关键字段:
| 字段 | 说明 | 示例值 |
|---|---|---|
Effect |
效果类型 | 28 (SPELL_EFFECT_SUMMON) |
EffectMiscValue |
召唤生物的 entry ID | creature_template.entry |
EffectMiscValueB |
召唤属性 ID | 参考 SummonProperties.dbc |
EffectApplyAuraName |
通常为 0 | 0 |
EffectAmplitude |
效果振幅 | 根据需求设置 |
EffectChainTarget |
连锁目标数 | 0 |
EffectDieSides |
伤害骰子面数 | 1 |
EffectBasePoints |
基础点数 | 召唤数量或等级相关 |
EffectMechanic |
机制类型 | 0 |
EffectImplicitTargetA |
目标 A | 取决于召唤位置 |
EffectImplicitTargetB |
目标 B | 通常为 0 |
SummonProperties.db2 配置
EffectMiscValueB 对应 SummonProperties.db2 中的条目,用于控制召唤的行为特性:
- Control: 控制类型(宠物、守卫、载具等)
- Flags: 特殊标志位
- Title: 召唤物标题/类型
- Slot: 装备槽位(如果是装备类召唤)
脚本注册与使用
基本脚本注册方式
cpp
class spell_example_summon : public SpellScript
{
PrepareSpellScript(spell_example_summon);
void HandleSummon(SpellEffIndex effIndex)
{
// 自定义召唤逻辑
PreventHitDefaultEffect(effIndex);
// 获取效果信息
if (SpellEffectInfo const* effect = GetEffectInfo(effIndex))
{
uint32 creatureEntry = effect->MiscValue; // 生物模板 ID
uint32 summonPropID = effect->MiscValueB; // 召唤属性 ID
// 执行自定义召唤逻辑
// ...
}
}
void Register() override
{
OnEffectLaunch += SpellEffectFn(spell_example_summon::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON);
}
};
在脚本加载器中注册
cpp
void AddSC_example_summon()
{
RegisterSpellScript(spell_example_summon);
}
使用场景
1. BOSS 战机制
- 召唤援军
- 阶段转换
- 特殊技能载体
2. 职业召唤系统
- 术士宠物:使用
SPELL_EFFECT_SUMMON_PET - 猎人宠物:类似机制但可能有特殊处理
- 死亡骑士食尸鬼:特定模板和属性
3. 功能性召唤
- 工程学机械:临时召唤修理机器人等
- 载具系统:召唤可骑乘的载具
- 图腾召唤:萨满图腾的特殊处理
4. 任务相关召唤
- 任务物品:召唤任务所需的 NPC 或物体
- 剧情触发:过场动画中的角色召唤
代码示例
示例 1: Boss 战召唤小怪
cpp
class spell_putricide_mutated_transformation : public SpellScript
{
PrepareSpellScript(spell_putricide_mutated_transformation);
void HandleSummon(SpellEffIndex effIndex)
{
// 阻止默认召唤效果
PreventHitDefaultEffect(effIndex);
Unit* caster = GetCaster();
Position pos = GetHitDest()->GetPosition();
if (!caster)
return;
// 召唤突变体
caster->SummonCreature(NPC_MUTATED_ABOMINATION, pos, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000);
}
void Register() override
{
OnEffectLaunch += SpellEffectFn(spell_putricide_mutated_transformation::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON);
}
};
示例 2: 战场宠物召唤
cpp
class spell_summon_battle_pet : public SpellScript
{
PrepareSpellScript(spell_summon_battle_pet);
void HandleSummon(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
Unit* caster = GetCaster();
if (!caster)
return;
Position pos = caster->GetPosition();
caster->SummonCreature(NPC_BATTLE_PET, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1000);
}
void Register() override
{
OnEffectLaunch += SpellEffectFn(spell_summon_battle_pet::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON);
}
};
示例 3: 自定义召唤属性
cpp
class spell_custom_summon_properties : public SpellScript
{
PrepareSpellScript(spell_custom_summon_properties);
void HandleSummon(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
Unit* caster = GetCaster();
Position pos = GetHitDest()->GetPosition();
if (!caster)
return;
TempSummonType summonType = TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
Milliseconds duration(60000);
if (caster->GetMap()->IsHeroic())
{
duration = Milliseconds(120000); // 英雄模式延长持续时间
}
caster->SummonCreature(NPC_CUSTOM_SUMMON, pos, summonType, duration);
}
void Register() override
{
OnEffectLaunch += SpellEffectFn(spell_custom_summon_properties::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON);
}
};
示例 4: 多目标召唤
cpp
class spell_summon_multiple_targets : public SpellScript
{
PrepareSpellScript(spell_summon_multiple_targets);
void HandleSummon(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
Unit* caster = GetCaster();
if (!caster)
return;
// 在目标位置召唤多个单位
Position pos = GetHitDest()->GetPosition();
// 召唤 3 个单位
for (int i = 0; i < 3; ++i)
{
Position offset = pos;
offset.m_positionX += frand(-2.0f, 2.0f);
offset.m_positionY += frand(-2.0f, 2.0f);
caster->SummonCreature(NPC_MINION, offset, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000);
}
}
void Register() override
{
OnEffectLaunch += SpellEffectFn(spell_summon_multiple_targets::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON);
}
};
示例 5: 召唤并绑定 AI
cpp
class spell_summon_with_ai : public SpellScript
{
PrepareSpellScript(spell_summon_with_ai);
void HandleSummon(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
Unit* caster = GetCaster();
Position pos = GetHitDest()->GetPosition();
if (!caster)
return;
Creature* summoned = caster->SummonCreature(NPC_SUMMONED_GUARDIAN, pos, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000);
if (summoned)
{
// 设置召唤物的 AI
summoned->SetFaction(caster->GetFaction());
summoned->SetReactState(REACT_DEFENSIVE);
// 如果是玩家召唤的,可以绑定到玩家
if (Player* player = caster->ToPlayer())
{
summoned->SetOwnerGUID(player->GetGUID());
}
}
}
void Register() override
{
OnEffectLaunch += SpellEffectFn(spell_summon_with_ai::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON);
}
};
最佳实践
1. 选择合适的召唤类型
根据需求选择正确的召唤类型:
cpp
// 临时召唤
caster->SummonCreature(entry, pos, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, duration);
// 宠物类型(持续存在直到死亡或解散)
caster->SummonCreature(entry, pos, TEMPSUMMON_CORPSE_DESPAWN, 0);
// 玩家宠物
caster->SummonCreature(entry, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 0);
2. 设置合理的持续时间
根据场景设置合适的持续时间:
cpp
// 短暂召唤(如战斗辅助)
Milliseconds duration(30000); // 30 秒
// 持续召唤(如 BOSS 战)
Milliseconds duration(600000); // 10 分钟
// 永久召唤(直到死亡)
Milliseconds duration(0); // 0 表示永久
3. 考虑召唤位置
确保召唤位置安全且合理:
cpp
void HandleSummon(SpellEffIndex effIndex)
{
Unit* caster = GetCaster();
Position pos = GetHitDest()->GetPosition();
// 检查位置是否有效
float groundZ = caster->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
if (groundZ > INVALID_HEIGHT)
{
pos.m_positionZ = groundZ; // 调整到地面高度
}
caster->SummonCreature(entry, pos, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, duration);
}
4. 处理召唤失败
始终处理召唤失败的情况:
cpp
void HandleSummon(SpellEffIndex effIndex)
{
Unit* caster = GetCaster();
if (!caster)
return;
Position pos = GetHitDest()->GetPosition();
Creature* summoned = caster->SummonCreature(entry, pos, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, duration);
if (!summoned)
{
TC_LOG_ERROR("scripts", "Failed to summon creature {}", entry);
return;
}
// 成功召唤后的处理
}
5. 管理召唤物生命周期
合理管理召唤物的生命周期:
cpp
void HandleSummon(SpellEffIndex effIndex)
{
Unit* caster = GetCaster();
Creature* summoned = caster->SummonCreature(entry, pos, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, duration);
if (summoned)
{
// 设置召唤物会在一定时间后自动消失
summoned->DespawnOrUnsummon(duration);
}
}
调试与故障排除
常见问题
-
召唤物未出现
- 检查
EffectMiscValue是否为有效的 creature_template.entry - 验证
EffectMiscValueB对应的 SummonProperties 条目存在 - 确认施法者有权限在该位置召唤
- 检查
-
召唤物立即消失
- 检查持续时间计算是否正确
- 验证召唤属性的 Flags 设置
- 确认地图支持该类型的召唤
-
召唤位置错误
- 检查
EffectImplicitTargetA的目标选择 - 验证施法者的朝向和位置数据
- 考虑碰撞检测和地面高度
- 检查
日志调试
cpp
void HandleSummon(SpellEffIndex effIndex)
{
TC_LOG_INFO("scripts", "Summoning creature entry {} with properties {}",
effectInfo->MiscValue, effectInfo->MiscValueB);
// 执行召唤逻辑
}
性能考虑
1. 批量召唤
对于需要召唤多个单位的技能,合理设置 numSummons:
cpp
// 使用数据库配置的召唤数量,而不是在脚本中循环
// 效率更高
2. 内存管理
及时清理临时召唤物,避免内存泄漏:
cpp
// 使用合适的召唤类型
TEMPSUMMON_TIMED_OR_DEAD_DESPAWN // 超时或死亡后消失
TEMPSUMMON_CORPSE_DESPAWN // 死亡后尸体消失
3. 网络同步
大量召唤时注意网络包大小和处理频率:
cpp
// 避免在短时间内召唤大量单位
// 可以使用延迟召唤
4. AI 负载
过多召唤物可能影响服务器性能,需要合理限制:
cpp
// 限制最大召唤数量
if (caster->GetGuardianCount() >= MAX_GUARDIANS)
return;
扩展与自定义
自定义召唤逻辑
可以通过继承 SpellScript 并重写相关方法来添加自定义行为:
cpp
class custom_summon_script : public SpellScript
{
void CustomSummonHandling()
{
// 修改召唤位置
// 设置特殊属性
// 绑定额外效果
// 自定义 AI 行为
}
};
动态召唤控制
根据战斗状态动态调整召唤参数:
cpp
void DynamicSummonAdjustment()
{
if (IsHeroicMode())
duration *= 2; // 英雄模式延长持续时间
if (caster->GetHealthPct() < 30.0f)
numSummons = 2; // 低血量时召唤更多援军
}
注意事项
1. 数据库/DB2配置
确保法术在数据库/DB2中正确配置:
sql
-- Effect=28 (SPELL_EFFECT_SUMMON)
UPDATE spell_effect
SET Effect = 28,
EffectMiscValue = CREATURE_ENTRY,
EffectMiscValueB = SUMMON_PROPERTIES_ID
WHERE id = YOUR_SPELL_ID;
2. 脚本注册
必须在脚本加载器中注册:
cpp
void AddSC_custom_summon()
{
RegisterSpellScript(spell_custom_summon);
}
3. 空值检查
始终检查关键指针:
cpp
void HandleSummon(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (!caster)
return;
// 安全的逻辑代码
}
4. 线程安全
注意 TrinityCore 是多线程的,确保代码是线程安全的:
- 避免静态变量
- 使用线程安全的数据结构
- 注意对象生命周期
5. 性能影响
召唤物会增加服务器负载:
- 限制召唤数量
- 合理设置持续时间
- 及时清理不需要的召唤物
总结
SPELL_EFFECT_SUMMON 是 TrinityCore 中实现召唤功能的强大工具,通过合理配置数据库字段和脚本逻辑,可以实现从简单的宠物召唤到复杂的 BOSS 战机制等各种功能。关键在于理解各个参数的作用关系,并根据具体需求选择合适的召唤类型和属性配置。
关键要点:
SPELL_EFFECT_SUMMON用于召唤各种游戏对象- 需要正确配置
EffectMiscValue和EffectMiscValueB - 支持通过
SpellScript进行深度定制 - 广泛应用于 BOSS 战、职业召唤、功能召唤等场景
- 注意性能、线程安全和召唤物生命周期管理