/* 
 * Copyright (C) 2003 Tim Martin
 *
 * 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 2 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <math.h>
#include <limits.h>

#include "landvalue.h"
#include "government.h"
#include "map.h"
#include "senkenconfig.h"

#define FARM_MINSIZE_X 3
#define FARM_MINSIZE_Y 3

typedef int circle_enumerate_func(map_t *map, int x, int y, float dist, void *rock);

static int find_flattest(map_t *map, tiles_t *tiles, int size, int *posx, int *posy);

static void
circle_iterate(map_t *map, int x, int y, int radius, 
	       circle_enumerate_func *func, void *rock)
{
    int j;
    int k;
    int mapsizex = map_get_sizex(map);
    int mapsizey = map_get_sizey(map);

    for (j = x-radius; j <= x+radius; j++) {
	for (k = y-radius; k <= y+radius; k++) {
	    float distaway;

	    /* must be within radius */
	    distaway = sqrt((abs(x-j) * abs(x-j)) + (abs(y-k) * abs(y-k)));

	    if ( distaway > radius)
		continue;
	    
	    /* must be within map */
	    if ((j < 0) || (j >= mapsizex)) continue;
	    if ((k < 0) || (k >= mapsizey)) continue;
	    
	    /* make callback */
	    func(map, j, k, distaway, rock);
	}
    }
}

static void
fill(map_t *map, int startx, int starty, int startheight,
     int x, int y, int radius, 
     circle_enumerate_func *func, void *rock)
{
    int h;
    float dist;
    int r;

    h = map_get_height(map, x, y);
    if (h != startheight) {
	return;
    }
    if (!map_islevel(map, x, y)) return;

    dist = sqrt((abs(x-startx) * abs(x-startx)) + 
		(abs(y-starty) * abs(y-starty)));
    if (dist > radius+rand()%(radius/4+1)) return;

    r = func(map, x, y, dist, rock);
    if (r) return;

    fill(map, startx, starty, startheight, 
	 x+1, y, radius, func, rock);
    fill(map, startx, starty, startheight, 
	 x-1, y, radius, func, rock);
    fill(map, startx, starty, startheight, 
	 x, y+1, radius, func, rock);
    fill(map, startx, starty, startheight, 
	 x, y-1, radius, func, rock);
}

static void
fill_iterate(map_t *map, int x, int y, int radius, 
	       circle_enumerate_func *func, void *rock)
{
    int starth = map_get_height(map, x, y);

    fill(map, x, y, starth, x, y, radius, func, rock);
}


static int
make_mountain_cb(map_t *map, int x, int y, float dist, void *rock)
{
    if (map_empty_land(map,x,y)) {
	map_raise_spot(map, x, y);
    }
    return 0;
}

static void
make_mountain(map_t *map, int x, int y, int radius, int height)
{
    int i;
    float change = ((float)radius)/((float)height);
    float rad = radius;

    for (i = 0; i < height; i++) {

	circle_iterate(map, x, y, rad, &make_mountain_cb, NULL);

	rad -= change;
	if (rad <= 1) rad = 1;
    }    
}

#define PI 3.1416

static void
create_some_mountains(map_t *map, float perc_land_cover,
		      int radius_avg, int radius_var,
		      int height_avg, int height_var)
{
    int i;
    int mapsizex = map_get_sizex(map);
    int mapsizey = map_get_sizey(map);
    int num;
    float avgarea = PI * ((float)radius_avg) * ((float)radius_avg); 

    num = ((float)mapsizex * mapsizey) / avgarea * (perc_land_cover / 100.0);

    for (i = 0; i < num; i++) {
	int posx;
	int posy;
	int radius = radius_avg - radius_var;
	int height = height_avg - height_var;

	if (radius_var) {
	    radius += (rand()%(2 * radius_var));
	}
	if (height_var) {
	    height += (rand()%(2 * height_var));
	}

	posx = rand()%(mapsizex);
	posy = rand()%(mapsizey);
	
	make_mountain(map, posx, posy, radius, height);
    }
}

static int
valid_farm_pos(map_t *map, int x, int y)
{
    if (x >= map_get_sizex(map)) return 0;
    if (y >= map_get_sizey(map)) return 0;

    if (!map_islevel(map, x, y)) return 0;
    
    if (map_get_maptype(map, x, y) == MAPTYPE_WATER) return 0;

    return 1;
}

