• 🏆 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!

Creating a legion td like map

Status
Not open for further replies.
Level 7
Joined
Feb 23, 2020
Messages
253
Hello everyone, i'd like to create a legion TD-like map. My knowledge with map development is good and i could manage most of it by myself.

What i dont know is how to save and store the units used each wave and re-create them, and how to lose the control of them while still getting the gold.

Thanks in advance! :)

Note: My experience with hashtables although is zero to none.
 
Level 25
Joined
Sep 26, 2009
Messages
2,381
how to save and store the units used each wave and re-create them
The basic idea is that you store the unit-type of each wave in an array. You fill the array at map initialization in such a way, that the array index corresponds to the wave's number
(i.e. index 1 = wave 1, index 5 = wave 5). You keep track of current wave number in an integer variable.
When you want to create new wave of creeps, you check the unit-type in the array under index of the new wave's number.

Variables
  • WaveCreepTypes: unit-type array
  • CreepType: unit-type
  • CurrentWaveNumber: integer
  • Map Ini
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set VariableSet CurrentWaveNumber = 0
      • -------- Wave 1 will create Footmen --------
      • -------- Wave 2 will create Knights --------
      • -------- Wave 3 will create Riflemen --------
      • Set VariableSet WaveCreepTypes[1] = Footman
      • Set VariableSet WaveCreepTypes[2] = Knight
      • Set VariableSet WaveCreepTypes[3] = Rifleman
Somewhere in a trigger that creates new wave:
  • Actions
    • Set VariableSet CurrentWaveNumber = (CurrentWaveNumber + 1)
    • Set VariableSet CreepType = WaveCreepTypes[CurrentWaveNumber]
    • -------- Creates 10 creeps for the selected wave --------
    • For each (Integer A) from 1 to 10, do (Actions)
      • Loop - Actions
        • Unit - Create 1 CreepType for some_player at some_location facing Default building facing degrees


how to lose the control of them while still getting the gold.
I am not sure if you are talking about receiving gold for killing creeps in a wave or talking about receiving gold for selling your own towers, so I will answer for both options :D

Receiving gold for killing creeps:
You can use the bounty system - in Object editor you can set gold and lumber bounty for each unit (see 'Stats - Gold/Lumber Bounty Awarded' fields). If you want a static bounty, then just set the amount in the '- Base' field and leave the '- Number of Dice' and '- Sides per Dice' fields as 0.
By default, only Neutral units award bounty, but you can override that via triggers. For example the below will award bounty to any player that kills player 2 (Blue)'s units:
  • Melee Initialization
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Player - Turn Gives bounty On for Player 2 (Blue)
Receiving gold for selling your own towers:
There are multiple approaches - starting from using some abilities to triggering the entire thing yourself. Other people may know of a better way, but what comes to my mind is using a modified version of the Alchemist Hero's Transmute ability. The cool thing about transmute is that it gives you a portion of the unit's original lumber and gold cost and you can configure how big that portion should be.

So the approach here would be as follows:
  1. Create an ability that does nothing and that requires no target. This will be an ability you give to your towers and that the player will click to sell the tower. Let's call it 'Sell Tower'
  2. Create a custom version of Transmute ability - make it non-hero spell, set mana cost and cooldown to 0, set the Lumber and Gold Cost factors (note: the default Gold Cost Factor is 0.8, but it is erroneously displayed as 1.0 in object editor, so if you want to get full refund for sold unit, set the factor to 1.001).
    1. Also make sure the 'Targets Allowed' field is set to friendly targets
  3. Create a dummy unit in object editor
  4. Create a trigger that fires when a tower starts casting the 'Sell Tower' ability
    1. In the trigger, create a dummy unit, give it the custom Transmute ability and order the dummy unit to cast Transmute on the tower that should be sold
    2. Cleanup
 
Level 7
Joined
Feb 23, 2020
Messages
253
The basic idea is that you store the unit-type of each wave in an array. You fill the array at map initialization in such a way, that the array index corresponds to the wave's number
(i.e. index 1 = wave 1, index 5 = wave 5). You keep track of current wave number in an integer variable.
When you want to create new wave of creeps, you check the unit-type in the array under index of the new wave's number.

Variables
  • WaveCreepTypes: unit-type array
  • CreepType: unit-type
  • CurrentWaveNumber: integer
  • Map Ini
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set VariableSet CurrentWaveNumber = 0
      • -------- Wave 1 will create Footmen --------
      • -------- Wave 2 will create Knights --------
      • -------- Wave 3 will create Riflemen --------
      • Set VariableSet WaveCreepTypes[1] = Footman
      • Set VariableSet WaveCreepTypes[2] = Knight
      • Set VariableSet WaveCreepTypes[3] = Rifleman
