Can't create custom units using their string name.

Status
Not open for further replies.
Level 4
Joined
Nov 13, 2019
Messages
47
Hey I'm trying to use this action


Unit - Create 1.(Unit-type(Grunts)) for (Owner of AttackerHero) at (Center of L5 <gen>) facing 180.00 degrees

I have a custom unit named "Grunts" which I would like to create, defining the type with just a string which is supposed to be its name, but this doesn't work. I've tried other names etc

QC0Lq9G.jpg


gog4DcW.jpg



If I try to spawn any of the default Melee units with a string Ie- "Footman" or "Grunt" this works without issue.

Has anyone encountered this before? Am I missing something?
 
Level 4
Joined
Nov 13, 2019
Messages
47
I'm creating a system where your hero carries his army with him in his inventory until it's time for combat. Each unit has a corresponding item with the exact same name of the unit it represents. Also each charge of the item = one actual unit.

Basically when it's time for combat I wanted to Create units on the battlefield based on the name of the items in his inventory. That's why I need strings to work.

It saves me a lot of time to do it this way, instead of "If hero carries "Grunts" item in slot 1, create "Grunts" unit equal to number of charges on item carried by hero in slot 1". Creating one trigger for each inventory slot and for each unit type in my game isn't optimal because there will be many.

Hope that made sense!
 
Last edited:
The strings appears to be hardcoded into the engine and cannot be changed/added upon.

constant native UnitId takes string unitIdString returns integer
is the native function that's handling the unit-type string request and it returns an unique integer that represent the string input (if found).

Any custom string of a custom unit name will return 0 as far as my tests go, but any original unit have an integer value attached to them.

Unless the unique integer returned from the UnitId native matches the raw data of the requested unit, the unit cannot be created (raw data can be seen in the object editor, pressing Ctrl + D).

See example below:
  • StringUnitTypeTest
    • Events
      • Time - Elapsed game time is 1.00 seconds
    • Conditions
    • Actions
      • Custom script: call BJDebugMsg("Grunt:")
      • Custom script: call BJDebugMsg(I2S(UnitId("Grunt"))) // Original grunt name
      • Custom script: call BJDebugMsg(I2S('ogru')) // The raw data for the original grunt
      • Custom script: call BJDebugMsg(" ")
      • Custom script: call BJDebugMsg("Grunts:")
      • Custom script: call BJDebugMsg(I2S(UnitId("Grunts"))) // Custom grunt with custom name
      • Custom script: call BJDebugMsg(I2S('o000')) // Raw data for our custom grunt
This trigger results in:
WC3ScrnShot_111619_183422_01.png
 
Level 45
Joined
Feb 27, 2007
Messages
5,578
The best way to store this relational item->utype data is going to be in a hashtable. For each pair, save the utype using the item type corresponding to it as a key (at map init). Then when a unit uses an item you input it’s itype as a key into the hashtable and out pops the proper unit type, no searching or if-blocks required.
 
Level 4
Joined
Nov 13, 2019
Messages
47
Thanks for the help guys
Excellent research there @lolreported. Looks like I have to abandon the string idea, unless maybe instead of creating custom units I edited the default ones to my need?

@Pyrogasm Actually the items are never going to be "used" for other than just being a reference to what and how many units the hero is carrying. If you have played any of the Heroes of Might and Magic games it's going to be a similar system. Checking the item and how many charges there are, then creating a single unit on the battlefield and multiplying its stats by X amount of charges the item has.

I havent used Hashtables before, do you mind showing an example of what a trigger would look like in the GUI?

PZgOiAt.png


(Note: Human hero is carrying both units atm because I haven't made the triggers for the Orc hero)
 
Last edited:
Level 4
Joined
Nov 13, 2019
Messages
47
There's probably a better way to do this, but the way I solved this problem is by creating a Hashtable and storing each unit type in it, then I load the desired unit by checking how much Hit Points the item carried by the hero has.
I.e. if Footmen unit type is 1 of 1 on my hashtable, I set the Footmen item to have 1 hit points. Then:

  • Unit - Create 1.(Unit-type of (Load (Item: (Item carried by AttackerHero in slot 1)'s Integer Field: Hit Points ('ihtp')) of (Item: (Item carried by AttackerHero in slot 1)'s Integer Field: Hit Points ('ihtp')) in UnitToItemCorrelation_HT.)) for (Owner of AttackerHero) at (Center of B2 <gen>) facing 0.00 degrees
Grunts are 2 of 2, so the item has 2 Hit Points and so on..

The laborious task in doing it this way is to store each unit type on map init, but at least I only have to do it once.
 
Level 45
Joined
Feb 27, 2007
Messages
5,578
The way you are doing it you might as well just use a unit-type array with the same indices. The advantage of the hashtable would be actually using the item type as the key instead.

  • Set Itype = Grunt Item
  • Set Utype = Grunt Unit
  • Custom script: set udg_Int_Itype = udg_Itype
  • Custom script: set udg_Int_Utype = udg_Utype
  • Hashtable - Save Int_Utype as Int_Itype of 0 in HASHTABLE
  • -------- --------
  • -------- --------
  • Set Itype = (Item carried by (Triggering Unit) in slot 1)
  • Custom script: set udg_Int_Itype = udg_Itype
  • Set Int_Utype = (Load Int_Itype of 0 from HASHTABLE)
  • Custom script: set udg_Utype = udg_Int_Utype
  • Unit - Create 1 Utype...
The reason the custom scripts are necessary is because GUI doesn't allow you to save 'unit type' or 'item type' in hashtables, nor will it allow you to use them as keys. They're really just integers anyway so we just store them as integers and assign variables with JASS. Itype is an item type, Int_Itype is an integer; Utype is a unit-type, Int_Utype is an integer. Those are 'save/load integer' hashtable actions.
 
Status
Not open for further replies.
Top