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

Baradé's Resources 1.0

This bundle is marked as pending. It has not been reviewed by a staff member yet.
Motivation
Many other real time strategy games use additional resource types. For example, Warcraft II had the additional resource type Oil and games like Age of Empires have even more different resource types. There is already several systems to support custom resources in Warcraft III. However, I wanted a very specific kind of system for my own map which uses units instead of destructibles as mines and emulates the behavior of Warcraft II for Oil which includes the harvest bonus after building an Oil Refinery. Other systems do not necessarily show the amount of harvested resources on workers or the amount on mines. This system provides all of these features.

Usage
Use the folder "Resources" from the triggers of the example map in your own map.
Libraries for the multiboard, GUI, costs, warnings and chat commands can simply be disabled.
They are all optional if you use this system.

Use the following code to register a custom resource:
JASS:
globals
    Resource Oil
endglobals

...

set Oil = AddResource("Oil")
call SetResourceGoldExchangeRate(Oil, 2.0)
call SetResourceIcon(Oil, "ReplaceableTextures\\CommandButtons\\BTNOil.blp")
call SetResourceIconAtt(Oil, "ReplaceableTextures\\ATTOil.blp")
call SetResourceColorRed(Oil, 50)
call SetResourceColorGreen(Oil, 50)
call SetResourceColorBlue(Oil, 50)
The name is used in GUIs/multiboards.
The gold exchange rate is used when selling/buying Oil for example with chat commands.
The icons are used in GUIs/multiboards.
The colors are used for the floating texts which appear when you harvest the resource.

Use the following code to add warnings for a resource:
JASS:
call SetNotEnoughResourcesSoundForAllPlayers(Oil, gg_snd_GruntNoOil1)
call SetResourceLowValue(Oil, 1500)
call SetLowResourcesSoundForAllPlayers(Oil, gg_snd_GruntOilPlatformLow1)
call SetLowResourcesMessageForAllPlayers(Oil, "A Oil Platform is running low.")
call SetCollapsedResourcesSoundForAllPlayers(Oil, gg_snd_GruntOilPlatformCollapsed1)
call SetCollapsedResourcesMessageForAllPlayers(Oil, "A Oil Platform has collapsed.")
The sounds are played for the player and all of the allies with shared unit control when you have not enough of the resource or your mines are running low or collapsed.
The low value determines when a mine is running low.
You can also set this per player for example when players have different races.
Use functions like SetNotEnoughResourcesSound and SetLowResourcesSound without the ForAllPlayers suffix to specify it per player.

Use the following code to register costs:
JASS:
call SetCosts('obot', Oil, 700)

call SetCosts('bspd', Oil, 200)
 
call SetResearchCostsForLevel('R000', 0, Oil, 1000)
call SetResearchCostsForLevel('R000', 1, Oil, 3000)
 
call SetAbilityCosts('A009', Oil, 150)
SetCosts can be used for units and items.
You can use SetResearchCosts without specifying the level instead of SetResearchCostsForLevel if your research has only one level.
SetAbilityCosts uses level 1 by default. You can use SetAbilityCostsForLevel if you want to specify the ability level.

Use the following code to add a worker:
JASS:
call AddWorker(worker)
call AddResourceToWorker(worker, Oil, 'A000', "harvest", 'A001', "roar", 'A004', "robogoblin", 100, 100, "gold")
AddResourceToWorker can be used to register any resources to the worker (multiple if you want to).
A000 is the harvest ability and "harvest" is the harvest order.
A001 is the return resources ability (without target) and "roar" is the return resources order (without target).
A004 is the hidden return resources ability (with target) and "robogoblin" is the hidden resources ability (with target).
"gold" is the animation property for the worker while carrying Oil.
The first 100 is the maximum amount of Oil which can be carried by the worker.
The second 100 is the amount of Oil which the worker gets from one gathering "hit".

The harvest and return abilities can be based on the Channel ability. Just look at the object data of the example map.

Use the following code to add a mine:
JASS:
call AddMineEx(mine, Oil, 20000)
It adds a mine only for Oil with 20 000 Oil in it.

You can add mines which allow to have exactly 1 worker inside (like Warcraft III gold mines) with this code:

JASS:
call SetMineTakeWorkerInside(mine, true)
call SetMineMaxWorkers(mine, 1)

It is recommended to give workers some harvest duration inside mines:
JASS:
call SetUnitHarvestDuration(worker, Oil, 2.0)