Somewhere in a trigger that creates new wave:
  • Actions
    • Set VariableSet CurrentWaveNumber = (CurrentWaveNumber + 1)
    • Set VariableSet CreepType = WaveCreepTypes[CurrentWaveNumber]
    • -------- Creates 10 creeps for the selected wave --------
    • For each (Integer A) from 1 to 10, do (Actions)
      • Loop - Actions
        • Unit - Create 1 CreepType for some_player at some_location facing Default building facing degrees



I am not sure if you are talking about receiving gold for killing creeps in a wave or talking about receiving gold for selling your own towers, so I will answer for both options :D

Receiving gold for killing creeps:
You can use the bounty system - in Object editor you can set gold and lumber bounty for each unit (see 'Stats - Gold/Lumber Bounty Awarded' fields). If you want a static bounty, then just set the amount in the '- Base' field and leave the '- Number of Dice' and '- Sides per Dice' fields as 0.
By default, only Neutral units award bounty, but you can override that via triggers. For example the below will award bounty to any player that kills player 2 (Blue)'s units:
  • Melee Initialization
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Player - Turn Gives bounty On for Player 2 (Blue)
Receiving gold for selling your own towers:
There are multiple approaches - starting from using some abilities to triggering the entire thing yourself. Other people may know of a better way, but what comes to my mind is using a modified version of the Alchemist Hero's Transmute ability. The cool thing about transmute is that it gives you a portion of the unit's original lumber and gold cost and you can configure how big that portion should be.

So the approach here would be as follows:
  1. Create an ability that does nothing and that requires no target. This will be an ability you give to your towers and that the player will click to sell the tower. Let's call it 'Sell Tower'
  2. Create a custom version of Transmute ability - make it non-hero spell, set mana cost and cooldown to 0, set the Lumber and Gold Cost factors (note: the default Gold Cost Factor is 0.8, but it is erroneously displayed as 1.0 in object editor, so if you want to get full refund for sold unit, set the factor to 1.001).
    1. Also make sure the 'Targets Allowed' field is set to friendly targets
  3. Create a dummy unit in object editor
  4. Create a trigger that fires when a tower starts casting the 'Sell Tower' ability
    1. In the trigger, create a dummy unit, give it the custom Transmute ability and order the dummy unit to cast Transmute on the tower that should be sold
    2. Cleanup
Thank you very much. Most of this is in my control, my biggest issue is how to restore the units after each wave. I searched to forum a bit and found this "Units like in Legion TD". But i still cant manage to figure out how to properly restore them only after each wave and not during the wave.
 
Level 7
Joined
Feb 23, 2020
Messages
253
So a wave of creeps can destroy your towers and you want to restore those towers back after the wave ends, is that correct?
Correct, just as in legion TD, you build the tower, they turn into units who fight the wave. And after each wave they are restored to their corresponding position
 
Level 25
Joined
Sep 26, 2009
Messages
2,381
You could use a standard array + indexing approach for this.
I think you need to keep track of up to 4 things when you want to restore the unit:
  1. Where you want to restore it
  2. What kind of unit it should be
  3. Which player owns the unit
  4. Which angle was the unit facing

You could try the following:
  • RestoreTower_MaxIndex: integer
  • RestoreTower_UnitType: unit-type array
  • RestoreTower_Angle: real array
  • RestoreTower_Location: point array
  • RestoreTower_Owner: player array
  • loopIndex: integer
  • Tower Gets Destroyed
    • Events
      • Unit - A unit Dies
    • Conditions
      • //Add your conditions here to make sure it is a user-controller tower that you want to restore
    • Actions
      • Set VariableSet RestoreTower_MaxIndex = (RestoreTower_MaxIndex + 1)
      • Set VariableSet RestoreTower_Angle[RestoreTower_MaxIndex] = (Facing of (Triggering unit))
      • Set VariableSet RestoreTower_Location[RestoreTower_MaxIndex] = (Position of (Triggering unit))
      • Set VariableSet RestoreTower_Owner[RestoreTower_MaxIndex] = (Triggering player)
      • Set VariableSet RestoreTower_UnitType[RestoreTower_MaxIndex] = (Unit-type of (Triggering unit))
  • Wave Ends
    • Events
    • Conditions
    • Actions
      • For each (Integer loopIndex) from 1 to RestoreTower_MaxIndex, do (Actions)
        • Loop - Actions
          • Unit - Create 1 RestoreTower_UnitType[loopIndex] for RestoreTower_Owner[loopIndex] at RestoreTower_Location[loopIndex] facing RestoreTower_Angle[loopIndex] degrees
          • -------- Below custom script removes location of the tower to prevent memory leak --------
          • Custom script: call RemoveLocation(udg_RestoreTower_Location[udg_loopIndex])
      • -------- Reset index back to 0 since all units have been restored --------
      • Set VariableSet RestoreTower_MaxIndex = 0
 
