added basic map generator configuration

This commit is contained in:
uid68803 2004-01-06 00:22:47 +00:00
parent 1ae8fc77f7
commit 8fa6c82b58
9 changed files with 270 additions and 64 deletions

View file

@ -6,7 +6,7 @@ iterations=1000
hill_size=10
max_lakes=40
villages=800
players=6
players=2
min_lake_height=500
lake_size=150
river_frequency=20

View file

@ -322,6 +322,14 @@ display_type="Display:"
full_screen="Full Screen"
windowed="Windowed"
map_generator="Map Generator"
regenerate_map="Regenerate"
generator_settings="Settings..."
num_players="Players"
map_width="Width"
map_height="Height"
hotkeys_button="Hotkeys"
action_quit="Quit Game"
action_unitlist="Unit List"

View file

@ -9,10 +9,17 @@
#include <ctime>
#include <vector>
#include "events.hpp"
#include "font.hpp"
#include "language.hpp"
#include "mapgen.hpp"
#include "pathfind.hpp"
#include "show_dialog.hpp"
#include "util.hpp"
#include "widgets/button.hpp"
#include "widgets/slider.hpp"
//function to generate a random map, from a string which describes
//the generator to use and its arguments
std::string random_generate_map(const std::string& parms)
@ -685,9 +692,141 @@ default_map_generator::default_map_generator(const config& game_config)
}
}
bool default_map_generator::allow_user_config() const { return false; }
bool default_map_generator::allow_user_config() const { return true; }
void default_map_generator::user_config(display& disp) {}
void default_map_generator::user_config(display& disp)
{
const events::resize_lock prevent_resizing;
const events::event_context dialog_events_context;
const int width = 600;
const int height = 400;
const int xpos = disp.x()/2 - width/2;
const int ypos = disp.y()/2 - height/2;
SDL_Rect dialog_rect = {xpos-10,ypos-10,width+20,height+20};
surface_restorer restorer(&disp.video(),dialog_rect);
gui::draw_dialog_frame(xpos,ypos,width,height,disp);
SDL_Rect title_rect = font::draw_text(NULL,disp.screen_area(),24,font::NORMAL_COLOUR,
string_table["map_generator"],0,0);
gui::button close_button(disp,string_table["close_window"]);
close_button.set_x(xpos + width/2 - close_button.width()/2);
close_button.set_y(ypos + height - close_button.height()-14);
const std::string& players_label = string_table["num_players"] + ":";
const std::string& width_label = string_table["map_width"] + ":";
const std::string& height_label = string_table["map_height"] + ":";
SDL_Rect players_rect = font::draw_text(NULL,disp.screen_area(),14,font::NORMAL_COLOUR,players_label,0,0);
SDL_Rect width_rect = font::draw_text(NULL,disp.screen_area(),14,font::NORMAL_COLOUR,width_label,0,0);
SDL_Rect height_rect = font::draw_text(NULL,disp.screen_area(),14,font::NORMAL_COLOUR,height_label,0,0);
const int horz_margin = 5;
const int text_right = xpos + horz_margin + maximum<int>(maximum<int>(players_rect.w,width_rect.w),height_rect.w);
players_rect.x = text_right - players_rect.w;
width_rect.x = text_right - width_rect.w;
height_rect.x = text_right - height_rect.w;
const int vertical_margin = 20;
players_rect.y = ypos + title_rect.h + vertical_margin*2;
width_rect.y = players_rect.y + players_rect.h + vertical_margin;
height_rect.y = width_rect.y + width_rect.h + vertical_margin;
const int max_players = 9;
const int right_space = 100;
const int slider_left = text_right + 10;
const int slider_right = xpos + width - horz_margin - right_space;
SDL_Rect slider_rect = { slider_left,players_rect.y,slider_right-slider_left,players_rect.h};
gui::slider players_slider(disp,slider_rect,gui::slider::normalize(nplayers_,2,max_players));
const int min_width = 20;
const int max_width = 80;
const int min_height = 20;
const int max_height = 80;
slider_rect.y = width_rect.y;
gui::slider width_slider(disp,slider_rect,gui::slider::normalize(width_,min_height,max_height));
slider_rect.y = height_rect.y;
gui::slider height_slider(disp,slider_rect,gui::slider::normalize(height_,min_width,max_width));
for(bool draw = true;; draw = false) {
int mousex, mousey;
const int mouse_flags = SDL_GetMouseState(&mousex,&mousey);
const bool left_button = mouse_flags&SDL_BUTTON_LMASK;
if(close_button.process(mousex,mousey,left_button)) {
break;
}
const double new_players = players_slider.process(mousex,mousey,left_button);
if(new_players >= 0.0) {
nplayers_ = gui::slider::denormalize(new_players,2,max_players);
std::cerr << "set players to " << nplayers_ << "," << new_players << "\n";
draw = true;
}
const double new_width = width_slider.process(mousex,mousey,left_button);
if(new_width >= 0.0) {
width_ = gui::slider::denormalize(new_width,min_width,max_width);
draw = true;
}
const double new_height = height_slider.process(mousex,mousey,left_button);
if(new_height >= 0.0) {
height_ = gui::slider::denormalize(new_height,min_height,max_height);
draw = true;
}
if(draw) {
gui::draw_dialog_frame(xpos,ypos,width,height,disp);
title_rect = font::draw_text(&disp,disp.screen_area(),24,font::NORMAL_COLOUR,
string_table["map_generator"],xpos+(width-title_rect.w)/2,ypos+10);
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,players_label,players_rect.x,players_rect.y);
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,width_label,width_rect.x,width_rect.y);
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,height_label,height_rect.x,height_rect.y);
std::stringstream players_str;
players_str << nplayers_;
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,players_str.str(),
slider_right+horz_margin,players_rect.y);
std::stringstream width_str;
width_str << width_;
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,width_str.str(),
slider_right+horz_margin,width_rect.y);
std::stringstream height_str;
height_str << height_;
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,height_str.str(),
slider_right+horz_margin,height_rect.y);
players_slider.draw();
width_slider.draw();
height_slider.draw();
close_button.draw();
update_rect(xpos,ypos,width,height);
}
disp.update_display();
SDL_Delay(10);
events::pump();
}
}
std::string default_map_generator::name() const { return "default"; }

