//Author of this Template Map is redscores.
Name | Type | is_array | initial_value |
AuthorName | string | No | |
Dummy | unitcode | No | |
HM_HeroName | string | No | |
HM_SpellNames | string | Yes | |
IntegerS | integer | No | |
ModeChooser | integer | No | |
RevivePoint | location | No | |
SM_SpellName | string | No | |
SPM_counter | integer | No | |
SPM_SpellNames | string | Yes | |
SPM_SpellPackName | string | No | |
TestCharacter | unit | No |
//TESH.scrollpos=50
//TESH.alwaysfold=0
scope FireGeysers initializer Init
globals
private constant integer SPELLID = 'A000' //ABILITY RAWCODE
private constant string EFFECT = "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl" //FIRE EFFECT
private constant integer EFFECTAMOUNT = 3 //HOW MANY FIRE GEYSERS ARE CREATED DURING A PERIOD
private constant integer AMOUNT = 3 //HOW MANY TIMES THE EFFECT OCCURS IN TOTAL. TO FIND OUT HOW LONG THE SPELL WILL LAST IN SECONDS: AMOUNT * PERIOD
private constant real PERIOD = 2.0 //HOW OFTEN THE EFFECT OCCURS
private constant real DAMAGE = 50.0 //DAMAGE DONE BY EACH FIRE GEYSER PER LEVEL
private constant real RNDMIN = 300.0 //MINIMUM DISTANCE THE EFFECT WILL OCCUR FROM THE CASTER
private constant real RNDMAX = 600.0 //MINIMUM DISTANCE THE EFFECT WILL OCCUR FROM THE CASTER
private constant attacktype ATTACKTYPE = ATTACK_TYPE_MAGIC //THE TYPE OF ATTACK (MAGIC, HERO, CHAOS, ETC.)
private constant damagetype DAMAGETYPE = DAMAGE_TYPE_FIRE //THE TYPE OF DAMAGE.
private constant weapontype WEAPONTYPE = WEAPON_TYPE_WHOKNOWS //FOR DIFFERENT TYPES OF WEAPONS. DON'T RECOMMAND YOU CHANGE IT.
//DON'T CHANGE ANYTHING AFTER THIS POINT UNLESS YOU KNOW WHAT YOU'RE DOING!
private group TEMPGROUP = CreateGroup()
endglobals
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == SPELLID
endfunction
private struct data
unit u = null
real ux = 0.0
real uy = 0.0
integer lvl = 0
integer count = 0
static method create takes unit u returns data
local data d = data.allocate()
set d.u = u
set d.ux = GetUnitX(u)
set d.uy = GetUnitY(u)
set d.lvl = GetUnitAbilityLevel(u, SPELLID)
return d
endmethod
endstruct
globals
private data TEMPSTRUCT
endglobals
private function Damage takes nothing returns boolean
call UnitDamageTarget(TEMPSTRUCT.u, GetFilterUnit(), DAMAGE * TEMPSTRUCT.lvl, false, false, ATTACKTYPE, DAMAGETYPE, WEAPONTYPE)
return false
endfunction
private function Periodic takes nothing returns nothing
local data d = data(GetTimerData(GetExpiredTimer()))
local real rndx = 0.0
local real rndy = 0.0
local real angle = 0.0
local integer i = 0
if d.count < AMOUNT then
loop
set rndx = d.ux + GetRandomReal(RNDMIN, RNDMAX) * Cos(GetRandomReal(0.00,57.29))
set rndy = d.uy + GetRandomReal(RNDMIN, RNDMAX) * Sin(GetRandomReal(0.00,57.29))
call DestroyEffect(AddSpecialEffect(EFFECT, rndx, rndy))
call GroupEnumUnitsInRange(TEMPGROUP, rndx, rndy, 200.0, Condition(function Damage))
set i = i + 1
exitwhen i == EFFECTAMOUNT
endloop
set d.count = d.count + 1
else
call ReleaseTimer(GetExpiredTimer())
call d.destroy()
endif
endfunction
private function Actions takes nothing returns nothing
local timer t = NewTimer()
call SetTimerData(t, data.create(GetTriggerUnit()))
call TimerStart(t, PERIOD, true, function Periodic)
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function Conditions))
call TriggerAddAction(t, function Actions)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
library_once TimerUtils initializer init
//*********************************************************************
//* TimerUtils (Blue flavor for 1.23b or later)
//* ----------
//*
//* 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 hashtable hasht //I <3 blizz
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
call SaveInteger(hasht,0, GetHandleId(t), value)
endfunction
function GetTimerData takes timer t returns integer
return LoadInteger(hasht, 0, GetHandleId(t))
endfunction
//==========================================================================================
globals
private timer array tT
private integer tN = 0
private constant integer HELD=0x28829022
//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
private function init takes nothing returns nothing
set hasht = InitHashtable()
endfunction
endlibrary
//TESH.scrollpos=48
//TESH.alwaysfold=0
This is the JESP standard document, if a map contains this document it means that there are
spells that follow this standard.
Spells of this map that follow the standard:
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
- Cold Snap
- Aura of Energy
Advantages of the Standard
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
- Implementing spells that follow the standard is relatively easier than implementing JASS
spells that don't follow the standard.
- Configuring/Balancing spells that follow the standard is relatively easier than
implementing JASS spells that don't follow the standard.
- Users may do the following procedure to make a new ability that uses the spell's script :
* Create a new Trigger with a name (case sensitive)
* Convert that trigger to custom text.
* Copy the spell's script to a text editor like Notepad or your OS equivalent.
* Replace the spell's Code name with the name you used on the trigger.
* Copy the new text to the new trigger
* Duplicate the Spell's original objects to have new ones for the new spell script.
You are now able to use that new version of the spell.
- In case two guys give the same name to 2 different spells, there are no conflict problems
because you can easily change the name of one of them
What is the JESP Standard?
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
The JESP standard was designed to make spell sharing much better. And to make sure JASS
enhanced spells follow a rule, to prevent chaos.
What does JESP Standard stands for?
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
JASS
Enhanced
Spell
Pseudotemplate
Requirements for a spell to follow the JESP Standard
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
- The spell is written in JASS
- The spell is 100% multi instanceable.
- The spell script is ready to support spells of any number of levels.
(default config header is not required to support all of them)
- The Spell has an specific code name.
- The Spell's trigger must have the spell's codename as name
- The Spell's InitTrig function must be named: InitTrig_<CodeName>
- The spell has a configuration header.
- It is mandatory that rawcodes of objects are configurable in the header.
- All the spell's specific code is inside the spell's "Trigger" (Trigger== that custom text
slot that world editor calls Trigger, the spell may use as many 'trigger' OBJECTS as needed)
- Every spell-specific single identifier or key works in such a way that reproducing the
spell's trigger but after performing a text-replace of codename with another name (and thus
renaming the cloned trigger to the new code name) it won't cause compile errors / conflicts
when playing the map.
- There is no code inside the spell's "Trigger" that is not specific to the spell.
- There are no requirements for GUI variables that are specific to the spell. If a system
used by the spell requires GUI variables the code for the system must be outside the "Trigger"
- Eyecandy and spell's balance have to be easy to configure
- The name of the author should be included in the spell's script.
- The reason to exist of this standard is spell sharing. This document should be included
within the map. And it should specify which spell follows the standard, in the top list.