1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. The 18th Icon Contest is ON! Choose any ingame unit and give him/her Hero abilities. Good luck to all.
    Dismiss Notice
  5. The Secrets of Warcraft 3 have revealed interesting works. The RESULTS for Abelhawk's Mini-Mapping Contest #15 have come out!
    Dismiss Notice
  6. Contestants are to create a scene set in the Stone Age. Come and see what you can come up with. We wish you the best of luck!
    Dismiss Notice
  7. Colour outside the lines! Techtree Contest #13 is a go. The contest is optionally paired.
    Dismiss Notice
  8. Night Rider gained several songs for his journey. The poll for the 12th Music Contest has started. Check it out!
    Dismiss Notice
  9. Greetings cerebrates, our Swarm needs new spawners that will have numerous children. Join the HIVE's 31st Modeling Contest - Spawners and Spawned! The contest is optionally paired.
    Dismiss Notice
  10. Join other hivers in a friendly concept-art contest. The contestants have to create a genie coming out of its container. We wish you the best of luck!
    Dismiss Notice
  11. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Resource System v1.3

Submitted by D1000
This bundle is marked as approved. It works and satisfies the submission rules.
A system I made a year ago, the last thing before I went more or less inactive in Wc3.
Originally made for a contest on inwarcraft.de, achieving one of the two first places.

Features:
  • Creation and handling of custom resources
  • Events for resource-related actions (e.g.: Buying an Item, casting a Spell, mining a resource)
  • Function to check if a building is finished

Requires:
  • JassHelper by Vexorian
  • TimerUtils by Vexorian
  • SimError by Vexorian
  • GroupUtils by Rising_Dusk
  • GetUnitCollisionSize by me. Code is included in the map, since I made this system for the Resource-System

Resource System
Code (vJASS):
//Resource System
//Made by Verethragna (aka D1000)
//v1.3
//For more informations read the readme

