|
|
|
|
 |
|
The Hive Workshop Spells:
LeBlanc the Deceiver Spellpack v1.2
|
|
|
|
Images
|
|
|
| Details |
| Uploaded: | 03:47, 30th Sep 2012 |
| Last Updated: | 15:15, 4th Oct 2012 |
| Keywords: | LeBlanc, LeBlanc the Deciever, Deciever, League of Legends, LoL, RiotGames, Arcane, AoS, Aeon of Strife, Sigil of Silence, Distortion, Ethereal Chains |
| Type: | Pack |
| Category: | vJASS |
LeBlanc the Deceiver Spellpack v1.2
by Lambdadelta (aka Siraraz and BlackRose)
Last updated: 13/10/2012
Introduction
This spellpack includes the champion, LeBlanc the Deceiver, from the League of Legends and her abilities: Sigil of Silence, Distortion, Ethereal Chains and Mimic. It does not include Mirror Image due to the complex nature of the illusion. Notes
Don't mind the relatively dull visuals, I couldn't think of the best way to match the effects from League of Legends. There may be a few bugs here and there, I haven't tested it fully. Also, the way I managed Mimic's varying mana cost and cooldown was by triggering them. It would be horrendous to have 15 levels for the mimic-abilities. I also haven't fully commented everything and documented either. Feedback is appreciated. Description of Spells
 | Sigil of Silence