Level 7
Joined
Feb 23, 2020
Messages
253
You could use a standard array + indexing approach for this.
I think you need to keep track of up to 4 things when you want to restore the unit:
  1. Where you want to restore it
  2. What kind of unit it should be
  3. Which player owns the unit
  4. Which angle was the unit facing

You could try the following:

  • RestoreTower_MaxIndex: integer
  • RestoreTower_UnitType: unit-type array
  • RestoreTower_Angle: real array
  • RestoreTower_Location: point array
  • RestoreTower_Owner: player array
  • loopIndex: integer
  • Tower Gets Destroyed
    • Events
      • Unit - A unit Dies
    • Conditions
      • //Add your conditions here to make sure it is a user-controller tower that you want to restore
    • Actions
      • Set VariableSet RestoreTower_MaxIndex = (RestoreTower_MaxIndex + 1)
      • Set VariableSet RestoreTower_Angle[RestoreTower_MaxIndex] = (Facing of (Triggering unit))
      • Set VariableSet RestoreTower_Location[RestoreTower_MaxIndex] = (Position of (Triggering unit))
      • Set VariableSet RestoreTower_Owner[RestoreTower_MaxIndex] = (Triggering player)
      • Set VariableSet RestoreTower_UnitType[RestoreTower_MaxIndex] = (Unit-type of (Triggering unit))
  • Wave Ends
    • Events
    • Conditions
    • Actions
      • For each (Integer loopIndex) from 1 to RestoreTower_MaxIndex, do (Actions)
        • Loop - Actions
          • Unit - Create 1 RestoreTower_UnitType[loopIndex] for RestoreTower_Owner[loopIndex] at RestoreTower_Location[loopIndex] facing RestoreTower_Angle[loopIndex] degrees
          • -------- Below custom script removes location of the tower to prevent memory leak --------
          • Custom script: call RemoveLocation(udg_RestoreTower_Location[udg_loopIndex])
      • -------- Reset index back to 0 since all units have been restored --------
      • Set VariableSet RestoreTower_MaxIndex = 0
I will test this out, thank you!