//! zinc
    library ResourceSystem requires GroupUtils, TimerUtils, GetUnitCollisionSize, SimError {
        private constant integer MAX_RESOURCES = 30; //Maximal number of resources, can't exceed 511
   
        private constant integer MINE_ABILITY = 'MINE'; // The id of the "Mine"-ability
        private constant string MINE_ORDER = "channel"; // The order of the "Mine"-Ability
        private constant integer RETURN_ABILITY = 'RETU'; // The id of the "Return"-ability
        private constant string RETURN_ORDER = "absorb"; // The order of the "Return"-Ability
       
        private constant boolean USE_EVENTS = false; //Set this to true, if you want to use events in your map. Setting it to false will make the system a bit faster.
       
        private constant real STORAGE_RANGE = 150, //How close the worker has to be to the storage to return the resources
                              STORAGE_SEARCH_RANGE = 6144, //Search range to return the resources
                              SOURCE_SEARCH_RANGE = 3072, //Search range to find new sources
                                           
                              MAX_BUILD_RANGE = 100; //I don´t know if it is posible to change it, but if you do, change this value too.
       
        private constant string NOT_ENOUGH_TEXT = "Not enough ", //Text displayed when trying to buy something with insufficient resources
       
                              MULTIBOARD_NAME = "Resources"; //Title of the multiboard
        private constant real MULTIBOARD_NAME_WIDTH = 0.05, // Width of the multiboard column for the name of the resources
                              MULTIBOARD_VALUE_WIDTH = 0.015, // Width of the multiboard column for the amount of the resources
               
                              BUILDING_REFUND_FACTOR = 0.75, //Percentage of the spent resources, that you'll get back when you cancel a building
                              ITEM_SELL_FACTOR = 0.75; //Percentage of the spent resources, that you'll get back when you sell an item
        //===================================================================\\
       
        public constant integer FARM_TYPE_INSTANT = 0,
                                FARM_TYPE_WALK = 1,
                                               
                                BUY_TYPE_SOLD = 1,
                                BUY_TYPE_BUILDING = 2,
                                BUY_TYPE_TRAINED = 3,
                                BUY_TYPE_ABILITY = 4;
                                                 
        public type ResourceEventCast extends function();
        public type ResourceEventItemSale extends function();
        public type ResourceEventUnitSale extends function();
        public type ResourceEventTrain extends function();
        public type ResourceEventBuildOrder extends function();
       
        public type ResourceEventMine extends function(Resource, unit, widget);
        public type ResourceEventReturn extends function(Resource, unit, integer, unit);
                                                 
        private trigger trigOnDeath;
           
        public struct Resource{            
            private static thistype number, tempResource;
            private static boolexpr addWorkerPick, addStoragePick, searchSourcePickUnit, searchSourcePickItem, searchSourcePickDestructable, searchStoragePick, allBuildings;
            private static rect wholeMap;
            private static integer tempType;
            private static real tempDistance, tempX, tempY;
            private static trigger inRange, trainCancelled, constructionCancelled, orderGiven;
            private static multiboard properties[12];
            private static widget tempWidget;
            private static unit tempUnit;
           
            private string name,
                           icon,
                           colour = "";
            private integer amount[0x10];
            private boolean onKill;
            private sound hitSound;
           
            private static constant integer AMOUNT_CARRIED = 0,
                                            GAIN_PER_HIT = 0x10,
                                            DAMAGE = 0x20,
                                            FARM_TYPE = 0x30,
                                            SPEED = 0x40,
                                            ANIMATION = -1,
                                            COSTS = -2,
                                            BUY_TYPE = -3,
                                            CURRENTLY_BUILDING = -4,
                                            FINISHED = -5,
                                           
                                            EVENT_CAST = -6,
                                            EVENT_ITEM = -7,
                                            EVENT_UNIT = -8,
                                            EVENT_TRAIN = -9,
                                            EVENT_BUILD = -10,
                                            EVENT_MINE = -11,
                                            EVENT_RETURN = -12,
                                           
                                            SOURCE = 0,
                                            MINER = 2,
                                            MINER_STRUCT = 3,
                                            STORAGE = 4,
                                                               
                                            ORDER_SMART = 851971;
                                            //ORDER_RALLIED = 851970; -> GetOrderTarget does not work in some cases
                                                               
            private static hashtable data = InitHashtable();
           
            static method create(string name, string icon, boolean onKill) -> thistype {
                integer i;
               
                number = thistype.allocate();
                static if (DEBUG_MODE)
                    if(integer(number) > MAX_RESOURCES)
                        BJDebugMsg("|cffFF0000ResourceSystem ERROR:|r Number of resources exceeded 'MAX_RESOURCES'");
                number.name = name;
                number.icon = icon;
                number.onKill = onKill;
               
                return number;
            }
           
            method getName() -> string {
                return name;
            }
           
            method getIcon() -> string {
                return icon;
            }
           
            method addSource(integer sourceId) {
                SaveInteger(data, SOURCE, sourceId, this);
            }
           
            static method getResourceBySource(integer sourceId) -> thistype {
                return LoadInteger(data, SOURCE, sourceId);
            }
           
            method addStorage(integer id) {
                group g;
                SaveBoolean(data, STORAGE*MAX_RESOURCES+this, id, true);
               
                if (LoadBoolean(data, STORAGE, id))
                    return;
                   
                SaveBoolean(data, STORAGE, id, true);
                tempType = id;
                GroupEnumUnitsInRect(ENUM_GROUP, wholeMap, addStoragePick);
                GroupClear(ENUM_GROUP);
            }
           
            method isStorage(integer id) -> boolean {
                return LoadBoolean(data, STORAGE*MAX_RESOURCES+this, id);
            }
           
            method addMiner(integer unitTypeId, string anim ,real speed, real damagePerHit, integer gain, integer amountCarried, integer farmType) {
                group g;
                integer i;
                for(0 <= i < bj_MAX_PLAYERS) {
                    SaveInteger(data, (i + AMOUNT_CARRIED)*MAX_RESOURCES+this, unitTypeId, amountCarried);
                    SaveInteger(data, (i + GAIN_PER_HIT)*MAX_RESOURCES+this, unitTypeId, gain);
                    SaveReal(data, (i + DAMAGE)*MAX_RESOURCES+this, unitTypeId, damagePerHit);
                    SaveInteger(data, (i + FARM_TYPE)*MAX_RESOURCES+this, unitTypeId, farmType);
                    SaveReal(data, (i + SPEED)*MAX_RESOURCES+this, unitTypeId, speed);
                    SaveStr(data, ANIMATION*MAX_RESOURCES+this, unitTypeId, anim);
                }
               
                if (LoadBoolean(data, MINER, unitTypeId))
                    return;
                   
                SaveBoolean(data, MINER, unitTypeId, true);
                tempType = unitTypeId;
                GroupEnumUnitsInRect(ENUM_GROUP, wholeMap, addWorkerPick);
                GroupClear(ENUM_GROUP);
            }
           
            method addProperty(integer whichPlayer, integer amount) {
                this.amount[whichPlayer] += amount;
                updateMultiboard(whichPlayer);
            }
           
            method setProperty(integer whichPlayer, integer amount) {
                this.amount[whichPlayer] = amount;
                updateMultiboard(whichPlayer);
            }
           
            method getProperty(integer whichPlayer) -> integer{
                return this.amount[whichPlayer];
            }
           
            static method showMultiboard(integer whichPlayer, boolean flag) {
                if (GetLocalPlayer() == Player(whichPlayer))
                    MultiboardDisplay(properties[whichPlayer], flag);
            }
           
            static method minimizeMultiboard(integer whichPlayer, boolean flag) {
                MultiboardMinimize(properties[whichPlayer], flag);
            }
           
            //A textmacro creating the set & get functions for integer values (AmountCarried, GainPerHit & FarmType)
            //! textmacro setDataInteger takes NAME, VAR
                method set$NAME$(player p, integer value, integer unitTypeId) {
                    SaveInteger(data, (GetPlayerId(p) + $VAR$)*MAX_RESOURCES+this, unitTypeId, value);
                }
           
                method set$NAME$ById(integer p, integer value, integer unitTypeId) {
                    SaveInteger(data, (p + $VAR$)*MAX_RESOURCES+this, unitTypeId, value);
                }
               
                method get$NAME$(player p, integer unitTypeId) -> integer {
                    return LoadInteger(data, (GetPlayerId(p) + $VAR$)*MAX_RESOURCES+this, unitTypeId);
                }
           
                method get$NAME$ById(integer p, integer unitTypeId) -> integer {
                    return LoadInteger(data, (p + $VAR$)*MAX_RESOURCES+this, unitTypeId);
                }
            //! endtextmacro
           
            //A textmacro creating the set & get functions for real values (Damage & Speed)
            //! textmacro setDataReal takes NAME, VAR
                method set$NAME$(player p, real value, integer unitTypeId) {
                    SaveReal(data, (GetPlayerId(p) + $VAR$)*MAX_RESOURCES+this, unitTypeId, value);
                }
           
                method set$NAME$ById(integer p, real value, integer unitTypeId) {
                    SaveReal(data, (p + $VAR$)*MAX_RESOURCES+this, unitTypeId, value);
                }
               
                method get$NAME$(player p, integer unitTypeId) -> real {
                    return LoadReal(data, (GetPlayerId(p) + $VAR$)*MAX_RESOURCES+this, unitTypeId);
                }
           
                method get$NAME$ById(integer p, integer unitTypeId) -> real {
                    return LoadReal(data, (p + $VAR$)*MAX_RESOURCES+this, unitTypeId);
                }
            //! endtextmacro
           
            //! runtextmacro setDataInteger("AmountCarried", "AMOUNT_CARRIED")
            //! runtextmacro setDataInteger("GainPerHit", "GAIN_PER_HIT")
            //! runtextmacro setDataReal("Damage", "DAMAGE")
            //! runtextmacro setDataReal("Speed", "SPEED")
            //! runtextmacro setDataInteger("FarmType", "FARM_TYPE")
           
            method setCosts(integer typeId, integer costs, integer buyType) {
                SaveInteger(data, COSTS*MAX_RESOURCES+this, typeId, costs);
                SaveInteger(data, BUY_TYPE, typeId, buyType);
            }
           
            method getCosts(integer typeId) -> integer {
                return LoadInteger(data,COSTS*MAX_RESOURCES+this,typeId);
            }
           
            method setAnimation(integer unitTypeId, string anim) {
                SaveStr(data, ANIMATION*MAX_RESOURCES+this, unitTypeId, anim);
            }
           
            method getAnimation(integer unitTypeId) -> string {
                return LoadStr(data, ANIMATION*MAX_RESOURCES+this, unitTypeId);
            }
           
            method setColour(string colour) {
                this.colour= "|cff" + colour;
            }
           
            method getColour() -> string {
                return colour;
            }
           
            static method isBuildingFinished(unit building) -> boolean {
                return LoadBoolean(data, FINISHED, GetHandleId(building));
            }
           
            method floatingValue(integer value, real x, real y) {
                texttag t = CreateTextTag();
                SetTextTagPos(t, x, y, 20);
                SetTextTagPermanent(t, false);
                SetTextTagText(t, colour + "+" + I2S(value)+ "|r", 0.023);
                SetTextTagVelocity(t, 0, 0.035);
                SetTextTagLifespan(t, 1.5);
                SetTextTagFadepoint(t, 0.8);
                t = null;
            }
           
            //A textmacro creating the functions to set static events
            //! textmacro setEvent takes NAME, VAR
                static method set$NAME$Event(integer id, ResourceEvent$NAME$ callback){
                    SaveInteger(data, EVENT_$VAR$, id, callback);
                }
            //! endtextmacro
           
            //! runtextmacro setEvent("Cast", "CAST")
            //! runtextmacro setEvent("ItemSale", "ITEM")
            //! runtextmacro setEvent("UnitSale", "UNIT")
            //! runtextmacro setEvent("Train", "TRAIN")
            //! runtextmacro setEvent("BuildOrder", "BUILD")
           
            //A textmacro creating the functions to set non-static events
            //! textmacro setEvent2 takes NAME, VAR
                method set$NAME$Event(ResourceEvent$NAME$ callback){
                    SaveInteger(data, EVENT_$VAR$, this, callback);
                }
            //! endtextmacro
           
            //! runtextmacro setEvent2("Mine", "MINE")
            //! runtextmacro setEvent2("Return", "RETURN")

//---------------------------------------------------------------------------------------------------------------------------------------------\\
//----------------------------------------------------Everything is private below this line----------------------------------------------------\\
//---------------------------------------------------------------------------------------------------------------------------------------------\\
           
            private static method getDistanceBetweenPointsXYSquare(real x1, real y1, real x2, real y2) -> real {
                return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
            }
           
            private method searchSource(miner worker) {                
                tempWidget = null;
                tempDistance = SOURCE_SEARCH_RANGE*SOURCE_SEARCH_RANGE;
                tempResource = this;
                tempX = GetUnitX(worker.worker); tempY = GetUnitY(worker.worker);
               
                GroupEnumUnitsInRect(ENUM_GROUP, wholeMap, searchSourcePickUnit);
                GroupClear(ENUM_GROUP);                
                EnumItemsInRect(wholeMap, searchSourcePickItem, null);
                EnumDestructablesInRect(wholeMap, searchSourcePickDestructable, null);
               
               
                IssueTargetOrder(worker.worker, MINE_ORDER, tempWidget);
            }
           
            //A textmacro creating the source-searching functions for destructables, items and units
            //! textmacro sourceFunc takes NAME, TYPE
            private static method searchSourceFunc$NAME$() -> boolean {
                $TYPE$ w = GetFilter$NAME$();
                real r = getDistanceBetweenPointsXYSquare(tempX, tempY, GetWidgetX(w), GetWidgetY(w));
               
                if(LoadInteger(data, SOURCE, Get$NAME$TypeId(w)) == tempResource && tempDistance >= r && GetWidgetLife(w) > 0.405) {
                    tempWidget = w;
                    tempDistance = r;
                }
               
                w = null;
                return false;
            }
            //! endtextmacro
           
            //! runtextmacro sourceFunc("Destructable", "destructable")
            //! runtextmacro sourceFunc("Item", "item")
            //! runtextmacro sourceFunc("Unit", "unit")
           
            private method searchStorage(miner worker) {
                integer farmType = LoadInteger(data, (worker.owner + FARM_TYPE)*MAX_RESOURCES+this, worker.unitType);
                group g;
               
                if (farmType == FARM_TYPE_INSTANT) {
                    addProperty(worker.owner, worker.currentlyCarryingAmount);
                    floatingValue(worker.currentlyCarryingAmount, GetUnitX(worker.worker), GetUnitY(worker.worker));
                    worker.currentlyCarryingAmount = 0;
                   
                    searchSource(worker);
                   
                } else if(farmType == FARM_TYPE_WALK) {
                    tempX = GetUnitX(worker.worker);  tempY = GetUnitX(worker.worker);
                    tempDistance = STORAGE_SEARCH_RANGE * STORAGE_SEARCH_RANGE;
                    tempResource = this;
                    tempUnit = null;
                   
                    GroupEnumUnitsOfPlayer(ENUM_GROUP, Player(worker.owner), searchStoragePick);
                    GroupClear(ENUM_GROUP);
                   
                    worker.currentStorage = tempUnit;
                    IssueTargetOrder(worker.worker, "smart", worker.currentStorage);
                }
            }
           
            private static method searchStorageFunc() -> boolean {
                unit u = GetFilterUnit();
                real r = getDistanceBetweenPointsXYSquare(tempX, tempY, GetWidgetX(u), GetWidgetY(u));
               
                if (tempResource.isStorage(GetUnitTypeId(u)) && !IsUnitType(u,UNIT_TYPE_DEAD) && isBuildingFinished(u) && tempDistance > r) {
                    tempUnit = u;
                    tempDistance = r;
                }
               
                u = null;
                return false;
            }
           
            //A textmacro to fill an integer array with the costs of a widget, used in multiple methods
            //! textmacro setCosts
                    for (0 < i < number+1) {
                        costs[i] = Resource(i).getCosts(boughtType);
                        if (costs[i] > Resource(i).getProperty(GetPlayerId(buyer))) {
                            SimError(buyer, NOT_ENOUGH_TEXT+Resource(i).name);
                            enough = false;
                            break;
                        }
                    }
            //! endtextmacro
           
            //A textmacro to get the pay for a widget from a player, used in multiple methods
            //! textmacro demandCosts
                    for (0 < i < number+1) {
                        Resource(i).addProperty(GetPlayerId(buyer), -costs[i]);
                    }
            //! endtextmacro
           
            //A textmacro to refund the costs of a widget to a player, used in multiple methods
            //! textmacro refundCosts takes FUNC, ID, FACTOR
                for (0 < i < number+1) {
                        Resource(i).addProperty($FUNC$(buyer), R2I(Resource(i).getCosts($ID$)$FACTOR$));
                }
            //! endtextmacro
           
            private static method stopConstruction() {
                    timer t = GetExpiredTimer();
                    tempUnit u = GetTimerData(t);
                    DisableTrigger(constructionCancelled);
                    DisableTrigger(orderGiven);
                    IssueImmediateOrder(u.u, "stop");
                    EnableTrigger(orderGiven);
                    EnableTrigger(constructionCancelled);
                    ReleaseTimer(t);
                    u.destroy();
            }
           
            private static method stopTraining() {
                    timer t = GetExpiredTimer();
                    tempUnit u = GetTimerData(t);
                    DisableTrigger(trainCancelled);
                    IssueImmediateOrderById(u.u,851976);
                    EnableTrigger(trainCancelled);
                    ReleaseTimer(t);
                    u.destroy();
            }
           
            private static method onConstructionCancelled() -> boolean {
                integer i, boughtType = GetUnitTypeId(GetCancelledStructure()), buyer = GetPlayerId(GetOwningPlayer(GetFilterUnit()));
               
                for (0 < i < number+1) {
                    Resource(i).addProperty(buyer, R2I(Resource(i).getCosts(boughtType) * BUILDING_REFUND_FACTOR));
                }
               
                return false;
            }
           
            private static method onConstructionStart() -> boolean {
                    unit u, b = GetTriggerUnit();
                    real x = GetUnitX(b), y = GetUnitY(b);
                    integer id = GetUnitTypeId(b);
                    orderTarget o;
                    b = null;
                   
                    GroupEnumUnitsInRange(ENUM_GROUP, x, y, MAX_BUILD_RANGE, null);
                   
                    u = FirstOfGroup(ENUM_GROUP);
                    while (u != null) {
                        o = LoadInteger(data, CURRENTLY_BUILDING, GetHandleId(u));
                        if (o.x == x && o.y == y && o.order == id) {
                            o.destroy();
                            SaveInteger(data, CURRENTLY_BUILDING, GetHandleId(u), 0);
                            u = null;
                            break;
                        }
                        GroupRemoveUnit(ENUM_GROUP,u);
                        u = FirstOfGroup(ENUM_GROUP);
                    }
                   
                    return false;
            }
           
            private static method onConstructionFinished() -> boolean {
                SaveBoolean(data, FINISHED, GetHandleId(GetTriggerUnit()), true);
                return false;
            }
           
            private static method onTrainCancelled() -> boolean {
                    integer i, boughtType = GetTrainedUnitType(), buyer = GetPlayerId(GetOwningPlayer(GetFilterUnit()));
               
                    if (boughtType == 0)
                        boughtType = GetResearched();
               
                    //! runtextmacro refundCosts("", "boughtType", "")
               
                    return false;
            }
           
            private static method onUnitCast() -> boolean {
                integer boughtType = GetSpellAbilityId(),
                        buyType = LoadInteger(data, BUY_TYPE, boughtType),
                        i,
                        costs[];
                boolean enough = true;
                player buyer;
               
                 if (buyType == BUY_TYPE_ABILITY) {
                    buyer = GetTriggerPlayer();
                    //! runtextmacro setCosts()
                    if (enough)
                        //! runtextmacro demandCosts()
                    else
                         IssueImmediateOrder(GetTriggerUnit(), "stop");
                }
               
                static if(USE_EVENTS)
                    if(enough){
                        i = LoadInteger(data, EVENT_CAST, boughtType);
                        if(i != 0)
                            ResourceEventCast(i).evaluate();
                    }
               
                return false;
            }
           
            private static method onUnitBought() -> boolean {
                integer boughtType = GetUnitTypeId(GetSoldUnit()),
                             buyType = LoadInteger(data, BUY_TYPE, boughtType),
                             i,
                             costs[];
                boolean enough = true;
                player buyer;
               
                 if (buyType == BUY_TYPE_SOLD) {
                    buyer = GetOwningPlayer(GetBuyingUnit());
                    //! runtextmacro setCosts()
                    if (enough){
                        //! runtextmacro demandCosts()
                       
                        static if(USE_EVENTS){
                            i = LoadInteger(data, EVENT_UNIT, boughtType);
                            if(i != 0)
                                ResourceEventUnitSale(i).evaluate();
                        }
                    } else {
                         RemoveUnit(GetSoldUnit());
                         //?????????????????????????????????????
                    }
                }
               
                return false;
            }
           
            private static method onItemBought() -> boolean {
                integer boughtType = GetItemTypeId(GetSoldItem()),
                             buyType = LoadInteger(data, BUY_TYPE, boughtType),
                             i,
                             costs[];
                boolean enough = true;
                player buyer;
               
                 if (buyType == BUY_TYPE_SOLD) {
                    buyer = GetOwningPlayer(GetBuyingUnit());
                    //! runtextmacro setCosts()
                    if (enough){
                        //! runtextmacro demandCosts()
                       
                        static if(USE_EVENTS){
                            i = LoadInteger(data, EVENT_ITEM, boughtType);
                            if(i != 0)
                                ResourceEventItemSale(i).evaluate();
                        }
                    } else {
                         RemoveItem(GetSoldItem());
                         //?????????????????????????????????????
                    }
                }
               
                return false;
            }
           
            private static method onItemSold() -> boolean {
                integer boughtType = GetItemTypeId(GetSoldItem()),
                             buyType = LoadInteger(data, BUY_TYPE, boughtType),
                             i,
                             buyer = GetPlayerId(GetTriggerPlayer());
               
                 if (buyType == BUY_TYPE_SOLD) {
                    //! runtextmacro refundCosts("", "boughtType", "*ITEM_SELL_FACTOR")
                }
               
                return false;
            }
           
            private static method onOrder() -> boolean {
                miner worker;
                thistype this;
                unit ordered = GetTriggerUnit();
                integer targetId,
                             boughtType = GetIssuedOrderId(),
                             buyType = LoadInteger(data, BUY_TYPE, boughtType),
                             i,
                             costs[];
                player buyer = GetOwningPlayer(ordered);
                boolean enough = true;
                timer t;
                orderTarget o = LoadInteger(data, CURRENTLY_BUILDING, GetHandleId(ordered));
               
                if (o > 0) {
                    //! runtextmacro refundCosts("GetPlayerId","o.order", "")
               
                    o.destroy();
                }
               
                if (buyType == BUY_TYPE_BUILDING) {
                    //! runtextmacro setCosts()
                    if (enough) {
                        //! runtextmacro demandCosts()
                        o = orderTarget.create();
                        o.x = GetOrderPointX();
                        o.y = GetOrderPointY();
                        o.order = boughtType;
                        SaveInteger(data, CURRENTLY_BUILDING, GetHandleId(ordered), o);
                       
                        static if(USE_EVENTS){
                            i = LoadInteger(data, EVENT_BUILD, boughtType);
                            if(i != 0)
                                ResourceEventCast(i).evaluate();
                        }
                    } else {
                        t = NewTimer();
                        SetTimerData(t, tempUnit.create(ordered));
                        TimerStart(t, 0, false, function Resource.stopConstruction);
                        SaveInteger(data, CURRENTLY_BUILDING, GetHandleId(ordered), 0);
                    }
                   
                } else {
                    SaveInteger(data, CURRENTLY_BUILDING, GetHandleId(ordered), 0);
                    if (buyType == BUY_TYPE_TRAINED) {
                        //! runtextmacro setCosts()
                        if (enough){
                            //! runtextmacro demandCosts()
                       
                            static if(USE_EVENTS){
                                i = LoadInteger(data, EVENT_TRAIN, boughtType);
                                if(i != 0)
                                    ResourceEventCast(i).evaluate();
                            }
                        } else {
                            t = NewTimer();
                            SetTimerData(t, tempUnit.create(ordered));
                            TimerStart(t, 0, false, function Resource.stopTraining);
                        }
                    }
                }
               
               
                buyer = null;
               
                if(LoadBoolean(data, MINER, GetUnitTypeId(ordered))) {
                    worker = LoadInteger(data, MINER_STRUCT, GetHandleId(ordered));
                    ordered = null;
               
                    if (worker.isMining) {
                        worker.isMining = false;
                        PauseTimer(worker.tim);
                    }
               
                    if (boughtType != ORDER_SMART) {
                        worker.currentStorage = null;
                        return false;
                    }
               
                    targetId = GetUnitTypeId(GetOrderTargetUnit());
                    if (targetId == 0) {
                        targetId = GetDestructableTypeId(GetOrderTargetDestructable());
                        if (targetId == 0) {
                            targetId = GetItemTypeId(GetOrderTargetItem());
                            if (targetId == 0)  {
                                worker.currentStorage = null;
                                return false;
                            }
                        }
                    }
                   
                    this = LoadInteger(data, SOURCE, targetId);
               
                    if(this > 0) {
                        if(LoadInteger(data, (worker.owner + AMOUNT_CARRIED)*MAX_RESOURCES+this, worker.unitType) > 0)
                            IssueTargetOrder(worker.worker, MINE_ORDER, GetOrderTarget());
                       
                        worker.currentStorage = null;
                        return false;
                    }
               
                    this = worker.currentlyCarrying;
               
                    if (LoadBoolean(data, STORAGE*MAX_RESOURCES+this, targetId) || true)
                        worker.currentStorage = GetOrderTargetUnit();
                } else
                    ordered = null;
                   
                return false;
            }
           
            private static method mine() {
                miner worker = GetTimerData(GetExpiredTimer());
                thistype this = worker.currentlyCarrying;
               
                integer gain = LoadInteger(data, (worker.owner + GAIN_PER_HIT)*MAX_RESOURCES+this, worker.unitType),
                             max = LoadInteger(data, (worker.owner + AMOUNT_CARRIED)*MAX_RESOURCES+this, worker.unitType),
                             farmType = LoadInteger(data, (worker.owner + FARM_TYPE)*MAX_RESOURCES+this, worker.unitType);
                real damage = LoadReal(data, (worker.owner + DAMAGE)*MAX_RESOURCES+this, worker.unitType),
                        life = GetWidgetLife(worker.currentTarget);
               
               
                if (life <= 0.405) {
                    searchSource(worker);
                    return;
                }
               
                if (GetUnitAbilityLevel(worker.worker, RETURN_ABILITY) <= 0 && farmType == FARM_TYPE_WALK)
                    UnitAddAbility(worker.worker, RETURN_ABILITY);
                   
                SetWidgetLife(worker.currentTarget, life - damage);
               
                if(!onKill){
                    worker.currentlyCarryingAmount += gain;
                   
                    static if(USE_EVENTS){
                        farmType = LoadInteger(data, EVENT_MINE, this);
                        if(farmType != 0)
                            ResourceEventMine(farmType).evaluate(this, worker.worker, worker.currentTarget);
                    }
                }
                   
                if (GetWidgetLife(worker.currentTarget) <= 0.405) {
                    if(onKill){
                        worker.currentlyCarryingAmount += gain;
                   
                        static if(USE_EVENTS){
                            farmType = LoadInteger(data, EVENT_MINE, this);
                            if(farmType != 0)
                                ResourceEventMine(farmType).evaluate(this, worker.worker, worker.currentTarget);
                        }
                    }
                   
                    if(worker.currentlyCarryingAmount >= max) {
                        worker.currentlyCarryingAmount = max;
                        searchStorage(worker);
                    } else
                        searchSource(worker);
                       
                } else if(worker.currentlyCarryingAmount >= max) {
                    worker.currentlyCarryingAmount = max;
                    searchStorage(worker);
                } else {
                    SetUnitAnimation(worker.worker , LoadStr(data, ANIMATION*MAX_RESOURCES+worker.currentlyCarrying, worker.unitType));
                   
                    TimerStart(worker.tim, LoadReal(data, (worker.owner + SPEED)*MAX_RESOURCES+this, worker.unitType), false, function Resource.mine);
                }
            }
           
            private static method onSpell() -> boolean {
                miner worker = LoadInteger(data, MINER_STRUCT, GetHandleId(GetTriggerUnit()));
                thistype this;
                integer targetId,
                             amount;
               
                if(GetSpellAbilityId() == RETURN_ABILITY) {
                    worker.currentlyCarrying.searchStorage(worker);
                } else if (GetSpellAbilityId() == MINE_ABILITY) {
                    targetId = GetUnitTypeId(GetSpellTargetUnit());
                    worker.currentTarget = GetSpellTargetUnit();
               
                    if (targetId == 0) {
                        targetId = GetDestructableTypeId(GetSpellTargetDestructable());
                        worker.currentTarget = GetSpellTargetDestructable();
                        if (targetId == 0) {
                            targetId = GetItemTypeId(GetSpellTargetItem());
                            worker.currentTarget = GetSpellTargetItem();
                            if (targetId == 0)
                                worker.currentStorage = null;
                                worker.currentTarget = null;
                                return false;
                        }
                    }
               
                    this = LoadInteger(data, SOURCE, targetId);
               
                    amount = LoadInteger(data, (worker.owner + AMOUNT_CARRIED)*MAX_RESOURCES+this, worker.unitType);
                    if (amount <= 0)
                        return false;
               
                    if (worker.currentlyCarrying != this) {
                        worker.currentlyCarrying = this;
                        worker.currentlyCarryingAmount = 0;
                        UnitRemoveAbility(worker.worker, RETURN_ABILITY);
                    }
               
                    if (amount <= worker.currentlyCarryingAmount) {
                        worker.currentlyCarryingAmount = amount;
                        IssueImmediateOrder(worker.worker, RETURN_ORDER);
                    } else {
                        IssueImmediateOrder(worker.worker, "stop");
                        SetUnitAnimation(worker.worker , LoadStr(data, ANIMATION*MAX_RESOURCES+worker.currentlyCarrying, worker.unitType));
                   
                        worker.isMining = true;
                        TimerStart(worker.tim, LoadReal(data, (worker.owner + SPEED)*MAX_RESOURCES+this, worker.unitType), false, function Resource.mine);
                    }
                }
                return false;
            }
           
            private static method workerInRange() -> boolean {
                miner worker = LoadInteger(data, MINER_STRUCT, GetHandleId(GetTriggerUnit()));
                static if(USE_EVENTS) integer i;
               
                if (worker.currentStorage != null && worker.currentlyCarryingAmount > 0 && IsUnitInRange(worker.worker, worker.currentStorage, STORAGE_RANGE+0.1)) {
                    UnitRemoveAbility(worker.worker, RETURN_ABILITY);
                    worker.currentlyCarrying.addProperty(worker.owner, worker.currentlyCarryingAmount);
                    worker.currentlyCarrying.floatingValue(worker.currentlyCarryingAmount, GetUnitX(worker.worker), GetUnitY(worker.worker));
                   
                    static if(USE_EVENTS){
                        i = LoadInteger(data, EVENT_RETURN, worker.currentlyCarrying);
                        if(i != 0)
                            ResourceEventReturn(i).evaluate(worker.currentlyCarrying, worker.worker, worker.currentlyCarryingAmount, worker.currentStorage);
                    }
                   
                    worker.currentlyCarryingAmount = 0;
                   
                    worker.currentlyCarrying.searchSource(worker);
                }
                return false;
            }
           
            private static method addWorkerFunc() -> boolean {
                if ((tempType == GetUnitTypeId(GetFilterUnit())) && (GetUnitAbilityLevel(GetFilterUnit(), MINE_ABILITY) <= 0))
                    SaveInteger(data, MINER_STRUCT, GetHandleId(GetFilterUnit()), miner.create(GetFilterUnit()));
                return false;
            }
           
            private static method addStorageFunc() -> boolean {
                if (tempType == GetUnitTypeId(GetFilterUnit()))
                    TriggerRegisterUnitInRange(inRange, GetFilterUnit(), STORAGE_RANGE + GetUnitCollisionSize(GetFilterUnit()), null);
                   
                return false;
            }
       
            private static method onUnitEntersMap() -> boolean {
                integer id = GetUnitTypeId(GetFilterUnit());
               
                if(LoadBoolean(data, MINER, id))
                    SaveInteger(data, MINER_STRUCT, GetHandleId(GetFilterUnit()), miner.create(GetFilterUnit()));
                   
                if(LoadBoolean(data, STORAGE, id))
                    TriggerRegisterUnitInRange(inRange, GetFilterUnit(), STORAGE_RANGE + GetUnitCollisionSize(GetFilterUnit()), null);
                   
                return false;
            }
           
            private static method pickFinishedBuildings() -> boolean {
                unit u = GetFilterUnit();
                if (IsUnitType(u, UNIT_TYPE_STRUCTURE))
                    SaveBoolean(data, FINISHED, GetHandleId(u), true);
                u = null;
                return false;
            }
           
            private static method onDeath() -> boolean{
                unit u = GetTriggerUnit();
                integer s = LoadInteger(data, CURRENTLY_BUILDING, GetHandleId(u)),
                            buyer,
                            i;
                if (s > 0) {
                    buyer = GetPlayerId(GetOwningPlayer(u));
                    //! runtextmacro refundCosts("","orderTarget(s).order", "")
                    orderTarget(s).destroy();
                }
               
                s = LoadInteger(data, MINER_STRUCT, GetHandleId(u));
                if (s > 0)
                    miner(s).destroy();
                   
                u = null;
                return false;
            }
           
            private static method onRemove(unit u) {
                integer s = LoadInteger(data, CURRENTLY_BUILDING, GetHandleId(u)),
                            buyer,
                            i;
                if (s > 0) {
                    buyer = GetPlayerId(GetOwningPlayer(u));
                    //! runtextmacro refundCosts("","orderTarget(s).order", "")
                    orderTarget(s).destroy();
                }
               
                s = LoadInteger(data, MINER_STRUCT, GetHandleId(u));
                if (s > 0)
                    miner(s).destroy();
            }
       
            private static method isMiner() -> boolean {
                return LoadBoolean(data, MINER, GetUnitTypeId(GetFilterUnit()));
            }
       
            private static method onInit(){
                trigger t = CreateTrigger(),
                            t2 = CreateTrigger(),
                            sellItem = CreateTrigger(),
                            buyItem = CreateTrigger(),
                            sellUnit = CreateTrigger(),
                            cast  = CreateTrigger(),
                            finish = CreateTrigger();
                region r = CreateRegion();
                integer i;
               
                wholeMap = GetWorldBounds();
               
                RegionAddRect(r, wholeMap);
                addWorkerPick = Condition(function Resource.onUnitEntersMap);
                TriggerRegisterEnterRegion(t, r, addWorkerPick);
               
                addWorkerPick = Condition(function Resource.isMiner);
                inRange = CreateTrigger();
                TriggerAddCondition(inRange, addWorkerPick);
                TriggerAddCondition(inRange, Condition(function Resource.workerInRange));
               
                trainCancelled = CreateTrigger();
                constructionCancelled = CreateTrigger();
                orderGiven = CreateTrigger();
                t = CreateTrigger();
               
                for(0 <= i < bj_MAX_PLAYERS){
                    TriggerRegisterPlayerUnitEvent(orderGiven, Player(i), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null);
                    TriggerRegisterPlayerUnitEvent(orderGiven, Player(i), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null);
                    TriggerRegisterPlayerUnitEvent(orderGiven, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null);
                   
                    TriggerRegisterPlayerUnitEvent(t2, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, addWorkerPick);
                   
                    TriggerRegisterPlayerUnitEvent(trainCancelled, Player(i), EVENT_PLAYER_UNIT_RESEARCH_CANCEL, null);
                    TriggerRegisterPlayerUnitEvent(trainCancelled, Player(i), EVENT_PLAYER_UNIT_TRAIN_CANCEL, null);
                   
                    TriggerRegisterPlayerUnitEvent(constructionCancelled, Player(i),EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL, null);
                   
                    TriggerRegisterPlayerUnitEvent(finish, Player(i),EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, null);
                   
                    TriggerRegisterPlayerUnitEvent(t, Player(i),EVENT_PLAYER_UNIT_CONSTRUCT_START, null);
                   
                    TriggerRegisterPlayerUnitEvent(buyItem, Player(i), EVENT_PLAYER_UNIT_SELL_ITEM, null);
                   
                    TriggerRegisterPlayerUnitEvent(sellItem, Player(i),EVENT_PLAYER_UNIT_PAWN_ITEM, null);
                   
                    TriggerRegisterPlayerUnitEvent(sellUnit, Player(i),EVENT_PLAYER_UNIT_SELL, null);
                   
                    TriggerRegisterPlayerUnitEvent(cast, Player(i),EVENT_PLAYER_UNIT_SPELL_CAST, null);
                }
               
                TriggerAddCondition(trainCancelled, Condition(function Resource.onTrainCancelled));
                TriggerAddCondition(constructionCancelled, Condition(function Resource.onConstructionCancelled));
                TriggerAddCondition(orderGiven, Condition(function Resource.onOrder));
                TriggerAddCondition(t2, Condition(function Resource.onSpell));
                TriggerAddCondition(t ,Condition(function Resource.onConstructionStart));
                TriggerAddCondition(finish, Condition(function Resource.onConstructionFinished));
                TriggerAddCondition(buyItem, Condition(function Resource.onItemBought));
                TriggerAddCondition(sellItem, Condition(function Resource.onItemSold));
                TriggerAddCondition(sellUnit, Condition(function Resource.onUnitBought));
                TriggerAddCondition(cast, Condition(function Resource.onUnitCast));
               
                trigOnDeath = CreateTrigger();
                TriggerAddCondition(trigOnDeath, Condition(function Resource.onDeath));
               
                addWorkerPick = Condition(function Resource.addWorkerFunc);
                addStoragePick = Condition(function Resource.addStorageFunc);
               
                searchSourcePickUnit = Condition(function Resource.searchSourceFuncUnit);
                searchSourcePickDestructable = Condition(function Resource.searchSourceFuncDestructable);
                searchSourcePickItem = Condition(function Resource.searchSourceFuncItem);
                searchStoragePick = Condition(function Resource.searchStorageFunc);
               
                allBuildings = Condition(function Resource.pickFinishedBuildings);
               
                TimerStart(CreateTimer(), 0, false, function Resource.createMultiboards);
                t = null;
                t2 = null;
                sellItem = null;
                buyItem = null;
                sellUnit = null;
               
                static if (DEBUG_MODE)
                    if(MAX_RESOURCES > 511 || MAX_RESOURCES <= 0)
                        BJDebugMsg("|cffFF0000ResourceSystem ERROR:|r 'MAX_RESOURCES' must be set to a positive value lower than 511");
            }
           
            private static method createMultiboards() {
                integer i, j, k = number;
                thistype this;
                multiboarditem mi;
               
                GroupEnumUnitsInRect(ENUM_GROUP, wholeMap, allBuildings);
               
                ReleaseTimer(GetExpiredTimer());
               
                for(0 <= i < 12) {
                    properties[i] = CreateMultiboard();
                    MultiboardSetTitleText(properties[i], MULTIBOARD_NAME);
                    MultiboardSetColumnCount(properties[i], 2);
                    MultiboardSetRowCount(properties[i], k);
                   
                    if(GetLocalPlayer() == Player(i))
                        MultiboardDisplay(properties[i], true);
                       
                    for(0 <= j < k) {
                        this = j+1;
                   
                        mi = MultiboardGetItem(properties[i], j, 0);
                        MultiboardSetItemIcon(mi, icon);
                        MultiboardSetItemValue(mi, colour + name + "|r");
                        MultiboardSetItemWidth(mi, MULTIBOARD_NAME_WIDTH);
                        MultiboardReleaseItem(mi);
                       
                        mi = MultiboardGetItem(properties[i], j, 1);
                        MultiboardSetItemStyle(mi, true, false);
                        MultiboardSetItemValue(mi, colour + I2S(amount[i]) + "|r");
                        MultiboardSetItemWidth(mi, MULTIBOARD_VALUE_WIDTH);
                        MultiboardReleaseItem(mi);
                    }
                }
               
                mi = null;
            }
           
            private static method updateMultiboard(integer whichPlayer) {
                integer i, j, k = number;
                thistype this;
                multiboarditem mi;
               
                MultiboardSetRowCount(properties[whichPlayer], k);
                       
                for(0 <= j < k) {
                    this = j+1;
                   
                    mi = MultiboardGetItem(properties[whichPlayer], j, 0);
                    MultiboardSetItemIcon(mi, icon);
                    MultiboardSetItemValue(mi, colour + name + "|r");
                    MultiboardSetItemWidth(mi, MULTIBOARD_NAME_WIDTH);
                    MultiboardReleaseItem(mi);
                       
                    mi = MultiboardGetItem(properties[whichPlayer], j, 1);
                    MultiboardSetItemStyle(mi, true, false);
                    MultiboardSetItemValue(mi, colour + I2S(amount[whichPlayer]) + "|r");
                    MultiboardSetItemWidth(mi, MULTIBOARD_VALUE_WIDTH);
                    MultiboardReleaseItem(mi);
                }
               
                mi = null;
            }
           
            private method destroy() {}
        }
       
        private struct miner {
            unit worker,
                    currentStorage;
           
            Resource currentlyCarrying;
            integer currentlyCarryingAmount,
                         unitType,
                         owner;
           
            widget currentTarget;
            real currentTargetX, currentTargetY;
           
            timer tim;
            boolean isMining = false;
           
            static method create(unit u)  -> thistype{
                thistype this = thistype.allocate();
                worker = u;
                unitType = GetUnitTypeId(u);
                owner = GetPlayerId(GetOwningPlayer(u));
               
                tim = NewTimer();
                SetTimerData(tim, this);
               
                UnitAddAbility(u, MINE_ABILITY);
               
                if (!IsUnitType(u, UNIT_TYPE_HERO))
                    TriggerRegisterUnitEvent(trigOnDeath, u, EVENT_UNIT_DEATH);
               
                return this;
            }
           
            private method onDestroy() {ReleaseTimer(tim);}
        }
       
        private struct tempUnit {
            unit u;
           
            static method create(unit u) -> tempUnit {
                thistype this = thistype.allocate();
                this.u = u;
                return this;
            }
        }
       
        private struct orderTarget {
            real x, y;
            integer order;
        }
    }
