• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Trying To Change Terrain Over A Region

Status
Not open for further replies.
Level 15
Joined
Nov 30, 2007
Messages
1,202
I'm trying to change terrain over a region but no units, no ping is created and it should be right?

  • test
    • Events
      • Time - Elapsed game time is 1.00 seconds
    • Conditions
    • Actions
      • Set Left = 10048
      • Set Right = 10624
      • Set Top = -3776
      • Set Bottom = -4352
      • For each (Integer A) from Left to Right, do (Actions)
        • Loop - Actions
          • For each (Integer B) from Top to Bottom, do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                • Then - Actions
                  • Set x = (Real((Integer A)))
                  • Set y = (Real((Integer B)))
                  • Unit - Create 1 Footman for Player 1 (Red) at (Point(x, y)) facing Default building facing degrees
                  • Cinematic - Ping minimap for (All players) at (Point(x, y)) for 1.00 seconds
                  • Environment - Change terrain type at (Point(x, y)) to Underground - Brick using variation -1 in an area of size 1 and shape Circle
                • Else - Actions
 
Hi,

First of all, the trigger is not working because you put all of your relevant actions in an "if-then-else" block, which is not necessary. Move everything between

  • Set x = (Real((Integer A)))
and

  • Enviroment - Change terrain type at (Point(x, y)) to ...
up one scope tier so that it's nested inside of

  • Loop - Actions
Then, simply delete the unnecessary if/then/else block.

The next issue you will encounter if you try to do this is an extremely large amount of lag (probably crashing the game), followed by a triangular/polygonal shaped "Underground - Brick".

The lag/crash part will happen because you attempt to create 331,776 units instantaneously, and creating 1 unit is already an expensive process.

The strange terrain shape will happen because you can't execute 331,776 actions in one thread - it will crash.

Hence, the next thing you'll want to do is remove the "create unit" and "ping minimap" commands, followed by one last step:

Terrain types on the heightmap are handled in 128x128 squares, therefore your trigger is working 16,384 times harder than it needs to.

To fix this final part, you need to make the loop register all *multiples of 128* for integer a and b - I won't explain how to do this in GUI though, because lastly:

If you want to use dynamic terrain/pathing, you should learn jass.
 
Now one stripe is created from bottom to top, the rest nothing happens to hmm... Perhaps its something with the multiplier. Gonna write it in JASS and return.

Yep, that's what I tried to warn you when I said

The strange terrain shape will happen because you can't execute 331,776 actions in one thread - it will crash.

Terrain types on the heightmap are handled in 128x128 squares, therefore your trigger is working 16,384 times harder than it needs to.

To fix this final part, you need to make the loop register all *multiples of 128* for integer a and b - I won't explain how to do this in GUI though, because lastly:

If you want to use dynamic terrain/pathing, you should learn jass.

If you need help doing it in jass let me/us know.

The triggers stops at some point. That's what a thread crash means. To avoid it you need to use separate threads(run the trigger multiple times)

He might not need to if he iterates 128 times less in each dimension - but otherwise you're correct.

