- Joined
- Jun 24, 2009
- Messages
- 1,409
I'm just wondering. Isn't there in JASS a func that increases an integer with 1? Just like the inc(i) in Pascal.
function inc takes integer i returns nothing
set i = i + 1
endfunction
Even if the meteors are instant, the smoke behind them should go away a bit slower. I mean from the top effect to the ground effect it takes less than 0.2 seconds to go away. You should increase that interval, will look a bit better due to the impale dust effect. It's just my opinion though.
Well, there's nothing I can do with the smoke itself, but I guess I could increase the interval at which the meteors hit the ground to compensate.Yeah, the smoke should stay for a while longer.
That's how the actual spell is. Look at the video in this post (Starts at 0:30).The big flash is overpoweing and you can't see any actual meteors falling...
![]() | Channels a soul orb to damage the first units in a line. If no enemy unit hit and the orb raches it's max distance, it disappears. The orb passes through magic immune units and buildings. |
Omg, i afraid that i will lose, here we have a good contestant!
Introduction
The Spells & Systems Contest is more of a fun code learning environment than a contest, due to its low requirements, its short time limit, and its small prize. Each spell must adhere to the theme listed below, and to win, it should be executed well and take the main judging points into consideration.
You had it right. If the value of:
Caster Health / Caster Health Max
Is less than the value of:
Target Health / Target Health Max
Then the caster has less health (in percentage) than the target.
So, if the caster has 500/1000 then the percentage is 50%, or 0.5. If the target has 200/300, then the percentage is 66.6%, or 0.666. Since 0.5 < 0.666, the caster would have less percentage than the target.
Got any ideas how to make it more balanced, by not just using flat life?
Got any ideas how to make it more balanced, by not just using flat life?
Berb said:Does anybody own Age of Mythology? There aren't any particularly good videos of the effect it has; from what I can tell it deals damage to enemies in an area and sucks them into the wind if they die as a result.
What happens when two tornadoes come in contact with each other? What happens to the units that are being blown around by the tornado? What happens to air units (if there are air units) when they are affected by the tornado?
TRD*TDR, that looks really good now; where did you get the light flashing effect from?
"Abilities\\Weapons\\RocketMissile\\RocketMissile.mdl"
and it's scaled to 16 times its own size. call DestroyEffect(AddSpecialEffectTarget(<derp>))
(Target because it's attached to a dummy unit so I could scale it).Okey, I'll implement that tomorrow. Not sure if I'll find fitting "godpower music" though without importing anything.Okay, TRD, I got the exact stuff now.
Meteor Storm does not damage allies and your own units; It does, however, knock them off flying, albeit more lightly than enemy units.
Meteor Storm also has cool 'godpower music' playing while it's being cast.![]()
library TornadoObject requires SafetyQueue, TimerUtils, Group
struct tornadoobject
//******************
//* Tornado Object
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//*
//*
//* ########################################################################################################
//* Config:
//* @ TORNADO_ID - the unit ID of the tornado visual unit.
//*
//* @ TORNADO_VISUAL_COUNT - the amount of tornado visuals created upon construction.
//* @ TORNADO_DEBRIS_COUNT - the amount of tornado debris visuals created upon construction.
//*
//* @ DAMAGE_FREQUENCY - the frequency enemies are damaged within the 'outerRadius'.
//* @ MOTION_UPDATE_FREQUENCY - the frequency at which motion is updated amongst tornado objects.
//*
//* @ TORNADO_OFFSET_LIMIT - the tornado visuals will be offset by a maximum of this value.
//* @ TORNADO_SCALE_MINIMUM - the smallest scale-size a tornado may have.
//* @ TORNADO_SCALE_MAXIMUM - the largest scale-size a tornado may have.
//*
//* @ DAMAGE_PER_SECOND - the damage dealt to enemies within a second.
//* ----
public static constant integer TORNADO_ID = 'hsor'
public static constant integer TORNADO_VISUAL_COUNT = 3
public static constant integer TORNADO_DEBRIS_COUNT = 4
public static constant real DAMAGE_FREQUENCY = 0.1
public static constant real MOTION_UPDATE_FREQUENCY = 0.033
public static constant real TORNADO_OFFSET_LIMIT = 30.00
public static constant real TORNADO_SCALE_MINIMUM = 1.4
public static constant real TORNADO_SCALE_MAXIMUM = 1.7
public static real array DAMAGE_PER_SECOND
//*
//*
//* ########################################################################################################
//*
//*
//* Members:
//*
//* ----
private unit originCaster = null
private player casterPlayer = null
private integer level
private unit array visualDummy [thistype.TORNADO_VISUAL_COUNT]
private tornadodebris array debrisDummy [thistype.TORNADO_DEBRIS_COUNT]
private extgroup effectGroup
private real x
private real y
private real outerRadius
private real innerRadius
private timer damageTimer = null
private timer motionTimer = null
//*
//*
//* Method: onDestroyGroupEnum ()
//* Iterates through the group 'effectGroup' to reset some of the states that may have been altered
//* during the spell such as invulnerability and pause-state.
//*
//* Uses the 'enumTempObject' member defined below to carry data to another function.
//* ----
private static method onDestroyGroupEnum takes nothing returns nothing
local unit en = GetEnumUnit()
call SetUnitFlyHeight(en, 0, 20000)
call SetUnitTimeScale(en, 1)
call PauseUnitSafe(en, false)
call SetUnitInvulnerableSafe(en, false)
call UnitDamageTarget(enumTempObject.originCaster, en, GetWidgetLife(en)*2, false, false, /*
*/ ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
set en = null
endmethod
//*
//*
//* Destructor:
//*
//* ----
method onDestroy takes nothing returns nothing
local integer i = 0
loop // destroy tornado visuals
exitwhen i == TORNADO_VISUAL_COUNT
call KillUnit(visualDummy[i])
set i = i + 1
endloop
set i = 0
loop // destroy tornado debris visuals
exitwhen i == TORNADO_DEBRIS_COUNT
call debrisDummy[i].destroy()
set i = i + 1
endloop
set enumTempObject = this
call ForGroup(effectGroup.g, function thistype.onDestroyGroupEnum)
call effectGroup.destroy()
call ReleaseTimer(damageTimer)
call ReleaseTimer(motionTimer)
endmethod
//*
//*
//* Method: createTornadoVisual ()
//* Creates a tornado unit for visual effect at an offset location to the given coordinates.
//* ----
private static real tempDist
private static real tempAngl
private static real tempX
private static real tempY
private static unit tempReturn
static method createTornadoVisual takes real x, real y, real scale returns unit
set tempDist = GetRandomReal(0, TORNADO_OFFSET_LIMIT)
set tempAngl = GetRandomReal(0, 2*bj_PI)
set tempX = x + tempDist * Cos(tempAngl)
set tempY = y + tempDist * Sin(tempAngl)
set tempReturn = CreateUnit(Player(12), TORNADO_ID, tempX, tempY, GetRandomReal(0, 360))
call SetUnitX(tempReturn, tempX)
call SetUnitY(tempReturn, tempY)
call SetUnitScale(tempReturn, scale, scale, scale)
call SetUnitTimeScale(tempReturn, 0.4)
call extunit[tempReturn].applyFader(255, 255, 200, 0, 255, 5.0)
return tempReturn
endmethod
//*
//*
//* Constructor:
//* Creates a tornado-object given coordinates and values for inner/outer radius, respectively.
//* ----
static method create takes unit caster, integer lvl, real x, real y, real radius1, real radius2 returns thistype
local thistype t = allocate()
local integer i
set t.x = x
set t.y = y
set t.originCaster = caster
set t.casterPlayer = GetOwningPlayer(caster)
set t.level = lvl
set t.effectGroup = extgroup.create()
if radius1 > radius2 then
set t.innerRadius = radius2
set t.outerRadius = radius1
else
set t.innerRadius = radius1
set t.outerRadius = radius2
endif
set i = 0
loop
exitwhen i == TORNADO_VISUAL_COUNT
set t.visualDummy[i] = createTornadoVisual(x, y, /*
*/ GetRandomReal(TORNADO_SCALE_MINIMUM, TORNADO_SCALE_MAXIMUM))
set i = i + 1
endloop
set t.damageTimer = NewTimer()
call SetTimerData(t.damageTimer, t)
call TimerStart(t.damageTimer, DAMAGE_FREQUENCY, true, function thistype.onDamageInterval)
set t.motionTimer = NewTimer()
call SetTimerData(t.motionTimer, t)
call TimerStart(t.motionTimer, MOTION_UPDATE_FREQUENCY, true, function thistype.onMotionInterval)
return t
endmethod
//*
//*
//* Method: onMotionIterate ()
//* Iterates through the group's contents and updates. There are a lot of execution trees here,
//* so to clarify what this is doing...
//*
//* "onMotionInterval" is executed after the tornado has been created on a periodic interval. The
//* timer "motionTimer" is responsible for this. On each execution of "onMotionInterval", the
//* members of the group "effectGroup" are iterated through.
//* ----
private static method onMotionIterate takes nothing returns nothing
local unit en = GetEnumUnit()
local real newX
local real newY
local real angl = Atan2(enumTempObject.y - GetUnitY(en), enumTempObject.x - GetUnitX(en))
local real rnd = GetRandomReal(-bj_PI/16, bj_PI/16)
if IsUnitInRangeXY(en, enumTempObject.x, enumTempObject.y, enumTempObject.innerRadius) then
set newX = GetUnitX(en) + 11 * Cos(angl+bj_PI/2+rnd)
set newY = GetUnitY(en) + 11 * Sin(angl+bj_PI/2+rnd)
call SetUnitFlyHeight(en, GetUnitFlyHeight(en)+1, 0)
else
set newX = GetUnitX(en) + 10 * Cos(angl)
set newY = GetUnitY(en) + 10 * Sin(angl)
set newX = newX + 11 * Cos(angl+bj_PI/2)
set newY = newY + 11 * Sin(angl+bj_PI/2)
endif
call SetUnitX(en, newX)
call SetUnitY(en, newY)
set en = null
endmethod
//*
//*
//* Method: onMotionInterval ()
//* This method uses the 'enumTempObject' which is defined below under 'onDamageInterval ()'.
//* ----
private static method onMotionInterval takes nothing returns nothing
set enumTempObject = GetTimerData(GetExpiredTimer())
call ForGroup(enumTempObject.effectGroup.g, function thistype.onMotionIterate)
endmethod
//*
//*
//* Method: onDamageFilter ()
//* This will damage nearby enemies to the tornado. The interval method is defined below which is
//* executed on a periodic basis, though similar to "onMotionInterval" it simply allocates the
//* iterative work-load to this method.
//* ----
private static method onDamageFilter takes nothing returns boolean
local boolean isValid = true
local unit filt = GetFilterUnit()
local thistype temp = enumTempObject
if not IsUnitInGroup(filt, temp.effectGroup.g) then
if not IsUnitEnemy(filt, temp.casterPlayer) or /*
*/ IsUnitType(filt, UNIT_TYPE_MAGIC_IMMUNE) then
set isValid = false
endif
if isValid then
if (DAMAGE_PER_SECOND[temp.level] * DAMAGE_FREQUENCY) >= GetWidgetLife(filt) then
if not (GetWidgetLife(filt) < 0.405) then
call SetUnitInvulnerableSafe(filt, true)
call PauseUnitSafe(filt, true)
call SelectUnit(filt, false)
call SetUnitTimeScale(filt, 6)
call UnitAddAbility(filt, 'Amrf')
call UnitRemoveAbility(filt, 'Amrf')
call GroupAddUnit(temp.effectGroup.g, filt)
endif
else
call UnitDamageTarget(temp.originCaster, filt, /*
*/ DAMAGE_PER_SECOND[temp.level] * DAMAGE_FREQUENCY, /*
*/ false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
endif
endif
endif
set filt = null
return false
endmethod
//*
//*
//* Method: onDamageInterval ()
//* On each damage interval nearby enemies are enumerated and dealt damage.
//* ----
private static group enumGroup = CreateGroup()
private static boolexpr enumFilter = null
private static thistype enumTempObject
private static method onDamageInterval takes nothing returns nothing
set enumTempObject = GetTimerData(GetExpiredTimer())
call GroupEnumUnitsInRange(enumGroup, enumTempObject.x, enumTempObject.y, /*
*/ enumTempObject.outerRadius, enumFilter)
endmethod
//*
//*
//* Initialization:
//*
//* ----
private static method onInit takes nothing returns nothing
set enumFilter = Filter(function thistype.onDamageFilter)
set DAMAGE_PER_SECOND[0] = 250.00
set DAMAGE_PER_SECOND[1] = 350.00
endmethod
//*
//*
//**********************************************************************************************************
endstruct
endlibrary
scope Tornado
struct tornado extends spell
//******************
//* Tornado
//* ¯¯¯¯¯¯¯
//* The spell-effect should be found in the "onSpellEffect" method.
//*
//*
//* ########################################################################################################
//* Config
//* @ ABIL_ID - the raw-code ability ID for the spell.
//* @ DURATION - the duration that the tornado will last until destruction.
//* ----
public static constant integer ABIL_ID = 'A000'
public static constant real DURATION = 25.00
//*
//*
//* ########################################################################################################
//*
//*
//* Method: onSpellExpire ()
//* Executes after the spell has been cast and the duration has expired. This will simply destroy
//* the tornado object which was created on spell effect.
//* ----
private static method onSpellExpire takes nothing returns nothing
call tornadoobject(GetTimerData(GetExpiredTimer())).destroy()
call ReleaseTimer(GetExpiredTimer())
endmethod
//*
//*
//* Method: onSpellEffect ()
//* Executes spell actions. User-interfaced method.
//* ----
method onSpellEffect takes nothing returns nothing
local timer t = NewTimer()
local tornadoobject obj = tornadoobject.create(GetTriggerUnit(), /*
*/ GetUnitAbilityLevel(GetTriggerUnit(), ABIL_ID), GetSpellTargetX(), GetSpellTargetY(), 80, 800)
call SetTimerData(t, obj)
call TimerStart(t, DURATION, false, function thistype.onSpellExpire)
set t = null
endmethod
//*
//*
//* Initialization:
//* Initialize 'tornado' spell struct.
//* ----
private static method onInit takes nothing returns nothing
call thistype.create(ABIL_ID)
endmethod
//*
//*
//**********************************************************************************************************
endstruct
endscope
library Unit requires AutoIndex, /*
*/ optional UnitTargetModule, /*
*/ optional UnitDamageModule, /*
*/ optional UnitFaderModule
struct extunit extends extunitinterface
//******************
//* Extended Unit
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯
//* The extended unit struct is implemented with AutoIndex because it is truly one of the easiest to
//* interface with for casual purposes, or at least to my standards.
//*
//* Modules can be implemented (as they are below) that add functionality in terms of API methods and
//* interface methods which make the unit struct very easy to work with.
//*
//*
//* Optional Modules:
//* @ UnitDamageModule - provides registration of unit structs in a damage-detection engine.
//* @ UnitTargetModule - provides an API for gathering unit targeting information.
//* @ UnitFaderModule - provides an API for fading a unit in alpha color.
//* ----
implement optional UnitDamageModule
implement optional UnitTargetModule
implement optional UnitFaderModule
//*
//*
//* Implemented Modules:
//* @ AutoCreate - provides automatic creation of 'extunit' structs for new units.
//* @ AutoDestroy - provides automatic recycling of 'extunit' structs when the
//* associated unit is removed from the game.
//* ----
implement AutoCreate
implement AutoDestroy
//*
//*
//**********************************************************************************************************
endstruct
endlibrary
library UnitFader
module UnitFaderModule
//******************
//* Unit Fader Module
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* Provides an API to the 'extunit' struct to fade a unit from a set starting alpha to a set final alpha. The
//* unit-fader comes with a method to determine whether or not a unit is being faded, but additional calls to
//* the unit-fader will simply over-ride each other.
//*
//*
//* Timer Members:
//* Variable members associated with the timed updates of the fader.
//* ----
private static timer fadeTimer = CreateTimer()
private static constant real fadeTimeout = 0.1
//*
//*
//* Stack Members:
//* Variable members that maintain a stack of units that are being told to fade.
//* ----
private static thistype array fadeStack
private static integer fadeStackSize = 0
private integer fadeStackIndex
private boolean fadeStackIn = false
//*
//*
//* Fade Data Members:
//* Data associated with the fade components and coloring components of the unit.
//* ----
private integer fadeVertexRed
private integer fadeVertexBlue
private integer fadeVertexGreen
private integer fadeVertexAlpha
private integer fadeVertexAlphaStep
private integer fadeVertexAlphaFinal
private real fadeTimeLeft
//*
//*
//* Method: removeFader ()
//* Removes the unit-fader from the stack. By the time 'removeFader()' is called the unit's final
//* alpha should be the same value given upon application.
//* ----
method removeFader takes nothing returns nothing
set fadeStackSize = fadeStackSize - 1
set fadeStack[fadeStackIndex] = fadeStack[fadeStackSize]
set fadeStack[fadeStackIndex].fadeStackIndex = fadeStackIndex
if fadeStackSize == 0 then
call PauseTimer(fadeTimer)
endif
endmethod
//*
//* Method: fadeRefresh ()
//* Updates the stack with appropriate fade levels.
//* ----
private static method fadeRefresh takes nothing returns nothing
local integer i = fadeStackSize - 1
local thistype d
loop
exitwhen i < 0
set d = fadeStack[i]
if d != 0 then
set d.fadeTimeLeft = d.fadeTimeLeft - fadeTimeout
if d.fadeTimeLeft <= 0.00 then
set d.fadeVertexAlpha = d.fadeVertexAlphaFinal
call SetUnitVertexColor(d.me, d.fadeVertexRed, d.fadeVertexGreen, /*
*/ d.fadeVertexBlue, d.fadeVertexAlpha)
// The unit-fader is complete and can be removed from the stack.
call d.removeFader()
else
set d.fadeVertexAlpha = R2I(d.fadeVertexAlpha + d.fadeVertexAlphaStep * fadeTimeout)
call SetUnitVertexColor(d.me, d.fadeVertexRed, d.fadeVertexGreen, /*
*/ d.fadeVertexBlue, d.fadeVertexAlpha)
endif
endif
set i = i - 1
endloop
endmethod
//*
//*
//* Method: applyFader ()
//* Applies the fader to a unit, adding the unit object to the stack so it can be updated.
//* ----
method applyFader takes integer red, integer grn, integer blu, /*
*/ integer alpha1, integer alpha2, real duration returns nothing
if fadeStackSize == 0 then
// The fade-stack is empty.
call TimerStart(fadeTimer, fadeTimeout, true, function thistype.fadeRefresh)
endif
if not fadeStackIn then
set fadeStack[fadeStackSize] = this
set fadeStackIndex = fadeStackSize
set fadeStackSize = fadeStackSize + 1
endif
call SetUnitVertexColor(me, red, grn, blu, alpha1)
set fadeVertexRed = red
set fadeVertexBlue = blu
set fadeVertexGreen = grn
set fadeVertexAlpha = alpha1
set fadeVertexAlphaStep = R2I((alpha2 - alpha1) / duration)
set fadeVertexAlphaFinal = alpha2
set fadeTimeLeft = duration
endmethod
//*
//*
//*
//**********************************************************************************************************
endmodule
endlibrary
library Spell requires SpellInterface, SpellSetupModule
struct spell extends spellinterface
//******************
//* Spell
//* ¯¯¯¯¯
//* Allows a fairly convenient interface for referencing spell-related data. Once a spell has been
//* created it is given an ID. This ID can be used to reference the spell struct.
//*
//* When you are comfortable to customize your spell, simply extend the 'spell' struct and define your
//* own actions for "onSpellEffect", or one of the other interface events.
//*
//* Each spell event must have the parameters for the caster of the spell, a target of some type, and
//* the level of the spell when it was cast. The target types are:
//* - Unit Target
//* - Point Target
//* - No Target
//*
//* If "0" is given as the target then it will know there is no target. If an object of type
//* "spelltargetunit" is given then it is a unit-target (target will have .targetUnit() method) or
//* if "spelltargetarea" is given then it is a point-target.
//*
//*
//* Spell Members:
//* @ id - the raw-code or integer ID of the spell.
//* ----
public integer id
//*
//*
//* System Members:
//* @ table - the hash table used to cross-reference spells and spell IDs.
//* ----
private static hashtable table = InitHashtable()
//*
//*
//* Operators:
//* These are used to make interfacing with the spell struct a little more convenient.
//* ----
static method operator [] takes integer id returns thistype
if HaveSavedInteger(table, id, 0) then
return LoadInteger(table, id, 0)
endif
return 0
endmethod
//*
//* Method: verify ()
//* Verifies whether or not a specific integer ID is already being used by a spell. The integer-ID
//* of the spell should be able to transform to the spell struct that stores it.
//* ----
private static method verify takes integer id returns boolean
return not HaveSavedInteger(table, id, 0)
endmethod
//*
//*
//* Method: register ()
//* Registers a spell ID to the spell struct system so that the ID cannot be shared. This also
//* allows the reference of spell structs directly from the spell IDs.
//* ----
private static method register takes integer id, thistype sp returns nothing
call SaveInteger(table, id, 0, sp)
endmethod
//*
//*
//* Destructor:
//* Destroys a spell struct, unregistering its ID.
//* ----
method onDestroy takes nothing returns nothing
call RemoveSavedInteger(table, id, 0)
endmethod
//*
//* Constructor:
//* Creates a spell struct with an ID. The spell is cross-referenced with the spell ID and can
//* be obtained from the spell ID with the syntax "spell[ ID ]". Spells may not share IDs.
//* ----
static method create takes integer id returns thistype
local thistype sp = 0
if verify(id) then
set sp = allocate()
set sp.id = id
call register(id, sp)
endif
return sp
endmethod
//*
//*
//* Implemented Modules:
//* @ SpellSetupModule - provides a setup for the spell struct that registers events to several
//* triggers so that they can be extended to the user interface.
//* ----
implement SpellSetupModule
//*
//*
//**********************************************************************************************************
endstruct
endlibrary
library Group
struct extgroup
public group g
method onDestroy takes nothing returns nothing
call GroupClear(g)
endmethod
static method create takes nothing returns thistype
local thistype s = allocate()
if (s.g == null) then
set s.g = CreateGroup()
endif
return s
endmethod
endstruct
endlibrary
Okey, I'll implement that tomorrow. Not sure if I'll find fitting "godpower music" though without importing anything.
Well,the guy should post the link himself,it will be much more neat ^^If anyone needs a video of his spell, let me know.
TEEHEE
-Berz- said:Now good luck guys and girls and may the best "copy pasta" spell wins x)
what recording prog are you using?Yeah sure. I'll edit this post with the videos.
Uploading . . .
Uploaded.
what recording prog are you using?