//! endzinc

hook RemoveUnit Resource.onRemove

GetUnitCollisionSize
Code (vJASS):
//GetUnitCollisionSize
//by Verethragna (aka D1000)
//v1.1

//Use "GetUnitCollsionSize(unit)" or "GetUnitTypeCollsionSize(unittype)" to get the approximate collsion size of a unit

//Based on Vexorians "GetUnitCollsionSize", but made in ZinC & saves values in a hashtable (if enabled)

//! zinc
    library GetUnitCollisionSize requires optional xebasic {
        //Only needed if xebasic is not used
            private constant real MAX_COLLSION_SIZE = 197;
        //Number of iterations used, the more, the accurate
            private constant integer ITERATIONS = 20;
        //If you want that collsion-values are saved in hashtables, set this to true. Else it will be calculated every time again.
            private constant boolean USE_HASHTABLE = true;
        //The position of eventual temporal units, if you use "GetUnitTypeCollisionSize"
            private constant real UNIT_POS_X = 0;
            private constant real UNIT_POS_Y = 0;
       
//==================================================================================================\\
//==================================================================================================\\
       
        private hashtable savedValues;
       
        //A textmacro containing the algorithm for getting the collision size, since it is used in two different functions
        //! textmacro unitCollisionSize
            static if (LIBRARY_xebasic)
                higher = XE_MAX_COLLISION_SIZE;
            else
                higher = MAX_COLLSION_SIZE;
            lower = 0;
           
            for(0 <= i < ITERATIONS) {
                middle = (lower+higher)/2;
                if (IsUnitInRangeXY(u, x+middle, y, 0))
                    lower = middle;
                else
                    higher = middle;
            }
           
            static if (USE_HASHTABLE)
                SaveReal(savedValues, 0, uType, middle);
        //! endtextmacro
       
        public function GetUnitCollisionSize(unit u) -> real {
            real lower, higher, middle, i, x, y;
           
            static if (USE_HASHTABLE) {
                integer uType = GetUnitTypeId(u);
                lower = LoadReal(savedValues, 0, uType);
                if(lower > 0)
                    return lower;
            }
           
            x = GetUnitX(u); y = GetUnitY(u);
            //! runtextmacro unitCollisionSize()
           
            return middle;
        }
       
        public function GetUnitTypeCollisionSize(integer uType) -> real {
            real lower, higher, middle, i, x = UNIT_POS_X, y = UNIT_POS_Y;
            unit u;
            static if (USE_HASHTABLE) {
                lower = LoadReal(savedValues, 0, uType);
                if(lower > 0)
                    return lower;
            }
                           
            u = CreateUnit(Player(15), uType, 0, 0, 0);
            ShowUnit(u, false);
           
            //! runtextmacro unitCollisionSize()
           
            RemoveUnit(u);
            u = null;
           
            return lower;
        }
       
        private function onInit() {
            static if (USE_HASHTABLE)
                savedValues = InitHashtable();
        }
    }