You can add return buildings with the following code:
JASS:
call AddReturnBuilding(whichUnit)
call AddUnitReturnResource(whichUnit, Oil)
You can add multiple return resources.

A shorter way to add a return building for only one resource is:
JASS:
call AddReturnBuildingEx(whichUnit, Oil)

Loaded mines can be added like this:
JASS:
call AddLoadedMine(mine, Oil, 50000, 10)
call AddLoadedMineWorkerUnitTypeId(mine, 'o006')
call AddLoadedMineWorkerUnitTypeId(mine, 'o007')
This will add a loaded mine with 50 000 Oil in it. For each worker inside you will get 10 Oil every 3 seconds. The interval is global for all loaded mines and can be modified in the library ResourcesLoadedMines.
Only the added worker unit types are allowed to be loaded into the mine.
Use Warcraft's cargo/load/unload abilities for the loaded mine building.

Example map
The example map has two Orc players: Yourself and your allied blue player with shared unit control
It contains the custom resources Oil, Rock and Wheat.
It uses Oil Platforms like in Warcraft II where Oil Tankers disappear inside the Oil Platforms to harvest (like Warcraft III gold mines).
Custom resources costs are written down in tooltips.
Return buildings like Oil Refineries give a harvesting bonus to the player.
Wheat has the same upkeep levels as gold.
Oil and Rock have no upkeep levels.
You have shared unit control with blue and see/hear all of the messages related to custom resources.
Use the chat command "-hr" to list all available chat commands.
You can use chat commands like "-ask 5000 oil blue" to receive 500 Oil from blue or "-give 5000 oil blue" to give blue 5000 Oil.
Asking works with all allied Computer players.
The building Trading Post allows buying/selling custom resources instead of using chat commands.
Rock Mine Shafts can be built on top of Rock Mines and be used as loaded mines similar to the Entangled Mines of Night Elf.

Features
- Add almost any number of custom resources. The limit is only given by JASS and vJass limits and by the number of columns in multiboards/your map.
- Taxes per player like for gold in Warcraft III.
- Automatic orders after constructing return buildings like lumber mills to return carried resources and find a new mine.
- Rally point support: Automatic ordering to mines targeted by rally points.
- Disabled unit pathing for harvesting workers like in Warcraft III to avoid blocking each other.
- Mines disappearing workers inside and a maximum number of workers inside.
- Player resources multiboard.
- Team resources multiboard.
- Shared unit control support: Error messages and sounds are seen and heard by all allies with shared unit control.
- Custom UI showing the resources of mines and carried by workers including player bonuses. It shows up to two different carried resources per worker (space limitations of the UI).
- Harvesting bonuses per players like it is provided in Warcraft II for Oil and lumber.
- Register costs for building, unit, item, ability and research types per player.
- Warning sounds and messages for missing resources, low and empty mines.
- Chat commands to buy, sell, exchanging resources. All chat commands can be listed with the chat command "-hr".
- Loaded mines support similar to Night Elf and Undead races with Warcraft's cargo abilities.

Future Work
- Wisp like worker support occupying the mine which can currently be done with a loaded mine and a cargo size of 1.
- Destructible mines like trees.
- Refactoring: For example, instead of using all the hashtable keys I could introduce the structs Mine and Worker and move the fields there.
- Professional announcer voice for the example map. :cool:2
Contents

Baradé's Resources 1.0 (Map)

Reviews
Wrda
Resources script: The first condition seems redundant, since "slotPlayer" will inevitably be "owner", which you are already adding beforehand. This is essentially the same, the first one can become the second if amount is negative. Simplify it...
Level 25
Joined
Feb 2, 2006
Messages
1,689
Thx it still needs some polishing.

Updates:
  • Added a check for the target pathing of mines and return buildings. It has to match the movement type of the worker now. Previously, a floating worker could return resources to a ground/land return building. This should be fixed now.
  • Add JASS function GetSingleSelectedUnit and use it to successfully detect the only selected unit per player for showing/hiding the custom GUI.
  • Always prefer harvested resources for the two resources shown in the custom GUI.
 
Last edited:
Level 25
Joined
Feb 2, 2006
Messages
1,689
I could add more example resources. However, it is just an example map on how to use the system and adding too many resources will probably make the multiboard unusable at some point. In my own map I have like 10 custom resources and only use multiboards for your own resources not the team ones.

I don't think there is any easy way to do this. The existing system I checked out also had it written in tooltips. You would have to modify the tooltip frame.

However, you can write a custom UI for shops etc. and add something like that.
 