static int
valid_farm_spot(map_t *map, int x, int y)
{
    int i;
    int j;
    int mapsizex = map_get_sizex(map);
    int mapsizey = map_get_sizey(map);

    if (x + FARM_MINSIZE_X >= mapsizex) return 0;
    if (y + FARM_MINSIZE_Y >= mapsizey) return 0;

    for (i = x; i < x+FARM_MINSIZE_X; i++) {
	for (j = y; j < y+FARM_MINSIZE_Y; j++) {

	    if (!valid_farm_pos(map, i, j)) return 0;
	}
    }

    return 1;
}

static void
set_farm(map_t *map, int x, int y)
{
    int i;
    int j;
    int mult = rand()%3+1;

    for (i = x; i < x+FARM_MINSIZE_X*mult; i++) {
	for (j = y; j < y+FARM_MINSIZE_Y*mult; j++) {
	    if (valid_farm_pos(map, i, j)) {
		set_map_byname(map, i, j, "Field", 0);
	    }
	}
    }
    
    do {
	i = rand()%FARM_MINSIZE_X + x;
	j = rand()%FARM_MINSIZE_Y + y;
    } while (!valid_farm_pos(map, i, j));

    set_map_byname(map, i, j, "Farm", 0);
}

static void
add_farms(map_t *map, int amount)
{
    int i;
    int mapsizex = map_get_sizex(map);
    int mapsizey = map_get_sizey(map);
    int added = 0;
    int trys;
    int farms;

    farms = amount * (mapsizex*mapsizey/1000);
    trys = farms*100;
    
    for (i = 0; (i < trys) && (added < farms); i++) {
	int posx;
	int posy;

	posx = rand()%(mapsizex);
	posy = rand()%(mapsizey);    

	if (valid_farm_spot(map, posx, posy)) {
	    set_farm(map, posx, posy);
	    added++;
	}
    }

}

typedef struct make_spot_struct_s {
    int owner;

    int school_every;
    mapspot_list_t *schoolslist;
    int police_every;
    mapspot_list_t *policelist;
    int hospital_every;
    mapspot_list_t *hospitallist;
    int fire_every;
    mapspot_list_t *firelist;
    int power_every;
    mapspot_list_t *powerlist;
    int water_tot;

    int perc_industry;
    int perc_office;
    int perc_commercial;
    int perc_housing;
    
} make_spot_struct_t;

static int
make_service(map_t *map, int owner, int x, int y, char *name,
	     int every, mapspot_list_t **list)
{
    if (!map_within_type(map, x, y, 5, MAPTYPE_ROAD, -1)) {
	return 0;
    }

    if (every) {
	if (mapspot_list_num_within(*list, x, y, every) <= 0) {
	    if (!set_map_byname(map, x, y, name, 0)) {		
		map_set_owner(map, owner, NULL, x, y, 1);
		mapspot_list_add(list, x, y, NULL);
	    }
	    return 1;
	}
    }

    return 0;
}

static int
make_town_spot(map_t *map, int x, int y, float dist, void *rock)
{
    mapobj_t curobj = map_get_type(map, x, y);
    make_spot_struct_t *st = (make_spot_struct_t *)rock;
    int num;
    int cnt;

    /* don't overwrite anything */
    if (!map_item_emptyland(curobj)) return 1;

    if (st->water_tot > 0) {
	if (!set_map_byname(map, x, y, "Well", 0)) {
	    map_set_owner(map, st->owner, NULL, x, y, 1);
	    st->water_tot--;
	}
    }

    if (make_service(map, st->owner, x, y, "PowerCoal",
		     st->power_every, &st->powerlist)) {
	return 0;
    }

    if (make_service(map, st->owner, x, y, "School",
		     st->school_every, &st->schoolslist)) {
	return 0;
    }

    if (make_service(map, st->owner, x, y, "Police",
		     st->police_every, &st->policelist)) {
	return 0;
    }

    if (make_service(map, st->owner, x, y, "Hospital",
		     st->hospital_every, &st->hospitallist)) {
	return 0;
    }

    if (make_service(map, st->owner, x, y, "FireStation",
		     st->fire_every, &st->firelist)) {
	return 0;
    }

    num = rand()%100;
    cnt = 0;

    cnt += st->perc_industry;    
    if ((num < cnt) &&
       (map_within_type(map, x, y, 4, MAPTYPE_ROAD, -1))) {
	set_map_byname(map, x, y, "ZoneIndustrial", 0);
	return 0;
    }

    cnt += st->perc_office;
    if ((num < cnt) &&
       (map_within_type(map, x, y, 3, MAPTYPE_ROAD, -1))) {
	set_map_byname(map, x, y, "ZoneOffice", 0);
	return 0;
    }

    cnt += st->perc_commercial;
    if ((num < cnt) &&
	(map_within_type(map, x, y, 3, MAPTYPE_ROAD, -1))) {	
	set_map_byname(map, x, y, "ZoneCommercial", 0);
	return 0;
    }

    cnt += st->perc_housing;
    if ((num < cnt) &&
	(map_within_type(map, x, y, 3, MAPTYPE_ROAD, -1))) {	
	set_map_byname(map, x, y, "ZoneHouse", 0);
	return 0;
    }

    return 1;
}

