HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

[Cjass][LinkedList]Holy Torch

01-06-2011, 07:09 AM#1
yatyfornetreg
After this spell is activated, the allies in front of you get X healing points per 2.5 sec..
This spell drains your mana continuously.

requires
TimerUtils
Expand TimerUtils:

GroupUtils
Expand GroupUtils:

The main code of this spell.

It was written by Cjass. I will re-do it later.
Bribe's post #8 below already shown the Zinc version of this code.

Expand Deprecated Cjass:

Add a textmacro in ListModule
(2011/02/02 updated)
Collapse Zinc:
//! textmacro WriteListModuleSearchInst takes t, s
static method SearchInst($t$ elem) -> thistype {
    thistype tmp = thistype.first;
    boolean found = false;
    while (tmp != 0 && !found) {
        if (tmp.$s$ == elem) {
            found = true;
        } else {
            tmp = tmp.next;
        }
    }
    if (found) {
        return tmp;
    } else {
        debug BJDebugMsg("|cffff0000Exception|r: No such $t$ in list.");
        return 0;
    }
}
//! endtextmacro
(2011/02/02 updated)
Well, I should use vJass syntax to do it.
(2011/02/02 updated)

And as the original idea, I put a unit in a group, and remove it from the group automatically.
This time I make it as a separated library.
(2011/02/02 updated)
Collapse Zinc:
//! zinc
library UnitTimedInGroup requires GroupUtils, TimerUtils {
//*=============================================================================
//* public struct UnitTimedInGroup
//*     static  create(group)   -> UnitTimedInGroup
//*             add(unit, real) -> nothing
//*             terminate()     -> nothing
//*=============================================================================

    private struct TimedRemove {
        private timer t;
        private group g;
        private unit u;
        
        private method destroy() {
            ReleaseTimer(this.t);
            this.t = null;
            this.u = null;
            this.g = null;
            this.deallocate();
        }
    
        private static method execute() {
            thistype this = GetTimerData(GetExpiredTimer());
            UnitTimedInGroup tmp = 0;
            GroupRemoveUnit(this.g, this.u);
            debug BJDebugMsg("Group removed unit");
            tmp = UnitTimedInGroup.SearchInst(this.g);
            if (tmp.destroying && FirstOfGroup(this.g) == null) {
                debug BJDebugMsg("Start to destroy UnitTimedInGroup");
                tmp.destroy();
            }
            this.destroy();
        }
        
        static method create(group g, unit u, real dur) -> thistype {
            thistype this = thistype.allocate();
            this.g = g;
            this.u = u;
            this.t = NewTimer();
            SetTimerData(this.t, this);
            TimerStart(this.t, dur, false, function thistype.execute);
            return this;
        }
    }

    public struct UnitTimedInGroup {
        module List;
        
        group g;
        boolean destroying;
        
        //! runtextmacro WriteListModuleSearchInst("group", "g")
        
        static method create(group g) -> thistype {
            thistype this = thistype.allocate();
            this.g = g;
            this.destroying = false;
            this.listAdd();
            debug BJDebugMsg("New UnitTimedInGroup");
            return this;
        }
        
        method add(unit u, real dur) {
            if (IsUnitInGroup(u, this.g) || this.destroying) {
                debug BJDebugMsg("Unit already in the group or is destroying");
            } else {
                GroupAddUnit(this.g, u);
                debug BJDebugMsg("Added unit");
                TimedRemove.create(this.g, u, dur);
            }
        }
        
        method terminate() {
            debug BJDebugMsg("Prepared to destroy UnitTimedInGroup");
            this.destroying = true;
            if (FirstOfGroup(this.g) == null) {
                debug BJDebugMsg("Start to destroy UnitTimedInGroup");
                this.destroy();
            }
        }
        
        method destroy() {
            ReleaseGroup(this.g);
            this.g = null;
            this.listRemove();
            this.deallocate();
            debug BJDebugMsg("Destroyed UnitTimedInGroup");
        }
    }

}
//! endzinc
(2011/02/02 updated)

