1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. The Melee Mapping Contest #4: 2v2 - Results are out! Step by to congratulate the winners!
    Dismiss Notice
  3. We're hosting the 15th Mini-Mapping Contest with YouTuber Abelhawk! The contestants are to create a custom map that uses the hidden content within Warcraft 3 or is inspired by any of the many secrets within the game.
    Dismiss Notice
  4. The 20th iteration of the Terraining Contest is upon us! Join and create exquisite Water Structures for it.
    Dismiss Notice
  5. Check out the Staff job openings thread.
    Dismiss Notice

TerrainInfection v2.1

Submitted by IcemanBo
This bundle is marked as approved. It works and satisfies the submission rules.
Info

TerrainInfection will start at given coordinates and infect nearby tiles. (change terrain type)
TerrainInfection also allows to undo the infection.

Furthermore it provides events for(un-)infection.

Uses

- WorldBounds (Nestharus)
- Table (Bribe)
- List (Nestharus)
- TileDefinition (IcemanBo)

Code
Code (vJASS):
library TerrainInfection/* v2.1    By IcemanBo

    TerrainInfection will start at given coordinates and infect nearby tiles. (change terrain type)
    TerrainInfection also allows to undo the infection.
   
    Furthermore it provides events for(un-)infection.
   
       */
requires /*

        */
TileDefinition /* hiveworkshop.com/forums/submissions-414/snippet-tiledefinition-259347/
        */
WorldBounds    /* github.com/nestharus/JASS/blob/master/jass/Systems/WorldBounds/script.j
        */
List           /* as Nestharus removed it check out the demo
        */