This is what i've got at the moment, but its actually just the demo map from the link i pasted, so i dont fully understand it myself and therefore have problem solving it.

  • Build Unit
    • Events
      • Unit - A unit Finishes construction
    • Conditions
    • Actions
      • Set VariableSet HashtableId = 5007214
      • For each (Integer LoopInt1) from 1 to LegionCount, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Unit-type of (Constructed structure)) Equal to LegionBuildingType[LoopInt1]
            • Then - Actions
              • Custom script: set udg_HandleId = GetHandleId( GetConstructedStructure() )
              • Custom script: set bj_lastCreatedUnit = CreateUnit( GetTriggerPlayer(), udg_LegionUnitType[udg_LoopInt1], GetUnitX( GetConstructedStructure() ), GetUnitY( GetConstructedStructure() ), 270. )
              • Hashtable - Save Handle Of(Last created unit) as HandleId of HashtableId in GlobalHashtable.
              • Unit - Turn collision for (Last created unit) Off.
              • Unit - Hide (Last created unit)
              • Custom script: call SetUnitX( bj_lastCreatedUnit, GetUnitX( GetConstructedStructure() ) )
              • Custom script: call SetUnitY( bj_lastCreatedUnit, GetUnitY( GetConstructedStructure() ) )
              • Custom script: set udg_HandleId = GetHandleId( bj_lastCreatedUnit )
              • Hashtable - Save Handle Of(Constructed structure) as HandleId of HashtableId in GlobalHashtable.
              • Unit Group - Add (Constructed structure) to LegionGroup
              • Skip remaining actions
            • Else - Actions

  • Change Units
    • Events
      • Time - SpawnTimer expires
    • Conditions
    • Actions
      • Set VariableSet HashtableId = 5007214
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • testbool Equal to True
        • Then - Actions
          • Set VariableSet testbool = False
          • -------- Building -> Unit --------
          • Unit Group - Pick every unit in LegionGroup and do (Actions)
            • Loop - Actions
              • Custom script: set udg_HandleId = GetHandleId( GetEnumUnit() )
              • Set VariableSet TempUnit1 = (Load HandleId of HashtableId in GlobalHashtable.)
              • Unit - Turn collision for (Picked unit) Off.
              • Unit - Hide (Picked unit)
              • Unit - Turn collision for TempUnit1 On.
              • Unit - Unhide TempUnit1
        • Else - Actions
          • Set VariableSet testbool = True
          • -------- Unit -> Building --------
          • Unit Group - Pick every unit in LegionGroup and do (Actions)
            • Loop - Actions
              • Custom script: set udg_HandleId = GetHandleId( GetEnumUnit() )
              • Set VariableSet TempUnit1 = (Load HandleId of HashtableId in GlobalHashtable.)
              • Unit - Turn collision for TempUnit1 Off.
              • Unit - Unhide (Picked unit)
              • Custom script: call SetUnitX( udg_TempUnit1, GetUnitX( GetEnumUnit() ) )
              • Custom script: call SetUnitY( udg_TempUnit1, GetUnitY( GetEnumUnit() ) )
              • Unit - Order TempUnit1 to Stop.
              • Unit - Make TempUnit1 face Default building facing over 0.00 seconds
              • Unit - Turn collision for (Picked unit) On.
              • Unit - Hide TempUnit1

  • Unit Dies
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Triggering player) Not equal to Player 12 (Brown)
    • Actions
      • Set VariableSet HashtableId = 5007214
      • Custom script: set udg_HandleId = GetHandleId( GetTriggerUnit() )
      • Set VariableSet TempUnit1 = (Load HandleId of HashtableId in GlobalHashtable.)
      • Unit - Unhide TempUnit1
      • Custom script: set bj_lastCreatedUnit = CreateUnit( GetTriggerPlayer(), GetUnitTypeId( GetTriggerUnit() ), GetUnitX( udg_TempUnit1 ), GetUnitY( udg_TempUnit1 ), 270. )
      • Unit - Turn collision for (Last created unit) Off.
      • Unit - Hide (Last created unit)
      • Custom script: call SetUnitX( bj_lastCreatedUnit, GetUnitX( udg_TempUnit1 ) )
      • Custom script: call SetUnitY( bj_lastCreatedUnit, GetUnitY( udg_TempUnit1 ) )
      • Custom script: set udg_HandleId = GetHandleId( udg_TempUnit1 )
      • Hashtable - Save Handle Of(Last created unit) as HandleId of HashtableId in GlobalHashtable.
      • Custom script: set udg_HandleId = GetHandleId( bj_lastCreatedUnit )
      • Hashtable - Save Handle OfTempUnit1 as HandleId of HashtableId in GlobalHashtable.

  • Units Upgrade
    • Events
      • Unit - A unit Finishes an upgrade
    • Conditions
    • Actions
      • Set VariableSet HashtableId = 5007214
      • Custom script: set udg_HandleId = GetHandleId( GetTriggerUnit() )
      • Unit - Remove (Load HandleId of HashtableId in GlobalHashtable.) from the game
      • For each (Integer LoopInt1) from 1 to LegionCount, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Unit-type of (Triggering unit)) Equal to LegionBuildingType[LoopInt1]
            • Then - Actions
              • Custom script: set bj_lastCreatedUnit = CreateUnit( GetTriggerPlayer(), udg_LegionUnitType[udg_LoopInt1], GetUnitX( GetTriggerUnit() ), GetUnitY( GetTriggerUnit() ), 270. )
              • Unit - Turn collision for (Last created unit) Off.
              • Unit - Hide (Last created unit)
              • Custom script: call SetUnitX( bj_lastCreatedUnit, GetUnitX( GetTriggerUnit() ) )
              • Custom script: call SetUnitY( bj_lastCreatedUnit, GetUnitY( GetTriggerUnit() ) )
              • Hashtable - Save Handle Of(Last created unit) as HandleId of HashtableId in GlobalHashtable.
              • Custom script: set udg_HandleId = GetHandleId( bj_lastCreatedUnit )
              • Hashtable - Save Handle Of(Triggering unit) as HandleId of HashtableId in GlobalHashtable.
              • Skip remaining actions
            • Else - Actions
 