Level 18
Joined
Nov 19, 2008
Messages
474
I could add more example resources. However, it is just an example map on how to use the system and adding too many resources will probably make the multiboard unusable at some point. In my own map I have like 10 custom resources and only use multiboards for your own resources not the team ones.

I don't think there is any easy way to do this. The existing system I checked out also had it written in tooltips. You would have to modify the tooltip frame.

However, you can write a custom UI for shops etc. and add something like that.
Thanx for your reply,your resource and the sound system are really great useful ~ Wish you can produce more like those.
 
Level 25
Joined
Feb 2, 2006
Messages
1,689
Changes:
  • Fix hitting resources more than once.
  • Fix showing/hiding resources UI.
  • Do not show stop message on targeting loaded mines for harvesting.
  • Allow harvesting from loaded mines which do not belong to you.
  • Allow ignoring players in resources multiboard.
  • Custom resource Ore with loaded mines.
  • Shredder like unit Drillbot to harvest Rock based on Goblin Drillbot 3000.
 
Level 18
Joined
Nov 19, 2008
Messages
474
Big updates! ~ Love to see you still do the works to improve your system~ And Chronicles of the Second War was released . in that mod they used more or less the same system . But they put the oil resource icon on the origin UI frame to instead the multiboard . I really wish you can solve the new custom resource on UI tiptools . Maybe this can be more like your sound system , We can set a unit custom resources cost in the codes.

You really did a great job~
 
Level 25
Joined
Feb 2, 2006
Messages
1,689
Big updates! ~ Love to see you still do the works to improve your system~ And Chronicles of the Second War was released . in that mod they used more or less the same system . But they put the oil resource icon on the origin UI frame to instead the multiboard . I really wish you can solve the new custom resource on UI tiptools . Maybe this can be more like your sound system , We can set a unit custom resources cost in the codes.

You really did a great job~
thx
I was thinking about providing some custom UI instead of the multiboard below the resource icons but the multiboard also shows allied resources.

There might be some way to access the tooltip frame similar to CustomConsoleUI but even if that would work I would need to get which tooltip you are looking at (maybe one can extract the text from the frame) to show the correct cost.
 
Level 18
Joined
Nov 19, 2008
Messages
474
thx
I was thinking about providing some custom UI instead of the multiboard below the resource icons but the multiboard also shows allied resources.

There might be some way to access the tooltip frame similar to CustomConsoleUI but even if that would work I would need to get which tooltip you are looking at (maybe one can extract the text from the frame) to show the correct cost.
Thanx for your reply ~ "I was thinking about providing some custom UI instead of the multiboard below the resource icons but the multiboard also shows allied resources" this is brilliant ! I agree with this , cause if you are playing melee mode , the enemy's resources shouldnt be shown with ours . I wish you can improve this much better ! I found this maybe it can give you some ideas~ResourceBar ItemShop
Sadly the attention to this spells section is too low now , but your system is really good and useful ~
 
Last edited:

Wrda

Spell Reviewer
Level 26
Joined
Nov 18, 2012
Messages
1,888
Resources script:
JASS:
private function GetAlliesWithSharedControl takes player owner returns force
    local force allies = CreateForce()
    local player slotPlayer = null
    local integer i = 0
    call ForceAddPlayer(allies, owner)
    loop
        exitwhen (i == bj_MAX_PLAYERS)
        set slotPlayer = Player(i)
        if (slotPlayer == owner or GetPlayerAlliance(owner, slotPlayer, ALLIANCE_SHARED_ADVANCED_CONTROL)) then
            call ForceAddPlayer(allies, slotPlayer)
        endif
        set slotPlayer = null
        set i = i + 1
    endloop
    return allies
endfunction
The first condition seems redundant, since "slotPlayer" will inevitably be "owner", which you are already adding beforehand.
JASS:
function AddPlayerResource takes player whichPlayer, Resource resource, integer amount returns nothing
    call SetPlayerResource(whichPlayer, resource, GetPlayerResource(whichPlayer, resource) + amount)
endfunction

function RemovePlayerResource takes player whichPlayer, Resource resource, integer amount returns nothing
    call SetPlayerResource(whichPlayer, resource, IMaxBJ(0, GetPlayerResource(whichPlayer, resource) - amount))
endfunction
This is essentially the same, the first one can become the second if amount is negative. Simplify it.

JASS:
function AddMine takes unit whichUnit returns nothing
    call GroupAddUnit(mines, whichUnit)
    call SetMineWorkers(whichUnit, CreateGroup())