static int
calc_dist(int x1, int y1, int x2, int y2)
{
    float distaway;
    
    distaway = sqrt((abs(x2-x1) * abs(x2-x1)) + (abs(y2-y1) * abs(y2-y1)));

    return distaway;
}

#define UP 0
#define DOWN 1
#define RIGHT 2
#define LEFT 3

static void
make_roads(map_t *map, int owner, int origx, int origy, int curx, 
	   int cury, int dir, int dist)
{
    mapobj_t curobj = map_get_type(map, curx, cury);
    int moved = 0;

    switch(dir) {
    case UP:
	while (calc_dist(origx, origy, curx, cury) < dist) {
	    curobj = map_get_type(map, curx, cury);
	    if (!map_item_emptyland(curobj)) return;
	    
	    if (set_map_byname(map, curx, cury, "Road", 0)) {
		return;
	    }
	    map_set_owner(map, owner, NULL, curx, cury, 1);
	    
	    cury--;
	    moved++;

	    if (moved >= 5+rand()%3) {
		if ((map_get_maptype(map, curx+1, cury+1) != MAPTYPE_ROAD) &&
		    (map_get_maptype(map, curx+1, cury-1) != MAPTYPE_ROAD)) {
		    make_roads(map, owner, origx, origy, curx+1, cury, RIGHT, dist);
		}
		if ((map_get_maptype(map, curx-1, cury+1) != MAPTYPE_ROAD) &&
		    (map_get_maptype(map, curx-1, cury-1) != MAPTYPE_ROAD)) {
		    make_roads(map, owner, origx, origy, curx-1, cury, LEFT, dist);
		}
		moved = 0;
	    }
	}

	break;
    case DOWN:
	while(calc_dist(origx, origy, curx, cury) < dist) {
	    curobj = map_get_type(map, curx, cury);
	    if (!map_item_emptyland(curobj)) return;

	    if (set_map_byname(map, curx, cury, "Road", 0)) {	    
		return;
	    }
	    map_set_owner(map, owner, NULL, curx, cury, 1);
	    
	    cury++;
	    moved++;

	    if (moved >= 5+rand()%3) {
		if ((map_get_maptype(map, curx+1, cury+1) != MAPTYPE_ROAD) &&
		    (map_get_maptype(map, curx+1, cury-1) != MAPTYPE_ROAD)) {
		    make_roads(map, owner, origx, origy, curx+1, cury, RIGHT, dist);
		}
		if ((map_get_maptype(map, curx-1, cury+1) != MAPTYPE_ROAD) &&
		    (map_get_maptype(map, curx-1, cury-1) != MAPTYPE_ROAD)) {
		    make_roads(map, owner, origx, origy, curx-1, cury, LEFT, dist);
		}
		moved = 0;
	    }
	}
	break;
    case RIGHT:
	while(calc_dist(origx, origy, curx, cury) < dist) {
	    curobj = map_get_type(map, curx, cury);
	    if (!map_item_emptyland(curobj)) return;

	    if (set_map_byname(map, curx, cury, "Road", 0)) {	    	    
		return;
	    }
	    map_set_owner(map, owner, NULL, curx, cury, 1);
	    
	    curx++;
	    moved++;

	    if (moved >= 5+rand()%3) {
		if ((map_get_maptype(map, curx+1, cury-1) != MAPTYPE_ROAD) &&
		    (map_get_maptype(map, curx-1, cury-1) != MAPTYPE_ROAD)) {
		    make_roads(map, owner, origx, origy, curx, cury-1, UP, dist);
		}
		if ((map_get_maptype(map, curx+1, cury+1) != MAPTYPE_ROAD) &&
		    (map_get_maptype(map, curx-1, cury+1) != MAPTYPE_ROAD)) {
		    make_roads(map, owner, origx, origy, curx, cury+1, DOWN, dist);
		}
		moved = 0;
	    }
	}
	break;
    case LEFT:
	while(calc_dist(origx, origy, curx, cury) < dist) {
	    curobj = map_get_type(map, curx, cury);
	    if (!map_item_emptyland(curobj)) return;

	    if (set_map_byname(map, curx, cury, "Road", 0)) {	    	    	
		return;
	    }
	    map_set_owner(map, owner, NULL, curx, cury, 1);
	    
	    curx--;
	    moved++;

	    if (moved >= 5+rand()%3) {
		if ((map_get_maptype(map, curx+1, cury-1) != MAPTYPE_ROAD) &&
		    (map_get_maptype(map, curx-1, cury-1) != MAPTYPE_ROAD)) {
		    make_roads(map, owner, origx, origy, curx, cury-1, UP, dist);
		}
		if ((map_get_maptype(map, curx+1, cury+1) != MAPTYPE_ROAD) &&
		    (map_get_maptype(map, curx-1, cury+1) != MAPTYPE_ROAD)) {
		    make_roads(map, owner, origx, origy, curx, cury+1, DOWN, dist);
		}
		moved = 0;
	    }
	}
	break;
    }
}