//! endzinc

Readme
Readme
Code (vJASS):
Resource System
Version 1.3
Made by Verethragna (aka D1000)

//==================================================\\
Requirements:
    Libraries:
        GetUnitCollisionSize made by Verethragna (aka D1000)
        GroupUtils made by Rising_Dusk
        TimerUtils made by Vexorian
        SimError made by Vexorian

    Abilities:
        Mine
        Return
//==================================================\\
Credits to:
    Vexorian: TimerUtils, SimError, JassHelper
    Rising_Dusk: GroupUtils
    Cedi: Got an idea how to get the constructing unit in the event EVENT_PLAYER_UNIT_CONSTRUCT_START
//==================================================\\
Import Instructions:
    1) Copy the ResourceSystem-Folder & the required libraries to your map
    2) Copy the two required abilities to your map (required abilities & libraries listed above)
    3) Adjust the constants in the "ResourceSystem"-Library
    4) Use the methods listed in "ResourceSystem API Resource Creation" to create and adjust new resources
    5) Give credits to me & the people who made the required libraries
    6) Enjoy
//==================================================\\
API: Resource Creation
Code (vJASS):
Resource System
Version 1.3
Made by Verethragna (aka D1000)

//==================================================\\
//Methods to create, adjust and manipulate resources.
//==================================================\\
____________________________________________
static method create(string name, string icon, boolean onKill) -> thistype
//Creates a new Resource.
//Usage:
local Resource yourResource = Resource.create("name","icon", true/false)
//Parameters:
name -> Name of the Resource
icon -> Multiboard-Icon of the Resource
onKill -> Defines if you get this resource each hit on a source or only if you kill it.
____________________________________________
method addSource(integer sourceId)
//Adds a source to the Resource
//Usage:
call yourResource.addSource('type')
//Parameter:
sourceId -> type-id of the source. Can be an item a unit or a destructable, but it must be selectable ingame.
____________________________________________
static method getResourceBySource(integer sourceId) -> thistype
//Returns the resource that can be extracted from the given source.
//Usage:
local Resource yourResource = getResourceBySource('type')
//Parameter:
sourceId -> type-id of the source
____________________________________________
method addStorage(integer id)
//Adds a Storage-building to the Resource. Only needed if your workers have the farm type "FARM_TYPE_WALK"
//Usage:
call yourResource.addStorage('type')
//Parameter:
id -> type-id of the storage. Should be a building.
____________________________________________
method isStorage(integer id) -> boolean
//Returns true if the given building is a storage of your resource
//Usage:
local boolean b = yourResource.isStorage('type')
//Paramter:
id -> The id of the building you want to check.
____________________________________________
method addMiner(integer unitTypeId, string anim ,real speed, real damagePerHit, integer gain, integer amountCarried, integer farmType)
//Adds a miner to the resource
//Usage:
call yourResource.addMiner('type', "animation", 0.0, 0.0, 0, 0, FARM_TYPE_INSTANT/WALK)
//Parameters:
unitTypeId -> type-id of the worker
anim -> animation that is played when the unit mines this resource
speed -> mining-speed
damagePerHit -> damage done to the source per hit
gain -> resource-gain per hit/kill
amountCarried -> how much of the resource the worker can mine until he brings it back to a storage. Should always be higher then "gain", even if the farm type is "FARM_TYPE_WALK"
farmType -> Either "FARM_TYPE_INSTANT" or "FARM_TYPE_WALK". Defines if the worker has to bring the mined resources back to a storage
____________________________________________
method setCosts(integer typeId, integer costs, integer buyType)
//Sets the costs of a Unit/Building/Item/Research
//Usage:
call yourResource.setCosts('type', 0, BUY_TYPE_SOLD/_BUILDING/_TRAINED/_ABILITY)
//Parameters:
typeId -> type-id of the object
costs -> how much the object should cost
buyType -> how the object is bought. If you add costs to this object for different resources, the buyType is set in the last call.
          (For example: call yourResource1.setCosts('type', 10, 0); call yourResource2.setCosts('type', 30, BUY_TYPE_SOLD); -> The buyType is BUY_TYPE_SOLD)