Level 25
Joined
Sep 26, 2009
Messages
2,381
But the example map does what you want.
In the example map, when you press Esc key, the towers are replaced by their non-tower equivalents and when you press Esc key again, it replaces the non-towers back to their tower equivalents.

I just placed in the map few Blood Mages so that I could destroy the 'non-tower' version.
What I did was:
  1. Build a 'Footman' tower
  2. Press Esc to convert the Footman into non-tower version
  3. Kill the non-tower version with blood mages
    1. This automatically shows the tower version of the killed unit
  4. Press Esc again -> this converts all non-towers back into towers.
    1. This may seem as if it did nothing because the previously killed unit was already in its 'tower' state
  5. Press Esc gain -> this converted all towers into non-towers as expected
I see in your trigger that you use a timer for converting towers to non-towers and back, but I think you need to split that trigger into two:
  1. When timer expires and new wave spawns, you run the part of the trigger that converts towers into non-towers
  2. Create a new trigger that fires when all units in a wave have been killed. In this trigger run the part that converts non-towers back to towers
If you don't want to show the 'tower' version when the 'non-tower' version has been destroyed, then just remove this line from the 'Unit dies' trigger:
  • Unit - Unhide TempUnit1
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,570
I'm sure Nichilus's method works great but I want to throw my own idea out there.

If I were to make a map like this I would avoid the need to create extra copies of your tower-units. This would be done by using a Damage Engine to detect lethal damage dealt to the towers during combat and in response "fake" their deaths. This way you could avoid the headache of having to transfer data between the tower and it's newly created copy since no new copy would be required. This would make things like a tower which gains a permanent +1 damage after every kill extremely easy to manage.

The trigger would look something like this:
On lethal damage -> Set damage dealt to 0 + make tower invulnerable + hide it + return it to it's original position + use special effects to mimic the death animation (if desired)

Then once the wave is over you simply loop over a Unit Group which contains all of your towers and reposition them + unhide them if they're "dead".

How you transition the tower from it's immobile tower-mode to mobile battle-mode could vary but I'm sure there's a good way that doesn't involve morphing/creating new units.
 
Last edited:
Level 7
Joined
Feb 23, 2020
Messages
253
But the example map does what you want.
In the example map, when you press Esc key, the towers are replaced by their non-tower equivalents and when you press Esc key again, it replaces the non-towers back to their tower equivalents.

I just placed in the map few Blood Mages so that I could destroy the 'non-tower' version.
What I did was:
  1. Build a 'Footman' tower
  2. Press Esc to convert the Footman into non-tower version
  3. Kill the non-tower version with blood mages
    1. This automatically shows the tower version of the killed unit
  4. Press Esc again -> this converts all non-towers back into towers.
    1. This may seem as if it did nothing because the previously killed unit was already in its 'tower' state
  5. Press Esc gain -> this converted all towers into non-towers as expected
I see in your trigger that you use a timer for converting towers to non-towers and back, but I think you need to split that trigger into two:
  1. When timer expires and new wave spawns, you run the part of the trigger that converts towers into non-towers
  2. Create a new trigger that fires when all units in a wave have been killed. In this trigger run the part that converts non-towers back to towers
If you don't want to show the 'tower' version when the 'non-tower' version has been destroyed, then just remove this line from the 'Unit dies' trigger:
  • Unit - Unhide TempUnit1
Thank you very much, this solved the problem! :)
 
Level 7
Joined
Feb 23, 2020
Messages
253
I'm sure Nichilus's method works great but I want to throw my own idea out there.

If I were to make a map like this I would avoid the need to create extra copies of your tower-units. This would be done by using a Damage Engine to detect lethal damage dealt to the towers during combat and in response "fake" their deaths. This way you could avoid the headache of having to transfer data between the tower and it's newly created copy since no new copy would be required. This would make things like a tower which gains a permanent +1 damage after every kill extremely easy to manage.

The trigger would look something like this:
On lethal damage -> Set damage dealt to 0 + make tower invulnerable + hide it + return it to it's original position + use special effects to mimic the death animation (if desired)

Then once the wave is over you simply loop over a Unit Group which contains all of your towers, repositioning them and unhiding them if they're "dead".

How you transition the tower from it's immobile tower-mode to mobile battle-mode could vary but I'm sure there's a good way that doesn't involve morphing/creating new units.
Sounds interesting, but i guess i have to remake most of my triggers in order to make this function?

Is there a simple way to still use the +1 damage after kills etc?
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,570
Sounds interesting, but i guess i have to remake most of my triggers in order to make this function?