static int
make_edgefarm(map_t *map, int x, int y, float dist, void *rock)
{
    int *minradius = (int *)rock;

    if (dist < *minradius) return 0;

    return set_map_byname(map, x, y, "ZoneFarm", 0);
}

static void
make_town(map_t *map, int playernum, int x, int y, int maxradius)
{
    int edgefarms = config_getswitch("initial_edgefarms", 0);
    make_spot_struct_t st;
    int area = maxradius * maxradius * PI;

    make_roads(map, playernum, x, y, x, y, UP, maxradius*1.5);
    make_roads(map, playernum, x, y, x, y-1, DOWN, maxradius*1.5);
    make_roads(map, playernum, x, y, x+1, y, RIGHT, maxradius*1.5);
    make_roads(map, playernum, x, y, x-1, y, LEFT, maxradius*1.5);

    memset(&st, 0, sizeof(make_spot_struct_t));
    st.owner = playernum;
    st.school_every = 25;
    st.police_every = 25;
    st.fire_every = 25;
    st.hospital_every = 25;
    st.perc_industry = 5;
    st.perc_office = 15;
    st.perc_commercial = 15;
    st.perc_housing = 60;
    st.power_every = 40;
    st.water_tot = area/100;

    circle_iterate(map, x, y, maxradius/4+2,
		   &make_town_spot, &st);

    circle_iterate(map, x, y, maxradius,
		   &make_town_spot, &st);

    if (edgefarms) {
	circle_iterate(map, x, y, maxradius*1.5,
		       &make_edgefarm, &maxradius);
    }
}

static void
add_towns(map_t *map, tiles_t *tiles, player_t *player,
	  int num_towns, int *centerx, int *centery)
{
    int i;
    int townradius = config_getint("initial_town_radius", 10);
    int playernum = player_getnum(player);

    for (i = 0; i < num_towns; i++) {
	int x;
	int y;

	do {
	    find_flattest(map, tiles, 10, &x, &y);
	} while (!map_empty_land(map, x, y));

	make_town(map, playernum, x, y, townradius);
	*centerx = x;
	*centery = y;
    }
}

static int
make_river_func(map_t *map, int x, int y, float dist, void *rock)
{
    set_map_byname(map, x, y, "Water", 1);
    return 0;
}

static void
random_edge_coordinate(map_t *map, int *outx, int *outy)
{
    int mapsizex = map_get_sizex(map);
    int mapsizey = map_get_sizey(map);
    int startx;
    int starty;
    
    if (rand()%2 == 0) {
	startx = rand()%mapsizex;
	if (rand()%2 == 0) {
	    starty = 0;
	} else {
	    starty = mapsizey - 1;
	}
    } else {
	starty = rand()%mapsizey;
	if (rand()%2 == 0) {
	    startx = 0;
	} else {
	    startx = mapsizex - 1;
	}
    }    

    *outx = startx;
    *outy = starty;
}