Just create a new variable for horizontal and vertical and set the value to [Top - Bottom] / 64 and the other one [Left - Right] / 64 and use those for the For iteration. (And increase the other coordinates by 64 as well.

Such a small number shouldn't be necessary since terrain tiles are 128x128
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
JASS:
function Trig_aaa_Actions takes nothing returns nothing

local real left= 10048
local real right = 10624
local real top = -3776
local real bottom = -4352

loop
    exitwhen left > right
        set top = -3776
        loop  
            exitwhen top < bottom
                if (GetTerrainType(Location(left,top)) == 'Arck') then
                call SetTerrainTypeBJ( Location(left,top), 'Glav', -1, 1, 0)                 
                endif
                set top = top - 128
            endloop
        set left = left + 128
        endloop
endfunction

//===========================================================================
function InitTrig_aaa takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterTimerEventSingle(t, 1.00 )
    call TriggerAddAction(t, function Trig_aaa_Actions )
    set t = null
endfunction
Would this loop do the job? I suppose there are places on the map where this wouldnt work...

The issue with this is that top is not always < bottom and same goes for left and right?
 
Last edited:
Hello,

As long as you give values such that top>bottom and left<right, this will work.

Here are some tips for you:

  • There is an operation limit for loops. Therefore if (right-left)*(top-bottom)/(128*128) is too large, the script will not change the whole region. There are ways to work around this but you shouldn't need it now.
  • You should use GetTerraintype() and SetTerrainType() instead of the "BJ" counterparts.
  • You should declare left and right directly as 'real' like this: local real left=10048. and therefore you don't need variables x and y (nor do you need the 'set x' and 'set y' lines).
  • Your set top = -3776 line is superfluous in this case because 'top' already has its correct value.
  • Use TriggerRegisterTimerEvent() instead of TriggerRegisterTimerEventSingle().
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
Hello,

As long as you give values such that top>bottom and left<right, this will work.

Here are some tips for you:

  • There is an operation limit for loops. Therefore if (right-left)*(top-bottom)/(128*128) is too large, the script will not change the whole region. There are ways to work around this but you shouldn't need it now.
  • You should use GetTerraintype() and SetTerrainType() instead of the "BJ" counterparts.
  • You should declare left and right directly as 'real' like this: local real left=10048. and therefore you don't need variables x and y (nor do you need the 'set x' and 'set y' lines).
  • Your set top = -3776 line is superfluous in this case because 'top' already has its correct value.
  • Use TriggerRegisterTimerEvent() instead of TriggerRegisterTimerEventSingle().

I need to reset the top value after every line is done, thats why it's there.

I dont understand how to make GerTerrainType() and SetTerrainType() to work ;(

I changed the integer to reals, I'm so acustomed to using integers for loops because of the gui.

Thank you for your help I appreciate it!
 
I need to reset the top value after every line is done, thats why it's there.

Whoops! You're exactly right. Not sure how I missed that.

I dont understand how to make GerTerrainType() and SetTerrainType() to work ;(

Do you have Jass Newgen Pack? There is a function list in which you can see the arguments of all natives - it should be pretty descriptive in parallel with SetTerrainTypeBJ() for example.
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
You still aren't understanding Codemonkey's first tip about using multiples of 128.

Here's code that works:
  • Actions
    • Set Bot = -30
    • Set Top = 30
    • Set Left = -30
    • Set Right = 30
    • For each (Integer A) from Left to Right, do (Actions)
      • Loop - Actions
        • For each (Integer B) from Bot to Top, do (Actions)
          • Loop - Actions
            • Set tempLoc1 = (Point(((Real((Integer A))) x 128.00), ((Real((Integer B))) x 128.00)))
            • Environment - Change terrain type at tempLoc1 to Lordaeron Summer - Grassy Dirt using variation -1 in an area of size 1 and shape Circle
            • Custom script: call RemoveLocation(udg_tempLoc1)
Where did I get the number 30 from? In the terrain editor, count the number of white grid squares. This is also the scale used in the map's size under Scenario -> Map Size and Camera Bounds.

EDIT: OP limit is 2500. So you can create a 50x50 terrain square in one go.
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
Op limit is 2500, you counted it? :D (and op limit as is is not 2500, it depends on what and how much of you call, for instance I can do 9180 set calls in loop before thread crashes)

Just over 2500 with the above code.

I haven't checked if the terrain change action is actually a nasty BJ that calls a similar function that uses points.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,258
Be aware that you are still limited to 16 tile types due to how WarCraft III is coded. You can load new tile types using triggers if there are still free slots but once a tile type is loaded it will persist until the end of the session.

Creating 50x50 terrain area does way more operations than 2500.
He named it incorrectly. He meant it has a throughput of over 2500 tiles before hitting op-limit so can do up to a 50*50 area.

For larger you need waits or to create new threads. Be warned that making multiple threads to do larger areas may result in the game dropping frames to allow the threads to execute.
 
Status
Not open for further replies.
Top