And this is the main spell. The way I calculate the trigonometric functions may not be that nice.
(2011/02/02 updated)
Collapse Zinc:
//! zinc
library HolyTorch requires UnitTimedInGroup {
    private constant    integer ABILITY_ID      = 'A000';           // ID of the spell
    private constant    string  ORDER_ID_ON     = "immolation";     // The order id of the spell
    private constant    string  ORDER_ID_OFF    = "unimmolation";   // The close order id of the spell
    private constant    real    RADIUS          = 600.0;            // Radius of the spell
    private constant    real    ANGLE           = bj_PI / 6.0;      // This angle indicates the angle between the 2 lights
    private constant    real    GAP             = 2.5;              // How often the units are affected.

    /**
     * The struct that manages the spell.
     */
    struct Activated {        
        module List;
        private static Activated tmp;
        private timer t;
        private unit u;
        private lightning leftHand;
        private lightning rightHand;
        private integer level;
        private UnitTimedInGroup ul;
        
        //! runtextmacro WriteListModuleSearchInst("unit", "u")
        
        private static method enumUnits() -> boolean {
            unit f = GetFilterUnit();
            real angle = 0.0;
            real facing = 0.0;
            if (f == thistype.tmp.u) {
                f = null;
                return false;
            }
            if (IsUnitEnemy(f, GetOwningPlayer(thistype.tmp.u))) {
                f = null;
                return false;
            }
            if (IsUnitType(f, UNIT_TYPE_DEAD)) {
                f = null;
                return false;
            }
            if (IsUnitInGroup(f, thistype.tmp.ul.g)) {
                f = null;
                return false;
            }
            angle = bj_RADTODEG * Atan2((GetUnitY(thistype.tmp.u) - GetUnitY(f)), (GetUnitX(thistype.tmp.u) - GetUnitX(f))) + 180.0;
            //BJDebugMsg("Angle : " + R2S(angle));
            facing = GetUnitFacing(thistype.tmp.u);
            //BJDebugMsg("Facin : " + R2S(facing));
            if ((RAbsBJ(angle - facing) <= ANGLE * bj_RADTODEG) || (RAbsBJ(RAbsBJ(angle - facing) - 360) <= ANGLE * bj_RADTODEG)) {
                SetWidgetLife(f, GetWidgetLife(f) + 10 * thistype.tmp.level);
                AddTimedEffectAtUnit.create("Abilities\\Spells\\Human\\Heal\\HealTarget.mdl", f, "origin", 1.0);
                thistype.tmp.ul.add(f, GAP);
            }
            f = null;
            return false;
        }
        
        private static method moveLightningEfx() {
            thistype this = GetTimerData(GetExpiredTimer());
            this.redirectLightning();
        }
        
        private method redirectLightning() {
            real x1 = GetUnitX(this.u);
            real y1 = GetUnitY(this.u);
            real z = GetUnitFlyHeight(this.u);
            real x2 = x1 + RADIUS * Cos(bj_DEGTORAD * (GetUnitFacing(u)) + ANGLE / 2);
            real y2 = y1 + RADIUS * Sin(bj_DEGTORAD * (GetUnitFacing(u)) + ANGLE / 2);
            if (this.leftHand == null) {
                this.leftHand = AddLightningEx("HWPB", false, x1, y1, z, x2, y2, z);
            } else {
                MoveLightningEx(this.leftHand, false, x1, y1, z, x2, y2, z);
            }
            x2 = x1 + RADIUS * Cos(bj_DEGTORAD * (GetUnitFacing(u)) - ANGLE / 2);
            y2 = y1 + RADIUS * Sin(bj_DEGTORAD * (GetUnitFacing(u)) - ANGLE / 2);
            if (this.rightHand == null) {
                this.rightHand = AddLightningEx("HWPB", false, x1, y1, z, x2, y2, z);
            } else {
                MoveLightningEx(this.rightHand, false, x1, y1, z, x2, y2, z);
            }
            this.level = GetUnitAbilityLevel(this.u, ABILITY_ID);
            thistype.tmp = this;
            GroupEnumUnitsInArea(ENUM_GROUP, GetUnitX(this.u), GetUnitY(this.u), RADIUS, Filter(function thistype.enumUnits));
        }
        
        static method create(unit u) -> thistype {
            thistype this = thistype.allocate();
            this.u = u;
            this.t = NewTimer();
            this.leftHand = null;
            this.rightHand = null;
            this.ul = UnitTimedInGroup.create(NewGroup());
            this.redirectLightning();
            this.listAdd();
            SetTimerData(this.t, this);
            TimerStart(this.t, 0.04, true, function thistype.moveLightningEfx);
            return this;
        }
        
        static method kill(unit u) {
            thistype tmp = thistype.SearchInst(u);
            tmp.listRemove();
            tmp.destroy();
        }    
        
        private method destroy() {
            ReleaseTimer(this.t);
            this.u = null;
            this.t = null;
            DestroyLightning(this.leftHand);
            DestroyLightning(this.rightHand);
            this.leftHand = null;
            this.rightHand = null;
            this.ul.terminate();
            this.deallocate();
        }    
    }

    private function launch() -> boolean {
        if (GetIssuedOrderId() == OrderId(ORDER_ID_ON)) {
            Activated.create(GetTriggerUnit());
        }
        if (GetIssuedOrderId() == OrderId(ORDER_ID_OFF)) {
            Activated.kill(GetTriggerUnit());
        }
        return false;
    }

    private function onInit() {
        trigger tg = CreateTrigger();
        TriggerRegisterAnyUnitEventBJ(tg, EVENT_PLAYER_UNIT_ISSUED_ORDER);
        TriggerAddCondition(tg, Condition(function launch));
        tg = null;
    }

}
//! endzinc
(2011/02/02 updated)