/*
 * -Pick 2 edge points
 * -Step from one to the other
 * -draw a circle of water for each step
 * -vary radius slightly as you go
 * -don't always go exactly toward the goal
 */
static void
add_river(map_t *map)
{
    int mapsizex = map_get_sizex(map);
    int mapsizey = map_get_sizey(map);
    int radius = 5;
    int startx;
    int starty;
    int endx;
    int endy;

    /* calculate random start/stop */
    if (rand()%2 == 0) {
	startx = rand()%mapsizex;
	starty = 0;
    } else {
	starty = rand()%mapsizey;
	startx = 0;
    }

    if (rand()%2 == 0) {
	endx = rand()%mapsizex;
	endy = mapsizey-1;
    } else {
	endy = rand()%mapsizey;
	endx = mapsizex-1;
    }

    
    while ((startx != endx) || (starty < endy)) {
	int rightx;
	int righty;

	/* move a little closer */
	if (endx > startx) {
	    rightx = 1;
	} else {
	    rightx = -1;
	}

	/* xxx */
	righty = 1;

	if (rand()%5 < 3) {
	    startx += rightx;
	} else {
	    startx -= rightx;
	}

	if (rand()%5 < 4) {
	    starty += righty;
	} else {
	    starty -= righty;
	}

	radius = 5 + (rand()%4 - 2);

	circle_iterate(map, startx, starty, radius, &make_river_func, NULL);
    }
}

static int
find_lowest(map_t *map, int x, int y, float dist, void *rock)
{
    int *lowest = (int *)rock;
    int h;

    h = map_get_height(map, x, y);

    if (h < *lowest) {
	*lowest = h;
    }

    return 0;
}

static int
make_lake_func(map_t *map, int x, int y, float dist, void *rock)
{
    int h;

    if (!map_islevel(map, x, y)) return 0;

    h = map_get_height(map, x, y);

    if (h == *(int *)rock) {
	set_map_byname(map, x, y, "Water", 1);
    }
    return 0;
}

static void
add_lake(map_t *map)
{
    int radius = config_getint("lake_radius", 5);
    int variance = config_getint("lake_variance", 3);
    int x;
    int y;
    int mapsizex = map_get_sizex(map);
    int mapsizey = map_get_sizey(map);
    int lowest = INT_MAX;

    x = rand()%mapsizex;
    y = rand()%mapsizey;
    if (variance) {
	radius = radius - variance + rand()%(variance*2);
    }

    /* find lowest */
    circle_iterate(map, x, y, radius, &find_lowest, &lowest);

    /* make lake */
    circle_iterate(map, x, y, radius, &make_lake_func, &lowest);
}

static int
set_spot(map_t *map, int x, int y, float dist, void *rock)
{
    mapobj_t *obj = (mapobj_t *)rock;
    mapobj_t curobj = map_get_type(map, x, y);
    int r;

    if (curobj == *obj) {
	return 1;
    }

    r = map_set_type(map, x, y, *obj, 0);   
    return r;
}

static int
set_types(map_t *map)
{
    const char *extra = config_getstring("initial_land_extra", NULL);
    int mapsizex = map_get_sizex(map);
    int mapsizey = map_get_sizey(map);
    
    if (extra) {
	int number;
	int radius;
	int variance;
	char kind[256];
	char type[256];
	mapobj_t obj;
	int posx;
	int posy;
	int i;

	sscanf(extra,"%64[^-]-%d-%d-%d-%s", kind, &number, &radius, &variance, type);

	for (i = 0; i < number; i++) {
	    obj = map_item_name2obj(type);
	    if (obj == MAPOBJ_INVALID) {
		printf(_("invalid type specified in initial_land_extra: %s"), type);
		return -1;
	    }
	    
	    posx = rand()%(mapsizex);
	    posy = rand()%(mapsizey);

	    if (variance) {
		radius = radius - (variance/2) + rand()%variance;
		if (radius < 0) radius = 0;
	    }
		
	    if (strcasecmp(kind, "circle") == 0) {

		circle_iterate(map, posx, posy, radius,
			   &set_spot, &obj);
	    } else if (strcasecmp(kind, "fill") == 0) {
		fill_iterate(map, posx, posy, radius,
			     &set_spot, &obj);
	    }
	}
    }

    return 0;
}