endfunction
I suppose SetMineWorkers shouldn't be called if unit is already in unit group, it would also leak a new group.

JASS:
function AddWorker takes unit whichUnit returns nothing
    local integer i = 0
    local integer max = GetMaxResources()
    call GroupAddUnit(workers, whichUnit)
endfunction
Unused variables.
JASS:
function CustomBountyEx takes unit worker, player whichPlayer, Resource resource, integer amount returns nothing
    call AddPlayerResource(whichPlayer, resource, amount)
    call CustomBountyFadingText(worker, resource, amount)
endfunction

function CustomBounty takes unit worker, Resource resource, integer amount returns nothing
    call CustomBountyEx(worker, GetOwningPlayer(worker), resource, amount)
endfunction
There's a risk of conflicting names with an actual custom bounty, related to unit kills.
Also, You don't need to clear groups if you're going to destroy them.

GetUnitReturnResource returns a boolean, I think the name should somewhat reflect that, e.g. IsUnitReturnResource.
Likewise for GetUnitDisableStopMiningOnError.

JASS:
function NextReturnBuilding takes unit worker returns unit
    local group returnBuildings = CreateGroup()
    local Resource resource = 0
    local unit groupMember = null
    local real groupMemberDistance = 0.0
    local real distance = 0.0
    local unit result = null
    local integer i = 0
    local integer max = 0
    local integer j = 0
    local integer max2 = 0
    local boolean valid = false
    set filterWorker = worker
    call GroupEnumUnitsOfPlayer(returnBuildings, GetOwningPlayer(worker), Filter(function FilterFunctionReturnBuilding))
    set max = BlzGroupGetSize(returnBuildings)
    loop
        exitwhen (i == max)
        set groupMember = BlzGroupUnitAt(returnBuildings, i)
        //call BJDebugMsg("Checking return building "  + GetUnitName(groupMember))
        
        set valid = false
        set j = 0
        set max2 = GetMaxResources()
        loop
            exitwhen (j == max2)
            set resource = GetResource(j)
            //call BJDebugMsg("Resource "  + GetResourceName(resource) + " carrying " + I2S(GetUnitResource(worker, resource)))
            if (GetUnitReturnResource(groupMember, resource) and GetUnitResource(worker, resource) > 0) then
                //call BJDebugMsg("Enable for resource "  + GetResourceName(resource))
                set valid = true
            endif
            set j = j + 1
        endloop
        
        if (valid) then
            set groupMemberDistance = DistanceBetweenUnits(worker, groupMember)
            if (result == null or groupMemberDistance < distance) then
                set result = groupMember
                set distance = groupMemberDistance
            endif
        else
            //call BJDebugMsg("Disabled")
        endif
        set groupMember = null
        set i = i + 1
    endloop
    
    call GroupClear(returnBuildings)
    call DestroyGroup(returnBuildings)
    set returnBuildings = null
    
    return result
endfunction
Return early on valid being true. setting "groupMember" to null should be done outside of the loop.

JASS:
private function TimerFunctionReleaseWorkerFromMine takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer handleId = GetHandleId(t)
    local unit worker = LoadUnitHandle(h, handleId, 0)
    local unit mine = LoadUnitHandle(h, handleId, 1)
    local Resource resource = LoadInteger(h, handleId, 2)
    local integer amount = Gather(worker, mine)
    
    // did not explode
    if (IsUnitAliveBJ(mine)) then
        call ReleaseWorkerFromMine(worker, mine)
        //all BJDebugMsg("Release worker with resource " + GetResourceName(resource))
    endif
    
    //call BJDebugMsg("Show and order return ability " + GetObjectName(GetUnitReturnAbilityId(worker, resource)))
    call BlzUnitHideAbility(worker, GetUnitHarvestAbilityId(worker, resource), true)
    call BlzUnitHideAbility(worker, GetUnitReturnAbilityId(worker, resource), false)
    call IssueImmediateOrderById(worker, GetUnitReturnOrderId(worker, resource))
    
    call FlushChildHashtable(h, handleId)
    call PauseTimer(t)
    call DestroyTimer(t)
    call SetUnitQueueWorkerReleaseTimer(worker, null)
    set t = null
endfunction
Unused variable "amount".

JASS:
private function CancelUnitQueueWorkerReleaseTimer takes unit worker returns nothing
    local timer t = GetUnitQueueWorkerReleaseTimer(worker)
    if (t != null) then
        call FlushChildHashtable(h, GetHandleId(t))
        call PauseTimer(t)
        call DestroyTimer(t)
    endif