____________________________________________
method getCosts(integer typeId) -> integer
//Gets the costs of an object
//Usage:
local integer i = yourResource.getCosts(typeId)
//Parameter:
typeId -> the type-id of the unit/building/item/research
____________________________________________
method getName() -> string
//Returns the name of your resource
//Usage:
local string s = yourResource.getName()
____________________________________________
method getIcon() -> string
//Returns the icon of your resource
//Usage:
local string s = yourResource.getIcon()
____________________________________________
method setAmountCarried(player p, integer value, integer typeId)
//Changes the amount of you resources that can be carried by the given unit and player
//Usage:
call yourResource.setAmountCarried(Player(0), 0, 'type')
//Paramters:
p -> The player who is affected by the change
value -> The new value
typeId -> The affected unitType
____________________________________________
method setAmountCarriedById(integer p, integer value, integer typeId)
//Changes the amount of you resources that can be carried by the given unit and player
//Usage:
call yourResource.setAmountCarried(0, 0, 'type')
//Paramters:
p -> The id of the player who is affected by the change
value -> The new value
typeId -> The affected unitType
____________________________________________
method getAmountCarried(player p,  integer typeId)
//Gets the amount of you resources that can be carried by the given unit and player
//Usage:
local integer i = yourResource.getAmountCarried(Player(0), 'type')
//Paramters:
p -> The player
typeId -> The unitType
____________________________________________
method getAmountCarriedById(integer p,  integer typeId)
//Gets the amount of you resources that can be carried by the given unit and player
//Usage:
local integer i = yourResource.getAmountCarried(0, 'type')
//Paramters:
p -> The id of the player
typeId -> The unitType
____________________________________________
method setGainPerHit(player p, integer value, integer typeId)
//Changes the gain per hit of the given unit and player
//Usage:
call yourResource.setGainPerHit(Player(0), 0, 'type')
//Paramters:
p -> The player who is affected by the change
value -> The new value
typeId -> The affected unitType
____________________________________________
method setGainPerHitById(integer p, integer value, integer typeId)
//Changes the gain per hit of the given unit and player
//Usage:
call yourResource.setGainPerHit(0, 0, 'type')
//Paramters:
p -> The id of the player who is affected by the change
value -> The new value
typeId -> The affected unitType
____________________________________________
method getGainPerHit(player p,  integer typeId)
//Gets the gain per hit of the given unit and player
//Usage:
local integer i = yourResource.getGainPerHit(Player(0), 'type')
//Paramters:
p -> The player
typeId -> The unitType
____________________________________________
method getGainPerHitById(integer p,  integer typeId)
//Gets the gain per hit of the given unit and player
//Usage:
local integer i = yourResource.getGainPerHit(0, 'type')
//Paramters:
p -> The id of the player
typeId -> The unitType
____________________________________________
method setDamage(player p, real value, integer typeId)
//Changes the damage per hit of the given unit and player
//Usage:
call yourResource.setDamage(Player(0), 0.0, 'type')
//Paramters:
p -> The player who is affected by the change
value -> The new value
typeId -> The affected unitType
____________________________________________
method setDamageById(integer p, real value, integer typeId)
//Changes the damage per hit of the given unit and player
//Usage:
call yourResource.setDamage(0, 0.0, 'type')
//Paramters:
p -> The id of the player who is affected by the change
value -> The new value
typeId -> The affected unitType
____________________________________________
method getDamage(player p,  integer typeId) -> real
//Gets the damage per hit of the given unit and player
//Usage:
local integer i = yourResource.getDamage(Player(0), 'type')
//Paramters:
p -> The player
typeId -> The unitType
____________________________________________
method getDamageById(integer p,  integer typeId) -> real
//Gets the damage per hit of the given unit and player
//Usage:
local integer i = yourResource.getDamage(0, 'type')
//Paramters:
p -> The id of the player
typeId -> The unitType
____________________________________________
method setSpeed(player p, real value, integer typeId)
//Changes the speed of the given unit and player
//Usage:
call yourResource.setSpeed(Player(0), 0.0, 'type')
//Paramters:
p -> The player who is affected by the change
value -> The new value
typeId -> The affected unitType
____________________________________________
method setSpeedById(integer p, real value, integer typeId)
//Changes the speed of the given unit and player
//Usage:
call yourResource.setSpeed(0, 0.0, 'type')
//Paramters:
p -> The id of the player who is affected by the change
value -> The new value
typeId -> The affected unitType
____________________________________________
method getSpeed(player p,  integer typeId) -> real
//Gets the speed of the given unit and player
//Usage:
local integer i = yourResource.getSpeed(Player(0), 'type')
//Paramters:
p -> The player
typeId -> The unitType
____________________________________________
method getSpeedById(integer p,  integer typeId) -> real
//Gets the speed of the given unit and player
//Usage:
local integer i = yourResource.getSpeed(0, 'type')
//Paramters:
p -> The id of the player
typeId -> The unitType
___________________________________________
method setFarmType(player p, integer value, integer typeId)
//Changes the FarmType of the given unit and player
//Usage:
call yourResource.setFarmType(Player(0), 0, 'type')
//Paramters:
p -> The player who is affected by the change
value -> The new value
typeId -> The affected unitType
____________________________________________
method setFarmTypeById(integer p, integer value, integer typeId)
//Changes the FarmType of the given unit and player
//Usage:
call yourResource.setFarmType(0, 0, 'type')
//Paramters:
p -> The id of the player who is affected by the change
value -> The new value
typeId -> The affected unitType
____________________________________________
method getFarmType(player p,  integer typeId)
//Gets the FarmType of the given unit and player
//Usage:
local integer i = yourResource.getFarmType(Player(0), 'type')
//Paramters:
p -> The player
typeId -> The unitType
____________________________________________
method getFarmTypeById(integer p,  integer typeId)
//Gets the FarmType of the given unit and player
//Usage:
local integer i = yourResource.getFarmType(0, 'type')
//Paramters:
p -> The id of the player
typeId -> The unitType
____________________________________________
method setColour(string colour)
//Sets the colour of the Resource in the multiboard and in the text-tags
//Usage:
call yourResource.setColour("000000")
//Parameter:
colour -> The colour as a hexadezimal number in a string. For example: "FF0000" is red, "000000" is black.
____________________________________________
method getColour() -> string
//Returns the colour of the Resource in the multiboard and in the text-tags in the format |cffXXXXXX
//Usage:
local string s = yourResource.getColour()
_____________________________________________
method setAnimation(integer unitTypeId, string anim)
//Sets the animation that is played by the given unitType when it mines this resource
//Usage:
call yourResource.setAnimation('type', "animation")
//Parameters:
unitTypeId -> The id of the unitType
anim -> The animation that should be played
_____________________________________________
method getAnimation(integer unitTypeId)
//Returns the animation that is played by the given unitType when it mines this resource
//Usage:
set string s = yourResource.setAnimation('type')
//Parameters:
unitTypeId -> The id of the unitType
_____________________________________________
method addProperty(integer whichPlayer, integer amount)
//Adds the given value to the amount of your Resource a players has. Use negative values to decrease it
//Usage:
call yourResource.addProperty(0, 0)
//Parameters
whichPlayer -> The id of the player
amount -> The amount which will be added to the chosen players properties
____________________________________________
method setProperty(integer whichPlayer, integer amount)
//Sets the given value to the amount of your Resource a players has. Use negative values to decrease it
//Usage:
call yourResource.setProperty(0, 0)
//Parameters
whichPlayer -> The id of the player
amount -> The properties of the chosen player will be set to this value
____________________________________________
method getProperty(integer whichPlayer) -> integer
//Returns the amount of your Resource the given player has.
//Usage:
local integer i = yourResource.getProperty(0)
//Parameters
whichPlayer -> The id of the player
_____________________________________________
API: Misc
Code (vJASS):
Resource System
Version 1.3
Made by Verethragna (aka D1000)