static void
slope_map(map_t *map)
{
    int x;
    int y;
    int mapsize = map_get_sizex(map);
    int slope = config_getint("slope_height", 0);

    if (slope == 0) return;

    random_edge_coordinate(map, &x, &y);
    make_mountain(map, x, y, mapsize*(rand()%200)/100, rand()%10);
}

extern int
government_randomize(map_t *map, tiles_t *tiles, player_t *player, 
		     int *centerx, int *centery)
{
    int i;
    int num_rivers = config_getint("num_rivers", 1);
    int num_lakes = config_getint("num_lakes", 1);
    int amount_mnts = config_getint("amount_mountains", 0);
    int bumpy_perc = config_getint("land_bumpy_perc", 5);
    int amount_farms = config_getint("amount_farms", 2);
    int num_towns = config_getint("initial_towns", 0);

    /* river (at sea level) */
    for (i = 0; i < num_rivers; i++) {
	add_river(map);
    }

    /* slope whole map */
    slope_map(map);

    /* lakes are at ground level */
    for (i = 0; i < num_lakes; i++) {
	add_lake(map);
    }

    /* raise some parts */
    create_some_mountains(map, amount_mnts,
			  20, 10,
			  20, 10);
    
    create_some_mountains(map, bumpy_perc,
			  2, 1,
			  1, 0);

    /* set land types */
    set_types(map);

    /* add some housing */    
    add_towns(map, tiles, player, num_towns, centerx, centery);

    /* add some farms */
    add_farms(map, amount_farms);

    return 0;
}

static int
count_level(map_t *map, int x, int y, float dist, void *rock)
{
    int *num = (int *)rock;
#if 0
	    num += government_calculate_onelandvalue(map, tiles, x, y);
#else
	    if ((map_islevel(map, x, y)) &&
		(map_item_emptyland(map_get_type(map, x, y)))) {
		(*num)++;
	    }
#endif /* 0 */

	    return 0;
}

typedef struct find_flattest_s {
    int radius;
    int onlytry;
    int x;
    int y;
    int num;
    tiles_t *tiles;
} find_flattest_t;

static void
find_flattest_cb(map_t *map, int mapx, int mapy, int owner, 
		 mapobj_t obj, void *rock)
{
    find_flattest_t *flat = (find_flattest_t *)rock;
    int num = 0;
    
    /*
     * Don't try every single square
     */
    if (flat->onlytry > 0) {
	if ((mapx % flat->onlytry != 0) || (mapy % flat->onlytry != 0)) {
	    return;
	}
    }

    circle_iterate(map, mapx, mapy, flat->radius,
		   &count_level, &num);

    if (num > flat->num) {
	flat->x = mapx;
	flat->y = mapy;
	flat->num = num;
    }	
}


static int
find_flattest(map_t *map, tiles_t *tiles, int size, int *posx, int *posy)
{
    find_flattest_t flat;

    flat.radius = size;
    flat.onlytry = flat.radius;
    flat.x = -1;
    flat.y = -1;
    flat.num = -1;    
    flat.tiles = tiles;

    government_enable_landvalue_cache(map);
    
    map_iterate(map, MAP_ITERATE_RANDOM, 0, 0, 0,
		NULL, NULL,
		NULL, NULL,
		&find_flattest_cb, &flat);

    government_disable_landvalue_cache();
    
    *posx = flat.x;
    *posy = flat.y;

    return 0;
}

static int
give_land(map_t *map, int x, int y, float dist, void *rock)
{
    player_t *player = (player_t *)rock;

    map_set_owner(map, player_getnum(player), NULL,
		  x, y, 1);

    return 0;
}

extern int
government_initial_player_land(map_t *map, tiles_t *tiles, player_t *player,
			       int *centerx, int *centery)
{
    int size = config_getint("initial_land_radius", 0);
    int posx = config_getint("initial_land_posx", -1);
    int posy = config_getint("initial_land_posy", -1);
    int owntown = config_getswitch("initial_land_population_center", 0);

    if (!size) return 0;

    if (owntown) {
	posx = *centerx;
	posy = *centery;
    } else if ((posx < 0) || (posy < 0)) {
	find_flattest(map, tiles, size, &posx, &posy);
    }

    /*
     * buy it
     */
    circle_iterate(map, posx, posy, size,
		   &give_land, player);

    *centerx = posx;
    *centery = posy;

    return 0;
}