Sometimes the structs seem not to be destroyed properly.

This time it works perfectly -- so far.
(2011/02/02 updated)

Expand Solved Problem:

Expand It is nothing:
Attached Files
File type: w3x[YDWE.Warft]Skill_Holy_Torch.w3x (41.4 KB)
01-08-2011, 02:08 PM#2
Bribe
Put it in Zinc tags, the redness makes it unreadable
01-09-2011, 11:09 AM#3
yatyfornetreg
Quote:
Originally Posted by Bribe
Put it in Zinc tags, the redness makes it unreadable
See.. then the entire code get red.

Since NewGen supports Cjass. why WC3C do not support Cjass wraps? It makes my life difficult
01-09-2011, 09:02 PM#4
Nestharus
Quote:
Since NewGen supports Cjass. why WC3C do not support Cjass wraps? It makes my life difficult

Because the bugs in cjass were never fixed... if you read through feedback, you'll see them all.
01-09-2011, 10:54 PM#5
yatyfornetreg
Quote:
Originally Posted by Nestharus
Because the bugs in cjass were never fixed... if you read through feedback, you'll see them all.

Could you please show me some references of them?. I mean what bugs are there in Cjass.

Since I knew Cjass syntaxes, I can hardly convert my behaviours into Vjass syntaxes.
Too many "set"s, "local"s consume time.
01-10-2011, 03:58 AM#6
Nestharus
Quote:
So here are 2 bugs if anyone cares :\
Just paste code at these links to see them.
http://www.hiveworkshop.com/forums/j...racking-142554
http://www.hiveworkshop.com/forums/s...ffbound-181307
Keep in mind CliffBound needs two thingies (linked in post)
First has to do with local variable declarations in static ifs.
Second is /* */