Table          /* hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
   
     API
   ¯¯¯¯¯¯
   
        function CreateTerrainInfection takes integer t, real x, real y, real chance, real interval returns TerrainInfection
            t           = infected terrain type
            x           = x of start
            y           = y of start
            chance      = chance to infect nearby tiles between 0 and 1
            interval    = interval to potentialy infect nearby tiles
       
         you also can set/read public members:
           
            real maxDistance = max distance to RootInfection
            real chance      = chance on infection between 0 and 1
            real maxX        = maxX of Infection
            real minX        = minX of Infection
            real maxY        = maxY of Infection
            real minY        = minY of Infection
            region bound     = bound region for infection
            boolean diagonal = should Infection act diagonal
            boolean enabled  = is Infection currently enabled
           
        you can read readonly members:
       
            real x                      =  x of infectionStart
            real y                      =  y of infectionStart
            integer size                =  amount of infected tiles
            integer terrainTypeInfected =  terrain type of infection
           
           
    methods (TerrainInfection)
   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
        destroy() returns nothing
       
        undoInfection() returns nothing
            Will un-infect all tiles.
           
        undoInfection_last() returns boolean
            Will un-infect the last tile.
            Returns false if there is no tile anymore.
           
           
    static methods (TerrainInfection)
   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
        enableResistor(integer Infector, integer Resistor, boolean b returns nothing
            Takes terrain types as paramater.
            Resistor will be immune against Infector. (true/false)
           
        enableInfections(boolean b) returns nothing
            Enables/disables all current running Infections.
           
        isTileInfected takes real x, real y returns boolean
           
   
    Events
   ¯¯¯¯¯¯¯¯
   You can use TriggerRegisterVariableEvent to catch following events:
   
        s__TerrainInfection_infection_state == 1 -> onInfection
       
        s__TerrainInfection_infection_state == 2 -> Infection has completly finished.
       
        s__TerrainInfection_infection_state == 3 -> onUnInfection
       
        s__TerrainInfection_infection_state == 4 -> Infection has been completly removed.
       
    onEvents you can use TerrainInfection_currrent as current instance.
    onEvents (1 and 3) you can use TerrainInfection_currentTileId to refer to operated tile.
   
    Look into "Event Example" for more info.
       
    Credits:
   ¯¯¯¯¯¯¯¯¯
        List (Nestharus)
        Table (Bribe)
        WorldBounds (Nestharus)

*/

    globals
        private hashtable hash = InitHashtable()
        private timer tim = CreateTimer()
        private constant real TIMEOUT              = .031250000
        private constant real TILE_SIDE_LENGTH     = 128.
        private constant real TILE_DIAGONAL_LENGTH = TILE_SIDE_LENGTH*SquareRoot(2.)
    endglobals
   
    private struct InfectionData extends array
        implement List
       
        integer tileId
        integer originTerrainType
    endstruct
   
    struct TerrainInfection
        private InfectionData list
       
        private real timeCountMax               // Interval of Infecion.
        private real timeCountCurrent           // Time left until next Infection.
   
        readonly real x                         // x of RootInfection
        readonly real y                         // y of RootInfection
        readonly integer size                   // size == amount of infected tiles
        readonly integer terrainTypeInfected    // new (infected) terrain type.
       
        // public members
        real maxDistance = -1
        real chance = 1
        real maxX = WorldBounds.maxX
        real minX = WorldBounds.minX
        real maxY = WorldBounds.maxY
        real minY = WorldBounds.minY
        region bound = null
        boolean diagonal = true
        boolean enabled = true
       
        // for list
        private thistype prev
        private thistype next
        private static thistype first = 0
       
        // for events
        static real infection_state = 0
        static thistype current = 0
        static integer currentTileId = 0
       
        // to save if a tile is infected
        private static key k
        private static Table table = k
       
        /*  
        *   These methods check if a point matches all conditions,
        *   so it can be infected successfully.
        */

       
        private method coordinateCheck takes real x, real y returns boolean
            return (bound == null or IsPointInRegion(bound, x, y)) and(x <= maxX and x >= minX and y <= maxY and y >= minY)
        endmethod
       
        private method distanceCheck takes real x, real y returns boolean
             return (maxDistance < 0 or SquareRoot((x-this.x)*(x-this.x) + (y-this.y)*(y-this.y)) <= maxDistance)
        endmethod
       
        private method terrainCheck takes real x, real y returns boolean
            return (GetTerrainType(x, y) != terrainTypeInfected) and  not(LoadBoolean(hash, terrainTypeInfected, GetTerrainType(x, y)))
        endmethod
       
        private method isPointValid takes real x, real y returns boolean
            return coordinateCheck(x,y) and distanceCheck(x,y) and terrainCheck(x,y)
        endmethod
       
        /*
        *     This method will make a circular check around given
        *     coordinates to find a terrain tile which is not
        *     infected yet. It will return boolean, if there exists
        *     a (new/old) tile around for potential infection.
        */

       
        private method checkNearbyTiles takes real x, real y returns boolean
            local real angle = 0
            local real angleChange
            local real xNew
            local real yNew
            local real offset
            local boolean diagonalCheck = true
            local InfectionData element
           
            if (this.diagonal) then
                set angleChange = bj_PI/4
            else
                set angleChange = bj_PI/2
            endif
           
            loop
                if (this.diagonal) then
                    // For 45/135/225/315 degrees the centre
                    // of the tile has an other distance, so
                    // we check if it's a digonal.
                    set diagonalCheck = not(diagonalCheck)
                    if (diagonalCheck) then
                        set offset = TILE_DIAGONAL_LENGTH
                    else
                        set offset = TILE_SIDE_LENGTH
                    endif
                else
                    set offset = TILE_SIDE_LENGTH
                endif
               
                set xNew = x + offset * Cos(angle)
                set yNew = y + offset * Sin(angle)
               
                if (this.isPointValid(xNew, yNew)) then
                   
                    if (GetRandomReal(0, 1) <= this.chance) then
                       
                        set element = this.list.enqueue()
                        set element.tileId = GetTileId(xNew,yNew)
                        set element.originTerrainType = GetTerrainType(xNew, yNew)
                       
                        call SetTerrainType(xNew, yNew, this.terrainTypeInfected, -1, 1, 1)
                        set thistype.table.boolean[element.tileId] = true
                        set this.size = (this.size + 1)
                       
                        // Fire onInfection event.
                        set thistype.current = this
                        set thistype.currentTileId = element.tileId
                        set thistype.infection_state = 1
                        set thistype.infection_state = 0
                        set thistype.current = 0
                        set thistype.currentTileId = 0
                    endif
                    return true
                endif
               
                set angle = angle + angleChange
                exitwhen (angle >= 2*bj_PI) // Full circular check was done.
            endloop
            return false
        endmethod
       
        // callback is called periodicly
   
        private static method callback takes nothing returns nothing
            local thistype this = thistype.first
            local InfectionData element
            local integer i
            local boolean b     // Will check if infection is completly finished.
           
            // loop through all instances (root infections)
            loop
                exitwhen (this == 0)
               
                if (this.enabled) then
               
                    set this.timeCountCurrent = this.timeCountCurrent - TIMEOUT
                        if (this.timeCountCurrent <= 0) then
                            set this.timeCountCurrent = this.timeCountMax
                            set element = this.list.first
                            set i = this.size
                            set b = false
                           
                            // We use pre-loop defined integer to define
                            // the cancel condition, because the list itself
                            // is dynamic, not static. (size can be changed during loop)
                           
                            //  loop through all infected tiles of an instance
                            loop
                                exitwhen (i < 1)
                                if this.checkNearbyTiles(GetTileCenterXById(element.tileId), GetTileCenterYById(element.tileId)) then
                                    set b = true
                                endif
                               
                                set element = element.next
                                set i = (i - 1)
                            endloop
                           
                            // if there is no potential tile left for infection
                            if not(b) then
                               
                                // Fire onFinish event.
                                set thistype.current = this
                                set thistype.infection_state = 2
                                set thistype.infection_state = 0
                                set thistype.current = 0
                            endif
                        endif
                       
                    endif
                set this = this.next
            endloop
        endmethod
       
        static method create takes integer t, real x, real y, real chance, real interval returns thistype
            local thistype this = thistype.allocate()
            local InfectionData element
           
            set this.list = InfectionData.create()
            set element = this.list.enqueue()
            set element.tileId = GetTileId(x,y)
            set element.originTerrainType = GetTerrainType(x, y)
           
            set this.x = x
            set this.y = y
            set this.terrainTypeInfected = t
            set this.chance = chance
            set this. size = 1
           
            if (interval < TIMEOUT) then
                set this.timeCountMax = TIMEOUT
            else
                set this.timeCountMax = interval
            endif
            set this.timeCountCurrent = this.timeCountMax
            call SetTerrainType(x, y, t, -1, 1, 1)
            set thistype.table.boolean[element.tileId] = true
           
            // Fire onInfection event.
            set thistype.current = this
            set thistype.currentTileId = element.tileId
            set thistype.infection_state = 1
            set thistype.infection_state = 0
            set thistype.current = 0
            set thistype.currentTileId = 0
           
            if (thistype.first == 0) then
                call TimerStart(tim, TIMEOUT, true, function thistype.callback)
            endif
            set this.next = thistype.first
            set thistype.first.prev = this
            set thistype.first = this
            set this.prev = 0
            return this
        endmethod
       
        method destroy takes nothing returns nothing
            set this.bound = null
            call this.deallocate()
            call this.list.destroy()
           
            if (this == thistype.first) then
                set thistype.first = this.next
            endif
            set this.next.prev = this.prev
            set this.prev.next = this.next
           
            if (thistype.first == 0) then
                call PauseTimer(tim)
            endif

        endmethod
       
        method undoInfection_last takes nothing returns boolean
            local InfectionData element = this.list.last
            local integer tileId = element.tileId
           
            if (element == 0) then
                // Fire onRemoved event.
                set thistype.current = this
                set thistype.infection_state = 4
                set thistype.infection_state = 0
                set thistype.current = 0
                return false
            endif
           
            call SetTerrainType(GetTileCenterXById(tileId), GetTileCenterYById(tileId), element.originTerrainType, -1, 1, 1)
               
            set this.size = this.size - 1
            call thistype.table.remove(tileId)
            call element.remove()
               
            // Fire onUnInfection event.
            set thistype.current = this
            set thistype.currentTileId = tileId
            set thistype.infection_state = 3
            set thistype.infection_state = 0
            set thistype.current = 0
            set thistype.currentTileId = 0
            return true
        endmethod
       
        // loop until all infected tiles are removed
        method undoInfection takes nothing returns nothing
            loop
                exitwhen not (this.undoInfection_last())
            endloop
        endmethod
       
        static method isTileInfected takes real x, real y returns boolean
            return thistype.table.has(GetTileId(x,y))
        endmethod
       
        static method enableResistor takes integer infector, integer resistor, boolean b returns nothing
            call SaveBoolean(hash, infector, resistor, b)
        endmethod
       
        static method enableInfections takes boolean b returns nothing
            if (b) then
                call TimerStart(tim, TIMEOUT, true, function thistype.callback)
            else
                call PauseTimer(tim)
            endif
        endmethod
    endstruct
   
    function CreateTerrainInfection takes integer t, real x, real y, real chance, real interval returns TerrainInfection
        return TerrainInfection.create(t, x, y, chance, interval)
    endfunction
   
