1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. Hey Guest, is it this your first time on the forums?

    Visit the Beginner's Box

    Introduce yourself, read some of the ins and outs of the community, access to useful links and information.

    Dismiss Notice

Grass growth

Discussion in 'Suggestions & Ideas' started by Vermilicious, Aug 22, 2013.

  1. joshua12131415

    joshua12131415 Horde Gibber Tester

    It seems like grass would randomly be growing everywhere. Wouldn't it be better if it spread like in terraria? So first you search for dirt blocks with already grown grass and then search all the dirt blocks around it and add grass to those.

    Would it be possible to read the map.png and find all the grass blocks here instead of searching (at the beginning of the game)?
    Then each grass block can be added to a list or something which is checked every few seconds and if those blocks have no grass, they are removed from the list. If they do have grass then you search all surrounding dirt blocks. If there is a nearby dirt block that has nothing on top, then grass is grown on it, and that new grass block is also added to the list.

    Or maybe this could be done client side and it can be one of the tick box things in settings so people can choose whether they want it on or not.
  2. EhRa

    EhRa Wait, so I can write anything here?! Official Server Admin Donator
    1. KRPG

    It shouldn't be client sided due to it possibly used as tactics (lying down in the grass).
  3. Vermilicious

    Vermilicious Base Burner

    A nice starting point from Geti. Quite simple.

    Yeah, that might be a good idea. The map loader has to iterate through everything anyway. It would grow very fast though, unless you adjust the tick rate. It doesn't quite have the same consistent performance appeal of Geti's suggestion. It doesn't seem like a very costly operation either way though.

    Most of the time, the dirt tiles below them is going to erode. If growing new grass is a good idea or not, I'm not sure. It is perhaps unlikely that map designers place grass strategically, or the opposite. It's simple enough though, just look for empty tiles with a dirt tile below. You might have to check for overlapping blobs too though (stuff like workbenches) because the grass gets in the way, visually.

    I might incorporate something along these lines myself.
  4. joshua12131415

    joshua12131415 Horde Gibber Tester

    When you build a shop wood back walls are automatically made. If a fire arrow destroys those back walls and the shop still stands then it looks bad anyway, having grass under will just make it look like it's out side more.
  5. Geti

    Geti Please avoid PMing me (poke a mod instead) THD Team Administrator Global Moderator

    The way I did it just regrows already existing grass - you'd need to check for empty tiles and then check the tile below for dirt and then place the most empty grass tile (CMap::tile_grass + 3) if you want it to grow grass on any dirt.

    iterating through the map at startup and finding the suitable tiles would be a fine optimisation probably as grass shouldn't grow where there's dirt backwall anyway and there's no way to create new dirt in vanilla anyway. Just track those offsets in an array and index into that rather than into the tilemap directly. No demo code for that though, sorry :)
  6. Vermilicious

    Vermilicious Base Burner

    I tried parts of your code, Geti, and it seems to work for the most part, but when the player cut the grass, nothing happens to it. Isn't the tile type changed, perhaps?

    For those that are curious, I built up an array of offset coordinates in my own PNG loader, and added a Map script to iterate over it. Extracted code below.

    //Enumeration used when storing special offsets when loading a map (extends enumeration in BasePNGLoader.as)
    enum UndeadInvasionPNGLoaderOffset {
      UNDEADINVASION_POI = offsets_count + 1, //Point of interest (not used)
      UNDEADINVASION_GRASS_CANDIDATE,         //Sky tiles (for post-stage check for grass growth)
      UNDEADINVASION_OFFSETS_COUNT            //End reference
    class UndeadInvasionPNGLoader : PNGLoader {
      //Keep an array of grass candidate tile offsets
      int[] mGrassCandidateOffsets;
      UndeadInvasionPNGLoader()    {
      bool loadMap(CMap@ map, const string& in filename) override {
        bool result = false;
        //Call super class' version of this method
        result = PNGLoader::loadMap(map, filename);
        //Store grass candidate tile offsets
        map.set("grassCandidateOffsets", mGrassCandidateOffsets);
        //Finished, return result
        return result;
      void handlePixel(SColor color_pixel, int offset) override {
        //Call super class' version of this method, to make sure we don't miss out on any default behaviour
        PNGLoader::handlePixel(color_pixel, offset);
        //Check if empty/sky
        if(color_pixel == sky || color_pixel == color_tile_grass) {
          offsets[UNDEADINVASION_GRASS_CANDIDATE].push_back(offset);                //Store offset reference
      void handleOffset(int type, int offset, int position, int count) override {
        //Call super class' version of this method, to make sure we don't miss out on any default behaviour
        PNGLoader::handleOffset(type, offset, position, count);
        //If grass candidate
          //Determine offset number for tile below
          int belowOffset = offset + map.tilemapwidth;
          //Determine offset number for the very last tile in the map
          int lastOffset = map.tilemapwidth * map.tilemapheight - 1;
          //Check if tile below is dirt/ground
          if(belowOffset <= lastOffset && map.getTile(belowOffset).type == CMap::tile_ground) {
            //Add this tile's offset
    void onInit(CMap@ this) {
      this.set_u32("nextGrassCandidateIndex", 0);
    void onTick(CMap@ this) {
      //Retrieve all grass candidate offsets
      int[] grassCandidateOffsets;
      this.get("grassCandidateOffsets", grassCandidateOffsets);
      //Retrive next candidate index
      u32 nextGrassCandidateIndex = this.get_u32("nextGrassCandidateIndex");
      //Find next offset
      int nextOffset = grassCandidateOffsets[nextGrassCandidateIndex];
      //Find tile
      Tile tile = this.getTile(nextOffset);
      print("type:" + tile.type);
      //Check if grass type and not yet fully grown (Thank you, Geti)
      if(this.isTileGrass(tile.type) && tile.type != CMap::tile_grass) {
        //Get position
        Vec2f position = this.getTileWorldPosition(nextOffset);
        //Grow grass (grass tiles are in decreasing order)
        this.server_SetTile(position, tile.type - 1);
      //Start over if end is reached
      if(nextGrassCandidateIndex > grassCandidateOffsets.length - 1) {
        nextGrassCandidateIndex = 0;
      //Update index
      this.set_u32("nextGrassCandidateIndex", nextGrassCandidateIndex);
    Last edited: Oct 5, 2017
  7. Geti

    Geti Please avoid PMing me (poke a mod instead) THD Team Administrator Global Moderator

    The tile type is definitely changed when the grass is cut. If you catch me next week monday or tuesday (australian time) I'll happily give this a quick look. An easily tested mod would make that a lot easier for me :wink:
  8. Vermilicious

    Vermilicious Base Burner

    While isolating into a separate example mod, and running it, it did indeed work as expected, so I will have to look closer into why it's not working in my original project.

    Anyway, the code is available here for those that are interested:
    king-george, joshua12131415 and Geti like this.

Share This Page