//==================================================\\
//Methods used for various things, not necessarily concerning resources.
//==================================================\\
___________________________________________
static method showMultiboard(integer whichPlayer, boolean flag)
//Shows/Hides the multiboard with the Resources of the given player to the given player
//Usage:
call Resource.showMultiboard(0, true/false)
//Parameters:
whichPlayer -> The id of the player
flag -> if true -> shows the multiboard, false -> hides the multiboard
_____________________________________________
static method minimizeMultiboard(integer whichPlayer, boolean flag)
//Minimizes/Maximizes the multiboard with the Resources of the given player
//Usage:
call Resource.minimizeMultiboard(0, true/false)
//Parameters:
whichPlayer -> The id of the player
flag -> if true -> minimizes the multiboard, false -> maximizes the multiboard
____________________________________________
static method isBuildingFinished(unit building) -> boolean
//Returns if the given building is finished, also works for building which are not used by the system
//Usage:
set boolean b = Resource.isBuildingFinished(yourBuilding)
//Parameters
building -> Your building
____________________________________________
method floatingValue(integer value, real x, real y)
//Creates a floating number in the resources colour at the given point
//Usage:
call yourResource.floatingValue(0,0.0,0.0)
//Parameters
value -> shown value
x -> x-coordinate of the value
y -> y-coordinate of the value
____________________________________________
API: Events
Code (vJASS):
Resource System
Version 1.3
Made by Verethragna (aka D1000)