and flush locals is ofc bugged
01-10-2011, 04:52 AM#7
Bribe
I heard textmacros don't work in cJass, either.
01-10-2011, 06:04 AM#8
Bribe
Collapse Zinc:
library HolyTorch {
    
    constant integer ABILITY_ID = 'A000';       // ID of the spell
    constant integer ORDER_ID_ON = OrderId("immolation"); // The order id of the spell
    constant integer ORDER_ID_OFF = OrderId("unimmolation"); // The close order id of the spell
    constant real RADIUS = 600.00;              // Radius of the spell
    constant real ANGLE = 30.0;                 // This angle indicates the angle between the 2 lights
    constant real GAP = 2.5;                    // How often the units are affected.
    constant integer MAX_SIMULTANEOUSLY = 16;   // Only 16 such spell can be casted at the same time. Change it to any number under 8192(Exclusive)
    
    /**
     * Represents a node in the linked list.
     */
    struct Node {
        Node prev;
        Node next;
        unit elem;
        
        method hasNext() -> boolean {
            return (this.next != 0);
        }
        
        static method create(unit u) -> thistype {
            thistype this = thistype.allocate();
            this.elem = u;
            this.prev = 0;
            this.next = 0;
            return this;
        }
        
        method destroy() {
            this.prev = 0;
            this.next = 0;
            this.elem = null;
            this.deallocate()
        }
    }
    
    /**
     * After GAP sec. the unit will be removed from the list.
     */
    struct RemoveNodeFromList {
        Node node;
        integer list;
        
        static method execute() {
            timer t = GetExpiredTimer();
            thistype this = GetTimerData(t);
            removeListProxy(this.list, this.node.elem).evaluate();
            ReleaseTimer(t);
            this.deallocate();
            t = null;
        }
        
        static method create(Node node, integer list, real cycle) -> thistype {
            thistype this = thistype.allocate();
            timer t = NewTimer();
            this.node = node;
            this.list = list;
            SetTimerData(t, this);
            TimerStart(t, cycle, false, function thistype.execute);
            t = null;
            return this;
        }
    }
    
    /**
     * The linked list which stores the units which are affected temporarily.
     * Function List:
     *      static UnitTimedInList create(real cycle)
     *      method add(unit u)
     *      method finish()
     * E.g.
     *      UnitTimedInList ul = UnitTimedInList.create(1.0);       // Create an instance and set the time - 1.0 sec.
     *      ul.add(unit1);                                          // After 1.0 sec. this unit - unit1 will be removed from the list
     *      ul.add(unit2);                                          // After 1.0 sec. this unit - unit2 will be removed from the list
     *      ul.finish();                                            // This list is deprecated, after the last unit is removed from the list
     *                                                              // this list will be destroyed automatically.
     */
    struct UnitTimedInList {
        private Node head;
        private Node last;
        private boolean used;
        private real cycle;
        
        method isEmpty() -> boolean {
            return (this.head == 0);
        }
        
        method locate(unit u) -> integer {
            integer index = -1;
            Node iterator = head;
            boolean find = false;
            if (this.isEmpty()) {
                return -1;
            }
            while (true) {                
                if (iterator.elem == u) {
                    break;
                } else {
                    iterator = iterator.next;       
                }
                index+=1;         
                if (iterator == 0) break;
            }
            if (find) {
                return index;
            } else {
                return -1;
            }
        }
        
        method contains(unit u) -> boolean {
            return (this.locate(u) != -1);
        }
        
        method add(unit u) {
            Node newNode;
            if (this.contains(u)) {
                debug BJDebugMsg("|cffff0000Exception in UnitTimedInList|r: unit " + GetUnitName(u) + " already exists in the list.");
                return;
            }
            if (this.used) {
                debug BJDebugMsg("|cff00ff00UnitTimedInList|r: is deprecated.");
                return;
            }
            newNode = Node.create(u);
            newNode.prev = this.last;
            if (this.isEmpty()) {
                this.head = newNode;
                this.last = this.head;
            } else {
                this.last.next = newNode;
                newNode.prev = this.last;
                this.last = newNode;
            }
            RemoveNodeFromList.create(newNode, this, this.cycle);
        }
        
        method remove(unit u) {
            integer index;
            Node tmp = this.head;
            if (!(this.contains(u))) {
                debug BJDebugMsg("|cffff0000Exception in UnitTimedInList|r: unit " + GetUnitName(u) + " does not exist in the list.");
                return
            }
            index = this.locate(u);
            while (index <= 0) {
                tmp = tmp.next;
                index-=1;
            }
            if (index < 0) {                
                debug BJDebugMsg("|cffff0000Exception in UnitTimedInList|r: unit " + GetUnitName(u) + " cannot be removed from the list.");
                return
            }
            if (tmp.prev == 0 && tmp.next == 0) {
                this.head = 0;
                this.last = 0;
            } else {
                if (tmp.prev != 0) {
                    tmp.prev.next = tmp.next;
                } else {
                    this.head = tmp.next;
                    this.head.prev = 0;
                }
                if (tmp.next != 0) {
                    tmp.next.prev = tmp.prev;
                } else {
                    this.last = tmp.prev;
                    this.last.next = 0;
                }
            }
            tmp.destroy();
            if (this.used && this.isEmpty()) {
                this.destroy();
                debug BJDebugMsg("|cff00ff00UnitTimedInList|r: Ready to be destroyed.")
            }
        }
        
        method finish() {
            if (used)
                debug BJDebugMsg("|cffff0000Exception in UnitTimedInList|r: List is already ready to be destroyed.");
            else 
                used = true;
        }
        
        static method create(real cycle) -> thistype {
            thistype this = thistype.allocate();
            this.head = 0;
            this.last = 0;
            this.used = false;
            this.cycle = cycle;
            return this;
        }
    }

    /**
     * The struct which manages the spell.
     */
    struct Activated {
        static Activated instances[];
        static integer index = 0;
        
        static Activated tmp;
        timer t;
        unit u;
        lightning leftHand;
        lightning rightHand;
        integer level;
        UnitTimedInList ul;
        
        method destroy() {
            ReleaseTimer(this.t);
            this.u = null;
            DestroyLightning(this.leftHand);
            DestroyLightning(this.rightHand);
            this.ul.finish();
            this.deallocate()
        }
        
        /**
         * Manages the instances of this struct.
         */
        static method add(thistype act) {
            integer count = 0;
            while (true) {
                thistype.index+=1;
                if (thistype.index >= MAX_SIMULTANEOUSLY)
                    thistype.index = 0;
                if ((thistype.instances[thistype.index] == 0) || (count >= MAX_SIMULTANEOUSLY))
                    break;
                count+=1;
            }
            if (count >= MAX_SIMULTANEOUSLY) {
                debug BJDebugMsg("|cffff0000Exception - HolyTorch|r : exhausted. destroy!");
                act.destroy();
            } else {
                thistype.instances[thistype.index] = act;
                debug BJDebugMsg("|cff00ff00HolyTorch|r : successfully added, index number - " + I2S(thistype.index));
            }
        }
        
        static method kill(unit u) {
            integer i = 0;
            boolean find = false;
            thistype tmp = 0;
            while (true) {
                i+=1;
                tmp = thistype.instances[i];
                if (tmp.u == u)
                    find = true;
                if (find || (i >= MAX_SIMULTANEOUSLY))
                    break;
            }
            if (i > MAX_SIMULTANEOUSLY) {
                debug BJDebugMsg("|cffff0000Exception - HolyTorch|r : no such unit is holding an instance.");
            } else if (find) {
                debug BJDebugMsg("|cff00ff00HolyTorch|r : destroying " + GetUnitName(tmp.u) + "'s instance - " + I2S(i - 1));
                thistype.instances[i - 1] = 0;
                tmp.destroy();
            } debug else {
                BJDebugMsg("|cffff0000Exception - HolyTorch|r : fatal error!");
            }
        }        
        
        static method enumUnits() -> boolean {
            unit f = GetFilterUnit();
            real angle
            real facing
            if (f == thistype.tmp.u) {
                f = null;
                return false;
            }
            if (IsUnitEnemy(f, GetOwningPlayer(thistype.tmp.u))) {
                f = null;
                return false;
            }
            if (IsUnitType(f, UNIT_TYPE_DEAD)) {
                f = null;
                return false;
            }
            if (thistype.tmp.ul.contains(f)) {
                f = null;
                return false;
            }
            angle = bj_RADTODEG * Atan2((GetUnitY(thistype.tmp.u) - GetUnitY(f)), (GetUnitX(thistype.tmp.u) - GetUnitX(f))) + 180.0;
            //BJDebugMsg("Angle : " + R2S(angle));
            facing = GetUnitFacing(thistype.tmp.u);
            //BJDebugMsg("Facin : " + R2S(facing));
            if ((RAbsBJ(angle - facing) <= ANGLE) || (RAbsBJ(RAbsBJ(angle - facing) - 360) <= ANGLE)) {
                SetWidgetLife(f, GetWidgetLife(f) + 10 * thistype.tmp.level);
                AddTimedEffectAtUnit.create("Abilities\\Spells\\Human\\Heal\\HealTarget.mdl", f, "origin", 1.0);
                thistype.tmp.ul.add(f);
            }
            f = null;
            return false;
        }
        
        method redirectLightning() {
            real x1 = GetUnitX(u);
            real y1 = GetUnitY(u);
            real z = GetUnitFlyHeight(u);
            real x2 = x1 + RADIUS * Cos(bj_DEGTORAD * (GetUnitFacing(u) + ANGLE / 2));
            real y2 = y1 + RADIUS * Sin(bj_DEGTORAD * (GetUnitFacing(u) + ANGLE / 2));
            if (leftHand == null) {
                leftHand = AddLightningEx("HWPB", false, x1, y1, z, x2, y2, z);
            } else {
                MoveLightningEx(leftHand, false, x1, y1, z, x2, y2, z);
            }
            x2 = x1 + RADIUS * Cos(bj_DEGTORAD * (GetUnitFacing(u) - ANGLE / 2));
            y2 = y1 + RADIUS * Sin(bj_DEGTORAD * (GetUnitFacing(u) - ANGLE / 2));
            if (rightHand == null) {
                rightHand = AddLightningEx("HWPB", false, x1, y1, z, x2, y2, z);
            } else {
                MoveLightningEx(rightHand, false, x1, y1, z, x2, y2, z);
            }
            this.level = GetUnitAbilityLevel(u, ABILITY_ID);
            thistype.tmp = this;            
            GroupEnumUnitsInArea(ENUM_GROUP, GetUnitX(u), GetUnitY(u), RADIUS, Filter(function thistype.enumUnits));
        }
        
        static method moveLightningEfx() {
            thistype(GetTimerData(GetExpiredTimer())).redirectLightning();
        }
        
        static method create(unit u) -> thistype {
            thistype this = thistype.allocate();
            this.u = u;
            this.t = NewTimer();
            this.leftHand = null;
            this.rightHand = null;
            this.redirectLightning();
            this.ul = UnitTimedInList.create(GAP);
            SetTimerData(this.t, this);
            TimerStart(this.t, 0.04, true, function thistype.moveLightningEfx);
            thistype.add(this);
            return this;
        }
    }
    
    function removeListProxy(UnitTimedInList list, unit elem) {
        list.remove(elem);
    }
    
    function launch() -> boolean {
        if (GetIssuedOrderId() == ORDER_ID_ON) {
            Activated.create(GetTriggerUnit());
        }
        else if (GetIssuedOrderId() == ORDER_ID_OFF) {
            Activated.kill(GetTriggerUnit());
        }
        return false;
    }

    function onInit() {
        trigger tg = CreateTrigger();
        TriggerRegisterAnyUnitEventBJ(tg, EVENT_PLAYER_UNIT_ISSUED_ORDER);
        TriggerAddCondition(tg, Condition(function launch));
        tg = null;
    }

}