endfunction
Missing nulling inside the conditon. There are reference leaks (local unit not being nulled or being returned) also, including in some of the other scripts.

TriggerActionCast function:
JASS:
elseif (not gatherInside and foundResource != 0 and amount == 0 or HasMaxOfMineResources(worker, mine)) then // return resources if necessary
Amount is always 0 if gatherInside is true.


Barades Resource Multiboard Gui script:
JASS:
function ShowPlayerResourceMultiboard takes player whichPlayer returns nothing
    call MultiboardDisplay(GetPlayerResourceMultiboard(whichPlayer), true)
endfunction


function HidePlayerResourceMultiboard takes player whichPlayer returns nothing
    call MultiboardDisplay(GetPlayerResourceMultiboard(whichPlayer), false)
endfunction
This could be merged by adding a boolean parameter. Likewise for ShowAllPlayerResourceMultiboards, and the team multiboard.

JASS:
function ShowAllPlayerResourceMultiboards takes nothing returns nothing
     local integer i = 0
    loop
        exitwhen (i == bj_MAX_PLAYERS)
        call MultiboardDisplay(GetPlayerResourceMultiboard(Player(i)), false)
        set i = i + 1
    endloop
endfunction
Seems like an error, should be "true" and not "false".
This script is using StringUtils, but isn't requiring it.

Barades Resources Gui script:

JASS:
private function ShowResourcesUI takes player whichPlayer returns nothing
    call SetResourcesUIVisible(whichPlayer, true)
endfunction

private function HideResourcesUI takes player whichPlayer returns nothing
    call SetResourcesUIVisible(whichPlayer, false)
endfunction

private function ShowResourcesGatheredUI takes player whichPlayer returns nothing
    call SetResourcesUIGatheredVisible(whichPlayer, true)
endfunction

private function HideResourcesGatheredUI takes player whichPlayer returns nothing
    call SetResourcesUIGatheredVisible(whichPlayer, false)
endfunction
Again, can be reduced to 2 functions. ShowResourcesUI and HideResourcesUI are unused.

JASS:
private function GetPrimaryResourceEx takes unit mine, Resource ignore returns Resource
    local Resource resource = 0
    local Resource result = 0
    local integer current = 0
    local integer currentMax = 0
    local integer v = 0
    local integer w = 0
    local integer i = 0
    local integer max = GetMaxResources()
    loop
        exitwhen (i == max)
        set resource = GetResource(i)
        if (resource != ignore) then
            set v = GetUnitResource(mine, resource)
            set w = GetUnitResourceMax(mine, resource)
            if (v > current) then
                set result = resource
                set current = v
            elseif (not IsStandardResource(resource) and current == 0 and w > currentMax) then
                set result = resource
                set currentMax = w
            endif
        endif
        set i = i + 1
    endloop
    return result
endfunction
I'd appreciate better variable names than 'v' and 'w'.
All Frames are using absolute point, the same parent and frame level. You should use more BlzFrameSetPoint as it sets a frame relative to another without worrying too much about many variables of positioning. You won't need to set frame level if you make most frames as child frames of the two main frames. Hit me up if you need a clearer explanation to deal with frames.

Barades Resources Cost script:

Why is there SetCosts when there is SetObjectTypeResourcesCosts? Same thing with GetCostsForLevel and GetCosts.
Also, GetCosts has player parameter but SetCosts not? Not very consistent. You can have dedicated "ForPlayer" functions besides the "AllPlayer" ones.

JASS:
private function TimerFunctionCancel takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer handleId = GetHandleId(t)
    local unit whichUnit = LoadUnitHandle(h2, handleId, 0)
    call DisableCancelTriggers()
    call IssueImmediateOrderById(whichUnit, CANCEL_ORDER_ID)
    call IssueImmediateOrder(whichUnit, "stop") // for constructions
    call EnableCancelTriggers()
    call FlushChildHashtable(h2, handleId)
    call PauseTimer(t)
    call DestroyTimer(t)
endfunction

private function TriggerActionIssue takes nothing returns nothing
    local timer t = CreateTimer()
    call SaveUnitHandle(h2, GetHandleId(t), 0, GetTriggerUnit())
    call TimerStart(t, 0.0, false, function TimerFunctionCancel)
endfunction
Reference leaks on local variables, to name a few.