endlibrary


Changelog

v2.1
- now uses List instead of Vector
- minor changes​
v2.0a
- removed not needed method
- changed documentation a bit​
v2.0
- undoInfection is now possible
- count infected tiles is possible
- check if a tile is infected is possible​
v1.0
- release​

Keywords:
Terrain, Infection, Creep, System, Tile, Effect, IcemanBo, null
Contents

TerrainInfection (Map)

Reviews
Moderator
TerrainInfection v2.1 | Reviewed by BPower | 07.07.2015 Concept[/COLOR]] [IMG]Create "terrain infections" starting from a given point x/y. As time goes by the infection eventually spreads to nearby tiles. Maximum size and infection speed can...
  1. TerrainInfection v2.1 | Reviewed by BPower | 07.07.2015
    • Concept[/COLOR]]
      [​IMG] Create "terrain infections" starting from a given point x/y.
      As time goes by the infection eventually spreads to nearby tiles.
      Maximum size and infection speed can be customized.
      Make use of infected tiles via
      isTileInfected(x, y)
      function.

      Definitly a useful, unique system.
      Due to it's innovativeness I will rate the concept with 5/5
    • Code[/COLOR]]
      [​IMG]
      • The system is MUI, leakless and working.
      [​IMG]
      • Nothing I could wish more.
    • Demo Map[/COLOR]]
      [​IMG]
      • The demo is done very well.
    • Rating[/COLOR]]
      CONCEPT CODE DEMO RATING STATUS
      5/5
      5/5
      4/5
      5/5
      APPROVED

     
  2. GywGod133

    GywGod133

    Joined:
    Jul 16, 2012
    Messages:
    646
    Resources:
    3
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    Resources:
    3
    interesting.....
     
  3. edo494

    edo494

    Joined:
    Apr 16, 2012
    Messages:
    3,855
    Resources:
    5
    Spells:
    1
    JASS:
    4
    Resources:
    5
    you mention bunch of methods, but the API never states the name of the struct.

    You also potentially generate TriggerEvaluation with your layout of TerrainInfection struct.

    This is because method create is way above method callback, and you still start timer in create and try to call callback from it.

    Also callback should be private.


    Also maybe you could make it possible to have different timeouts for each infection instance, so you can have one spreading faster than another, but this is just suggestion.
     
  4. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,100
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    Done.

    Thank you, I did not know that inside structs. Changed.

    Done.

    It actually is already. (interval) Thank you! :csmile:
     
  5. Laiev

    Laiev

    Joined:
    Oct 11, 2008
    Messages:
    273
    Resources:
    1
    Template:
    1
    Resources:
    1
    OMG :O You just did the Creep Tumor from Starcraft :O I love it, definitely.

    A little bit of adaptation and it become exactly how it is in Starcraft, based on range.

    Nice work :)

    Edit: If someone didn't know what is Creep Tumor from Starcraft, take a look at the image.

    Tumor
    [​IMG]
     
  6. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,100
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    Ah yes, you are right. ^^ Thank you.

    You could use this method, to create a limitation for a new builded structure, so it would only infect until a certain area:

    Code (vJASS):

    /**      method setRegion takes region returns nothing
    **          Infection will be limited to this region.

    Of course the user would have to define the region by himself, for each building type individually.
     
  7. Zeatherann

    Zeatherann

    Joined:
    Nov 25, 2008
    Messages:
    1,303
    Resources:
    6
    Skins:
    1
    Tools:
    1
    Maps:
    4
    Resources:
    6

    This is nice. I created a blight system myself, though it solely mimics Blizzard's blight spreading (the default spell can be edited to slow it down to look like Starcraft I's creep).

     
  8. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    IsPointInfectedXY takes real x ,real y returns boolean
     
  9. Zeatherann

    Zeatherann

    Joined:
    Nov 25, 2008
    Messages:
    1,303
    Resources:
    6
    Skins:
    1
    Tools:
    1
    Maps:
    4
    Resources:
    6

    Why do you have all the setter and getter functions?

     
  10. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,100
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    I would need to take track of each tile that was ever infected. :/
    At the moment an instance gets destroyed, once there is no infectable tile around it, because it's not needed anymore.
    Would you have an other idea?

    But anyway I'm not very happy at the moment with not tracking them at all, because user has no controle of infected tiles and it's behaviour, once they are destroyed. So you can't post-change the behaviour, but only after creation. :S

    Do you mean to change some readonly members to accessible members, instead of the setters?
    What getters do you mean?
     
  11. Zeatherann

    Zeatherann

    Joined:
    Nov 25, 2008
    Messages:
    1,303
    Resources:
    6
    Skins:
    1
    Tools:
    1
    Maps:
    4
    Resources:
    6
    Code (vJASS):
    method setChance takes real chance returns nothing
                set infectionChance = chance
            endmethod
           
            method setTerrainType takes integer t returns nothing
                set terrainType = t
            endmethod
           
            method setInterval takes real interv returns nothing
                set interval = interv
            endmethod
           
            method enable takes boolean b returns nothing
                set enabled = b
            endmethod
           
            method setMaxX takes real r returns nothing
                set maxX = r
            endmethod
           
            method setMinX takes real r returns nothing
                set minX = r
            endmethod

            method setMaxY takes real r returns nothing
                set maxY = r
            endmethod

    These are what I'm referring to.

     
  12. Spellbound

    Spellbound

    Joined:
    Jan 9, 2005
    Messages:
    1,910
    Resources:
    15
    Skins:
    5
    Spells:
    9
    JASS:
    1
    Resources:
    15
    Preface: I don't understand JASS or vJASS

    This looks really interesting. How would I use it to make a building spread sand in a 600 aoe around it, and then stop spreading sand once it dies/uproots?
     
  13. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,100
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    Sorry, I completly forgot about your post and this resource. Updated and added this distance limitation. In the demo, there is an example.

    I still don't infinitly keep tracking of all tiles and lose controle of the behaviour once it gets destroyed, it's kind of discouraging...

    Well, but it still may be used in some scenarios. :D
     
  14. Heinvers

    Heinvers

    Arena Moderator

    Joined:
    May 7, 2010
    Messages:
    7,985
    Resources:
    83
    Models:
    2
    Icons:
    50
    Packs:
    3
    Skins:
    25
    Template:
    3
    Resources:
    83
    Finish this please.

    I want creep in wc3 :p
     
  15. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,220
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    • SquareRoot((xNew-rootX)*(xNew-rootX) + (yNew-rootY)*(yNew-rootY)) <= rootDistance

      =>
      (xNew-rootX)*(xNew-rootX) + (yNew-rootY)*(yNew-rootY) <= rootDistance*rootDistance
    • You don't need this:
      Code (vJASS):

              private constant integer INDEX_START = -1
              private integer maxIndex = INDEX_START
    • You can declare
      (2*bj_PI)
      once as "TAU". And another crap calculation like PI/2, rename it to whatever you want. :p
    • You can shorten your infect method to:
      Code (vJASS):

              private method infectNearbyPoint takes real x, real y returns boolean
                  local real angle = 0
                  local real xNew
                  local real yNew
                  @local integer counter = 0@
                  local real offset
                  local boolean diagonal = true
                 
                  loop
                      if (diagonalInfection) then
                          // For 45/135/225/315 degrees the centre
                          // of the tile has an other distance, so
                          // we check if it's a digonal.
                          set diagonal = not(diagonal)
                          if (diagonal) then
                              set offset = TILE_DIAGONAL_LENGTH
                          else
                              set offset = TILE_SIDE_LENGTH
                          endif
                          set angle = angle + bj_PI/4
                      else
                          set offset = TILE_SIDE_LENGTH
                          set angle = angle + bj_PI/2
                      endif
                     
                      set xNew = x + offset * Cos(angle)
                      set yNew = y + offset * Sin(angle)
                     
                      if (isPointValid(xNew, yNew)) then
                     
                          //  A new tile gets infected.
                          return copyData(thistype.create(terrainType, xNew, yNew, infectionChance, interval, infectionEffect))
                      endif
                     
                      exitwhen angle > (2*bj_PI) // Full circular check was done.
                  endloop
                  return false
              endmethod

      And it doesn't need to take another x and y, it's a non static:
      Code (vJASS):
      private method infectNearbyPoint takes @real x, real y@ returns boolean

      EDIT: and you don't need local variable "counter".
    • Code (vJASS):

                  if (interv < TIMEOUT) then
                      set interval = TIMEOUT
                  else
                      set interval = interv
                  endif
      Ermmm......
    • You forgot to remove not null infectionRegion on destroy method.
    You made this very effective. Max infection range and specific infection region was a very diligent feature, I like it.
     
    Last edited: Jan 7, 2015
  16. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,100
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    Thanks! I will think of it in the further update. :csmile:

    Sorry, I forgot what in the destroy method?
     
  17. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,220
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    when infectionRegion is not null, you need to remove it:
    call RemoveRegion(infectionRegion)


    Also I have edited the last review ;)
     
  18. BlueSaint

    BlueSaint

    Joined:
    Jun 18, 2012
    Messages:
    2,726
    Resources:
    3
    Tools:
    1
    Spells:
    2
    Resources:
    3
    Code (vJASS):
    /*     Requires:
    **    ----------
    **
    **       - nothing*/

    Hehe :D I'm also working on vanilla JASS spell, on which I won't use any external scripts.

    I think I have use for this, waiting for status change.. +rep
     
  19. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,100
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    ^Thanks.

    It can be used actually, but I'm not satisfied enough with functionality at the moment. So I will work on it some later. :) (probably not soon)