祈求者 - 混沌陨石
invoker_chaos_meteor.ts
import {BaseAbility, registerAbility} from "../lib/dota_ts_adapter";
import {modifier_invoker_chaos_meteor_thinker} from "../modifiers/modifier_invoker_chaos_meteor_thinker";
@registerAbility()
export class invoker_chaos_meteor extends BaseAbility
{
OnSpellStart()
{
const caster = this.GetCaster();
const point = this.GetCursorPosition();
CreateModifierThinker(caster, this,
modifier_invoker_chaos_meteor_thinker.name, {},
point, caster.GetTeamNumber(), false);
}
}
modifier_invoker_chaos_meteor_burn.ts
import {BaseModifier, registerModifier} from "../lib/dota_ts_adapter";
@registerModifier()
export class modifier_invoker_chaos_meteor_burn extends BaseModifier
{
IsHidden(): boolean
{
return false;
}
IsDebuff(): boolean
{
return true;
}
IsStunDebuff(): boolean
{
return false;
}
IsPurgable(): boolean
{
return false;
}
private _damageTable:ApplyDamageOptions;
OnCreated(params: object)
{
if (!IsServer())
return
const hero = this.GetCaster() as CDOTA_BaseNPC_Hero;
this._damageTable = {
victim: this.GetParent(),
attacker: this.GetCaster(),
damage: hero.GetIntellect() * this.GetAbility().GetSpecialValueFor("burn_damage"),
damage_type: DAMAGE_TYPES.DAMAGE_TYPE_MAGICAL,
ability: this.GetAbility()
}
this.StartIntervalThink(1);
}
OnIntervalThink()
{
ApplyDamage(this._damageTable)
const sound_tick = "Hero_Invoker.ChaosMeteor.Damage"
EmitSoundOn( sound_tick, this.GetParent())
}
GetEffectName(): string
{
return "particles/units/heroes/hero_invoker/invoker_chaos_meteor_burn_debuff.vpcf";
}
GetEffectAttachType(): ParticleAttachment_t
{
return ParticleAttachment_t.PATTACH_ABSORIGIN_FOLLOW;
}
}
modifier_invoker_chaos_meteor_thinker.ts
import {BaseModifier, registerModifier} from "../lib/dota_ts_adapter";
import {modifier_invoker_chaos_meteor_burn} from "./modifier_invoker_chaos_meteor_burn";
@registerModifier()
export class modifier_invoker_chaos_meteor_thinker extends BaseModifier
{
private _burn_duration: number;
private _intellectual_multiplier: number;
private _travel_speed: number;
private _damageTable: ApplyDamageOptions;
private _delay: number = 1.26;
private _caster_origin: Vector;
private _parent_origin: Vector;
private _direction: Vector;
private _damageInterval: number = 0.5;
private _damageRadius: number = 275;
private _distance: number = 1500;
OnCreated(params: object)
{
if (!IsServer())
return;
let ability = this.GetAbility();
let caster = this.GetCaster() as CDOTA_BaseNPC_Hero;
this._caster_origin = caster.GetOrigin();
this._parent_origin = this.GetParent().GetOrigin();
this._direction = this._parent_origin.__sub(this._caster_origin);
this._direction.z = 0;
this._direction = this._direction.Normalized();
this._burn_duration = ability.GetSpecialValueFor("burn_duration");
this._intellectual_multiplier = ability.GetSpecialValueFor("intellectual_multiplier");
this._travel_speed = ability.GetSpecialValueFor("travel_speed");
this._damageTable = {
damage: caster.GetIntellect() * this._intellectual_multiplier,
ability: ability,
victim: undefined,
attacker: caster,
damage_type: ability.GetAbilityDamageType()
};
//落地时间延迟
this.StartIntervalThink(this._delay);
this._playEffects1();
}
private _fallen: boolean = false;
OnIntervalThink()
{
if (!this._fallen)
{
this._fallen = true;
this.StartIntervalThink(this._damageInterval);
this._burn();
this._playEffects2();
}
else
{
this._move_Burn();
}
}
private _burn()
{
const enemies = FindUnitsInRadius(
this.GetCaster().GetTeamNumber(),
this.GetParent().GetOrigin(),
undefined,
this._damageRadius,
this.GetAbility().GetAbilityTargetTeam(),
this.GetAbility().GetAbilityTargetType(),
this.GetAbility().GetAbilityTargetFlags(),
FindOrder.FIND_ANY_ORDER,
false
);
for (let enemy of enemies)
{
this._damageTable.victim = enemy;
ApplyDamage(this._damageTable);
enemy.AddNewModifier(
this.GetCaster(),
this.GetAbility(),
modifier_invoker_chaos_meteor_burn.name,
{"duration": this._burn_duration});
}
}
private _move_Burn()
{
const parent = this.GetParent();
const parent_origin = this._parent_origin;
const target = this._direction.__mul(this._travel_speed).__mul(0.5);
parent.SetOrigin(parent.GetOrigin().__add(target));
this._burn();
if ((parent.GetOrigin().__sub(parent_origin).__add(target).Length2D() > this._distance))
this.Destroy();
}
OnDestroy()
{
if (!IsServer())
return;
const sound_loop = "Hero_Invoker.ChaosMeteor.Loop";
const sound_stop = "Hero_Invoker.ChaosMeteor.Destroy";
StopSoundOn(sound_loop, this.GetParent());
EmitSoundOnLocationWithCaster(this.GetParent().GetOrigin(), sound_stop, this.GetCaster());
}
private _playEffects1()
{
const particle_cast = "particles/units/heroes/hero_invoker/invoker_chaos_meteor_fly.vpcf";
const sound_impact = "Hero_Invoker.ChaosMeteor.Cast";
const height = 1000;
const height_target = -0;
const effect_cast = modifier_invoker_chaos_meteor_thinker._createEffect(this, particle_cast, ParticleAttachment_t.PATTACH_WORLDORIGIN, undefined);
ParticleManager.SetParticleControl(effect_cast, 0, this._caster_origin.__add(Vector(0, 0, height)));
ParticleManager.SetParticleControl(effect_cast, 1, this._parent_origin.__add(Vector(0, 0, height_target)));
ParticleManager.SetParticleControl(effect_cast, 2, Vector(this._delay, 0, 0));
ParticleManager.ReleaseParticleIndex(effect_cast);
EmitSoundOnLocationWithCaster(this._caster_origin, sound_impact, this.GetCaster());
}
private _playEffects2()
{
const particle_cast = "particles/units/heroes/hero_invoker/invoker_chaos_meteor.vpcf";
const sound_impact = "Hero_Invoker.ChaosMeteor.Impact";
const sound_loop = "Hero_Invoker.ChaosMeteor.Loop";
const effect_cast = modifier_invoker_chaos_meteor_thinker._createEffect(this, particle_cast, ParticleAttachment_t.PATTACH_WORLDORIGIN, undefined);
ParticleManager.SetParticleControl(effect_cast, 0, this._parent_origin);
ParticleManager.SetParticleControlForward(effect_cast, 0, this._direction);
ParticleManager.SetParticleControl(effect_cast, 1, this._direction.__mul(this._travel_speed));
this.AddParticle(
effect_cast,
false,
false,
-1,
false,
false
)
EmitSoundOnLocationWithCaster( this._parent_origin, sound_impact, this.GetCaster())
EmitSoundOn( sound_loop, this.GetParent())
}
private static _referenceEffects(): { [key: string]: string }
{
return {
["particles/units/heroes/hero_antimage/antimage_manavoid.vpcf"]: "particles/rubick_manavoid.vpcf",
["particles/units/heroes/hero_crystalmaiden/maiden_freezing_field_explosion.vpcf"]: "particles/rubick_freezing_field_explosion.vpcf",
["particles/units/heroes/hero_crystalmaiden/maiden_freezing_field_snow.vpcf"]: "particles/rubick_freezing_field_snow.vpcf",
["particles/units/heroes/hero_dark_willow/dark_willow_wisp_aoe.vpcf"]: "particles/rubick_wisp_aoe_proj.vpcf",
["particles/units/heroes/hero_dark_willow/dark_willow_wisp_aoe_cast.vpcf"]: "particles/rubick_wisp_aoe_cast.vpcf",
["particles/units/heroes/hero_dark_willow/dark_willow_wisp_spell_channel.vpcf"]: "particles/rubick_wisp_spell_channel.vpcf",
["particles/units/heroes/hero_dark_willow/dark_willow_willowisp_base_attack.vpcf"]: "particles/rubick_willowisp_base_attack.vpcf",
["particles/units/heroes/hero_dark_willow/dark_willow_willowisp_ambient.vpcf"]: "particles/rubick_willowisp_ambient.vpcf",
["particles/units/heroes/hero_earthshaker/earthshaker_fissure.vpcf"]: "particles/rubick_fissure.vpcf",
["particles/units/heroes/hero_enigma/enigma_blackhole.vpcf"]: "particles/rubick_blackhole.vpcf",
["particles/units/heroes/hero_faceless_void/faceless_void_chronosphere.vpcf"]: "particles/rubick_chronosphere.vpcf",
["particles/units/heroes/hero_invoker/invoker_chaos_meteor.vpcf"]: "particles/rubick_chaos_meteor.vpcf",
["particles/units/heroes/hero_invoker/invoker_chaos_meteor_fly.vpcf"]: "particles/rubick_chaos_meteor_fly.vpcf",
["particles/econ/items/lich/lich_ti8_immortal_arms/lich_ti8_chain_frost.vpcf"]: "particles/rubick_chain_frost.vpcf",
["particles/units/heroes/hero_shredder/shredder_chakram.vpcf"]: "particles/rubick_chakram.vpcf",
["particles/units/heroes/hero_shredder/shredder_chakram_stay.vpcf"]: "particles/rubick_chakram_stay.vpcf",
["particles/units/heroes/hero_shredder/shredder_chakram_return.vpcf"]: "particles/rubick_chakram_return.vpcf",
["particles/units/heroes/hero_omniknight/omniknight_guardian_angel_ally.vpcf"]: "particles/rubick_guardian_angel_ally.vpcf",
["particles/units/heroes/hero_omniknight/omniknight_guardian_angel_omni.vpcf"]: "particles/rubick_guardian_angel_rubick.vpcf"
};
}
private static _createEffect(self: BaseModifier, particle_name: string, iAttach: ParticleAttachment_t, hUnit?: CDOTA_BaseNPC, iTeam?: DOTATeam_t)
{
const ability = self.GetAbility();
const spell_steal = ability.GetCaster().FindAbilityByName("rubick_spell_steal_lua");
const stolen = (ability.IsStolen() && spell_steal);
const particle_alternate = this._referenceEffects()[particle_name] || particle_name;
//实际这里返回就行,这里多半做了下拉比克偷技能的处理
if (!stolen)
return ParticleManager.CreateParticle(particle_name, iAttach, hUnit);
let effect_cast;
if (iTeam)
effect_cast = ParticleManager.CreateParticleForTeam(particle_alternate, iAttach, hUnit, iTeam);
else
effect_cast = ParticleManager.CreateParticle(particle_alternate, iAttach, hUnit);
let color = Vector(0, 0, 0);
let level = spell_steal.GetLevel();
if (level == 1)
color.x = 255;
else if (level == 2)
color.y = 255;
else if (level == 3)
color.z = 255;
ParticleManager.SetParticleControl(effect_cast, 60, color);
ParticleManager.SetParticleControl(effect_cast, 61, Vector(1, 0, 0));
return effect_cast;
}
}
kv
"invoker_chaos_meteor" {
"BaseClass" "ability_lua"
"ScriptFile" "abilities/invoker_chaos_meteor"
"AbilityTextureName" "throw_coal"
"AbilityType" "DOTA_ABILITY_TYPE_BASIC"
"AbilityBehavior" "DOTA_ABILITY_BEHAVIOR_POINT | DOTA_ABILITY_BEHAVIOR_IGNORE_BACKSWING"
"AbilityUnitTargetTeam" "DOTA_UNIT_TARGET_TEAM_ENEMY"
"AbilityUnitTargetType" "DOTA_UNIT_TARGET_HERO | DOTA_UNIT_TARGET_BASIC"
"AbilityUnitDamageType" "DAMAGE_TYPE_MAGICAL"
"AbilityUnitTargetFlags" "DOTA_UNIT_TARGET_FLAG_NO_INVIS"
"MaxLevel" "1"
"AbilityCastAnimation" "ACT_DOTA_CAST_ABILITY_3"
"AbilityCastPoint" "0.3"
"AbilityCooldown" "1"
"AbilityDuration" "5"
"AbilityCastRange" "1200"
"AbilitySpecial"
{
"01"
{
"var_type" "FIELD_INTEGER"
"burn_duration" "5"
}
"02"
{
"var_type" "FIELD_FLOAT"
"burn_damage" "0.15"
}
"03"
{
"var_type" "FIELD_FLOAT"
"intellectual_multiplier" "0.8"
}
"04"
{
"var_type" "FIELD_INTEGER"
"travel_speed" "300"
}
}
}
效果
我还写了一个ProjectileManager.CreateLinearProjectile
的版,本,Projectile实现
ProjectileManager.CreateLinearProjectile
对特效的控制权少了很多