技能 - 天火被动技能
最近在研究dota2的技能制作,记录下实现的过程,看完教程后自己制作了一个天火 Boom!!!
的技能,每隔一段时间以自己为中心随机范围内的目标释放一个阳炎冲击(之后管他叫天火)
.
- 伤害为类型为:真实
- 伤害目标:所有单位
- 伤害团队:所有团队
得知一些设置后就可以开始设置了
首先在npc_abilities_custom.txt
中添加一个tianhuo_boom
的技能
"tianhuo_boom"
{
// General
//-------------------------------------------------------------------------------------------------------------
"BaseClass" "ability_lua"
"AbilityTextureName" "invoker/magus_apex/invoker_sun_strike"
//技能逻辑脚本
"ScriptFile" "abilities/tianhuo_boom"
//技能是一个被动
"AbilityBehavior" "DOTA_ABILITY_BEHAVIOR_PASSIVE"
//技能伤害团队为所有,在代码中会用到
"AbilityUnitTargetTeam" "DOTA_UNIT_TARGET_TEAM_BOTH"
//技能目标类型为全部,在代码中会用到
"AbilityUnitTargetType" "DOTA_UNIT_TARGET_ALL"
//-------------------------------------------------------------------------------------------------------------
"AbilitySpecial"
{
"01"
{
"var_type" "FIELD_INTEGER"
//释放间隔
"interval" "5 4 3 2"
}
"03"
{
"var_type" "FIELD_FLOAT"
//伤害
"damage" "60 80 100 120"
}
"03"
{
"var_type" "FIELD_FLOAT"
//释放检测范围
"range" "300 500 800 1500"
}
"04"
{
"var_type" "FIELD_FLOAT"
//伤害范围
"damageRange" "175"
}
"05"
{
"var_type" "FIELD_FLOAT"
//伤害产生延迟
"delay" "1.7"
}
}
}
接下来是创建技能逻辑tianhuo_boom
,需要放在game/scripts/vscripts/abilities
目录中
import {BaseAbility, registerAbility} from "../lib/dota_ts_adapter";
@registerAbility()
export class tianhuo_boom extends BaseAbility
{
private _interval:number;
private _range:number;
private _damage:number;
private _damageRange:number;
private _delay:number;
//技能释放
OnSpellStart()
{
if (!IsClient())
this.SetThink(()=> this._sun_strike(), this, tianhuo_boom.name, this._interval)
}
//技能升级,需要重新读取一下数值和重新释放技能
OnUpgrade()
{
this._interval = this.GetSpecialValueFor("interval");
this._range = this.GetSpecialValueFor("range");
this._damage = this.GetSpecialValueFor("damage");
this._damageRange = this.GetSpecialValueFor("damageRange");
this._delay = this.GetSpecialValueFor("delay");
this.StopThink(tianhuo_boom.name);
this.OnSpellStart();
}
//英雄复活后释放技能启动轮询
OnOwnerSpawned()
{
this.OnSpellStart();
}
//英雄死亡,停止技能轮询
OnOwnerDied()
{
this.StopThink(tianhuo_boom.name);
}
//天火的准备阶段特效
private readonly _sunS = "particles/econ/items/invoker/invoker_apex/invoker_sun_strike_team_big_ray_immortal1.vpcf";
////天火的爆炸特效
private readonly _sunBoom = "particles/units/heroes/hero_invoker/invoker_sun_strike.vpcf";
//天火的准备阶段音效
private readonly _sunSSound = "Hero_Invoker.SunStrike.Charge";
//天火的爆炸音效
private readonly _sunBoomSound = "Hero_Invoker.SunStrike.Ignite";
//技能轮询逻辑
private _sun_strike()
{
const caster = this.GetCaster();
//查找range范围内的所有目标,以自己为中心,这里就使用到在kv中设置的AbilityUnitTargetTeam和AbilityUnitTargetType
const targets = FindUnitsInRadius(DOTATeam_t.DOTA_TEAM_NEUTRALS, caster.GetAbsOrigin(), undefined, this._range,
this.GetAbilityTargetTeam(),
this.GetAbilityTargetType(),
this.GetAbilityTargetFlags(), FindOrder.FIND_ANY_ORDER, false);
if (targets.length > 0)
{
//随机一个单位
const index = math.floor(math.random() * targets.length);
const target = targets[index];
let origin = target.GetAbsOrigin();
//创建天火准备特效
const pid = ParticleManager.CreateParticle(this._sunS, ParticleAttachment_t.PATTACH_CUSTOMORIGIN, caster);
ParticleManager.SetParticleControl(pid, 0, origin);
EmitSoundOnLocationWithCaster(origin, this._sunSSound, caster);
//缓存伤害和伤害范围,避免伤害开始但技能升级,使用了最新等级的数值
const damageRange = this._damageRange;
const damage = this._damage;
//等待延迟
GameRules.GetGameModeEntity().SetThink(()=>
{
//创建爆炸特效
const pid = ParticleManager.CreateParticle(this._sunBoom, ParticleAttachment_t.PATTACH_CUSTOMORIGIN, caster);
ParticleManager.SetParticleControl(pid, 0, origin);
EmitSoundOnLocationWithCaster(origin, this._sunBoomSound, caster);
//搜索以目标点为中心伤害范围的目标,这里也使用到在kv中设置的AbilityUnitTargetTeam和AbilityUnitTargetType
const targets = FindUnitsInRadius(DOTATeam_t.DOTA_TEAM_NEUTRALS, origin, undefined, damageRange,
this.GetAbilityTargetTeam(),
this.GetAbilityTargetType(),
this.GetAbilityTargetFlags(), FindOrder.FIND_ANY_ORDER, false);
if (targets.length > 0)
{
//平摊伤害,最大目标为10个,这里这个10个目标的数值可以暴露在kv的AbilitySpecial中
const damageValue = math.max(damage / targets.length, damage / 10);
//只拿前10个
const maxLenght = math.min(targets.length, 10);
for (let i = 0; i < maxLenght; i++)
{
const target = targets[i];
//创建伤害表
const damageTable:ApplyDamageOptions = {
damage: damageValue,
damage_flags:DOTADamageFlag_t.DOTA_DAMAGE_FLAG_NONE,
damage_type: DAMAGE_TYPES.DAMAGE_TYPE_PURE,
ability: this,
attacker: caster,
victim:target
}
//应用伤害
ApplyDamage(damageTable);
}
}
//这里返回undefined就会停止,也就是单次的
return undefined;
}, this, "_boom"+GameRules.GetGameTime(), this._delay)
}
return this._interval;
}
}
使用隐藏技能的版本(无法改变伤害单位类型和团队类型,控制力较弱,使用简单,但是缺点大于优点),这里只贴代码段,具体代码已经删了=-=
tianhuo_boom
中的OnUpgrade
和_sun_strike
替换为如下代码,不一定能正确,在写这篇文章时回忆着写的,大概逻辑就是添加技能后,释放添加的技能,核心是SetCursorPosition
和OnSpellStart
,SetCursorPosition
设置施法点,OnSpellStart
释放技能
private _sunAbility:CDOTABaseAbility;
OnUpgrade()
{
const caster = this.GetCaster();
if (!caster.HasAbility("tianhuo_sun_strike"))
{
this._sunAbility = caster.AddAbility("tianhuo_sun_strike");
this._sunAbility.SetHidden(true);//隐藏起来
}
this._sunAbility.SetLevel(this.GetLevel());//等级同步
}
private _sun_strike()
{
const caster = this.GetCaster();
const targets = FindUnitsInRadius(DOTATeam_t.DOTA_TEAM_NEUTRALS, caster.GetAbsOrigin(), undefined, this._range,
this.GetAbilityTargetTeam(),
this.GetAbilityTargetType(),
this.GetAbilityTargetFlags(), FindOrder.FIND_ANY_ORDER, false);
if (targets.length > 0)
{
const index = math.floor(math.random() * targets.length);
const target = targets[index];
let origin = target.GetAbsOrigin();
caster.SetCursorPosition(origin);
this._sunAbility.OnSpellStart();
}
return this._interval;
}
tianhuo_sun_strike
技能的kv,这个技能kv比较特殊,是从invoker_sun_strike
派生,这个是祈求者的阳炎冲击
技能,无法覆盖AbilityUnitTargetTeam
和AbilityUnitTargetType
"tianhuo_sun_strike" {
"BaseClass" "invoker_sun_strike"
"ScriptFile" "abilities/over_invoker_sun_strike"
"AbilityFunctionType" "HarmSkill"
"AbilityType" "DOTA_ABILITY_TYPE_BASIC"
"AbilityBehavior" "DOTA_ABILITY_BEHAVIOR_POINT"
"AbilityUnitTargetTeam" "DOTA_UNIT_TARGET_TEAM_BOTH"
"AbilityUnitTargetType" "DOTA_UNIT_TARGET_ALL"
"AbilityUnitDamageType" "DAMAGE_TYPE_MAGICAL"
"MaxLevel" "1"
//"IsHidden" "1"
"AbilityCastPoint" "0"
"AbilityManaCost" "0"
"AbilityCooldown" "15"
"AbilityCastRange" "3000"
"AbilitySpecial"
{
"01"
{
"var_type" "FIELD_INTEGER"
"delay" "1"
}
"02"
{
"var_type" "FIELD_INTEGER"
"area_of_effect" "200"
}
"03"
{
"var_type" "FIELD_INTEGER"
"damage" "3000"
}
"04"
{
"var_type" "FIELD_INTEGER"
"vision_distance" "400"
}
"05"
{
"var_type" "FIELD_INTEGER"
"vision_duration" "3"
}
"06"
{
"var_type" "FIELD_INTEGER"
"cataclysm_cooldown" "90"
}
"07"
{
"var_type" "FIELD_INTEGER"
"cataclysm_min_range" "160"
}
"08"
{
"var_type" "FIELD_INTEGER"
"cataclysm_max_range" "200"
}
}
}
效果