Is there a simple way to still use the +1 damage after kills etc?
You could probably delete most of those triggers since you no longer need to track the units in a Hashtable. Obviously you still want that spawning system though since that's basically unrelated to what I'm suggesting, although it may need some tweaking.

For tracking the +1 damage you would share the data between the two units. It depends on how you want to store data.

You could create a custom Unit Indexer that uses Custom Value to track the data:
  • Events
    • Unit - A unit dies
  • Conditions
    • Killing unit has your +1 damage ability
  • Actions
    • Set Variable KCV = Custom value of (Killing unit)
    • Set Variable DamageBonus[KCV] = DamageBonus[KCV] + 1
Then just make sure whenever you create a copy of your tower you give the copy the same Custom Value as the tower. Then both units can reference the DamageBonus variable by plugging their Custom Value into it's [index]. You'd also want to make sure your Unit Indexer doesn't recycle the Custom Value of copied units since the tower will still be alive and using that Custom Value. You could probably tweak Bribe's Unit Indexer to do this easily.
 
Level 7
Joined
Feb 23, 2020
Messages
253
You could probably delete most of those triggers since you no longer need to track the units in a Hashtable. Obviously you still want that spawning system though since that's basically unrelated to what I'm suggesting, although it may need some tweaking.

For tracking the +1 damage you would share the data between the two units. It depends on how you want to store data.

You could create a custom Unit Indexer that uses Custom Value to track the data:
  • Events
    • Unit - A unit dies
  • Conditions
    • Killing unit has your +1 damage ability
  • Actions
    • Set Variable KCV = Custom value of (Killing unit)
    • Set Variable DamageBonus[KCV] = DamageBonus[KCV] + 1
Then just make sure whenever you create a copy of your tower you give the copy the same Custom Value as the tower. Then both units can reference the DamageBonus variable by plugging their Custom Value into it's [index]. You'd also want to make sure your Unit Indexer doesn't recycle the Custom Value of copied units since the tower will still be alive and using that Custom Value. You could probably tweak Bribe's Unit Indexer to do this easily.
I see, thanks a lot!

Another question, as in legion TD, YOUR units turn into "Light Blue" (The computer) so you cant control them, but you still get gold/bounty for the kills. Do you know how i can fix this?
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,570
I see, thanks a lot!

Another question, as in legion TD, YOUR units turn into "Light Blue" (The computer) so you cant control them, but you still get gold/bounty for the kills. Do you know how i can fix this?
You can trigger the bounty system yourself, it's a fairly simple concept: A unit dies -> Add gold to the "true" owner of the killing unit

The "true" ownership could be tracked on the unit itself upon creation (again, using a Unit Indexer):
  • Events
    • Unit - A unit Finishes construction
  • Conditions
  • Actions
    • Set Variable CV = Custom value of (Triggering unit)
    • Set Variable Owner[CV] = (Owner of (Triggering unit))
Now when an enemy dies:
  • Events
    • Unit - A unit dies
  • Conditions
    • (Dying unit) is a spawned enemy unit
  • Actions
    • Player - Add 10 gold to Owner[Custom value of (Killing unit)]
You can set the bounty amount using Arrays like you were doing in the Spawn System or simply Get the info from the unit's data fields using the Integer Field functions.

Of course if you're making copies of units make sure to pass this information from the original to the copy.
 
Last edited:
Level 7
Joined
Feb 23, 2020
Messages
253
You can trigger the bounty system yourself, it's a fairly simple concept: A unit dies -> Add gold to the "true" owner of the killing unit

The "true" ownership could be tracked on the unit itself upon creation (again, using a Unit Indexer):
  • Events
    • Unit - A unit Finishes construction
  • Conditions
  • Actions
    • Set Variable CV = Custom value of (Triggering unit)
    • Set Variable Owner[CV] = (Owner of (Triggering unit))
Now when an enemy dies:
  • Events
    • Unit - A unit dies
  • Conditions
    • (Dying unit) is a spawned enemy unit
  • Actions
    • Player - Add 10 gold to Owner[Custom value of (Killing unit)]
You can set the bounty amount using Arrays like you were doing in the Spawn System or simply Get the info from the unit's data fields using the Integer Field functions.

Of course if you're making copies of units make sure to pass this information from the original to the copy.
Thank you very much for your help!
 
Level 7
Joined
Feb 23, 2020
Messages
253
You can trigger the bounty system yourself, it's a fairly simple concept: A unit dies -> Add gold to the "true" owner of the killing unit