View file

@ -269,8 +269,8 @@ int play_multiplayer(display& disp, game_data& units_data, config cfg,
state.gold = 100;
// Dialog width and height
int width=600;
int height=290;
int width=640;
int height=340;
int cur_selection = -1;
int cur_villagegold = 1;
@ -363,15 +363,26 @@ int play_multiplayer(display& disp, game_data& units_data, config cfg,
launch_game.set_xy((disp.x()/2)-launch_game.width()*2-19,(disp.y()-height)/2+height-29);
cancel_game.set_xy((disp.x()/2)+cancel_game.width()+19,(disp.y()-height)/2+height-29);
gui::button regenerate_map(disp,string_table["regenerate_map"]);
regenerate_map.set_xy(rect.x+6,rect.y+30+(3*fog_game.height())+6);
regenerate_map.backup_background();
gui::button generator_settings(disp,string_table["generator_settings"]);
generator_settings.set_xy(rect.x+6,rect.y+30+(4*fog_game.height())+8);
generator_settings.backup_background();
//player amount number background
rect.x = ((disp.x()-width)/2+10)+35;
rect.y = (disp.y()-height)/2+235;
rect.w = 145;
rect.h = 25;
SDL_Surface* playernum_bg=get_surface_portion(disp.video().getSurface(), rect);
surface_restorer playernum_bg(&disp.video(),rect);
update_whole_screen();
//the current map generator
map_generator* generator = NULL;
CKey key;
config* level_ptr = NULL;
for(;;) {
@ -464,6 +475,9 @@ int play_multiplayer(display& disp, game_data& units_data, config cfg,
update_rect(rect);
}
//work out if we have to generate a new map
bool map_changed = false;
//Villages can produce between 1 and 10 gold a turn
//FIXME: Should never be a - number, but it is sometimes
int check_villagegold=1+int(9*villagegold_slider.process(mousex,mousey,left_button));
@ -483,68 +497,22 @@ int play_multiplayer(display& disp, game_data& units_data, config cfg,
}
if(maps_menu.selection() != cur_selection) {
map_changed = true;
generator = NULL;
cur_selection = maps_menu.selection();
if(size_t(maps_menu.selection()) != options.size()-1) {
level_ptr = levels[maps_menu.selection()];
std::string map_data = (*level_ptr)["map_data"];
std::string& map_data = (*level_ptr)["map_data"];
if(map_data == "" && (*level_ptr)["map"] != "") {
map_data = read_file("data/maps/" + (*level_ptr)["map"]);
}
//if the map should be randomly generated
if(map_data == "" && (*level_ptr)["map_generation"] != "") {
map_data = random_generate_map((*level_ptr)["map_generation"]);
//record the map data of the map, so that when we send to
//remote clients, they will use the given map, and won't try
//to generate their own.
(*level_ptr)["map_data"] = map_data;
if((*level_ptr)["map_generation"] != "") {
generator = get_map_generator((*level_ptr)["map_generation"]);
}
gamemap map(cfg,map_data);
//if there are less sides in the configuration than there are starting
//positions, then generate the additional sides
const int map_positions = map.num_valid_starting_positions();
std::cerr << "map_positions: " << map_positions << "\n";
for(int pos = level_ptr->get_children("side").size(); pos < map_positions; ++pos) {
std::cerr << "adding side...\n";
config& side = level_ptr->add_child("side");
side["enemy"] = "1";
char buf[50];
sprintf(buf,"%d",(pos+1));
side["side"] = buf;
side["team_name"] = buf;
side["canrecruit"] = "1";
side["controller"] = "human";
}
const scoped_sdl_surface mini(image::getMinimap(145,145,map));
if(mini != NULL) {
rect.x = ((disp.x()-width)/2+10)+35;
rect.y = (disp.y()-height)/2+80;
rect.w = 145;
rect.h = 145;
SDL_BlitSurface(mini, NULL, disp.video().getSurface(), &rect);
update_rect(rect);
}
//Display the number of players
rect.x = ((disp.x()-width)/2+10)+35;
rect.y = (disp.y()-height)/2+235;
rect.w = 145;
rect.h = 25;
SDL_BlitSurface(playernum_bg, NULL, disp.video().getSurface(), &rect);
config& level = *level_ptr;
const int nsides = level.get_children("side").size();
std::stringstream players;
players << "Players: " << nsides;
font::draw_text(&disp,disp.screen_area(),12,font::GOOD_COLOUR,
players.str(),rect.x+45,rect.y);
update_rect(rect);
}else{
const scoped_sdl_surface disk(image::get_image("misc/disk.png",image::UNSCALED));
@ -561,13 +529,79 @@ int play_multiplayer(display& disp, game_data& units_data, config cfg,
rect.y = (disp.y()-height)/2+235;
rect.w = 145;
rect.h = 25;
SDL_BlitSurface(playernum_bg, NULL, disp.video().getSurface(), &rect);
playernum_bg.restore();
font::draw_text(&disp,disp.screen_area(),12,font::GOOD_COLOUR,
" Load Map ",rect.x+45,rect.y);
update_rect(rect);
}
}
if(generator != NULL && generator->allow_user_config() && generator_settings.process(mousex,mousey,left_button)) {
generator->user_config(disp);
}
if(generator != NULL && (map_changed || regenerate_map.process(mousex,mousey,left_button))) {
//generate the random map
(*level_ptr)["map_data"] = generator->create_map(std::vector<std::string>());
map_changed = true;
}
if(map_changed) {
if(generator != NULL) {
generator_settings.draw();
regenerate_map.draw();
} else {
generator_settings.hide();
regenerate_map.hide();
}
const std::string& map_data = (*level_ptr)["map_data"];
gamemap map(cfg,map_data);
//if there are less sides in the configuration than there are starting
//positions, then generate the additional sides
const int map_positions = map.num_valid_starting_positions();
std::cerr << "map_positions: " << map_positions << "\n";
for(int pos = level_ptr->get_children("side").size(); pos < map_positions; ++pos) {
std::cerr << "adding side...\n";
config& side = level_ptr->add_child("side");
side["enemy"] = "1";
char buf[50];
sprintf(buf,"%d",(pos+1));
side["side"] = buf;
side["team_name"] = buf;
side["canrecruit"] = "1";
side["controller"] = "human";
}
const scoped_sdl_surface mini(image::getMinimap(145,145,map));
if(mini != NULL) {
rect.x = ((disp.x()-width)/2+10)+35;
rect.y = (disp.y()-height)/2+80;
rect.w = 145;
rect.h = 145;
SDL_BlitSurface(mini, NULL, disp.video().getSurface(), &rect);
update_rect(rect);
}
//Display the number of players
rect.x = ((disp.x()-width)/2+10)+35;
rect.y = (disp.y()-height)/2+235;
rect.w = 145;
rect.h = 25;
playernum_bg.restore();
config& level = *level_ptr;
const int nsides = level.get_children("side").size();
std::stringstream players;
players << "Players: " << nsides;
font::draw_text(&disp,disp.screen_area(),12,font::GOOD_COLOUR,
players.str(),rect.x+45,rect.y);
update_rect(rect);
}
events::pump();
disp.video().flip();
SDL_Delay(20);

View file

@ -373,10 +373,10 @@ void show_preferences_dialog(display& disp)
log_scope("show_preferences_dialog");
const int xpos = disp.x()/2 - 300;
const int ypos = disp.y()/2 - 200;
const int width = 600;
const int height = 400;
const int xpos = disp.x()/2 - width/2;
const int ypos = disp.y()/2 - height/2;
//make sure that the frame buffer is restored to its original state
//when the dialog closes. Not const, because we might want to cancel

View file

@ -100,12 +100,22 @@ bool button::checked() const
return state_ == PRESSED || state_ == PRESSED_ACTIVE;
}
void button::backup_background()
{
const SDL_Rect area = {x_,y_,w_,h_};
restorer_ = surface_restorer(&display_->video(),area);
}
void button::hide()
{
restorer_.restore();
}
void button::draw()
{
if(type_ == TYPE_CHECK) {
restorer_.restore();
const SDL_Rect area = {x_,y_,w_,h_};
restorer_ = surface_restorer(&display_->video(),area);
hide();
backup_background();
}
SDL_Surface* image = image_;

View file

@ -50,6 +50,9 @@ public:
bool process(int mousex, int mousey, bool button);
void backup_background();
void hide();
private:
surface_restorer restorer_;
std::string label_;

View file

@ -66,6 +66,16 @@ int slider::height(display& disp)
return 0;
}
double slider::normalize(int value, int min_value, int max_value)
{
return (double(value) - double(min_value))/double(max_value - min_value);
}
int slider::denormalize(double value, int min_value, int max_value)
{
return min_value + int(value*double(max_value - min_value));
}
void slider::draw()
{
drawn_ = true;

View file

@ -42,6 +42,8 @@ public:
slider& operator=(const slider& o);
static int height(display& disp);
static double normalize(int value, int min_value, int max_value);
static int denormalize(double value, int min_value, int max_value);
void draw();