Please check for syntax errors as this is converted to Zinc from my memory of Zinc and working around the existing bugs ("features") of Zinc. Please do not ever ask for help with cJass scripts as that is not a supported language as it is totally broken.

onDestroy - never use! Use the plain destroy method and from it call deallocate.

keywords, I don't remember if they work in Zinc so I made a proxy function to avoid typecasting errors.

In regards to the thing not being destroyed properly, I recommend you put bj debug messages in all of your destroy functions and also right before you destroy, which say "expected to destroy type of X" before destroying and, from the destroy method, "destroyed type of X".

If the type X do not match, you are destroying the wrong type of struct.
01-10-2011, 08:56 AM#9
yatyfornetreg
To: Nestharus #6
Thank you for the two links, although I do not really comprehend your posts. But I made a note, some day they will be useful :)

And I never use "flush locals", because I did not trust them initially somehow.

To: Bribe #8
I greatly appreciate this.

And thank you for the suggestions on "Destroy"s.

And by the way.
Quote:
I heard textmacros don't work in cJass, either.
Sometimes it does not work MAYBE because of "//! endtextmacro" is the last line instead "A white line" is the last line.
I'm not sure but textmacros work well in Cjass in some of my previous works. And when "//! endtextmacro" became the last line of a trigger. sometimes it does not work properly
01-10-2011, 12:34 PM#10
Anitarf
Quote:
Sometimes the structs seem not to be destroyed properly.
Which structs?