//==================================================\\
//Methods for setting events. Events can be used instead of triggers (-> less triggers) and only react, when the player has enough resources
//                                                                                                     (or there aren't any resource-costs anyway)
//Don't forget to set 'USE_EVENTS' to 'true', if you want to use events.
//You can use 0 as function name, if you want to reset the event
//==================================================\\
___________________________________________
static method setCastEvent(integer id, ResourceEventCast callback)
//Sets the function, which is to be called, when the given ability is casted
//Usage:
call Resource.setCastEvent('type', functionName)
//Parameters:
id -> type-id of the ability which should trigger the event
callback -> Function which should be called
//Type:
public type ResourceEventCast extends function();
___________________________________________
static method setItemSaleEvent(integer id, ResourceEventItemSale callback)
//Sets the function, which is to be called, when the given item is bought by a unit
//Usage:
call Resource.setItemSaleEvent('type', functionName)
//Parameters:
id -> type-id of the item which should trigger the event
callback -> Function which should be called
//Type:
public type ResourceEventItemSale extends function();
___________________________________________
static method setUnitSaleEvent(integer id, ResourceEventUnitSale callback)
//Sets the function, which is to be called, when the given unit is brought (not trained!)
//Usage:
call Resource.setUnitSaleEvent('type', functionName)
//Parameters:
id -> Id of the unit which should trigger the event
callback -> Function which should be called
//Type:
public type ResourceEventUnitSale extends function();
___________________________________________
static method setTrainEvent(integer id, ResourceEventTrain callback)
//Sets the function, which is to be called, when the given unit/upgrade is trained/researched
//Usage:
call Resource.setTrainEvent('type', functionName)
//Parameters:
id -> Id of the unit or upgrade which should trigger the event
callback -> Function which should be called
//Type:
public type ResourceEventTrain extends function();
___________________________________________
static method setBuildOrderEvent(integer id, ResourceEventBuildOrder callback)
//Sets the function, which is to be called, when a unit is ordered to construct the given building
//Usage:
call Resource.setBuildOrderEvent('type', functionName)
//Parameters:
id -> Id of the building which should trigger the event
callback -> Function which should be called
//Type:
public type ResourceEventBuildOrder extends function();
___________________________________________
method setMineEvent(ResourceEventMine callback)
//Sets the function, which is to be called, when the given resource is mined
//Usage:
call yourResource.setMineEvent(functionName)
//Parameters:
callback -> Function which should be called
//Type:
public type ResourceEventMine extends function(Resource, unit, widget);
//Type-Parameters:
Resource -> The resource this reacts to
unit -> The mining unit
widget -> The unit, item or destructable which is mined
___________________________________________
method setReturnEvent(ResourceEventReturn callback)
//Sets the function, which is to be called, when the given resource is brought to a storage
//Usage:
call yourResource.setReturnEvent(functionName)
//Parameters:
callback -> Function which should be called
//Type:
public type ResourceEventReturn extends function(Resource, unit, integer, unit);
//Type-Parameters:
Resource -> The resource this reacts to
unit -> The unit, which brings the resource
integer -> Amount of the resource, which is brought
unit -> The storage-unit
___________________________________________

Known Problems
Code (vJASS):
|____________________________________________________________________________________________________
|"Bugs which are known to me, but I don't know how to fix:"|
|____________________________________________________________________________________________________
|• No Rally-Point-Support
|• Nearest storage/resource is determined via beeline, thus there are problems if the way is blocked
|   (Could solve this with a path-finding-algorithm, but it would probably need to much computing)
|• Trying to buy an item/merc without having enough of a custom resource reduces the item/merc stock by 1

|____________________________________________________________________________________________________

Changelog
Code (vJASS):
_____________________________________________
|'v1.3 - December 22th, 2011'|
|'Bugs fixed:'|
|---
|'New features:'|
|• Text displayed when trying to buy something with insufficient resources is now changeable
|• Added "getColour"-method
|• Added events (see "ResourceSystem API Events" for details)
|• Added comments to the examples
|• "floatingValue"-method is now public accessible (see "ResourceSystem API Misc" for details)
|'Other changes:'|
|• Fixed mistakes in the Readme
|• The system now requires only one hashtable, instead of one plus one per resource
|• Restructured Readme in multiple files
|• Changed "Known Bugs" to "Known Problems"
_____________________________________________
|'v1.2 - July 20th, 2011'|
|'Bugs fixed:'|
|---
|'New features:'|
|• "GetUnitCollisionSize" now has functions for units and unittypes
|• Commented the textmacros
|• Added import instructions to the readme
|'Other changes:'|
|• Improved "GetCollisionSize" and renamed it to "GetUnitCollisionSize"
|• Changed the respective function-calls in the resource-system
|• Now using GroupUtil´s "ENUM_GROUP" instead of creating a new group in some cases
|• Renamed the Readme, Changelog & Known Bugs, to avoid name-conflicts with other systems
_____________________________________________
|'v1.1 - June 25th, 2011'|
First release on "http://www.hiveworkshop.com" (english)
|'Bugs fixed:'|
|• Fixed an issue involving "smart"-orders targetting items
|'New features:'|
|• Added "Changelog"
|• Added "Known Bugs"
|'Other changes:'|
|• Made the methods "minimizeMultiboard" and "showMultiboard" static
|• Changed my name in the description and everywhere else to the more up-to-date "Verethragna"
|• Tried to add rally-point-support, failed
_____________________________________________
|'v1.0 - July 6th, 2010'|
First release, only on "http://warcraft.ingame.de/forum/showthread.php?t=203327" (german)
'Bugs fixed:'|
|• Its not possible anymore to return resources to unfinished buildings
|'New features:'|
|• Resources can now be used to buy things like items or units...
|• ...and respective methods were added
|• added static method "isBuildingFinished"
|'Other changes:'|
|• Now using TriggerAddCondition instead of TriggerAddAction
_____________________________________________
|'v0 - Somewhen between February 13th and 27th, 2010'|
Unfinished version, submitted to the "Trigger-it-Out"-Contest on "http://warcraft.ingame.de/forum/showthread.php?t=198065" (german)
|'Bugs fixed:'|
|---
|'New features:'|
|• Resource System
|• Readme
|• GetCollisionSize System
|'Other changes:'|
|---
_____________________________________________


Keywords:
Resource System, Resource, System, Verethragna, D1000, Custom Resource, ZinC
Contents

Resource System (Map)

