initial commit, lordsawar source, slightly modified
[lordsawar] / src / CreateScenario.cpp
diff --git a/src/CreateScenario.cpp b/src/CreateScenario.cpp
new file mode 100644 (file)
index 0000000..59e746d
--- /dev/null
@@ -0,0 +1,806 @@
+// Copyright (C) 2003, 2004, 2005, 2006 Ulf Lorenz
+// Copyright (C) 2003 Michael Bartl
+// Copyright (C) 2004 John Farrell
+// Copyright (C) 2004, 2005, 2006 Andrea Paternesi
+// Copyright (C) 2006, 2007, 2008, 2009 Ben Asselstine
+// Copyright (C) 2007 Ole Laursen
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU Library General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
+//  02110-1301, USA.
+
+#include <sstream>
+#include <sigc++/functors/mem_fun.h>
+
+#include "CreateScenario.h"
+#include "GameScenario.h"
+#include "army.h"
+#include "GameMap.h"
+#include "counter.h"
+#include "player.h"
+#include "playerlist.h"
+#include "stacklist.h"
+#include "citylist.h"
+#include "city.h"
+#include "ruinlist.h"
+#include "ruin.h"
+#include "rewardlist.h"
+#include "Itemlist.h"
+#include "templelist.h"
+#include "temple.h"
+#include "signpostlist.h"
+#include "signpost.h"
+#include "portlist.h"
+#include "port.h"
+#include "bridgelist.h"
+#include "bridge.h"
+#include "roadlist.h"
+#include "road.h"
+#include "armysetlist.h"
+#include "citysetlist.h"
+#include "real_player.h"
+#include "ai_fast.h"
+#include "ai_smart.h"
+#include "ai_dummy.h"
+#include "File.h"
+#include "MapGenerator.h"
+#include "QuestsManager.h"
+#include "Configuration.h"
+#include "FogMap.h"
+#include "history.h"
+
+using namespace std;
+
+#define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<endl<<flush;}
+//#define debug(x)
+
+CreateScenario::CreateScenario(int width, int height)
+    :d_scenario(0), d_generator(0)
+{
+    debug("CreateScenario::CreateScenario")
+   
+    //make sure that objects are deleted
+    GameMap::deleteInstance();
+    Playerlist::deleteInstance();
+    Templelist::deleteInstance();
+    Ruinlist::deleteInstance();
+    Rewardlist::deleteInstance();
+    Portlist::deleteInstance();
+    Bridgelist::deleteInstance();
+    Citylist::deleteInstance();
+    Itemlist::deleteInstance();
+
+    QuestsManager::deleteInstance();
+
+    fl_counter = new FL_Counter();
+
+    setWidth(width);
+    setHeight(height);
+
+    d_generator = new MapGenerator();
+    d_generator->progress.connect (sigc::mem_fun(*this, &CreateScenario::on_progress));
+}
+
+CreateScenario::~CreateScenario()
+{
+    debug("CreateScenario::~CreateScenario")
+
+    if (d_generator)
+        delete d_generator;
+
+    if (d_scenario)
+        delete d_scenario;
+}
+
+void CreateScenario::on_progress(double percent, std::string description)
+{
+  progress.emit();
+}
+
+void CreateScenario::setPercentages(int pgrass, int pwater, int pforest,
+                                    int pswamp, int phills, int pmountains)
+{
+    debug("CreateScenario::setPercentages")
+
+    //handle input with !=100% sum
+    int sum = pgrass + pwater + pforest + pswamp +phills + pmountains;
+
+    if (sum != 100)
+    {
+        double factor = 100 / static_cast<double>(sum);  
+
+        pwater = static_cast<int>(pwater * factor);
+        pforest = static_cast<int>(pforest * factor);
+        pswamp = static_cast<int>(pswamp * factor);
+        phills = static_cast<int>(phills * factor);
+        pmountains = static_cast<int>(pmountains * factor);
+    }
+
+    //the multiplication doesn't round up, so the figures should be OK now, the
+    //missing percentage is implicitely added to the grass part.
+    d_generator->setPercentages(pwater, pforest, pswamp, phills, pmountains);
+}
+
+void CreateScenario::setMapTiles(std::string tilesname)
+{
+    debug("CreateScenario::setMapTiles")
+    d_tilesname = tilesname;
+}
+
+void CreateScenario::setShieldset(std::string shieldset)
+{
+    debug("CreateScenario::setShieldset")
+    d_shieldsname = shieldset;
+}
+
+void CreateScenario::setCityset(std::string citysetname)
+{
+    debug("CreateScenario::setCityset")
+    d_citysetname = citysetname;
+    d_generator->setCityset(Citysetlist::getInstance()->getCityset(citysetname));
+}
+
+void CreateScenario::setNoCities(int nocities)
+{
+    debug("CreateScenario::setNoCities")
+
+    d_generator->setNoCities(nocities);
+}
+
+void CreateScenario::setNoRuins(int noruins)
+{
+    debug("CreateScenario::setNoRuins")
+
+    d_generator->setNoRuins(noruins);
+}
+
+void CreateScenario::setNoSignposts (int nosignposts)
+{
+    debug("CreateScenario::setNoSignposts")
+
+    d_generator->setNoSignposts(nosignposts);
+}
+
+void CreateScenario::setNoTemples(int notemples)
+{
+    debug("CreateScenario::setNoTemples")
+
+    d_generator->setNoTemples(notemples);
+}
+
+void CreateScenario::setWidth(int width)
+{
+    debug("CreateScenario::setWidth")
+
+    if (width < 0)
+    {
+        std::cerr << "CreateScenario:: wrong width given\n";
+        return;
+    }
+
+    d_width = width;
+
+    //IMPORTANT!!
+    GameMap::setWidth(width);
+}
+void CreateScenario::setHeight(int height)
+{
+    debug("CreateScenario::setHeight")
+
+    if (height < 0)
+    {
+        std::cerr << "CreateScenario:: wrong height given\n";
+        return;
+    }
+
+    d_height = height;
+
+    //IMPORTANT!!
+    GameMap::setHeight(height);
+}
+
+Player* CreateScenario::addPlayer(std::string name, guint32 armyset,
+                                Gdk::Color color, int type)
+{
+    debug("CreateScenario::addPlayer")
+
+    Player* p = Player::create(name, armyset, color, d_width, d_height,
+                              Player::Type(type));
+    Playerlist::getInstance()->add(p);
+
+    return p;
+}
+
+bool CreateScenario::addNeutral(std::string name, guint32 armyset,
+                                Gdk::Color color, int type)
+{
+    // for consistency, we only allow exactly one neutral player
+    if (Playerlist::getInstance()->getNeutral() != 0)
+        return false;
+
+    Player* p = addPlayer(name, armyset, color, Player::Type(type));
+    Playerlist::getInstance()->setNeutral(p);
+    return true;
+}
+
+int CreateScenario::getNoPlayers() const
+{
+    return Playerlist::getInstance()->size();
+}
+
+Player* CreateScenario::getPlayer(int number) const
+{
+    debug("CreateScenario::getPlayer")
+
+    if (number >= static_cast<int>(Playerlist::getInstance()->size()))
+        return 0;
+
+    Playerlist::iterator it;
+    for (it = Playerlist::getInstance()->begin(); number > 0; number--)
+        it++;
+
+    return (*it);
+}
+
+int CreateScenario::getNoCities() const
+{
+    if (!d_generator)
+        return -1;
+
+    return d_generator->getNoCities();
+}
+
+int CreateScenario::getNoRuins() const
+{
+    if (!d_generator)
+        return -1;
+
+    return d_generator->getNoRuins();
+}
+
+int CreateScenario::getNoTemples() const
+{
+    if (!d_generator)
+        return -1;
+
+    return d_generator->getNoTemples();
+}
+
+bool CreateScenario::create(const GameParameters &g)
+{
+    debug("CreateScenario::create")
+
+    d_scenario = new GameScenario("AutoGenerated", "AutoGenerated", d_turnmode);
+
+    GameScenario::s_see_opponents_stacks = g.see_opponents_stacks;
+    GameScenario::s_see_opponents_production = g.see_opponents_production;
+    GameScenario::s_play_with_quests = g.play_with_quests;
+    GameScenario::s_hidden_map = g.hidden_map;
+    GameScenario::s_diplomacy = g.diplomacy;
+    GameScenario::s_cusp_of_war = g.cusp_of_war;
+    GameScenario::s_neutral_cities = g.neutral_cities;
+    GameScenario::s_razing_cities = g.razing_cities;
+    GameScenario::s_military_advisor= g.military_advisor;
+    GameScenario::s_random_turns = g.random_turns;
+    GameScenario::s_intense_combat = g.intense_combat;
+
+    if (!createMap())
+        return false;
+
+    // fog it up
+    if (GameScenario::s_hidden_map)
+      {
+        Playerlist::iterator pit = Playerlist::getInstance()->begin();
+        for (; pit != Playerlist::getInstance()->end(); pit++)
+          (*pit)->getFogMap()->fill(FogMap::CLOSED);
+      }
+
+    if (!setupTemples())
+        return false;
+    
+    int sage_factor;
+    int no_guardian_factor;
+    int stronghold_factor;
+
+    getRuinDifficulty (g.difficulty, &sage_factor, &no_guardian_factor,
+                      &stronghold_factor);
+    if (!setupRuins(GameScenario::s_play_with_quests != GameParameters::NO_QUESTING, 20, 10, 6))
+        return false;
+
+    int base_gold;
+    getBaseGold (g.difficulty, &base_gold);
+    if (!setupPlayers(g.random_turns, base_gold))
+        return false;
+
+    if (!setupItems())
+        return false;
+
+    if (!setupRoads())
+        return false;
+    
+    if (!setupBridges())
+        return false;
+    
+    if (!distributePlayers())
+        return false;
+
+    int number_of_armies_factor;
+    getCityDifficulty(g.difficulty, &number_of_armies_factor);
+    if (!setupCities(g.cities_can_produce_allies, number_of_armies_factor))
+        return false;
+
+    int signpost_ratio;
+    getSignpostDifficulty (g.difficulty, g.hidden_map, &signpost_ratio);
+    if (!setupSignposts(signpost_ratio))
+        return false;
+
+    return true;
+}
+
+bool CreateScenario::dump(std::string filename) const
+{
+    debug("CreateScenario::dump")
+
+    if (d_scenario)
+        return d_scenario->saveGame(filename, "map");
+
+    return false;
+}
+
+bool CreateScenario::createMap()
+{
+    debug("CreateScenario::createMap")
+
+    const Maptile::Building* map;
+    
+    Rewardlist::getInstance();
+
+    //have the generator make the map...
+    d_generator->makeMap(d_width, d_height, true);
+    
+    //...fill the terrain...
+    GameMap::getInstance(d_tilesname, d_shieldsname,
+                        d_citysetname)->fill(d_generator);
+
+    //...and create cities, temples, ruins ,signposts
+    map = d_generator->getBuildings(d_width, d_height);
+    Cityset *cityset = Citysetlist::getInstance()->getCityset(d_citysetname);
+    
+    for (int y = 0; y < d_height; y++)
+        for (int x = 0; x < d_width; x++)
+        {
+            switch (map[y*d_width + x])
+            {
+                case Maptile::SIGNPOST:
+                    Signpostlist::getInstance()->add(new Signpost(Vector<int>(x,y)));
+                    break;
+                case Maptile::TEMPLE:
+                    Templelist::getInstance()->add
+                     (new Temple(Vector<int>(x,y), 
+                                 cityset->getTempleTileWidth(),
+                                 popRandomTempleName()));
+                    break;
+                case Maptile::RUIN:
+                   Ruinlist::getInstance()->add
+                     (new Ruin(Vector<int>(x,y), 
+                               cityset->getRuinTileWidth(),
+                               popRandomRuinName()));
+                   break;
+                case Maptile::CITY:
+                    Citylist::getInstance()->add
+                     (new City(Vector<int>(x,y), cityset->getCityTileWidth()));
+                    break;
+                case Maptile::ROAD:
+                    Roadlist::getInstance()->add(new Road(Vector<int>(x,y)));
+                    break;
+                case Maptile::PORT:
+                    Portlist::getInstance()->add(new Port(Vector<int>(x,y)));
+                    break;
+                case Maptile::BRIDGE:
+                    Bridgelist::getInstance()->add(new Bridge(Vector<int>(x,y)));
+                    break;
+                case Maptile::NONE:
+                   break;
+            }
+        }
+    //the other details such as giving names are done later
+    
+    return true;
+}
+
+void CreateScenario::createCapitalCity(Player *player, City *city)
+{
+  // distribute capitals for the players
+  city->conquer(player);
+  city->setCapitalOwner(player);
+  city->setCapital(true);
+
+  History_CityWon *item = new History_CityWon();
+  item->fillData(city);
+  player->addHistory(item);
+}
+
+bool CreateScenario::tooNearToOtherCapitalCities(City *c, std::list<City*> capitals, guint32 distance)
+{
+  for (std::list<City*>::iterator it = capitals.begin(); it != capitals.end(); 
+       it++)
+    {
+      int d = dist(c->getPos(), (*it)->getPos());
+      if ((guint32) d < distance)
+       return true;
+    }
+  return false;
+}
+
+bool CreateScenario::distributePlayers()
+{
+    debug("CreateScenario::distributePlayers")
+
+    Citylist* cl = Citylist::getInstance();
+    const Playerlist* pl = Playerlist::getInstance();
+
+    //okay, everyone starts out as neutral.
+    for (Citylist::iterator cit = cl->begin(); cit != cl->end(); cit++)
+      {
+        City *c = *cit;
+       if (c->isBurnt() == false)
+         c->setOwner(pl->getNeutral());
+      }
+
+    std::list<City*> capitals;
+    //now pick some equidistant cities for capitals, that aren't too close.
+    for (Playerlist::const_iterator pit = pl->begin(); pit != pl->end(); pit++)
+      {
+       int tries = 0;
+       if (*pit == pl->getNeutral())
+         continue;
+       while (1)
+         {
+           Vector<int> pos = Vector<int>(rand() % d_width, rand() % d_height);
+           City *city = Citylist::getInstance()->getNearestCity(pos);
+           if (city->isBurnt() == false && city->isCapital() == false)
+             {
+               if (tooNearToOtherCapitalCities(city, capitals, 30) == false || 
+                   tries > 50)
+                 {
+                   createCapitalCity(*pit, city);
+                   capitals.push_back(city);
+                   break;
+                 }
+               else
+                 tries++;
+             }
+           else
+             tries++;
+           if (tries > 100)
+             break;
+         }
+      }
+
+    return true;
+}
+
+bool CreateScenario::setupCities(bool cities_can_produce_allies,
+                                int number_of_armies_factor)
+{
+    debug("CreateScenario::setupCities")
+
+    for (Citylist::iterator it = Citylist::getInstance()->begin();
+        it != Citylist::getInstance()->end(); it++)
+    {
+        City *c = *it;
+        //1. set a reasonable cityname
+        c->setName(popRandomCityName());
+
+        //2. distribute the income a bit (TBD)
+
+        //3. set the city production
+        c->setRandomArmytypes(cities_can_produce_allies, 
+                             number_of_armies_factor);
+
+       c->setGold(getRandomCityIncome(c->isCapital()));
+    }
+
+    return true;
+}
+
+
+bool CreateScenario::setupRoads()
+{
+  Roadlist* rl = Roadlist::getInstance();
+  for (Roadlist::iterator it = rl->begin(); it != rl->end(); it++)
+    (*it)->setType(calculateRoadType((*it)->getPos()));
+  return true;
+}
+
+bool CreateScenario::setupBridges()
+{
+  Bridgelist* bl = Bridgelist::getInstance();
+  for (Bridgelist::iterator it = bl->begin(); it != bl->end(); it++)
+    (*it)->setType(Bridgelist::getInstance()->calculateType((*it)->getPos()));
+  return true;
+}
+
+bool CreateScenario::setupTemples()
+{
+    Templelist* tl = Templelist::getInstance();
+    for (Templelist::iterator it = tl->begin(); it != tl->end(); it++)
+    {
+        // set a random temple type
+        int type= (int) ((TEMPLE_TYPES*1.0) * (rand() / (RAND_MAX + 1.0)));
+        (*it)->setType(type);
+
+    }
+
+    return true;
+}
+bool CreateScenario::setupRuins(bool strongholds_invisible, int sage_factor,
+                               int no_guardian_factor, int stronghold_factor)
+{
+    debug("CreateScenario::setupRuins")
+
+    //The aim of this function is to put a strong stack as sentinel in all
+    //ruins.
+
+    for (Ruinlist::iterator it = Ruinlist::getInstance()->begin();
+        it != Ruinlist::getInstance()->end(); it++)
+    {
+        // set a random ruin type
+        if (rand() % stronghold_factor == 0) //one in six ruins is a stronghold
+          {
+            (*it)->setType(Ruin::STRONGHOLD);
+            if (strongholds_invisible == true)
+              {
+                (*it)->setHidden(true);
+                (*it)->setOwner(NULL);
+              }
+          }
+        else
+          (*it)->setType(Ruin::RUIN);
+
+        //one in twenty ruins is a sage
+        if (rand() % sage_factor == 0 && (*it)->getType() == Ruin::RUIN) 
+          {
+            (*it)->setSage (true);
+            continue;
+          }
+
+
+        //one in ten ruins doesn't have a guardian
+        if (rand() % no_guardian_factor == 0 && (*it)->getType() == Ruin::RUIN) 
+          continue;
+
+        // and set a guardian
+        Stack* s;
+        Army* a = 0;
+        Vector<int> pos = (*it)->getPos();
+        
+       a = getRandomRuinKeeper(Playerlist::getInstance()->getNeutral());
+        if (a)
+          {
+            //create a stack:
+            s = new Stack(0, pos);
+            
+            s->push_back(a);
+            a = 0;
+
+            //now mark this stack as guard
+            (*it)->setOccupant(s);
+          }
+    }
+
+    return true;
+}
+
+bool CreateScenario::setupSignposts(int ratio)
+{
+    int randno;
+    int dynamicPercent = static_cast<int>(1.0 / ratio * 100);
+    debug("CreateScenario::setupSignposts")
+    Signpostlist *sl = Signpostlist::getInstance();
+
+    for (Signpostlist::iterator it = sl->begin(); it != sl->end(); it++)
+    {
+       if (randomSignpostsEmpty())
+           randno = dynamicPercent;
+       else
+           randno = rand() % 100;
+       if (randno < dynamicPercent)
+       {
+            // set up a signpost from the list of signposts
+           (*it)->setName(popRandomSignpost());
+       }
+       else
+       {
+            (*it)->setName(getDynamicSignpost(*it));
+       }
+    }
+
+    return true;
+}
+
+bool CreateScenario::setupPlayers(bool random_turns, 
+                                 int base_gold)
+{
+    debug("CreateScenario::setupPlayers")
+
+    Playerlist *pl = Playerlist::getInstance();
+
+    // Give players some gold to start with
+    for (Playerlist::iterator pit = pl->begin(); pit != pl->end(); pit++)
+      (*pit)->setGold(adjustBaseGold(base_gold));
+
+
+    if (random_turns)
+      pl->randomizeOrder();
+    return true;
+}
+
+bool CreateScenario::setupItems()
+{
+  Itemlist::createStandardInstance();
+  return true;
+}
+
+void CreateScenario::getRuinDifficulty (int difficulty, int *sage_factor, 
+                                       int *no_guardian_factor, 
+                                       int *stronghold_factor)
+{
+  if (difficulty < 50)
+    {
+      *sage_factor = 3;
+      *no_guardian_factor = 5;
+      *stronghold_factor = 12;
+    }
+  else if (difficulty < 60)
+    {
+      *sage_factor = 9;
+      *no_guardian_factor = 6;
+      *stronghold_factor = 10;
+    }
+  else if (difficulty < 70)
+    {
+      *sage_factor = 14;
+      *no_guardian_factor = 8;
+      *stronghold_factor = 9;
+    }
+  else if (difficulty < 80)
+    {
+      *sage_factor = 20;
+      *no_guardian_factor = 10;
+      *stronghold_factor = 6;
+    }
+  else if (difficulty < 90)
+    {
+      *sage_factor = 22;
+      *no_guardian_factor = 12;
+      *stronghold_factor = 4;
+    }
+  else 
+    {
+      *sage_factor = 24;
+      *no_guardian_factor = 15;
+      *stronghold_factor = 3;
+    }
+}
+    
+void CreateScenario::getSignpostDifficulty (int difficulty, bool hidden_map, 
+                                           int *signpost_ratio)
+{
+  //the idea here is that we're on a hidden map, and if it's harder
+  //difficulty, then we don't get as many signs directing us to cities.
+  if (hidden_map)
+    {
+      if (difficulty < 60)
+       *signpost_ratio = 2; //50% of signs point to cities
+      else if (difficulty < 70)
+       *signpost_ratio = 3; //33% of signs point to cities
+      else if (difficulty < 80)
+       *signpost_ratio = 6; //16% of signs point to cities
+      else if (difficulty < 90)
+       *signpost_ratio = 9; //11% of signs point to cities
+      else
+       *signpost_ratio = 15; //6% of signs point to cities
+    }
+  else
+    *signpost_ratio = 6;
+}
+
+    
+void CreateScenario::getCityDifficulty(int difficulty, 
+                                      int *number_of_armies_factor)
+{
+  if (difficulty < 50)
+    *number_of_armies_factor = 3;
+  else if (difficulty < 60)
+    *number_of_armies_factor = 2;
+  else if (difficulty < 70)
+    *number_of_armies_factor = 1;
+  else 
+    *number_of_armies_factor = 0;
+}
+    
+int CreateScenario::calculateRoadType (Vector<int> t)
+{
+    Roadlist *rl = Roadlist::getInstance();
+    Bridgelist *bl = Bridgelist::getInstance();
+
+    // examine neighbour tiles to discover whether there's a road or
+    // bridge on them
+    bool u = false; //up
+    bool b = false; //bottom
+    bool l = false; //left
+    bool r = false; //right
+
+    if (t.y > 0)
+      u = rl->getObjectAt(t + Vector<int>(0, -1));
+    if (t.y < GameMap::getHeight() - 1)
+      b = rl->getObjectAt(t + Vector<int>(0, 1));
+    if (t.x > 0)
+      l = rl->getObjectAt(t + Vector<int>(-1, 0));
+    if (t.x < GameMap::getWidth() - 1)
+      r = rl->getObjectAt(t + Vector<int>(1, 0));
+
+    if (!u && t.y > 0)
+      u = bl->getObjectAt(t + Vector<int>(0, -1));
+    if (!b && t.y < GameMap::getHeight() - 1)
+      b = bl->getObjectAt(t + Vector<int>(0, 1));
+    if (!l && t.x > 0)
+      l = bl->getObjectAt(t + Vector<int>(-1, 0));
+    if (!r && t.x < GameMap::getWidth() - 1)
+      r = bl->getObjectAt(t + Vector<int>(1, 0));
+
+    // then translate this to the type
+    int type = 2; 
+    //show road type 2 when no other road tiles are around
+    if (!u && !b && !l && !r)
+       type = 2;
+    else if (u && b && l && r)
+       type = 2;
+    else if (!u && b && l && r)
+       type = 9;
+    else if (u && !b && l && r)
+       type = 8;
+    else if (u && b && !l && r)
+       type = 7;
+    else if (u && b && l && !r)
+       type = 10;
+    else if (u && b && !l && !r)
+       type = 1;
+    else if (!u && !b && l && r)
+       type = 0;
+    else if (u && !b && l && !r)
+       type = 3;
+    else if (u && !b && !l && r)
+       type = 4;
+    else if (!u && b && l && !r)
+       type = 6;
+    else if (!u && b && !l && r)
+       type = 5;
+    else if (u && !b && !l && !r)
+       type = Road::CONNECTS_NORTH;
+    else if (!u && b && !l && !r)
+       type = Road::CONNECTS_SOUTH;
+    else if (!u && !b && l && !r)
+       type = Road::CONNECTS_WEST;
+    else if (!u && !b && !l && r)
+       type = Road::CONNECTS_EAST;
+    return type;
+}
+
+int CreateScenario::calculateNumberOfSignposts(int width, int height, int grass)
+{
+  int area = width * height;
+  return int(area * (grass / 100.0) * SIGNPOST_FREQUENCY);
+}