LeBlanc projects an orb towards her target, dealing magic damage and marking the target for 3.5 seconds. If the target takes damage from one of LeBlanc's abilities, the mark will trigger, dealing magic damage and silencing the target for 2 seconds. |  | Distortion
LeBlanc rapidly dashes to a target location, dealing magic damage to units near the location. In the following 3 seconds, she can activate Distortion again to blink back to her starting location. |  | Ethereal Chains
LeBlanc flings illusionary chains in a line towards a target location. If it hits an enemy unit, it will deal initial magic damage and leash to it, slowing their movement speed by 25% while the leash remains. If the target remains leashed after 2 seconds, the target takes additional magic damage and is rooted for a few seconds. |  | Mimic
LeBlanc casts the previous spell she cast. The mimicked spell deals significantly increased damage. |
Descriptions were taken directly from http://leagueoflegends.wikia.com/wik...c_the_Deceiver. Coding Details
Requirements:
Script:
Constants
Jass:
library LeBlanc
globals
public constant integer SIGIL_ID = 'A000'
public constant integer DISTORTION_ID = 'A001'
public constant integer ETHEREAL_CHAINS_ID = 'A002'
public constant integer MIMIC_ID = 'A00G'
public constant integer MIMIC_SIGIL_ID = 'A00A'
public constant integer MIMIC_DISTORTION_ID = 'A00E'
public constant integer MIMIC_ETHEREAL_CHAINS_ID = 'A00B'
endglobals
endlibrary
Sigil of Silence
Jass:
scope SigilOfSilence initializer OnInit
//************************************************************************************************
//* Sigil of Silence
//* ----------------
//* - LeBlanc projects an orb towards her target, dealing magic damage
//* and marking the target for 3.5 seconds. If the target takes damage
//* from one of LeBlanc's abilities, the mark will trigger, dealing magic
//* damage and silencing the target for 2 seconds.
//*
//* Requirements:
//* - SpellEffectEvent
//* - xecast
//* - xemissile
//* - xedamage
//* - Table
//* - ARGB
//*
//* - LeBlanc
//* - Mimic
//*
//* ----------------------------------------------------------------------------------------------
//* CALIBRATION SECTION
//* ----------------------------------------------------------------------------------------------
globals
// ABILITY RAWCODES
// ----------------
// Sigil of Silence id and mimic'd Sigil
private constant integer SIGIL_ID = LeBlanc_SIGIL_ID
private constant integer MIMIC_SIGIL_ID = LeBlanc_MIMIC_SIGIL_ID
// Silence id and order string
private constant integer SILENCE_ID = 'A009'
private constant string SILENCE_ORDER = "soulburn"
// Mark of Sigil id and order string
private constant integer MARK_ID = 'A008'
private constant string MARK_ORDER = "cripple"
// Mark of Sigil buff id
private constant integer MARK_BUFF_ID = 'B001'
// VISUALS
// =---------------
// The projectile model and the scale of it
private constant string ORB_MODEL_PATH = "Abilities\\Weapons\\FaerieDragonMissile\\FaerieDragonMissile.mdx"
private constant real ORB_MODEL_SCALE = 2.50
// Projectile colour and mimic'd orb version colour
private constant integer ORB_COLOUR = 0xFFFFFFFF // RGB: 255/255/255
private constant integer ORB_MIMIC_COLOUR = 0xFFC840FF // RGB: 200/64/255
// STATS
// =---------------
private constant integer MAX_ABILITY_LEVEL = 5 // Maximum level of Sigil of Silence; must update for Mimic to work
private constant real ORB_MOVESPEED = 1500. // The movespeed of projectile in Warcraft units/second
private constant real ORB_MOVE_ARC = 0.00 // The arc of projectile trajectory
private constant real ORB_HEIGHT_OFFSET = 45. // The distance of projectile from the ground
endglobals
//
// The primary damage dealt by the orb.
// Default: 70/110/150/190/230
private function SpellDamage takes integer level returns real
return 40. * level + 30
endfunction
//
// The secondary damage dealt when the mark
// is activated by another spell.
// Default: 20/40/60/80/100
private function SecondaryDamage takes integer level returns real
return 20. * level
endfunction
// Ignore this part:
globals
private xedamage DamageOptions // Used for damage purposes
private Table MarkTable // Used for tracking units with the Mark of Sigil buff
endglobals
//
// Setup the damage properties of the spell
//
private function SetupDamageOptions takes nothing returns nothing
set DamageOptions.atype = ATTACK_TYPE_NORMAL
set DamageOptions.dtype = DAMAGE_TYPE_FIRE
set DamageOptions.wtype = null
set DamageOptions.damageSelf = true
set DamageOptions.damageAllies = true
set DamageOptions.damageNeutral = true
endfunction
//* ----------------------------------------------------------------------------------------------
// END OF CALIBRATION
//* ----------------------------------------------------------------------------------------------
// -------------------------------------------------------------------
// Methods accessible from outside. These are used to active the mark
// placed by Sigil of Silence. Putting
// SigilOfSilence_MarkBuff.fire(caster, target)
// will check if the target has the buff and removes, silences and
// damages if it does.
//
public struct MarkBuff extends array
static method fire takes unit sourceUnit, unit targetUnit returns nothing
local xecast xc
local integer level
// The targeted unit does have the Mark of Sigil
if GetUnitAbilityLevel(targetUnit, MARK_BUFF_ID) > 0 then
// Remove the mark and deal damage
set level = MarkTable[GetHandleId(targetUnit)]
call UnitRemoveAbility(targetUnit, MARK_BUFF_ID)
set MarkTable[GetHandleId(targetUnit)] = 0
if level > MAX_ABILITY_LEVEL then
set level = level - 5
call DamageOptions.damageTarget(sourceUnit, targetUnit, SecondaryDamage(level) * Mimic_DamageIncrease(GetUnitAbilityLevel(sourceUnit, LeBlanc_MIMIC_ID)))
else
call DamageOptions.damageTarget(sourceUnit, targetUnit, SecondaryDamage(level))
endif
// Silence target
set xc = xecast.createA()
set xc.abilityid = SILENCE_ID
set xc.orderstring = SILENCE_ORDER
set xc.owningplayer = GetOwningPlayer(sourceUnit)
set xc.level = level
call xc.castOnTarget(targetUnit)
endif
endmethod
endstruct
// Uses xehomingmissile to provide the motion functionality
private struct SigilMain extends xehomingmissile
unit caster // Caster of spell
unit target // Target unit of spell
integer level // Level of spell at time of cast
player owningPlayer // Owner of caster at time of cast
boolean isMimic = false // Determines whether instance was a Mimic
private method onDestroy takes nothing returns nothing
set .caster = null
set .target = null
endmethod
static method create takes unit caster, unit target returns thistype
local real x = GetUnitX(caster)
local real y = GetUnitY(caster)
local real z = GetUnitFlyHeight(caster) + ORB_HEIGHT_OFFSET
local SigilMain this = SigilMain.allocate(x, y, z, target, ORB_HEIGHT_OFFSET)
set .caster = caster
set .target = target
set .owningPlayer = GetTriggerPlayer()
set .level = GetUnitAbilityLevel(caster, SIGIL_ID)
set .fxpath = ORB_MODEL_PATH
set .scale = ORB_MODEL_SCALE
// Comparing spell id to check whether instance is a Mimic-version
if GetSpellAbilityId() == MIMIC_SIGIL_ID then
set .isMimic = true
call .ARGBrecolor(ORB_MIMIC_COLOUR)
else
call .ARGBrecolor(ORB_COLOUR)
endif
call .launch(ORB_MOVESPEED, ORB_MOVE_ARC)
return this
endmethod
// make mimic sigil apply mark as well as silence
private method onHit takes nothing returns nothing
local xecast xc = xecast.createA()
// Check for Mark of Sigil buff
call MarkBuff.fire(.caster, .target)
// Apply Mark of Sigil buff
set xc.abilityid = MARK_ID
set xc.orderstring = MARK_ORDER
set xc.owningplayer = .owningPlayer
set xc.level = .level
call xc.castOnTarget(.target)
// Apply extra Mimic-damage
if .isMimic then
set MarkTable[GetHandleId(.target)] = .level + MAX_ABILITY_LEVEL
call DamageOptions.damageTarget(.caster, .target, SpellDamage(.level) * Mimic_DamageIncrease(GetUnitAbilityLevel(.caster, LeBlanc_MIMIC_ID)))
else
call DamageOptions.damageTarget(.caster, .target, SpellDamage(.level))
set MarkTable[GetHandleId(.target)] = .level
endif
endmethod
endstruct
private function OnSpellEffect takes nothing returns nothing
call SigilMain.create(GetTriggerUnit(), GetSpellTargetUnit())
endfunction
private function OnInit takes nothing returns nothing
// Register when spell and mimic-spell goes into effect
call RegisterSpellEffectEvent(SIGIL_ID, function OnSpellEffect)
call RegisterSpellEffectEvent(MIMIC_SIGIL_ID, function OnSpellEffect)
// Create mark table and damage properties
set MarkTable = Table.create()
set DamageOptions = xedamage.create()
// Run damage setup
call SetupDamageOptions()
endfunction
endscope
Distortion
Jass:
scope Distortion initializer OnInit
globals
// OBJECT RAWCODES
// ---------------
// Distortion and mimic-Distortion id
private constant integer DISTORTION_ID = LeBlanc_DISTORTION_ID
private constant integer MIMIC_DISTORTION_ID = LeBlanc_MIMIC_DISTORTION_ID
// Return and mimic-Return id
private constant integer RETURN_ID = 'A004'
private constant integer MIMIC_RETURN_ID = 'A005'
// Dummy unit id
private constant integer DUMMY_ID = 'e001'
// STATS
// ---------------
// IMPORTANT: You must update this variable to match your Distortion otherwise it will not work.
private constant integer MAX_ABILITY_LEVEL = 5
// Speed in Warcraft III units/second that caster moves at
private constant real DASH_SPEED = 1250.
// Time allowed for caster to return back to starting point
private constant real RETURN_DURATION = 3.0
// Whether return is permitted (it will just be a charge-spell if false)
private constant boolean ALLOW_RETURN = true
// Radius for area of effect circle to deal damage
private constant real DISTORTION_DAMAGE_RADIUS = 250.
// VISUALS
// ---------------
// The distance in Warcraft III units between each afterimage of the caster
private constant real AFTERIMAGE_SPACING = 60.
private constant playercolor AFTERIMAGE_COLOUR = PLAYER_COLOR_ORANGE
private constant playercolor MIMIC_AFTERIMAGE_COLOUR = PLAYER_COLOR_PURPLE
private constant integer AFTERIMAGE_ALPHA = 128 // Slightly lucent
// The effect created when an afterimage is created
private constant string AFTERIMAGE_SPAWN_EFFECT = "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdx"
private constant string AFTERIMAGE_SPAWN_EFFECT_ATTACHMENT = "origin"
// The model path for the marker of the starting point
private constant string DISTORT_ORIGIN_MARKER = "Buildings\\Other\\CircleOfPower\\CircleOfPower.mdx"
// Player colours of marker
private constant playercolor MARKER_COLOUR = PLAYER_COLOR_YELLOW
private constant playercolor MIMIC_MARKER_COLOUR = PLAYER_COLOR_PURPLE
// Effect created at the end of the charge
private constant string DISTORT_CHARGE_EFFECT = "Abilities\\Spells\\Undead\\FreezingBreath\\FreezingBreathMissile.mdx"
private constant string DISTORT_CHARGE_EFFECT_ATTACHMENT = "chest"
// Effect created at the start-market point on return point
private constant string DISTORT_EFFECT_ORIGIN = "Abilities\\Spells\\Undead\\FreezingBreath\\FreezingBreathMissile.mdx"
// Effect created at the position of caster before returning to start
private constant string DISTORT_EFFECT_CASTER = "Objects\\Spawnmodels\\NightElf\\NEDeathSmall\\NEDeathSmall.mdx"
endglobals
private keyword Distortion
globals
private Table ReturnTable
private Table MimicReturnTable
private xedamage DamageOptions
endglobals
private function UnitFilter takes unit whichUnit, Distortion dat returns boolean
return IsUnitEnemy(whichUnit, dat.owningPlayer) and not IsUnitType(whichUnit, UNIT_TYPE_DEAD) and /*
*/ not IsUnitType(whichUnit, UNIT_TYPE_STRUCTURE)
endfunction
//
// Damage dealt to units at the end of Distortion
// Default: 85/125/165/205/245
private function SpellDamage takes integer level returns real
return 40. * level + 45.
endfunction
//
// Setup the damage properties of the spell/visual effect
//
private function SetupDamageOptions takes nothing returns nothing
set DamageOptions.atype = ATTACK_TYPE_NORMAL
set DamageOptions.dtype = DAMAGE_TYPE_FIRE
set DamageOptions.wtype = null
call DamageOptions.useSpecialEffect("Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdx","origin")
endfunction
private struct Distortion
boolean isMimic
boolean added
unit caster
player owningPlayer
integer level
integer ticks
xefx returnfx = 0
real returnX
real returnY
real targX
real targY
real angle
real cos
real sin
real speed
real dist = 0.
timer timer
group trail
private static Distortion Temp
private method destroy takes nothing returns nothing
call ReleaseGroup(.trail)
set .caster = null
set .timer = null
set .trail = null
static if ALLOW_RETURN then
call .returnfx.destroy()
endif
endmethod
method returnStart takes nothing returns nothing
call ForGroup(.trail, function Distortion.DestroyTrail)
call DestroyEffect(AddSpecialEffect(DISTORT_EFFECT_CASTER, GetUnitX(.caster), GetUnitY(.caster)))
call DestroyEffect(AddSpecialEffect(DISTORT_EFFECT_ORIGIN, .returnX, .returnY))
if .isMimic then
call UnitRemoveAbility(.caster, MIMIC_RETURN_ID)
call SetUnitAbilityLevel(.caster, MIMIC_DISTORTION_ID, .level)
else
call UnitRemoveAbility(.caster, RETURN_ID)
call SetUnitAbilityLevel(.caster, DISTORTION_ID, .level)
endif
call PauseUnit(.caster, true)
call IssueImmediateOrder(.caster, "stop")
call PauseUnit(.caster, false)
call SetUnitX(.caster, .returnX)
call SetUnitY(.caster, .returnY)
call ReleaseTimer(.timer)
call .destroy()
endmethod
private static method removeReturn takes nothing returns nothing
local Distortion this = GetTimerData(GetExpiredTimer())
if .isMimic then
call UnitRemoveAbility(.caster, MIMIC_RETURN_ID)
call SetUnitAbilityLevel(.caster, MIMIC_DISTORTION_ID, .level)
else
call UnitRemoveAbility(.caster, RETURN_ID)
call SetUnitAbilityLevel(.caster, DISTORTION_ID, .level)
endif
call ReleaseTimer(GetExpiredTimer())
call .destroy()
endmethod
private method endCharge takes nothing returns nothing
local unit u
local real dmg = SpellDamage(.level)
call ForGroup(.trail, function Distortion.DestroyTrail)
call DestroyEffect(AddSpecialEffectTarget(DISTORT_CHARGE_EFFECT, .caster, DISTORT_CHARGE_EFFECT_ATTACHMENT))
if .isMimic then
set dmg = dmg * Mimic_DamageIncrease(GetUnitAbilityLevel(.caster, LeBlanc_MIMIC_ID))
endif
call GroupEnumUnitsInArea(ENUM_GROUP, GetUnitX(.caster), GetUnitY(.caster), DISTORTION_DAMAGE_RADIUS, null)
loop
set u = FirstOfGroup(ENUM_GROUP)
exitwhen u == null
call GroupRemoveUnit(ENUM_GROUP, u)
if UnitFilter(u, this) then
call SigilOfSilence_MarkBuff.fire(.caster, u)
call DamageOptions.damageTarget(.caster, u, dmg)
endif
endloop
endmethod
private static method DestroyTrail takes nothing returns nothing
call RemoveUnit(GetEnumUnit())
endmethod
private static method timerCallback takes nothing returns nothing
local Distortion this = GetTimerData(GetExpiredTimer())
local unit u
local real tx = GetUnitX(.caster) + .cos
local real ty = GetUnitY(.caster) + .sin
local real dx = .targX - tx
local real dy = .targY - ty
call SetUnitX(.caster, tx)
call SetUnitY(.caster, ty)
set .dist = .dist + .speed
if .dist >= AFTERIMAGE_SPACING then
set .dist = 0.
set u = CreateUnit(.owningPlayer, DUMMY_ID, tx, ty, .angle)
call SetUnitVertexColor(u, 255, 255, 255, AFTERIMAGE_ALPHA)
if .isMimic then
call SetUnitColor(u, MIMIC_AFTERIMAGE_COLOUR)
else
call SetUnitColor(u, AFTERIMAGE_COLOUR)
endif
call GroupAddUnit(.trail, u)
call SetUnitX(u, tx)
call SetUnitY(u, ty)
call DestroyEffect(AddSpecialEffectTarget(AFTERIMAGE_SPAWN_EFFECT, u, AFTERIMAGE_SPAWN_EFFECT_ATTACHMENT))
endif
static if ALLOW_RETURN then
if not .added then
set .added = true
if not .isMimic then
call UnitAddAbility(.caster, RETURN_ID)
call SetUnitAbilityLevel(.caster, DISTORTION_ID, MAX_ABILITY_LEVEL)
call IncUnitAbilityLevel(.caster, DISTORTION_ID)
set .returnfx.teamcolor = MARKER_COLOUR
else
call UnitAddAbility(.caster, MIMIC_RETURN_ID)
call SetUnitAbilityLevel(.caster, MIMIC_DISTORTION_ID, MAX_ABILITY_LEVEL)
call IncUnitAbilityLevel(.caster, MIMIC_DISTORTION_ID)
set .returnfx.teamcolor = MIMIC_MARKER_COLOUR
endif
endif
endif
if .ticks == 0 then
call .endCharge()
call PauseTimer(.timer)
static if ALLOW_RETURN then
call TimerStart(.timer, RETURN_DURATION - (.ticks * XE_ANIMATION_PERIOD), false, function Distortion.removeReturn)
endif
else
set .ticks = .ticks - 1
endif
set u = null
endmethod
static method create takes unit caster returns thistype
local Distortion this = Distortion.allocate()
local real dx
local real dy
local real dist
// Setup spell variables
set .caster = caster
set .level = GetUnitAbilityLevel(caster, DISTORTION_ID)
set .owningPlayer = GetTriggerPlayer()
// Setup point coordinates
set .returnX = GetUnitX(caster)
set .returnY = GetUnitY(caster)
set .targX = GetSpellTargetX()
set .targY = GetSpellTargetY()
set dx = .targX - .returnX
set dy = .targY - .returnY
// Do math to find distance/angle
set dist = SquareRoot((dx * dx) + (dy * dy))
set .angle = Atan2(dy, dx) * bj_RADTODEG
set .speed = DASH_SPEED * XE_ANIMATION_PERIOD
set .cos = .speed * Cos(.angle * bj_DEGTORAD)
set .sin = .speed * Sin(.angle * bj_DEGTORAD)
set .ticks = R2I(dist / .speed)
set .isMimic = GetSpellAbilityId() == MIMIC_DISTORTION_ID
static if ALLOW_RETURN then
set .added = false
set .returnfx = xefx.create(.returnX, .returnY, .angle)
set .returnfx.fxpath = DISTORT_ORIGIN_MARKER
set .returnfx.scale = 0.75
call DestroyEffect(AddSpecialEffect(DISTORT_EFFECT_ORIGIN, .returnX, .returnY))
if .isMimic then
set MimicReturnTable[GetHandleId(.caster)] = this
else
set ReturnTable[GetHandleId(.caster)] = this
endif
endif
set .trail = NewGroup()
set .timer = NewTimerEx(this)
call TimerStart(.timer, XE_ANIMATION_PERIOD, true, function Distortion.timerCallback)
return this
endmethod
endstruct
private function SpellEffectDistortion takes nothing returns nothing
call Distortion.create(GetTriggerUnit())
endfunction
private function SpellEffectReturn takes nothing returns nothing
if GetSpellAbilityId() == RETURN_ID then
call Distortion(ReturnTable[GetHandleId(GetTriggerUnit())]).returnStart()
elseif GetSpellAbilityId() == MIMIC_RETURN_ID then
call Distortion(MimicReturnTable[GetHandleId(GetTriggerUnit())]).returnStart()
endif
endfunction
private function OnInit takes nothing returns nothing
// Register when spell and mimic-spell goes into effect
call RegisterSpellEffectEvent(DISTORTION_ID, function SpellEffectDistortion)
call RegisterSpellEffectEvent(MIMIC_DISTORTION_ID, function SpellEffectDistortion)
// Register when return-Distortion is activated
static if ALLOW_RETURN then
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CAST, function SpellEffectReturn)
//call RegisterSpellEffectEvent(RETURN_ID, function SpellEffectReturn)
//call RegisterSpellEffectEvent(MIMIC_RETURN_ID, function SpellEffectReturn)
set ReturnTable = Table.create()
set MimicReturnTable = Table.create()
endif
// Setup damage options
set DamageOptions = xedamage.create()
call SetupDamageOptions()
endfunction
endscope
Ethereal Chains
Jass:
scope EtherealChains initializer OnInit
/************************************************************************************************
* Ethereal Chains
* ---------------
* - LeBlanc flings illusionary chains in a line towards a target location. If it hits an enemy
* unit, it will deal initial magic damage and leash to it, slowing their movement speed by 25%
* while the leash remains. If the target remains leashed after 2 seconds, the target takes
* additional magic damage and is rooted for a few seconds.
*
* Requirements:
* - GroupUtils
* - SimError
* - SpellEffectEvent
* - Table
* - TimerUtils
* - xecast, xedamage
*
* - LeBlanc
* - Mimic
*
* ----------------------------------------------------------------------------------------------
* CALIBRATION SECTION
* --------------------------------------------------------------------------------------------*/
globals
// ABILITY RAWCODES
// ----------------
// Ethereal Chains and mimic id
private constant integer SPELL_ID = LeBlanc_ETHEREAL_CHAINS_ID
private constant integer MIMIC_SPELL_ID = LeBlanc_MIMIC_ETHEREAL_CHAINS_ID
// Slow effect placer id, buff id and order string
private constant integer SLOW_ID = 'A00C'
private constant integer SLOW_BUFF_ID = 'B002'
private constant string SLOW_ORDERSTRING = "slow"
// Snare effect placer id and order string id
private constant integer SNARE_ID = 'A00F'
private constant string SNARE_ORDERSTRING = "entanglingroots"
// STATS
// ----------------
// Time of leash to remain until snare effect
private constant real LEASH_DURATION = 2.
// Speed leash extends outwards in Warcraft III units/second
private constant real PROJECT_SPEED = 1250.
// VISUALS
// ----------------
/* Lightning ID's (thanks to PurgeandFire111):
Chain Lightning - Primary = "CLPB"
Chain Lightning - Secondary = "CLSB"
Drain = "DRAB"
Drain Life = "DRAL"
Drain Mana = "DRAM"
Finger of Death = "AFOD"
Forked Lightning = "FORK"
Healing Wave - Primary = "HWPB"
Healing Wave - Secondary = "HWSB"
Lightning Attack = "CHIM"
Magic Leash = "LEAS"
Mana Burn = "MBUR"
Mana Flare = "MFPB"
Spirit Link = "SPLK"
*/
private constant string LIGHTNING_CODE = "LEAS"
// Colour values of lightning
private constant real LIGHTNING_RED = 1.0
private constant real LIGHTNING_GREEN = 1.0
private constant real LIGHTNING_BLUE = 0.0
// Colour values of lightning for Mimic-Ethereal Chains
private constant real LIGHTNING_RED_MIMIC = 1.0
private constant real LIGHTNING_GREEN_MIMIC = 0.0
private constant real LIGHTNING_BLUE_MIMIC = 1.0
private constant real LIGHTNING_HEIGHT_OFFSET = 60.
private constant real LEASH_COLLISION_RADIUS = 128.
endglobals
// Ignore this section
private keyword Chains
globals
private xedamage DamageOptions
private Table LeashTable
endglobals
private function UnitFilter takes unit whichUnit, Chains whichChain returns boolean
return IsUnitEnemy(whichUnit, whichChain.owningPlayer) and not IsUnitType(whichUnit, UNIT_TYPE_DEAD) and /*
*/ not IsUnitType(whichUnit, UNIT_TYPE_STRUCTURE)
endfunction
private constant function ChainMaxRange takes integer level returns real
return 1000.
endfunction
// Initial damage dealt when the chain lands on a target.
// Default: 40/65/90/115/140
private constant function InitialDamage takes integer level returns real
return 25. * level + 15
endfunction
// The damage dealt when the chain remains on a target for the required duration.
// Default: 40/65/90/115/140
private constant function DelayedDamage takes integer level returns real
return 25. * level + 15
endfunction
//
// Setup the damage properties of the spell
//
private function SetupDamageOptions takes nothing returns nothing
set DamageOptions.atype = ATTACK_TYPE_NORMAL
set DamageOptions.dtype = DAMAGE_TYPE_FIRE
set DamageOptions.wtype = null
set DamageOptions.damageAllies = true
set DamageOptions.damageNeutral = true
endfunction
//* ----------------------------------------------------------------------------------------------
// END OF CALIBRATION
//* ----------------------------------------------------------------------------------------------
private struct Chains
// Standard spell-variables
unit caster
integer level
player owningPlayer
unit target
// Determines whether instance is mimic or not
boolean isMimic
// Coordinates of leash end/target
real x1
real x2
real y1
real y2
real z1
real z2
// Motion variables
real speed
real leashRange
real dist
real cos
real sin
// Leash effect
lightning lightning
// Motion timer
timer timer
real seconds
// Slow/Snare caster
xecast xc
// Global location used to find the z-coordinate of a point
private static location TempLocation = Location(0., 0.)
private method destroy takes nothing returns nothing
if .target != null then
set LeashTable[GetHandleId(.target)] = LeashTable[GetHandleId(.target)] - 1
call UnitRemoveAbility(.target, SLOW_BUFF_ID)
set .target = null
endif
call DestroyLightning(.lightning)
call ReleaseTimer(.timer)
set .caster = null
set .lightning = null
set .timer = null
call .deallocate()
endmethod
private static method timerCallback takes nothing returns nothing
local Chains this = GetTimerData(GetExpiredTimer())
local unit u
set .x1 = GetUnitX(.caster)
set .y1 = GetUnitY(.caster)
call MoveLocation(Chains.TempLocation, .x1, .y1)
set .z1 = GetUnitFlyHeight(.caster) + GetLocationZ(Chains.TempLocation) + LIGHTNING_HEIGHT_OFFSET
// Chain has a target
if .target != null then
set .x2 = GetUnitX(.target)
set .y2 = GetUnitY(.target)
call MoveLocation(Chains.TempLocation, .x2, .y2)
set .z2 = GetUnitFlyHeight(.target) + GetLocationZ(Chains.TempLocation) + LIGHTNING_HEIGHT_OFFSET
set .dist = (.y2 - .y1) * (.y2 - .y1) + (.x2 - .x1) * (.x2 - .x1)
// Track time target is leashed
set .seconds = .seconds + XE_ANIMATION_PERIOD
if .seconds >= LEASH_DURATION then
// Remove slow when finished
if LeashTable[GetHandleId(.target)] == 1 then
call UnitRemoveAbility(.target, SLOW_BUFF_ID)
endif
// Damage target unit
if .isMimic then
call DamageOptions.damageTarget(.caster, .target, DelayedDamage(.level) * Mimic_DamageIncrease(GetUnitAbilityLevel(.caster, LeBlanc_MIMIC_ID)))
else
call DamageOptions.damageTarget(.caster, .target, DelayedDamage(.level))
endif
// Check for Mark of Sigil buff
call SigilOfSilence_MarkBuff.fire(.caster, .target)
// Snare target unit
set .xc.abilityid = SNARE_ID
set .xc.level = .level
set .xc.orderstring = SNARE_ORDERSTRING
set .xc.owningplayer = .owningPlayer
call .xc.castOnTarget(.target)
call .xc.destroy()
call .destroy()
return
else
// Continuously slow target unit
call .xc.castOnTarget(.target)
endif
// Destroy leash if target out of range or is dead
if .dist >= .leashRange or IsUnitType(.target, UNIT_TYPE_DEAD) then
call .destroy()
else
// Update lightning coordinates between two units
call MoveLightningEx(.lightning, false, .x1, .y1, .z1, .x2, .y2, .z2)
endif
else // No target is found
// Extend end of chain
set .x2 = .x2 + .cos
set .y2 = .y2 + .sin
call MoveLocation(Chains.TempLocation, .x2, .y2)
set .z2 = GetLocationZ(Chains.TempLocation) + LIGHTNING_HEIGHT_OFFSET
// Search for target at end of chain
call GroupEnumUnitsInArea(ENUM_GROUP, .x2, .y2, LEASH_COLLISION_RADIUS, null)
loop
set u = FirstOfGroup(ENUM_GROUP)
exitwhen u == null
call GroupRemoveUnit(ENUM_GROUP, u)
// Check unit in group matches condition
if UnitFilter(u, this) then
set .target = u
set LeashTable[GetHandleId(.target)] = LeashTable[GetHandleId(.target)] + 1
// Deal initial chain damage
if .isMimic then
call DamageOptions.damageTarget(.caster, .target, InitialDamage(.level) * Mimic_DamageIncrease(GetUnitAbilityLevel(.caster, LeBlanc_MIMIC_ID)))
else
call DamageOptions.damageTarget(.caster, .target, InitialDamage(.level))
endif
// Check for Mark of Sigil buff
call SigilOfSilence_MarkBuff.fire(.caster, .target)
// Apply slow buff
set .xc = xecast.create()
set .xc.abilityid = SLOW_ID
set .xc.level = .level
set .xc.orderstring = SLOW_ORDERSTRING
set .xc.owningplayer = .owningPlayer
call .xc.castOnTarget(.target)
exitwhen true
endif
endloop
// Update lightning
call MoveLightningEx(.lightning, false, .x1, .y1, .z1, .x2, .y2, .z2)
// If chain extends fully then destroy instance
set .dist = .dist - .speed
if .dist <= 0. then
call .destroy()
endif
endif
endmethod
static method create takes unit caster returns thistype
local Chains this = Chains.allocate()
local real angle
local real dx
local real dy
// Setup spell variables
set .caster = caster
set .level = GetUnitAbilityLevel(caster, SPELL_ID)
set .isMimic = GetSpellAbilityId() == MIMIC_SPELL_ID
set .owningPlayer = GetOwningPlayer(caster)
set .target = null
// Assign coordinates of caster position and target position
set .x1 = GetUnitX(caster)
set .y1 = GetUnitY(caster)
set .x2 = .x1
set .y2 = .y1
// Find angle between cast and target
set dx = GetSpellTargetX() - .x1
set dy = GetSpellTargetY() - .y1
set angle = Atan2(dy, dx)
// Find z-coordinate of caster position
call MoveLocation(Chains.TempLocation, .x1, .y1)
set .z1 = GetLocationZ(Chains.TempLocation) + LIGHTNING_HEIGHT_OFFSET
// Create lightning and assign colour based on spell-instance property
set .lightning = AddLightningEx(LIGHTNING_CODE, false, .x1, .y1, .z1, .x1, .y1, .z1)
if .isMimic then
call SetLightningColor(.lightning, LIGHTNING_RED_MIMIC, LIGHTNING_GREEN_MIMIC, LIGHTNING_BLUE_MIMIC, 1.0)
else
call SetLightningColor(.lightning, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, 1.0)
endif
set .leashRange = ChainMaxRange(.level) * ChainMaxRange(.level)
set .dist = ChainMaxRange(.level)
set .speed = PROJECT_SPEED * XE_ANIMATION_PERIOD
set .cos = .speed * Cos(angle)
set .sin = .speed * Sin(angle)
set .seconds = 0.
set .timer = NewTimerEx(this)
call TimerStart(.timer, XE_ANIMATION_PERIOD, true, function Chains.timerCallback)
return this
endmethod
endstruct
private function OnSpellEffect takes nothing returns nothing
call Chains.create(GetTriggerUnit())
endfunction
private function OnInit takes nothing returns nothing
// Register when spell and mimic-spell goes into effect
call RegisterSpellEffectEvent(SPELL_ID, function OnSpellEffect)
call RegisterSpellEffectEvent(MIMIC_SPELL_ID, function OnSpellEffect)
// Create leash table and damage properties
set LeashTable = Table.create()
set DamageOptions = xedamage.create()
// Run damage setup
call SetupDamageOptions()
endfunction
endscope
Mimic
Jass:
library Mimic initializer OnInit requires LeBlanc, SpellEffectEvent, SimError
/************************************************************************************************
* Mimic
* -----
* - LeBlanc casts the previous spell she cast. The mimicked spell
* deals significantly increased damage.
*
* Requirements:
* - SpellEffectEvent
* - SimError
*
* ----------------------------------------------------------------------------------------------
* CALIBRATION SECTION
* --------------------------------------------------------------------------------------------*/
// The percentage of damage that Mimic spells do.
// Currently at 1.1/1.25/1.4 times the normal damage.
// The functions is public as it is needed to be accessed from the other
// spells' code in order to determine how much extra damage is dealt.
public function DamageIncrease takes integer level returns real
return 1. + 0.150 * level - 0.050
endfunction
// Mana cost of the Mimic spells (100/50/0)
private function ManaCost takes integer level returns integer
return 150 - 50 * level
endfunction
// Cooldown of the Mimic spells (40/32/24 seconds)
private function Cooldown takes integer level returns real
return 5.//48. - 8. * level
endfunction
//* ----------------------------------------------------------------------------------------------
// END OF CALIBRATION
//* ----------------------------------------------------------------------------------------------
globals
private hashtable MimicHT = InitHashtable() // Used to keep track of all data for Mimic
endglobals
private struct MimicData
unit caster // Source of Mimic
boolean cooldown // Determine whether spell is in cooldown or not
integer level // Current level of Mimic
integer currSkill // Current mimic-ability
integer origSkill // Original ability id
timer timer // Used for tracking cooldown of ability
// Updates the current mimic-ability id based on the argument
// which must be one of the three origianl abilities
public method adjustSkillId takes integer spellId returns nothing
set .origSkill = spellId
if spellId == LeBlanc_SIGIL_ID then
set .currSkill = LeBlanc_MIMIC_SIGIL_ID
elseif spellId == LeBlanc_DISTORTION_ID then
set .currSkill = LeBlanc_MIMIC_DISTORTION_ID
elseif spellId == LeBlanc_ETHEREAL_CHAINS_ID then
set .currSkill = LeBlanc_MIMIC_ETHEREAL_CHAINS_ID
debug else
debug call BJDebugMsg(SCOPE_PREFIX + " - adjustSkillId method: The spell " + GetObjectName(spellId) + " was input as argument and is not recognised.")
endif
endmethod
public static method create takes unit whichUnit returns thistype
local MimicData this = MimicData.allocate()
set .caster = whichUnit
set .cooldown = false // Spell is not on cooldown initialy
set .level = GetUnitAbilityLevel(whichUnit, LeBlanc_MIMIC_ID)
// If the unit cast a spell before learning
// then assign that spell as the mimic spell.
if HaveSavedInteger(MimicHT, GetHandleId(.caster), StringHash("prevAbil")) then
call .adjustSkillId(LoadInteger(MimicHT, GetHandleId(.caster), StringHash("prevAbil")))
else
// Else assign Sigil of Silence by default
set .origSkill = LeBlanc_MIMIC_SIGIL_ID
set .currSkill = LeBlanc_MIMIC_SIGIL_ID
endif
// Add mimic-ability to unit
call UnitAddAbility(.caster, .currSkill)
// Attach mimic data to unit
call SaveInteger(MimicHT, GetHandleId(GetTriggerUnit()), StringHash("MimicData"), this)
return 0
endmethod
endstruct
// Fires when original spell is cast
private function OnSpellEffect takes nothing returns nothing
local MimicData dat
local unit caster = GetTriggerUnit()
local integer i = GetHandleId(caster)
// If unit has Mimic data attached:
if HaveSavedInteger(MimicHT, i, StringHash("MimicData")) then
set dat = LoadInteger(MimicHT, i, StringHash("MimicData"))
// Remove current mimic-ability and update current ability mimic'd
call UnitRemoveAbility(dat.caster, dat.currSkill)
set i = GetSpellAbilityId()
call dat.adjustSkillId(i)
call UnitAddAbility(dat.caster, dat.currSkill)
call SetUnitAbilityLevel(dat.caster, dat.currSkill, GetUnitAbilityLevel(caster, i))
else
// Else merely store the previous ability on the unit so the Mimic ability when it is learnt
// the first time updates to the correct previous ability
call SaveInteger(MimicHT, GetHandleId(GetTriggerUnit()), StringHash("prevAbil"), GetSpellAbilityId())
endif
set caster = null
endfunction
// Fires when timer in MimicSpellEffect expires, resets cooldown of Mimic spell
private function ResetCooldown takes nothing returns nothing
local MimicData dat = GetTimerData(GetExpiredTimer())
set dat.cooldown = false
call ReleaseTimer(dat.timer)
endfunction
// Fires when a mimic-ability goes into effect (after cast-event)
private function MimicSpellEffect takes nothing returns nothing
local MimicData dat
local unit caster = GetTriggerUnit()
local integer hid = GetHandleId(caster)
// If unit has Mimic data attached:
if HaveSavedInteger(MimicHT, hid, StringHash("MimicData")) then
// Set spell off into triggered-cooldown
set dat = LoadInteger(MimicHT, hid, StringHash("MimicData"))
set dat.cooldown = true
set dat.timer = NewTimerEx(dat)
call TimerStart(dat.timer, Cooldown(dat.level), false, function ResetCooldown)
// Deduct mana off caster
call SetUnitState(caster, UNIT_STATE_MANA, GetUnitState(caster, UNIT_STATE_MANA) - ManaCost(dat.level))
// Else the unit has no mimic data, meaning a unit has a mimic-ability for some odd reason
debug else
debug call BJDebugMsg(SCOPE_PREFIX + " For some reason another unit has a mimiced ability.")
endif
set caster = null
endfunction
private function MimicSpellCastResponse takes nothing returns nothing
local MimicData dat
local unit caster = GetTriggerUnit()
local integer hid = GetHandleId(caster)
// If unit has Mimic data attached then:
if HaveSavedInteger(MimicHT, hid, StringHash("MimicData")) then
set dat = LoadInteger(MimicHT, hid, StringHash("MimicData"))
// If spell is in triggered-cooldown then simulate error message and stop caster
if dat.cooldown then
call PauseUnit(caster, true)
call SimError(GetTriggerPlayer(), "Mimic is in cooldown (" + I2S(R2I(TimerGetRemaining(dat.timer))) + " seconds left).")
call IssueImmediateOrder(caster, "stop")
call PauseUnit(caster, false)
// Else caster has insufficient mana then simulate not enough mana error message and stop caster
elseif GetUnitState(caster, UNIT_STATE_MANA) < ManaCost(dat.level) then
call PauseUnit(caster, true)
call SimError(GetTriggerPlayer(), "Not enough mana.")
call IssueImmediateOrder(caster, "stop")
call PauseUnit(caster, false)
endif
endif
set caster = null
endfunction
// Fires when any of the mimic abilities are cast (before effect-event)
private function MimicSpellCast takes nothing returns nothing
local integer spellid = GetSpellAbilityId()
if spellid == LeBlanc_MIMIC_SIGIL_ID or /*
*/ spellid == LeBlanc_MIMIC_DISTORTION_ID or /*
*/ spellid == LeBlanc_MIMIC_ETHEREAL_CHAINS_ID then
call MimicSpellCastResponse()
endif
endfunction
private function LearnMimicResponse takes nothing returns nothing
local MimicData dat
local unit learner = GetLearningUnit()
local integer hid = GetHandleId(learner)
// If learner unit already has Mimic then update level variable
if HaveSavedInteger(MimicHT, hid, StringHash("MimicData")) then
set dat = LoadInteger(MimicHT, hid, StringHash("MimicData"))
set dat.level = GetUnitAbilityLevel(learner, LeBlanc_MIMIC_ID)
else
// Else create a new instance of Mimic struct for unit
call MimicData.create(learner)
endif
set learner = null
endfunction
// Fired when Mimic is leveled up
private function OnHeroSkill takes nothing returns nothing
if GetLearnedSkill() == LeBlanc_MIMIC_ID then
call LearnMimicResponse()
endif
endfunction
private function OnInit takes nothing returns nothing
// Register when Mimic is leveled
call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function OnHeroSkill)
// Register when any of the spells are cast (fires before effect event)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CAST, function MimicSpellCast)
// Register when original abilities are cast
call RegisterSpellEffectEvent(LeBlanc_SIGIL_ID, function OnSpellEffect)
call RegisterSpellEffectEvent(LeBlanc_DISTORTION_ID, function OnSpellEffect)
call RegisterSpellEffectEvent(LeBlanc_ETHEREAL_CHAINS_ID, function OnSpellEffect)
// Register when mimic abilities are cast
call RegisterSpellEffectEvent(LeBlanc_MIMIC_SIGIL_ID, function MimicSpellEffect)
call RegisterSpellEffectEvent(LeBlanc_MIMIC_DISTORTION_ID, function MimicSpellEffect)
call RegisterSpellEffectEvent(LeBlanc_MIMIC_ETHEREAL_CHAINS_ID, function MimicSpellEffect)
endfunction
endlibrary
Credits
I'd like to give credit to the following:- Magtheridon96 for RegisterPlayerUnitEvent and whose existing works acted as a guideline for how I should do things
- Bribe for SpellEffectEvent
- Rising_Dusk for GroupUtils
- Vexorian, Cohadar and anyone who contribued to JassHelper
- Cohadar again for the wc3Borderizor tool
- Vexorian and Anitarf for the xe system
- Vexorian for TimerUtils, Table, ARGB and SimError
- PitzerMike and anyone else who contributed to JassNewGenPack
- SFilip and anyone else who contributed to TESH
- Halo7568/Krysho for his findings on the exploit with Channel and cooldown preservations.
More info: http://www.wc3c.net/showpost.php?p=1029039&postcount=86
- Riot Games for the icons and concept
- leagueoflegends.wikia.com for the icons
- _sPy for the holy missile model used in Sigil of Silence
- Sellenisko for the Alexstrazsa model used for LeBlanc
Changelog
v1.2 (13/10/2012)- Fixed a bug with Distortion not ending if distance was zero
v1.1 (04/10/2012)
General- Added a message to the tooltip to inform users that cooldown is triggered and not shown
- Nulled struct members at destruction of instance
Sigil of Silence- Targets Allowed change from any to air,ground,enemy,organic,neutral
Distortion- Fixed a bug in which the afterimages would not be removed
- Return no longer uses hero cast time (it's now instant)
Mimic-Distortion- After-image playercolour is now configurable (purple by default)
v1.0 (30/09/2012)
|
| Rating - 5.00 (1 vote) |
|
|
| Moderator Comments |
|
Recommended
17:19, 30th Sep 2012
Magtheridon96: Approved.
Awesome. The code is very clear and readable, and the documentation is excellent.
Also, lovely description!
|
|
This spell is approved and works properly.
 (409.19 KB, 483 Downloads)
|
09-30-2012, 11:22 AM
|
#2 (permalink)
|
|
\m/
Join Date: May 2006
Posts: 1,996
|
I read your code and tested the map. Very nicely done. 5* etc.
Quote:
|
It does not include Mirror Image due to the complex nature of the illusion.
|
What is complex about it? If you take damage below a certain point you create an illusionary double - there should be a library for that. If not, you're welcome to take a look at the code I use for it:
Jass:
public function addIllusion takes unit source, real duration returns unit
local unit dummy=CreateUnit(GetOwningPlayer(source),DUMMYID,GetUnitX(source),GetUnitY(source),270)
call UnitAddAbility(dummy,ILLUSIONID)
call UnitAddAbility(dummy,'Aloc')
call UnitApplyTimedLife(dummy,'BTLF',1.)
call IssueTargetOrderById(dummy,ILLUSIONORDER,source)
call UnitApplyTimedLife(lastCreatedIllusion,'BTLF',duration)
return lastCreatedIllusion
endfunction
(and then you need to register a condition on
EVENT_PLAYER_UNIT_SUMMON
to set lastCreatedIllusion)
Jass:
private function illusionC takes nothing returns boolean
local unit s=GetSummonedUnit()
if IsUnitIllusion(s) then
set lastCreatedIllusion=s
endif
set s=null
return false
endfunction
|
|
|
09-30-2012, 11:32 AM
|
#3 (permalink)
|
|
Inactive
Join Date: Jul 2009
Posts: 816
|
It was more of the fact that the illusion "has 53 + (17 x level) less health" and the "illusion's autoattacks will proc on-hit effects (including damage)". The dynamic health and the illusions ability to do on-hit effects are what made me not want to do it. Having the illusion be summoned isn't difficult at all.
I could do the less health by just setting the health of the illusion to that value instead of adjusting the maximum health I suppose. Do illusions in Warcraft III do the on-hit effects naturally? Or do I have to trigger that aspect somehow?
Hmm, I may very well end up adding Mirror Image. Thanks for the feedback.
|
|
|
09-30-2012, 11:37 AM
|
#4 (permalink)
|
|
\m/
Join Date: May 2006
Posts: 1,996
|
Quote:
Originally Posted by Lambdadelta
It was more of the fact that the illusion "has 53 + (17 x level) less health" and the "illusion's autoattacks will proc on-hit effects (including damage)". The dynamic health and the illusions ability to do on-hit effects are what made me not want to do it. Having the illusion be summoned isn't difficult at all.
|
Dynamic health is possible by abusing one bug - I think the common library that people were using to do it is called SetUnitMaxState, but it's not very efficient, and honestly, probably not worth using because of:
Quote:
|
I could do the less health by just setting the health of the illusion to that value instead of adjusting the maximum health I suppose. Do illusions in Warcraft III do the on-hit effects naturally? Or do I have to trigger that aspect somehow?
|
I think that might be your best bet in vanilla warcraft 3. Regarding on-hit effects, I think league of legends included that in the description for things like phage, because LeBlanc doesn't have any on-hit effects other than that, besides perhaps her chance to critically strike.
|
|
|
09-30-2012, 12:05 PM
|
#5 (permalink)
|
|
bot
Join Date: Jul 2011
Posts: 956
|
5/5 incredible originality excellent coding
|
|
|
09-30-2012, 02:05 PM
|
#6 (permalink)
|
|
JESUS MAN
Resource Moderator
Join Date: Dec 2008
Posts: 5,701
|
Congratulations for being the first person to upload something in vJASS without putting the code in Hidden tags to create an ugly font since I started working here.
|
|
|
09-30-2012, 07:31 PM
|
#7 (permalink)
|
|
Invasion in Duskwood
Join Date: Aug 2009
Posts: 1,114
|
Cool pack, once I was thinking of coding all her spells (and Morgana's spells too). One thing though: Distortion's secondary spell should be based on something that doesn't stop the unit's movement, for example Windwalk, Berserk, or Divine Shield. They're also instant (it would make the spells look even more like they do in LoL)
Another suggestion: to show Mimic's cooldown, you could add another of those instant-cast spells, and whenever a mimic'd spell is cast, you'd add it to the hero and order them to cast it. While it's in cooldown, you wouldn't be getting all those mimic spells icons, but this dummy ability will be show on the hero's command cart. It'd be more informal IMO, it took me like 4 minutes to notice the error message.
P.s: I hate xe :S It doesn't matter though as I'm not going to use any spells from public sources.
|
|
|
10-01-2012, 02:17 AM
|
#8 (permalink)
|
|
Inactive
Join Date: Jul 2009
Posts: 816
|
Quote:
Originally Posted by Cokemonkey11
Dynamic health is possible by abusing one bug - I think the common library that people were using to do it is called SetUnitMaxState, but it's not very efficient, and honestly, probably not worth using because of:
|
I was thinking of a library that allows adjustment of maximum hp/mp, but I don't think it's worth it on such a small spell.
Quote:
Originally Posted by Cokemonkey11
I think that might be your best bet in vanilla warcraft 3. Regarding on-hit effects, I think league of legends included that in the description for things like phage, because LeBlanc doesn't have any on-hit effects other than that, besides perhaps her chance to critically strike.
|
I suppose I'll make Mirror Image as just summoning an illusion and causing her to go invisible for a little bit when she goes x% health.
Quote:
Originally Posted by gorillabull
5/5 incredible originality excellent coding
|
Thank you :)
Quote:
Originally Posted by Magtheridon96
Congratulations for being the first person to upload something in vJASS without putting the code in Hidden tags to create an ugly font since I started working here.
|
Surely can't be the first one to do so? JASS tags have the option to expand/hide, why would there be a need to place them in hidden tags...?
Quote:
Originally Posted by Luorax
Cool pack, once I was thinking of coding all her spells (and Morgana's spells too).
|
Thank you :) It'd be interesting to see a Morgana spellpack, you should do it :P I may make a Cassiopeia spellpack if I ever get around to it, although there'd be some limitations that I can't get around.
Quote:
Originally Posted by Luorax
One thing though: Distortion's secondary spell should be based on something that doesn't stop the unit's movement, for example Windwalk, Berserk, or Divine Shield. They're also instant (it would make the spells look even more like they do in LoL)
|
That's a good point. I'll make this change in the next update. Thanks.
Quote:
Originally Posted by Luorax
Another suggestion: to show Mimic's cooldown, you could add another of those instant-cast spells, and whenever a mimic'd spell is cast, you'd add it to the hero and order them to cast it. While it's in cooldown, you wouldn't be getting all those mimic spells icons, but this dummy ability will be show on the hero's command cart. It'd be more informal IMO, it took me like 4 minutes to notice the error message.
|
This may also work. I'll try playing around with this idea and see how it turns out.
Quote:
Originally Posted by Luorax
P.s: I hate xe :S It doesn't matter though as I'm not going to use any spells from public sources.
|
I find xe quite useful as it does so much stuff for you. Plus I'm just lazy so that's why I used it :P That's fair enough, I don't tend to use spells from public sources as well.
Thank-you for the comments everyone :)
|
|
|
10-01-2012, 01:12 PM
|
#9 (permalink)
|
|
Mapper - vJasser
Join Date: Mar 2008
Posts: 729
|
Hiho,
I was testing your abilities because I really like Le Blanc in League of Legends.^^
All in all the are good.
However, I've found some bugs.
1. Mirror Images while teleport spell (W) didn't disappear all the time properly but I don't know why or when.
2. The teleport speed on W is too slow and should be much faster.
3. The range of the E ability is too high imo.
4. You should make the trigger system like in LoL where you can for example target an area which is far away but your hero will still teleport to the direction with maximum distance to that target point. In your map the targeting system will move your hero to the spot so that the hero will always land properly at the target position - however, I think that the other system is much better - so why made it Riot just like that?
5. You are able to target yourself or allies with the Q ability.
That's all I think. =)
Robbepop
|
|
|
10-02-2012, 02:51 AM
|
#10 (permalink)
|
|
Inactive
Join Date: Jul 2009
Posts: 816
|
Quote:
Originally Posted by Robbepop
Hiho,
I was testing your abilities because I really like Le Blanc in League of Legends.^^
All in all the are good.
However, I've found some bugs.
1. Mirror Images while teleport spell (W) didn't disappear all the time properly but I don't know why or when.
2. The teleport speed on W is too slow and should be much faster.
3. The range of the E ability is too high imo.
4. You should make the trigger system like in LoL where you can for example target an area which is far away but your hero will still teleport to the direction with maximum distance to that target point. In your map the targeting system will move your hero to the spot so that the hero will always land properly at the target position - however, I think that the other system is much better - so why made it Riot just like that?
5. You are able to target yourself or allies with the Q ability.
That's all I think. =)
Robbepop
|
- I'll look into this.
- I've changed that for the next update. It no longer uses cast point.
- All the figures are directly from LoL, so I guess 1000 range in Warcraft III is quite high compared to LoL. You can always change it.
- I think LoL does the same. It'll move the hero until it reaches in range. I think Distortion is the same? I might test it out later.
- You're quite the observant one :) I had it set to allies for testing purposes, I didn't want the enemies to attack. I could have just made my units Ethereal or something I suppose, oh well. You can always adjust this if you like.
Thanks for the feedback :)
Edit:
Quote:
|
Another suggestion: to show Mimic's cooldown, you could add another of those instant-cast spells, and whenever a mimic'd spell is cast, you'd add it to the hero and order them to cast it. While it's in cooldown, you wouldn't be getting all those mimic spells icons, but this dummy ability will be show on the hero's command cart. It'd be more informal IMO, it took me like 4 minutes to notice the error message.
|
This would be fine if it was just Sigil of Silence and Ethereal Chains, but Distortion will cause problems. If you don't return, I could just have a separate ability with a cooldown that's shorter, but if you return earlier the cooldown indicator should be longer to match. I think I may leave it as triggered cooldown for now.
Also, the image doesn't seem to be updating...
Last edited by Lambdadelta; 10-04-2012 at 04:02 AM.
|
|
|
10-07-2012, 11:55 PM
|
#11 (permalink)
|
|
Level 2
Join Date: Aug 2012
Posts: 656
|
Hiho,
Babe you are aMEWzing 5/5 +REPT ;) ;)
FRENGERS
__________________
Level 2/20
Each level need 100 Reputation....
|
|
|
10-10-2012, 07:44 PM
|
#12 (permalink)
|
|
Survivor
Join Date: Aug 2012
Posts: 155
|
If you cast Distortion and then cast Mimic Distortion in exactly the same place, LeBlanc shoots off across the map with no controllability, leaving a massive trail of ghost 'blancs :L Only a small bug that I stumbled across!
Other than that, some of the best spells I have even seen in Warcraft III, glad to see some LoL content here :) Planning on making an other packs for LoL characters?
__________________
|
|
|
10-12-2012, 09:39 AM
|
#13 (permalink)
|
|
Inactive
Join Date: Jul 2009
Posts: 816
|
Quote:
Originally Posted by Maldruzard
If you cast Distortion and then cast Mimic Distortion in exactly the same place, LeBlanc shoots off across the map with no controllability, leaving a massive trail of ghost 'blancs :L Only a small bug that I stumbled across!
|
Interesting. I'll investigate further. Thanks for reporting this.
Edit
I have fixed this now in v1.2.
Quote:
Originally Posted by Maldruzard
Other than that, some of the best spells I have even seen in Warcraft III, glad to see some LoL content here :) Planning on making an other packs for LoL characters?
|
At the moment, I won't be. I don't know/like too many other champions from LoL (I hardly play it either) :P
Last edited by Lambdadelta; 10-13-2012 at 01:28 AM.
|
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
|
|
|
|
|
|
|
|
|
All times are GMT. The time now is 05:47 PM.
|