| 01-29-2010, 10:45 PM | #1 |
JASS:scope GinreiKojaku initializer in_Ginrei_Kojaku private struct Ginrei unit caster integer arrows // (Agility / TIMES) integer times real damage real x real y endstruct globals private constant integer GINREI = 'A042' private constant string EFFECT = "Abilities\\Weapons\\ColdArrow\\ColdArrowMissile.mdl" private constant string MESSAGE = "Ginrei Kojaku!" private constant integer TIMES = 10 // TIMES * TIMER = Ultimate's Duration private constant real TIMER = 0.5 // How often happens each sequence private constant real ANGLE = 0.35 // 20 DEG, How much variation between arrow's angle //private constant real MAXDIST = 400 // Max distance for teleport //private Ginrei array ginrei[12] endglobals private struct arrowMissile extends xecollider unit caster real damage method onUnitHit takes unit target returns nothing if TargetCheck(this.caster, target) then if SpellHit(this.caster, target, GINREI) then call UnitDamageTargetEx(this.caster, target, this.damage, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_SPELL, false, true) endif call this.terminate() endif endmethod endstruct function Ginrei_Kojaku_Conditions takes nothing returns boolean return (GetSpellAbilityId() == GINREI) endfunction //function Ginrei_Teleport_Location takes unit temp, real tx, real ty returns nothing // local integer p = GetPlayerId(GetOwningPlayer(temp)) // if not(ginrei[p] == null) then // set ginrei[p].x = tx // set ginrei[p].y = ty // endif //endfunction //function Ginrei_Check_Ultimate takes unit temp returns boolean // if (ginrei[GetPlayerId(GetOwningPlayer(temp))] == null) then // return false // endif // return true //endfunction function Ginrei_Kojaku_Fire takes nothing returns nothing local Ginrei g = GetTimerData(GetExpiredTimer()) local arrowMissile xc local group tempgroup = CreateGroup() local unit tempunit local unit minunit local integer count = 0 local real tangle local real tx local real ty local real dx local real dy local real dist local real mindist = 99999 //just a random high value set g.times = g.times + 1 set g.x = GetUnitX(g.caster) set g.y = GetUnitY(g.caster) call BJDebugMsg("g.times = " + I2S(g.times)) //Here we get the nearest enemy! DIE! call GroupEnumUnitsInRange(tempgroup, g.x, g.y, 1200, null) loop set tempunit = FirstOfGroup(tempgroup) exitwhen (tempunit == null) if TargetCheck(g.caster, tempunit) and IsUnitVisible(tempunit, GetOwningPlayer(g.caster)) then set dx = GetUnitX(tempunit) - g.x set dy = GetUnitY(tempunit) - g.y set dist = SquareRoot(dx * dx + dy * dy) if (dist < mindist) then set minunit = tempunit set mindist = dist endif endif call GroupRemoveUnit(tempgroup, tempunit) endloop call BJDebugMsg("Min Ok") call BJDebugMsg("minunit = " + GetUnitName(minunit)) //Now we must shoot at it, we wanna kill it after all if (minunit != null) then set dx = GetUnitX(minunit) set dy = GetUnitY(minunit) set tangle = Atan2(dy - g.y, dx - g.x) //Get our arrow's angle loop exitwhen (count == g.arrows) set xc = arrowMissile.create(g.x, g.y, (tangle + GetRandomReal(-ANGLE, ANGLE))) //Some noise to the angle set xc.fxpath = EFFECT set xc.damage = g.damage set xc.speed = 1500.0 set xc.expirationTime = 1.13 set xc.z = 100.0 set xc.caster = g.caster set xc.collisionSize = 80 set count = count + 1 call BJDebugMsg("count = " + I2S(count)) endloop endif call BJDebugMsg("Shoot ok") //Oh, already ended? if (g.times == TIMES) then call BJDebugMsg("TEH ENDZ") set g.caster = null call ReleaseTimer(GetExpiredTimer()) call g.destroy() endif call BJDebugMsg("End ok") call DestroyGroup(tempgroup) set tempgroup = null set tempunit = null set minunit = null endfunction function Ginrei_Kojaku_Start takes nothing returns nothing local Ginrei g = Ginrei.create() local timer t local integer arrows local integer level local real damage set g.times = 0 set g.caster = GetTriggerUnit() set arrows = R2I(GetHeroAgi(g.caster, true) / TIMES) set level = GetUnitAbilityLevel(g.caster, GINREI) if (arrows < R2I((50 * level)/TIMES)) then set g.arrows = R2I((50 * level)/TIMES) else set g.arrows = arrows endif set damage = (0.25 * GetHeroInt(g.caster, true)) if (damage < (5 * level)) then set g.damage = (5 * level) else set g.damage = damage endif set g.x = GetUnitX(g.caster) set g.y = GetUnitY(g.caster) call DisplayText(g.caster, MESSAGE, 2) set t = NewTimer() call SetTimerData(t,g) call TimerStart(t, TIMER, true, function Ginrei_Kojaku_Fire) call BJDebugMsg("g.arrows = " + I2S(g.arrows)) call BJDebugMsg("g.damage = " + R2S(g.damage)) endfunction //=========================================================================== function in_Ginrei_Kojaku takes nothing returns nothing local trigger = t_Ginrei_Kojaku = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(t_Ginrei_Kojaku, EVENT_PLAYER_UNIT_SPELL_EFFECT) call TriggerAddCondition(t_Ginrei_Kojaku, Condition(function Ginrei_Kojaku_Conditions)) call TriggerAddAction(t_Ginrei_Kojaku, function Ginrei_Kojaku_Start) set t_Ginrei_Kojaku = null endfunction endscope This spells is supposed to get the nearest enemy in 1200 range, and shoots arrows at it every 0,5s. But it never ends! Display: When there is no enemy near: g.times = X Min Ok (repeat) When there is a enemy near: g.times = X Min Ok Shoot Ok End Ok (repeat) And it just keep going, never stops. Thanks in advance for any help! |
| 01-29-2010, 11:38 PM | #2 |
This is what happens when no enemies are nearby (without BJDebugCalls): JASS:// minunit initialized without a value local unit minunit // .... // Group loop, blahblah // Doesn't set a value to minunit if nobody's nearby // .... // JASS now tries to read minunit and compare it to null // JASS cannot read minunit, it doesn't have a value // JASS stops this code right here. if (minunit != null) then Initializing minunit to null should solve this. JASS:local unit minunit = null |
| 01-29-2010, 11:47 PM | #3 |
I thought jass initialized variables, like Java. Like integers = 0. I'm trying it, will edit if it works! Thanks! |
| 01-30-2010, 12:14 AM | #4 |
Just to clarify, arrays will initialize automotically to their null values (0, "", null, false) but single variables will not. You need to explicitly set them. At one time, they caused threads to crash and wc3 to close when accessed, although I'm not sure on the current effects (as JNGP can prevent crashes). |
| 01-30-2010, 01:36 AM | #5 |
Yes. I had a loop once where I forgot to set i = 0 and I had something like... exitwhen i > 3 and my 'logic' thought it was already set to 0. Suffice to say, the loop never ran because i was some crazy value. |
| 01-30-2010, 02:56 AM | #6 |
Thanks! Its working now! But how can I force my unit to play the attack animation every time he shoot the arrows? SetUnitAnimation is not doing anything. Tried SetUnitAnimationByIndex but its still being overlaped by simply moving commands. Also, how can I instantly change a unit facing? SetUnitFacing is making the unit turns instead of setting the angle. |
| 01-30-2010, 02:40 PM | #7 | |
Quote:
|
| 01-30-2010, 07:31 PM | #8 |
Use of uninitialized variables does cause a thread crash, but not a game crash. JNGP can not prevent these since TFT 1.22 because that is when war3err stopped working. Unless you somehow lock the unit by either pausing it or making the spell a channeling spell, it will always interrupt the animations you are trying to play with its own actions. There is no way to instantly change the facing of a unit. |
