Name | Type | is_array | initial_value |
i | integer | Yes | |
Integer | integer | Yes |
//TESH.scrollpos=47
//TESH.alwaysfold=0
//==Tentacle Attack==
//2oo9 by Squiggy
//Spell needs jngp and TimerUtils
//Credits go to HINDYhat for teaching me jass
//The next spell will include methods, yes yes D:
scope TentacleAttack initializer Init
globals
private constant integer SPELLID = 'A000' //This is the spell's id
private constant string EFFPATH = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
private constant string EFFPATH2 = "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl"
private constant integer DUMMYID = 'n000' //Here, we aet the dummy WITHOUT the attack which impales the enemy
private constant integer DUMMYID2 = 'n001' //Now we set the dummy WITH attack which rapes the target
private constant real DURATION = 7 //Here goes the duration of the spell
private constant real FLYHEIGHT = 350 //Flying height to which the target is changed
private constant real RANDOM_MIN_X = 0 //Those are the random values for the tentacles' placement
private constant real RANDOM_MAX_X = 400
private constant real RANDOM_MIN_Y = 0
private constant real RANDOM_MAX_Y = 400
private constant real RANDOM_MIN_ANG = 0
private constant real RANDOM_MAX_ANG = 360
private constant real FALLRATE = 4000 //And here's the speed at which the target falls down
endglobals
private struct tentacle //We define all values which we need for the second part of the spell
unit caster
unit target
integer i
real tx
real ty
integer index
player p
endstruct
private function Conditions takes nothing returns boolean //First, we check which ability is being cast
return GetSpellAbilityId() == SPELLID
endfunction
private function Conditions2 takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == DUMMYID //This is the condition for the second trigger - it checks the type of the dying unit
endfunction
private function grpenu takes nothing returns boolean //Group filter to your left checking for the buff 'rape'
return GetUnitAbilityLevel(GetFilterUnit(), 'B000')>0
endfunction
private function Tentacles takes nothing returns nothing //Here we deal with everything aftert the first tentacle is created
local real rndx
local real rndy
local real rnda
local unit u2
local tentacle tc = tentacle(GetTimerData(GetExpiredTimer())) //we get the data
set rndx = GetRandomReal(RANDOM_MIN_X, RANDOM_MAX_X) //Now we create the dummy
set rndy = GetRandomReal(RANDOM_MIN_Y, RANDOM_MAX_Y)
set rnda = GetRandomReal(RANDOM_MIN_ANG, RANDOM_MAX_ANG)
set u2 = CreateUnit(tc.p, DUMMYID2, (tc.tx + rndx*Cos((rnda)*bj_DEGTORAD)), tc.ty + rndy*Sin((rnda)*bj_DEGTORAD), rnda)
call IssueTargetOrder(u2, "attack", tc.target) //We order it to attack the target
call UnitApplyTimedLife(u2, 'BTLF', DURATION)
call DestroyEffect(AddSpecialEffect(EFFPATH2, GetUnitX(u2), GetUnitY(u2))) //And add an effect
set tc.index = tc.index+1 //To limit the number of dummies, we set the maximum to lvl*3
if tc.i == tc.index then
call ReleaseTimer(GetExpiredTimer())
set u2 = null
call tc.destroy()
endif
endfunction
private function Actions takes nothing returns nothing //Here's the first part which creates the impaling tentacle
local unit caster = GetTriggerUnit()
local unit u
local real x = GetUnitX(caster)
local real y = GetUnitY(caster)
local timer t = NewTimer()
local timer t2 = NewTimer()
local tentacle tc = tentacle.create()
call SetTimerData(t, integer(tc))
set tc.target = GetSpellTargetUnit()
set tc.tx = GetUnitX(tc.target)
set tc.ty = GetUnitY(tc.target)
set tc.i = GetUnitAbilityLevel(caster, SPELLID)*3
set tc.index = 0
set tc.p = GetOwningPlayer(caster)
set u = CreateUnit(tc.p, DUMMYID, tc.tx, tc.ty, 90)
call UnitApplyTimedLife(u, 'BTLF', DURATION+1.2)
call UnitAddAbility(tc.target, 'Amrf') //We add and remove 'crow form' to the target
call UnitRemoveAbility(tc.target, 'Amrf')
call SetUnitFlyHeight(tc.target, FLYHEIGHT, FLYHEIGHT*3) //And make it raise
call DestroyEffect(AddSpecialEffectTarget(EFFPATH, tc.target, "origin"))
call TimerStart(t, 0.2, true, function Tentacles)
call SetUnitAnimation(u, "birth") //Now we make the tentacle appear out of the ground and set it's animation speed to 0
call SetUnitFlyHeight(u, 0, FLYHEIGHT*3)
call SetUnitTimeScale(u, 0)
call SetUnitUserData(tc.target, GetUnitUserData(tc.target)+1) //Adding a custom value will prevent the target from falling dow too soon
set caster = null
set u = null
endfunction
private function Death takes nothing returns nothing //The third and last part is to bring the target back to the ground when the first tentacle dies
local unit u = GetTriggerUnit()
local unit gru
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local group g = CreateGroup()
call SetUnitTimeScale(u, 1)
call GroupEnumUnitsInRange(g, x, y, 100, Filter(function grpenu)) //We pick the nearby target which still has the buff 'rape'
loop
set gru = FirstOfGroup(g)
exitwhen gru == null
call SetUnitUserData(gru, GetUnitUserData(gru)-1) //Now as the instance is over, we substract 1 of the custom value
if GetUnitUserData(gru) == 0 then //And if there are no instances running (cv == 0),
call SetUnitFlyHeight(gru, 0, FALLRATE) //we bring it down
endif
call GroupRemoveUnit(g, gru)
endloop
call DestroyGroup(g)
set u = null
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
local trigger t2 = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerRegisterAnyUnitEventBJ(t2, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t, Condition(function Conditions))
call TriggerAddCondition(t2, Condition(function Conditions2))
call TriggerAddAction(t, function Actions)
call TriggerAddAction(t2, function Death)
endfunction
endscope
//TESH.scrollpos=13
//TESH.alwaysfold=0
library_once TimerUtils
//*********************************************************************
//* TimerUtils (Blue flavor)
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3campaigns.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Blue Flavor: Slower than the red flavor, it got a 408000 handle id
//* limit, which means that if more than 408000 handle ids
//* are used in your map, TimerUtils might fail, this
//* value is quite big and it is much bigger than the
//* timer limit in Red flavor.
//*
//********************************************************************
//================================================================
globals
private constant integer MAX_HANDLE_ID_COUNT = 40800
// values lower than 8191: very fast, but very unsafe.
// values bigger than 8191: not that fast, the bigger the number is the slower the function gets
// Most maps don't really need a value bigger than 50000 here, but if you are unsure, leave it
// as the rather inflated value of 408000
endglobals
//=================================================================================================
private function H2I takes handle h returns integer
return h
return 0
endfunction
//==================================================================================================
globals
private integer array data[MAX_HANDLE_ID_COUNT]
private constant integer MIN_HANDLE_ID=0x100000
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
debug if(H2I(t)-MIN_HANDLE_ID>=MAX_HANDLE_ID_COUNT) then
debug call BJDebugMsg("SetTimerData: Handle id too big, increase the max handle id count or use gamecache instead")
debug endif
set data[H2I(t)-MIN_HANDLE_ID]=value
endfunction
function GetTimerData takes timer t returns integer
debug if(H2I(t)-MIN_HANDLE_ID>=MAX_HANDLE_ID_COUNT) then
debug call BJDebugMsg("GetTimerData: Handle id too big, increase the max handle id count or use gamecache instead")
debug endif
return data[H2I(t)-MIN_HANDLE_ID]
endfunction
//==========================================================================================
globals
private timer array tT
private integer tN = 0
private constant integer HELD=0x4326789432
//use a totally random number here, the more improbable someone uses it, the better.
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
if (tN==0) then
set tT[0]=CreateTimer()
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==8191) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
endlibrary