The "true" ownership could be tracked on the unit itself upon creation (again, using a Unit Indexer):
  • Events
    • Unit - A unit Finishes construction
  • Conditions
  • Actions
    • Set Variable CV = Custom value of (Triggering unit)
    • Set Variable Owner[CV] = (Owner of (Triggering unit))
Now when an enemy dies:
  • Events
    • Unit - A unit dies
  • Conditions
    • (Dying unit) is a spawned enemy unit
  • Actions
    • Player - Add 10 gold to Owner[Custom value of (Killing unit)]
You can set the bounty amount using Arrays like you were doing in the Spawn System or simply Get the info from the unit's data fields using the Integer Field functions.

Of course if you're making copies of units make sure to pass this information from the original to the copy.
How di i pass on this information, tried a lot but i cant seem to make it work

  • Tower to unit
    • Events
    • Conditions
    • Actions
      • Set VariableSet HashtableId = 5007214
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • testbool Equal to True
        • Then - Actions
          • Set VariableSet testbool = False
          • -------- Building -> Unit --------
          • Unit Group - Pick every unit in LegionGroup and do (Actions)
            • Loop - Actions
              • Custom script: set udg_HandleId = GetHandleId( GetEnumUnit() )
              • Set VariableSet TempUnit1 = (Load HandleId of HashtableId in GlobalHashtable.)
              • Unit - Turn collision for (Picked unit) Off.
              • Unit - Hide (Picked unit)
              • Unit - Turn collision for TempUnit1 On.
              • Unit - Unhide TempUnit1
              • Unit - Change ownership of TempUnit1 to Player 10 (Light Blue) and Change color
        • Else - Actions
I tried to set the same variables in this trigger but didnt work either

  • Bounty trigger
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Owner of (Dying unit)) Equal to Player 12 (Brown)
    • Actions
      • -------- --------
      • Set VariableSet Bounty_Level[BountyCV] = (Level of (Dying unit))
      • Player - Add Bounty_Level[BountyCV] to BountyOwner[(Custom value of (Killing unit))].Current gold
      • -------- --------
      • Floating Text - Create floating text that reads (+ + (String(Bounty_Level[BountyCV]))) above (Dying unit) with Z offset 0.00, using font size 10.00, color (80.00%, 68.00%, 0.00%), and 0.00% transparency
      • Floating Text - Set the velocity of (Last created floating text) to 64.00 towards 90.00 degrees
      • Floating Text - Change (Last created floating text): Disable permanence
      • Floating Text - Change the lifespan of (Last created floating text) to 2.00 seconds
      • Floating Text - Change the fading age of (Last created floating text) to 1.50 seconds
And this is my bounty trigger
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,570
I'm not too sure what you're trying to do with that first trigger. Do you have a Unit Indexer in your map? Because all of my examples were based around that system.

Your Bounty trigger doesn't really make any sense either. There's no reason to use Bounty_Level since you want to Add gold equal to the level of the dying unit. Also, you've never Set BountyCV so that variable could have any random value which will give you random results.

Anyway, this should do the trick for the bounty stuff:
  • Bounty trigger
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Owner of (Dying unit)) Equal to Player 12 (Brown)
    • Actions
      • -------- --------
      • Set VariableSet Bounty = (Level of (Dying unit))
      • Player - Add Bounty to BountyOwner[(Custom value of (Killing unit))].Current gold
      • -------- --------
      • Floating Text - Create floating text that reads (+ + (String(Bounty))) above (Dying unit) with Z offset 0.00, using font size 10.00, color (80.00%, 68.00%, 0.00%), and 0.00% transparency
      • Floating Text - Set the velocity of (Last created floating text) to 64.00 towards 90.00 degrees
      • Floating Text - Change (Last created floating text): Disable permanence
      • Floating Text - Change the lifespan of (Last created floating text) to 2.00 seconds
      • Floating Text - Change the fading age of (Last created floating text) to 1.50 seconds
For BountyOwner, you need to Set the variable upon creating the unit:
  • Unit - Create 1 whatever...
  • Set Variable BountyOwner[Custom value of (Last created unit)] = (Owner of (Last created unit))
You'll want to research how a Unit Indexer works if you're interested in this design. If you understand how to use Hashtables then it should be easy since it's basically just a simplified version of that.
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,570
So I was able to create a demo map that demonstrates the method I described before. The included system allows you to build and use the same units (towers) throughout the game, instead of needing to create copies of them or use other annoying methods. This should make things a lot easier to manage since you'll no longer have to pass data between the original unit and it's copies.

