• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Spell bug

Status
Not open for further replies.
Level 4
Joined
Jul 4, 2009
Messages
48
Hey. I have a problem. Yesterday, i made a simple spell, a meteor one: you cast it and it damages enemies in 200 AoE after 2.2 seconds. I made it with timers and so, it was perfectly all right, everything worked.
When today i tried tested the map again, it got bugged after like 4 uses, now it's always bugged and i didn't change anything: when the meteor hits the ground, it should create floating texts, to write the damage done to the screen, it does this, but it doesn't damage the picked units, only the first one.

  • Meteor
    • Events
      • Unit - A unit starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Meteor
    • Actions
      • Countdown Timer - Start MeteorTimer[Custom Value of (Casting unit)] as a One-shot timer that will expire in 2.20 seconds
      • Set MeteorLoc[Custom Value of (Casting unit)] = (Target point of ability being cast)
      • Special Effect - Create a special effect at MeteorLoc[Custom Value of (Casting Unit) using war3imported/ChaosMeteorV3.mdx
      • Set Blood[BloodCounter] = (Last created special effect)
      • Countdown Timer - Start Bloodtimer[Bloodcounter] as a One-shot timer that will expire in 5.00 seconds
      • Trigger - Add to BloodFXDestroy <gen> the event (Time - Bloodtimer[Bloodcounter] expires)
      • Set Bloodcounter = (Bloodcounter + 1)
  • MeteorDamage
    • Events
      • Time - MeteorTimer[1] expires
      • Time - MeteorTimer[2] expires
      • Time - MeteorTimer[3] expires
      • Time - MeteorTimer[4] expires
      • Time - MeteorTimer[5] expires
      • Time - MeteorTimer[6] expires
    • Conditions
    • Actions
      • For each (Integer A) from 1 to 6, do (Actions)
        • Custom script: if GetExpiredTimer() == udg_MeteorTimer[GetForLoopIndexA()] then
        • Set MeteorArea[(Integer A)] = (Units within 200.00 of MeteorLoc[(Integer A) matching ((((Owner of Matching unit is an enemy of (Owner of (Hero[(Integer A)])) Equal to True) and ((((Matching unit) is alive) Equal to True) and (Unit-type of (Matching uit) is Not Equal to Fireball)
        • Unit Group - Pick every unit in MeteorArea[(Integer A)] and do (Actions)
          • Loop - Actions
            • Set MeteorDamage[(Integer A)] = ((((Random real number between 38.00 and 42.00) + Spellpower[(Integer A)]) x (1 + ((Real(Hero Level of Hero[(Integer A)])/12.00)) x (1 - ElementalRes[(Custom Value of (Picked unit))]))
            • Floating Text - Create floating text that reads (String((Integer(MeteorDamage[(Integer A)])))) above (Picked unit) with Z offset 5.00, using font size 10, color (100.00%, 80.00%, 0.00%), and 0.00% transparency
            • Set Degrees = (Random real number between 80.00 and 100.00)
            • Floating Text - Set the velocity of (Last created floating text) to 64.00 towards Degrees degrees
            • Floating Text - Change (Last created floating text): Disable permanence
            • Floating Text - Change lifespan of (Last created floating text) to 3.00 seconds
            • Floating Text - Change the fading age of (Last created floating text) to 2.00 seconds
            • Floating Text - Hide (Last created floating text) for (All players)
            • Floating Text - Show (Last created floating text) for (Player group((Owner of Hero[(Integer A)])))
            • Unit - Cause Hero[(Integer A)] to damage (Picked unit), dealing MeteorDamage[(Integer A)] damage of attack type Spells and damage type Normal
        • Custom script: call RemoveLocation (udg_MeteorLoc[GetForLoopIndexA()])
        • Custom script: call DestroyGroup( udg_MeteorArea[GetForLoopIndexA()])
        • Custom script: endif
Any help would be appriciated!
-psipenge
 
Last edited:
Level 4
Joined
Jul 4, 2009
Messages
48
Forgot to say it in my first post, i set the custom value of my hero to player number, and for the enemies, i have an integer variable to use as the custom value. I set the enemies' custom value from 7 to the max number of enemies in the map.
 
Level 37
Joined
Mar 6, 2006
Messages
9,240
You leak a player group with the Floating Text - Show.
Don't use an array for the unit group.
GetForLoopIndexA() -> bj_forLoopAIndex

You must have the timers initialized, they are not initialized automatically. Set the initial size of the timer array to max number of players + 1.

By using a hashtable, you could get rid of looping through the timers and load data attached to the timer directly.
 
Level 4
Joined
Jul 4, 2009
Messages
48
Thanks for the suggestions. I'll try it out tomorrow with hashtables, I'm just too tired to recreate the triggers right now :)
Just a few questions Maker: one, if i use the hashtables, i still have to check which timer expires, so i have to loop through them, if you meant this, to discover which one expires.
Two, what's the difference between GetForLoopInexA() and bj_forLoopAIndex?
And the last one, why isn't it a good idea to use unit group arrays? It can make something bugged or simply not needed?
Thanks for your replies!
 
Level 37
Joined
Mar 6, 2006
Messages
9,240
By using a hashtable, you can save the handle of the location, hero and effect for the timer. Then you can load those using the expired timer's handle, no need to loop through all the timers.

Like this:
set integer_variable = GetHandleId(GetExpiredTimer())
set loc = LoadLocationHandle(hashtable, integer_variable, child_key)

GetForLoopInexA() returns the value of bj_forLoopAIndex. By using that bj directly, you are skipping the function call.

Arrays are slower, and you don't need the variable to be an array.
 
Status
Not open for further replies.
Top