Reviews
Moderator
10 Nov 2011 Bribe: Vexorian's GetUnitCollisionSize does not use game cache... it uses Table. Your re-write of it is still bad and GetUnitTypeCollisionSize does not need the textmacro it just needs to call the other function. Don't abuse textmaros....
  1. 10 Nov 2011
    Bribe: Vexorian's GetUnitCollisionSize does not use game cache... it uses Table. Your re-write of it is still bad and GetUnitTypeCollisionSize does not need the textmacro it just needs to call the other function. Don't abuse textmaros.

    I have no idea why you make this so complex. The code is so enormous in length that it makes it impossible to determine what code is superflous and what actually needs to be there.

    I will start with some things I can make sense out of:

    Textmacros... so many of them... makes the code impossible to read actually. A lot of very similar functions that look to me from what I can tell could be structured very differently without the need to make the system so complex.

    RegisterPlayerUnitEvent will help a lot.

    There are systems and snippets in general that could make your life easier, but I am going to require a PhD in your system to figure out how to give this thing a proper review.

    Right now I'm going to say "it works" and I can't spot any critical room for error without that PhD, so I recommend adjusting that Collision library and meanwhile, your resource is now approved.
     
  2. Justify

    Justify

    Joined:
    Mar 16, 2008
    Messages:
    935
    Resources:
    5
    Models:
    1
    Icons:
    1
    Spells:
    3
    Resources:
    5
    Hey, you finished the system. I was realy sad that such a perfect system was unfinished and unusable although it had such a nice code. Well done ;)
     
  3. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    OMG

    Code (vJASS):
                private static thistype number, tempResource;
                private static boolexpr addWorkerPick, addStoragePick, searchSourcePickUnit, searchSourcePickItem, searchSourcePickDestructable, searchStoragePick, allBuildings;
                private static rect wholeMap;
                private static integer tempType;
                private static real tempDistance, tempX, tempY;
                private static trigger inRange, trainCancelled, constructionCancelled, orderGiven;
                private static multiboard properties[12];
                private static widget tempWidget;
                private static unit tempUnit;
               
                private string name,
                                        icon,
                                        colour = "";
                private hashtable data = InitHashtable();
                private integer amount[0x10];
                private boolean onKill;
               
                private static constant integer AMOUNT_CARRIED = 0,
                                                                    GAIN_PER_HIT = 0x10,
                                                                    DAMAGE = 0x20,
                                                                    FARM_TYPE = 0x30,
                                                                    SPEED = 0x40,
                                                                    ANIMATION = -1,
                                                                    COSTS = -2,
                                                                    BUY_TYPE = -3,
                                                                    CURRENTLY_BUILDING = -4,
                                                                    FINISHED = -5,
                                                                   
                                                                    SOURCE = 0,
                                                                    MINER = 2,
                                                                    MINER_STRUCT = 3,
                                                                    STORAGE = 4,
                                                                   
                                                                    ORDER_SMART = 851971;
     


    You abused the Same-Line-Same-Type feature :p
    Please don't that >.< xD
     
  4. D1000

    D1000

    Joined:
    Jun 22, 2008
    Messages:
    53
    Resources:
    3
    Spells:
    3
    Resources:
    3
    I should stop using a different font in my editor, everything I format looks just stupid for everyone else xD


    I thought that's what it's for

    I uploaded the finished version about a year ago on InWc, but no one seemed to care about it (at least nobody wrote a comment for a whole year...)
     
    Last edited: Jun 27, 2011
  5. Justify

    Justify

    Joined:
    Mar 16, 2008
    Messages:
    935
    Resources:
    5
    Models:
    1
    Icons:
    1
    Spells:
    3
    Resources:
    5
    InWc has a nice small community, but there are to less people with enough knowledge to cherish something like this. It's the reason why im even more inactive then already here D:
     
  6. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Yup, but here, it affects readability :p
     
  7. cedi

    cedi

    Joined:
    May 19, 2008
    Messages:
    165
    Resources:
    7
    Icons:
    2
    Spells:
    5
    Resources:
    7
    Sadly that the people doesn't see how much effort and time D1000 used for this system and don't even rate such a welldone and nice system. Not even one of the mods looked at it...

    Its also sad that the people would be much more responsive if it was done in GUI. But we can't anticipate more from a community full of GUI'ler which don't even try to understand the beauty and very good performance of a system done in a improved language and by a good coder.

    Anyway. You showed me this a year ago and its still the best and only ressource system on this site.

    +RP and 5/5
     
  8. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    7,994
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    I can appreciate the work he put into this system the only issue is the
    steep learning curve it's not something that you can just drag and drop
    into a map like most resources.

    This thing really deserves more attention.
     
  9. D1000

    D1000

    Joined:
    Jun 22, 2008
    Messages:
    53
    Resources:
    3
    Spells:
    3
    Resources:
    3
    I won't use the original one, since it doesn't use hashtables, but I'll rewrite mine.

    Okay, I'll change that too

    The multiboard can be hidden

    What do you mean?

    I Think they make it easier to read...

    Thanks^^
     
  10. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    7,994
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    It produces thousands of lines of text. But based on what I've seen so far
    it might be worth it anyway.

    Writing in textmacros is like writing in Perl - almost always it's only the
    person who created the code is able to read the code.
     
  11. D1000

    D1000

    Joined:
    Jun 22, 2008
    Messages:
    53
    Resources:
    3
    Spells:
    3
    Resources:
    3
    Well, they DO make the code shorter, so I don't want to remove them
    But I commented them in the new version, I uploaded a few hours ago

    /€: About the textmacros in the CollisionSize system: well, it's one function-call less this way^^
     
    Last edited: Dec 24, 2011
  12. JollyD

    JollyD

    Joined:
    Jun 13, 2011
    Messages:
    1,272
    Resources:
    112
    Icons:
    111
    Skins:
    1
    Resources:
    112
    useful!
     
  13. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    You know, this system can be replaced entirely with this:

    Code (vJASS):
    //! zinc

    public struct Resource[] {
        private static integer stack = 0;
        private integer amount;
        method add(integer i) {
            this.amount += i;
        }
        method subtract(integer i) {
            this.amount -= i;
        }
        method get()->integer {
            return this.amount;
        }
        method set(integer i) {
            this.amount = i;
        }
        static method create()->thistype {
            stack++;
            return stack;
        }
    }

    //! endzinc


    This way, ANYONE wanting to add an extra resource to his map could use this and do anything.
     
  14. D1000

    D1000

    Joined:
    Jun 22, 2008
    Messages:
    53
    Resources:
    3
    Spells:
    3
    Resources:
    3
    Soo your snippets allows you to
    • assign workers to the resource, which automatically search for assigned sources and bring them to an assigned storage after an assigned time
    • buy items, units, upgrades and buildings with this resources
    • show the resources in sepparate multiboard for each player
    and a few more details?

    (sorry for the mistakes, i'm writing this on a mobile)

    /€: did you even take a look at the API or the Testmap?
     
  15. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Yes I did, and that API is what limited the user.

    This is a solution:

    You can take code and a player unit event from the user, then convert the code to a boolexpr and store it in a Table.
    Then you'd store the event in another Table using the same index you used for the boolexpr and you'd use an integer to track the number of boolexprs you added for a certain instance.
    And then, you'd just have to call RegisterPlayerUnitEvent(playerunitevent, function onEvent)

    onEvent would be a function inside your library. You'd loop through all the Resources (start at 1 and exit the loop when the instance is greater than stack).

    You should nest a loop in it that would loop from index 0 to "number of boolexprs" for a certain instance. Then, you'd check if the event loaded from the Table with this index is equal to the Triggering trigger's event, and if that's true, call ForceEnumPlayersCounted(TEMP_FORCE, boolexpr, 1) to evaluate the boolexpr. (Or you can call FireCondition(boolexpr) with this http://www.hiveworkshop.com/forums/submissions-414/snippet-needs-work-firecode-208389/)
    Exit the loop if your index becomes equal to the number of boolexprs.

    Note: TEMP_FORCE is a global force set to CreateForce(). (I know setting it to bj_FORCE_PLAYER[0] saves a handle, but that would totally ruin the force itself killing all other systems that use it.

    That would be efficient and it would have the useful features.

    As for the multiboard, a lot of users aren't going to need one.
     
  16. cedi

    cedi

    Joined:
    May 19, 2008
    Messages:
    165
    Resources:
    7
    Icons:
    2
    Spells:
    5
    Resources:
    7
    As for the multiboard, a lot of users aren't going to need one.

    LAL, seriously? But you're right, why should anyone want a multiboard that shows him how much of what ressources he has? No one needs that ...

    And btw. most events this system uses are not existing as a hardcoded event. So you can't register them for the units.

    Also the system is really easy to use at the moment, but if D1000 would change the code to fit it your suggeston, no GUI user would ever be able to use it, because they had to write most of the code by themselves and not only copy and paste a few lines.

    Next if you want a system that isn't limited by an API then you should write it yourself. This system is made for people that don't have the skill or the time to do it by themselves.

    Last I think you coded you're system and you're really proud of it, gratz. I don't have a problem with that, but suggesting that you're way is the best and telling the author to rewrite all the code of his well working system only to find you're approval is what I don't like.
     
  17. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    I was suggesting a rewrite because most of the code is really messy.
    It's a good system at the moment, but why would GUI users use a vJass system?
    Most of the GUIers I know only like using GUI systems and have problems implementing Jass scripts because a lot of them don't know how to create a trigger with custom text and there are even more who don't know where the map header is.

    The majority of the people who could benefit from using this are the vJassers.
    And vJass has a lot of standards.

    GUI users are more comfortable using GUI systems like Bribe's UnitIndexer which he wrote in GUI-Jass (A combination of the 2)

    Plus, any GUIer who uses this system would be expected to know the least bit about Jass, so modifying anything isn't a problem. And who said anything about Breaking backwards compatibilty? You can keep the current API and add to it, then rewrite the old functions so that they'd just call the new ones.
     
  18. D1000

    D1000

    Joined:
    Jun 22, 2008
    Messages:
    53
    Resources:
    3
    Spells:
    3
    Resources:
    3
    To summarize your comments:
    First you wrote:
    This statement is nothing but wrong. Your snippet isn't able to do even remotely the same. If you think it does, you didn't look at the testmap at all.

    Later you wrote:
    Well, if you think so, please explain what you mean. Otherwise it's just a plain insult.

    The other comment between these two, was at least a bit constructive.
    [link]
    But I'm not sure I get what you're writing about. Either you're talking about the whole system, or about the events. If it's the former, I have no idea what you mean, in the case of the latter it's nonsense. Firstly, not all of the events can be registered with TriggerRegisterPlayerUnitEvent, since some of them (Hit, Return) don't exist without my system. Secondly the whole purpose of the other events is, that you don't have to use TriggerRegisterPlayerUnitEvent & to trigger your function only, if you have enough resources (if there were any resource-costs assigned to the given unit/ability/item/upgrade/building), since, for example, EVENT_PLAYER_UNIT_SPELL_CAST triggers, even when you don't have enough resources to cast your spell. (The system can't stop the cast completely, but just order the casting unit stop it instantly. Effects from the object editor are stopped this way, triggers are not.)
    Furthermore the events are nothing but a small extra.


    Btw, @Bribe:
    Where? In my init function? It will just
    1) Add an additional function-call per trigger
    2) Use a separate loop for all of the triggers, instead of using one big loop
    Maybe it reduces the amount of TriggerRegisterPlayerUnitEvent in the whole map, but just for my system alone, it doesn't make sense, no event is used twice.
     
  19. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Ofcourse it's not going to cover everything. What do you expect me to do? Rewrite the entire thing? I just gave you the basis of what it should look like to be more versatile.
    You can add all those little functions like getIcon into it.

    Well, I'm not trying to insult you here. It's not your fault, it's Zincs fault.
    The least you could do is add more comments at the core of the code and put more linebreaks so that it's easier to read.
    And if you remove it from the hidden tag, it will look a lot better (The font is ugly inside hidden tags)

    And to think I'd invest my time to insult you, is an insult to me :(

    You know, TriggerRegisterAnyUnitEventBJ is one of the very few BJs we're ok with using :/
    It does nothing for efficiency, but it decreases code size, which is a plus.
    If you use RegisterPlayerUnitEvent, you wouldn't need those TriggerAddCondition lines and you wouldn't need those triggers.