The spell is kinda long. It would be a lot easier to debug if it used an outside linked list library like LinkedList or Stack. Actually, since you're storing units, you could just use a unit group, there's no need for using a linked list in the first place. If the bug remains after these changes, it should be a lot easier to find.
01-10-2011, 12:48 PM#11
Nestharus
@yatyfonrnetreg

Collapse JASS:
library PlayerManager uses /*
    */Event //hiveworkshop.com/forums/submissions-414/snippet-event-186555/
endlibrary

The /*\n*/ bugs in cjass ;P.

Collapse JASS:
static if true then
    local real r
endif

That will get declared twice because cjass doesn't see it at the top of the script.
Collapse JASS:
local real r
static if true then
    local real r
endif
01-11-2011, 06:22 AM#12
yatyfornetreg
To: Anitarf #10
Hmm.. yes, it was me who is complexifying the problem. Thank you for the suggestion and the two libraries.
Quote:
Which structs?
When more than 1 units cast the spell simultaneously, and cancle, and cast... in a high frequency. There is a small chance that causes the "Activated" can not be destroyed correctly, but never mind. I will re-do this spell after the exams.

To: Nestharus #11
Yes, I can see it now. And I will avoid them. Thank you.

To: Bribe #8
I get used with Zinc syntax now, it is more strict than Cjass, which is good. For example, the semi-colon is necessary in Zinc but not in Cjass. And the for loop and while loop is awesome. I like them. Thank you for telling that.