JASS:
private function GetUnitShop takes nothing returns integer
    return 'ngme' // This is the raw code for the goblin shop
endfunction

private function GetUnitSell takes nothing returns integer
    return 'Hpal' // This is the raw code for the paladin
endfunction
This is falling under the assumption that the shop and the hero has the abilities necessary for this to work. Most of the time users might not modify these units, but it can be risky.

JASS:
private function GetItemValueGoldFresh takes integer i returns integer
    local real x= 0
    local real y= 0
    local unit u1= CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), ('ngme'), x, y, 0) // INLINED!!
    local unit u2= CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), ('Hpal'), x, y - 100, 90) // INLINED!!
    local item a= UnitAddItemByIdSwapped(i, u2)
    local integer g1= GetPlayerState(Player(PLAYER_NEUTRAL_PASSIVE), PLAYER_STATE_RESOURCE_GOLD)
    local integer g2= 0
    call UnitDropItemTarget(u2, a, u1)
    set g2=GetPlayerState(Player(PLAYER_NEUTRAL_PASSIVE), PLAYER_STATE_RESOURCE_GOLD) - g1
    call SetPlayerState(Player(PLAYER_NEUTRAL_PASSIVE), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Player(PLAYER_NEUTRAL_PASSIVE), PLAYER_STATE_RESOURCE_GOLD) - g2)
    call RemoveUnit(u1)
    call RemoveUnit(u2)
    set u1=null
    set u2=null
    set a=null
    return g2
endfunction
Perhaps have the shop and the hero to be always the same units, just hidden, and then if required to get the gold amount, then show, move nearby, and get the gold difference.

Barades Resources Warnings Script:
JASS:
private function TriggerConditionGather takes nothing returns boolean
    local Resource resource = GetTriggerResource()
    local unit mine = GetTriggerMine()
    local unit worker = GetTriggerWorker()
    local player owner = GetOwningPlayer(worker)
    if (GetLowResourcesSound(owner, resource) != null and GetUnitResource(mine, resource) <= GetResourceLowValue(resource) and  GetUnitResource(mine, resource) + resource > GetResourceLowValue(resource)) then
        call StartSoundForAllies(owner, GetLowResourcesSound(GetOwningPlayer(GetTriggerWorker()), resource))
        call PingMinimapForAllies(owner, GetUnitX(mine), GetUnitY(mine))
        if (GetLowResourcesMessage(owner, resource) != null and GetLowResourcesMessage(owner, resource) != "") then
            call SimErrorForAllies(owner, GetLowResourcesMessage(owner, resource))
        endif
    endif
    if (GetCollapsedResourcesSound(owner, resource) != null and GetUnitResource(mine, resource) <= 0) then
        call StartSoundForAllies(owner, GetCollapsedResourcesSound(owner, resource))
        call PingMinimapForAllies(owner, GetUnitX(mine), GetUnitY(mine))
        if (GetCollapsedResourcesMessage(owner, resource) != null and GetCollapsedResourcesMessage(owner, resource) != "") then
            call SimErrorForAllies(owner, GetCollapsedResourcesMessage(owner, resource))
        endif
    endif
    set mine = null
    set worker = null
    set mine = null
    set owner = null
    return false
endfunction
(Double variable nulling ;) )

Barades Resources Chat Commands script:
JASS:
function GetResourceFromString takes string s returns Resource
    local string lower = StringCase(s, false)
    local integer index = S2I(s)
    local Resource resource = 0
    local integer i = 0
    local integer max = GetMaxResources()
    loop
        exitwhen (i == max)
        set resource = GetResource(i)
        if (StringCase(GetResourceName(resource), false) == lower) then
            return resource
        endif
        set i = i + 1
    endloop
    
    if (i >= 1 and i <= max) then
        return GetResource(i - 1)
    endif
    
    return 0
endfunction
I'm not sure why this belongs in another script other than the primary system. It might be used only in this script, but in reality it's another form of "GetResource" function.
local integer index = S2I(s) not being used.

I'm not sure but I didn't see Barades Resources Gui script's frames showing at all, even when enabled.
"Not enough X" sounds stop playing if one clicks the button again to train whatever unit that uses custom resources. IsSoundPlaying should prove useful here.
Documentation and a list of all the available API are missing, although you gave specific examples on the page and on a great demo map.
Please also provide links to the other resources on the page and/or in the map. And a changelog on the page/or in the map.
This resource should also have contains external material tag.

Took a while to review everything. 😅
 
Top