Keep in mind I didn't cover everything that goes into Legion TD (I barely know the map) and my map is setup for demonstrative purposes so you will need to adapt the triggers to work with your own map.

When testing the map, use the Peasant to build as many Footman towers as you want. While in Build Mode, which is the default mode, you can type -battle to enter Battle Mode, which will turn your towers from buildings into non-building units that can move around and attack. While in Battle Mode, you can type -spawn to create enemy Knights that will fight with your towers. You'll see when you kill a Knight you get rewarded with gold and when one of your towers "dies" it doesn't actually die and simply gets hidden until you enter Build Mode again. Then you can type -build to enter Build Mode again, resetting your towers to their original positions, unhiding any that "died", and restoring them back to full health.

Also, I gave the Footman towers the stacking attack damage ability that I described before which shows the benefits of this design. Since the Footman or any tower for that matter can never truly die (unless canceled or sold), it's data will never get lost, so an ability like this becomes extremely easy to manage.

Note that I can't guarantee that everything I've done here is bug free as I only tested so much.
 

Attachments

  • Legion Td Example 1.w3m
    78.3 KB · Views: 24
Last edited:
Level 7
Joined
Feb 23, 2020
Messages
253
So I was able to create a demo map that demonstrates the method I described before. The included system allows you to build and use the same units (towers) throughout the game, instead of needing to create copies of them or use other annoying methods. This should make things a lot easier to manage since you'll no longer have to pass data between the original unit and it's copies.

Keep in mind I didn't cover everything that goes into Legion TD (I barely know the map) and my map is setup for demonstrative purposes so you will need to adapt the triggers to work with your own map.

When testing the map, use the Peasant to build as many Footman towers as you want. While in Build Mode, which is the default mode, you can type -battle to enter Battle Mode, which will turn your towers from buildings into non-building units that can move around and attack. While in Battle Mode, you can type -spawn to create enemy Knights that will fight with your towers. You'll see when you kill a Knight you get rewarded with gold and when one of your towers "dies" it doesn't actually die and simply gets hidden until you enter Build Mode again. Then you can type -build to enter Build Mode again, resetting your towers to their original positions, unhiding any that "died", and restoring them back to full health.

Also, I gave the Footman towers the stacking attack damage ability that I described before which shows the benefits of this design. Since the Footman or any tower for that matter can never truly die (unless canceled or sold), it's data will never get lost, so an ability like this becomes extremely easy to manage.

Note that I can't guarantee that everything I've done here is bug free as I only tested so much.
Impressive, i will look onto your design. Seems more "friendly" to manage and too learn from. Also, i want upgrades for my towers(fighters). Can i implement that simply by runnning an "finishes an upgrade event" and running the same CV variables again?

----------

Also, for some reason i get all of these error messages trying to copying the folder. The entire script..
1675268218832.png
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,570
Make sure you have JassHelper enabled in your Trigger Editor. Also, confirm that you don't already have a Damage Engine/Unit Indexer in your map, duplicates are bad! After enabling JassHelper you will have to enable some of the triggers that were disabled, I believe it should only be the two Damage Engine triggers.

Upgrades can be done without triggers, just use the standard Warcraft 3 system for them. For custom abilities like Damage Boost (the Footman ability) you can follow the pattern that I used in the triggers for that ability, but it really depends on the type of ability you're creating, since not everything requires a Unit Indexer.

First and foremost you should research how to use a Unit Indexer: GUI Unit Indexer 1.4.0.0
This thread as well as the demo map can help you understand it better.
 
Last edited:
Level 7
Joined
Feb 23, 2020
Messages
253
Make sure you have JassHelper enabled in your Trigger Editor. Also, confirm that you don't already have a Damage Engine/Unit Indexer in your map, duplicates are bad! After enabling JassHelper you will have to enable some of the triggers that were disabled, I believe it should only be the two Damage Engine triggers.

Upgrades can be done without triggers, just use the standard Warcraft 3 system for them. For custom abilities like Damage Boost (the Footman ability) you can follow the pattern that I used in that trigger, but it really depends on the type of ability, not everything requires a Unit Indexer.

First and foremost you should research how to use a Unit Indexer: GUI Unit Indexer 1.4.0.0
This thread as well as the demo map can help you understand it better.
Thank you, a lot! May i ask some general questions about triggering in messages? Just to keep the thread from growing.
 
Status
Not open for further replies.
Top