1 // Copyright (C) 2007 Ole Laursen
2 // Copyright (C) 2007, 2008, 2009, 2014, 2015, 2017, 2020 Ben Asselstine
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Library General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 // 02110-1301, USA.
18
19 #include <config.h>
20
21 #include <sigc++/functors/mem_fun.h>
22 #include <gtkmm.h>
23 #include <algorithm>
24 #include <map>
25 #include <vector>
26
27 #include "new-random-map-dialog.h"
28
29 #include "defs.h"
30 #include "Configuration.h"
31 #include "File.h"
32 #include "tileset.h"
33 #include "tilesetlist.h"
34 #include "armysetlist.h"
35 #include "citysetlist.h"
36 #include "shieldsetlist.h"
37 #include "ucompose.hpp"
38 #include "GameScenarioOptions.h"
39 #include "CreateScenarioRandomize.h"
40 #include "CreateScenario.h"
41 #include "player.h"
42 #include "counter.h"
43 #include "rnd.h"
44
45 #define method(x) sigc::mem_fun(*this, &NewRandomMapDialog::x)
46
NewRandomMapDialog(Gtk::Window & parent)47 NewRandomMapDialog::NewRandomMapDialog(Gtk::Window &parent)
48 : LwDialog(parent, "new-random-map-dialog.ui")
49 {
50 xml->get_widget("dialog-vbox1", dialog_vbox);
51 xml->get_widget("dialog-action_area1", dialog_action_area);
52 xml->get_widget("map_size_combobox", map_size_combobox);
53 xml->get_widget("grass_scale", grass_scale);
54 ActiveTerrainType terrain = GRASS;
55 grass_scale->signal_value_changed().connect
56 (sigc::bind(sigc::mem_fun (this, &NewRandomMapDialog::on_value_changed), terrain));
57 xml->get_widget("water_scale", water_scale);
58 terrain = WATER;
59 water_scale->signal_value_changed().connect
60 (sigc::bind(sigc::mem_fun (this, &NewRandomMapDialog::on_value_changed), terrain));
61 xml->get_widget("swamp_scale", swamp_scale);
62 terrain = SWAMP;
63 swamp_scale->signal_value_changed().connect
64 (sigc::bind(sigc::mem_fun (this, &NewRandomMapDialog::on_value_changed), terrain));
65 xml->get_widget("forest_scale", forest_scale);
66 terrain = FOREST;
67 forest_scale->signal_value_changed().connect
68 (sigc::bind(sigc::mem_fun (this, &NewRandomMapDialog::on_value_changed), terrain));
69 xml->get_widget("hills_scale", hills_scale);
70 terrain = HILLS;
71 hills_scale->signal_value_changed().connect
72 (sigc::bind(sigc::mem_fun (this, &NewRandomMapDialog::on_value_changed), terrain));
73 xml->get_widget("mountains_scale", mountains_scale);
74 terrain = MOUNTAINS;
75 mountains_scale->signal_value_changed().connect
76 (sigc::bind(sigc::mem_fun (this, &NewRandomMapDialog::on_value_changed), terrain));
77 xml->get_widget("cities_scale", cities_scale);
78 xml->get_widget("accept2_button", accept_button);
79 accept_button->signal_clicked().connect (method(on_accept_clicked));
80 xml->get_widget("cancel2_button", cancel_button);
81 cancel_button->signal_clicked().connect (method(on_cancel_clicked));
82 xml->get_widget("grass_random_checkbutton", grass_random_checkbutton);
83 grass_random_checkbutton->signal_toggled().connect
84 (method(on_grass_random_toggled));
85 xml->get_widget("water_random_checkbutton", water_random_checkbutton);
86 water_random_checkbutton->signal_toggled().connect
87 (method(on_water_random_toggled));
88 xml->get_widget("swamp_random_checkbutton", swamp_random_checkbutton);
89 swamp_random_checkbutton->signal_toggled().connect
90 (method(on_swamp_random_toggled));
91 xml->get_widget("forest_random_checkbutton", forest_random_checkbutton);
92 forest_random_checkbutton->signal_toggled().connect
93 (method(on_forest_random_toggled));
94 xml->get_widget("hills_random_checkbutton", hills_random_checkbutton);
95 hills_random_checkbutton->signal_toggled().connect
96 (method(on_hills_random_toggled));
97 xml->get_widget("mountains_random_checkbutton", mountains_random_checkbutton);
98 mountains_random_checkbutton->signal_toggled().connect
99 (method(on_mountains_random_toggled));
100 xml->get_widget("cities_random_checkbutton", cities_random_checkbutton);
101 cities_random_checkbutton->signal_toggled().connect
102 (method(on_cities_random_toggled));
103 xml->get_widget("progress_treeview", progress_treeview);
104
105 // fill in tile themes combobox
106
107 guint32 counter = 0;
108 guint32 default_id = 0;
109 Gtk::Box *box;
110
111 //fill in tile sizes combobox
112 tile_size_combobox = manage(new Gtk::ComboBoxText);
113 std::list<guint32> sizes;
114 Tilesetlist::getInstance()->getSizes(sizes);
115 Citysetlist::getInstance()->getSizes(sizes);
116 Armysetlist::getInstance()->getSizes(sizes);
117 for (std::list<guint32>::iterator it = sizes.begin(); it != sizes.end();
118 it++)
119 {
120 Glib::ustring s = String::ucompose("%1x%1", *it);
121 tile_size_combobox->append(s);
122 if ((*it) == Tileset::getDefaultTileSize())
123 default_id = counter;
124 counter++;
125 }
126 tile_size_combobox->set_active(default_id);
127 xml->get_widget("tile_size_box", box);
128 box->pack_start(*tile_size_combobox, Gtk::PACK_SHRINK);
129 tile_size_combobox->signal_changed().connect (method(on_tile_size_changed));
130
131 // make new tile themes combobox
132 tile_theme_combobox = manage(new Gtk::ComboBoxText);
133 xml->get_widget("tile_theme_box", box);
134 box->pack_start(*tile_theme_combobox, Gtk::PACK_SHRINK);
135
136 // make new army themes combobox
137 army_theme_combobox = manage(new Gtk::ComboBoxText);
138 xml->get_widget("army_theme_box", box);
139 box->pack_start(*army_theme_combobox, Gtk::PACK_SHRINK);
140
141 // make new city themes combobox
142 city_theme_combobox = manage(new Gtk::ComboBoxText);
143 xml->get_widget("city_theme_box", box);
144 box->pack_start(*city_theme_combobox, Gtk::PACK_SHRINK);
145
146 counter = 0;
147 default_id = 0;
148 shield_theme_combobox = manage(new Gtk::ComboBoxText);
149 Shieldsetlist *sl = Shieldsetlist::getInstance();
150 std::list<Glib::ustring> shield_themes = sl->getValidNames();
151 for (std::list<Glib::ustring>::iterator i = shield_themes.begin(),
152 end = shield_themes.end(); i != end; ++i)
153 {
154 if (*i == _("Default"))
155 default_id = counter;
156 shield_theme_combobox->append(Glib::filename_to_utf8(*i));
157 counter++;
158 }
159
160 shield_theme_combobox->set_active(default_id);
161
162 xml->get_widget("shield_theme_box", box);
163 box->pack_start(*shield_theme_combobox, Gtk::PACK_SHRINK);
164
165 on_tile_size_changed();
166
167 // map size
168 map_size_combobox->set_active(MAP_SIZE_NORMAL);
169 map_size_combobox->signal_changed().connect(method(on_map_size_changed));
170
171 xml->get_widget("cities_can_produce_allies_checkbutton",
172 cities_can_produce_allies_checkbutton);
173
174 xml->get_widget("notebook", notebook);
175
176 grass_scale->set_value(78);
177 water_scale->set_value(7);
178 swamp_scale->set_value(2);
179 forest_scale->set_value(3);
180 hills_scale->set_value(5);
181 mountains_scale->set_value(5);
182 on_map_size_changed();
183 dialog_response = Gtk::RESPONSE_CANCEL;
184 d_active_terrain = NONE;
185 d_inhibit_scales = false;
186
187 //progressbar, what a pain
188 progress_treeview->property_headers_visible () = false;
189 progress_liststore = Gtk::ListStore::create(progress_columns);
190 progress_treeview->set_model (progress_liststore);
191 row = *(progress_liststore->append());
192 auto cell = Gtk::manage (new Gtk::CellRendererProgress());
193 cell->property_text () = "";
194 int cols_count = progress_treeview->append_column ("progress", *cell);
195 auto pColumn = progress_treeview->get_column(cols_count -1);
196 if (pColumn)
197 pColumn->add_attribute(cell->property_value (), progress_columns.perc);
198
199 }
200
run()201 int NewRandomMapDialog::run()
202 {
203 dialog->show_all();
204 dialog_action_area->hide();
205 progress_treeview->hide();
206 //we're not using the buttons from the action area.
207 //we have our own buttons so that we can show a progress bar after the
208 //button is clicked.
209 dialog->run();
210 return dialog_response;
211 }
212
on_map_size_changed()213 void NewRandomMapDialog::on_map_size_changed()
214 {
215 switch (map_size_combobox->get_active_row_number()) {
216 case MAP_SIZE_SMALL:
217 map.width = MAP_SIZE_SMALL_WIDTH;
218 map.height = MAP_SIZE_SMALL_HEIGHT;
219 cities_scale->set_value(15);
220 break;
221
222 case MAP_SIZE_TINY:
223 map.width = MAP_SIZE_TINY_WIDTH;
224 map.height = MAP_SIZE_TINY_HEIGHT;
225 cities_scale->set_value(10);
226 break;
227
228 case MAP_SIZE_NORMAL:
229 default:
230 map.width = MAP_SIZE_NORMAL_WIDTH;
231 map.height = MAP_SIZE_NORMAL_HEIGHT;
232 cities_scale->set_value(20);
233 break;
234 }
235 }
236
get_active_tile_size()237 guint32 NewRandomMapDialog::get_active_tile_size()
238 {
239 return (guint32) atoi(tile_size_combobox->get_active_text().c_str());
240 }
241
on_tile_size_changed()242 void NewRandomMapDialog::on_tile_size_changed()
243 {
244 guint32 default_id = 0;
245 guint32 counter = 0;
246
247 accept_button->set_sensitive(true);
248 tile_theme_combobox->remove_all();
249
250 Tilesetlist *tl = Tilesetlist::getInstance();
251 std::list<Glib::ustring> tile_themes = tl->getValidNames(get_active_tile_size());
252 for (std::list<Glib::ustring>::iterator i = tile_themes.begin(),
253 end = tile_themes.end(); i != end; ++i)
254 {
255 if (*i == _("Default"))
256 default_id = counter;
257 tile_theme_combobox->append(Glib::filename_to_utf8(*i));
258 counter++;
259 }
260
261 if (counter > 0)
262 tile_theme_combobox->set_active(default_id);
263 else
264 accept_button->set_sensitive(false);
265
266
267 army_theme_combobox->remove_all();
268
269 Armysetlist *al = Armysetlist::getInstance();
270 std::list<Glib::ustring> army_themes = al->getValidNames(get_active_tile_size());
271 counter = 0;
272 default_id = 0;
273 for (std::list<Glib::ustring>::iterator i = army_themes.begin(),
274 end = army_themes.end(); i != end; ++i)
275 {
276 if (*i == _("Default"))
277 default_id = counter;
278 army_theme_combobox->append(Glib::filename_to_utf8(*i));
279 counter++;
280 }
281
282 if (counter > 0)
283 army_theme_combobox->set_active(default_id);
284 else
285 accept_button->set_sensitive(false);
286
287 city_theme_combobox->remove_all();
288
289 Citysetlist *cl = Citysetlist::getInstance();
290 std::list<Glib::ustring> city_themes = cl->getValidNames(get_active_tile_size());
291 counter = 0;
292 default_id = 0;
293 for (std::list<Glib::ustring>::iterator i = city_themes.begin(),
294 end = city_themes.end(); i != end; ++i)
295 {
296 if (*i == _("Default"))
297 default_id = counter;
298 city_theme_combobox->append(Glib::filename_to_utf8(*i));
299 counter++;
300 }
301
302 if (counter > 0)
303 city_theme_combobox->set_active(default_id);
304 else
305 accept_button->set_sensitive(false);
306 }
307
assign_random_terrain(GameParameters & g)308 void NewRandomMapDialog::assign_random_terrain (GameParameters &g)
309 {
310 double sum = 0;
311 std::vector<ActiveTerrainType> ter;
312
313 if (!grass_random_checkbutton->get_active())
314 sum += grass_scale->get_value ();
315 else
316 {
317 ter.push_back(GRASS);
318 g.map.grass = 0;
319 }
320
321
322 if (!water_random_checkbutton->get_active())
323 sum += water_scale->get_value ();
324 else
325 {
326 ter.push_back(WATER);
327 g.map.water = 0;
328 }
329
330 if (!forest_random_checkbutton->get_active())
331 sum += forest_scale->get_value ();
332 else
333 {
334 ter.push_back(FOREST);
335 g.map.forest = 0;
336 }
337
338 if (!hills_random_checkbutton->get_active())
339 sum += hills_scale->get_value ();
340 else
341 {
342 ter.push_back(HILLS);
343 g.map.hills = 0;
344 }
345
346 if (!swamp_random_checkbutton->get_active())
347 sum += swamp_scale->get_value ();
348 else
349 {
350 ter.push_back(SWAMP);
351 g.map.swamp = 0;
352 }
353
354 if (!mountains_random_checkbutton->get_active())
355 sum += mountains_scale->get_value ();
356 else
357 {
358 ter.push_back(MOUNTAINS);
359 g.map.mountains= 0;
360 }
361 double excess = 100 - sum;
362 if (excess <= 0)
363 return;
364 if (excess == 1)
365 {
366 g.map.grass++;
367 return;
368 }
369 if (ter.empty () == false)
370 {
371 for (int i = 0; i < int(excess); i++)
372 {
373 ActiveTerrainType type = ter[Rnd::rand() % ter.size()];
374 switch (type)
375 {
376 case GRASS:
377 g.map.grass++;
378 break;
379 case WATER:
380 g.map.water++;
381 break;
382 case FOREST:
383 g.map.forest++;
384 break;
385 case HILLS:
386 g.map.hills++;
387 break;
388 case SWAMP:
389 g.map.swamp++;
390 break;
391 case MOUNTAINS:
392 g.map.mountains++;
393 break;
394 default:
395 break;
396 }
397 }
398 }
399 }
400
getParams()401 GameParameters NewRandomMapDialog::getParams()
402 {
403 CreateScenarioRandomize random;
404 GameParameters g;
405 GameParameters::Player p;
406 p.type = GameParameters::Player::HUMAN;
407 g.players.clear();
408 p.name = random.getPlayerName(Shield::WHITE);
409 p.id = int(Shield::WHITE);
410 g.players.push_back(p);
411 p.id = int(Shield::GREEN);
412 p.name = random.getPlayerName(Shield::Colour(p.id));
413 g.players.push_back(p);
414 p.id = int(Shield::YELLOW);
415 p.name = random.getPlayerName(Shield::Colour(p.id));
416 g.players.push_back(p);
417 p.id = int(Shield::DARK_BLUE);
418 p.name = random.getPlayerName(Shield::Colour(p.id));
419 g.players.push_back(p);
420 p.id = int(Shield::ORANGE);
421 p.name = random.getPlayerName(Shield::Colour(p.id));
422 g.players.push_back(p);
423 p.id = int(Shield::LIGHT_BLUE);
424 p.name = random.getPlayerName(Shield::Colour(p.id));
425 g.players.push_back(p);
426 p.id = int(Shield::RED);
427 p.name = random.getPlayerName(Shield::Colour(p.id));
428 g.players.push_back(p);
429 p.id = int(Shield::BLACK);
430 p.name = random.getPlayerName(Shield::Colour(p.id));
431 g.players.push_back(p);
432
433 g.map_path = "";
434 switch (map_size_combobox->get_active_row_number()) {
435 case MAP_SIZE_SMALL:
436 g.map.width = MAP_SIZE_SMALL_WIDTH;
437 g.map.height = MAP_SIZE_SMALL_HEIGHT;
438 g.map.ruins = 20;
439 g.map.temples = 4;
440 break;
441
442 case MAP_SIZE_TINY:
443 g.map.width = MAP_SIZE_TINY_WIDTH;
444 g.map.height = MAP_SIZE_TINY_HEIGHT;
445 g.map.ruins = 15;
446 g.map.temples = 4;
447 break;
448
449 case MAP_SIZE_NORMAL:
450 default:
451 g.map.width = MAP_SIZE_NORMAL_WIDTH;
452 g.map.height = MAP_SIZE_NORMAL_HEIGHT;
453 g.map.ruins = 25;
454 g.map.temples = 4;
455 break;
456 }
457 g.map.signposts =
458 CreateScenario::calculateNumberOfSignposts(g.map.width, g.map.height,
459 int(grass_scale->get_value()));
460
461 if (!grass_random_checkbutton->get_active())
462 g.map.grass = int(grass_scale->get_value());
463
464 if (!water_random_checkbutton->get_active())
465 g.map.water = int(water_scale->get_value());
466
467 if (!swamp_random_checkbutton->get_active())
468 g.map.swamp = int(swamp_scale->get_value());
469
470 if (!forest_random_checkbutton->get_active())
471 g.map.forest = int(forest_scale->get_value());
472
473 if (!hills_random_checkbutton->get_active())
474 g.map.hills = int(hills_scale->get_value());
475
476 if (!mountains_random_checkbutton->get_active())
477 g.map.mountains = int(mountains_scale->get_value());
478
479 assign_random_terrain (g);
480
481 if (cities_random_checkbutton->get_active())
482 g.map.cities =
483 int(cities_scale->get_adjustment()->get_lower()) +
484 (Rnd::rand() % (int(cities_scale->get_adjustment()->get_upper()) -
485 int(cities_scale->get_adjustment()->get_lower()) + 1));
486 else
487 g.map.cities = int(cities_scale->get_value());
488
489 Tilesetlist *tl = Tilesetlist::getInstance();
490 Armysetlist *al = Armysetlist::getInstance();
491 Shieldsetlist *sl = Shieldsetlist::getInstance();
492 Citysetlist *cl = Citysetlist::getInstance();
493 g.tile_theme = tl->getSetDir
494 (Glib::filename_from_utf8(tile_theme_combobox->get_active_text()),
495 get_active_tile_size());
496
497 g.army_theme = al->getSetDir
498 (Glib::filename_from_utf8(army_theme_combobox->get_active_text()),
499 get_active_tile_size());
500
501 g.shield_theme = sl->getSetDir
502 (Glib::filename_from_utf8(shield_theme_combobox->get_active_text()));
503
504 g.city_theme = cl->getSetDir
505 (Glib::filename_from_utf8(city_theme_combobox->get_active_text()),
506 get_active_tile_size());
507
508 g.see_opponents_stacks = GameScenarioOptions::s_see_opponents_stacks;
509 g.see_opponents_production = GameScenarioOptions::s_see_opponents_production;
510 g.play_with_quests = GameScenarioOptions::s_play_with_quests;
511 g.hidden_map = GameScenarioOptions::s_hidden_map;
512 g.neutral_cities = GameScenarioOptions::s_neutral_cities;
513 g.razing_cities = GameScenarioOptions::s_razing_cities;
514 g.diplomacy = GameScenarioOptions::s_diplomacy;
515 g.random_turns = GameScenarioOptions::s_random_turns;
516 g.quick_start = Configuration::s_quick_start;
517 g.intense_combat = GameScenarioOptions::s_intense_combat;
518 g.military_advisor = GameScenarioOptions::s_military_advisor;
519 g.cities_can_produce_allies =
520 cities_can_produce_allies_checkbutton->get_active();
521 g.cusp_of_war = GameScenarioOptions::s_cusp_of_war;
522 g.vectoring_mode = GameScenarioOptions::s_vectoring_mode;
523 g.build_production_mode = GameScenarioOptions::s_build_production_mode;
524 g.sacking_mode = GameScenarioOptions::s_sacking_mode;
525
526 g.name = _("Autogenerated");
527 random.cleanup();
528 return g;
529 }
530
on_grass_random_toggled()531 void NewRandomMapDialog::on_grass_random_toggled()
532 {
533 grass_scale->set_sensitive(!grass_random_checkbutton->get_active());
534 }
535
on_water_random_toggled()536 void NewRandomMapDialog::on_water_random_toggled()
537 {
538 water_scale->set_sensitive(!water_random_checkbutton->get_active());
539 }
540
on_swamp_random_toggled()541 void NewRandomMapDialog::on_swamp_random_toggled()
542 {
543 swamp_scale->set_sensitive(!swamp_random_checkbutton->get_active());
544 }
545
on_forest_random_toggled()546 void NewRandomMapDialog::on_forest_random_toggled()
547 {
548 forest_scale->set_sensitive(!forest_random_checkbutton->get_active());
549 }
550
on_hills_random_toggled()551 void NewRandomMapDialog::on_hills_random_toggled()
552 {
553 hills_scale->set_sensitive(!hills_random_checkbutton->get_active());
554 }
555
on_mountains_random_toggled()556 void NewRandomMapDialog::on_mountains_random_toggled()
557 {
558 mountains_scale->set_sensitive(!mountains_random_checkbutton->get_active());
559 }
560
on_cities_random_toggled()561 void NewRandomMapDialog::on_cities_random_toggled()
562 {
563 cities_scale->set_sensitive(!cities_random_checkbutton->get_active());
564 }
565
create_and_dump_scenario(const Glib::ustring & file,const GameParameters & g,sigc::slot<void> * pulse)566 Glib::ustring NewRandomMapDialog::create_and_dump_scenario(const Glib::ustring &file,
567 const GameParameters &g, sigc::slot<void> *pulse)
568 {
569 CreateScenario creator (g.map.width, g.map.height);
570
571 // then fill the other players
572 Armyset *as = Armysetlist::getInstance()->get(g.army_theme);
573 int army_id = as->getId();
574 Shieldsetlist *ssl = Shieldsetlist::getInstance();
575 guint32 id = ssl->get(g.shield_theme)->getId();
576 for (std::vector<GameParameters::Player>::const_iterator
577 i = g.players.begin(), end = g.players.end();
578 i != end; ++i) {
579
580 if (i->type == GameParameters::Player::OFF)
581 {
582 fl_counter->getNextId();
583 continue;
584 }
585
586 Player::Type type;
587 if (i->type == GameParameters::Player::EASY)
588 type = Player::AI_FAST;
589 else if (i->type == GameParameters::Player::HARD)
590 type = Player::AI_SMART;
591 else
592 type = Player::HUMAN;
593
594 creator.addPlayer(i->name, army_id, ssl->getColor(id, i->id), type);
595 }
596
597
598 CreateScenarioRandomize random;
599 // the neutral player must come last so it has the highest id among players
600 creator.addNeutral(random.getPlayerName(Shield::NEUTRAL), army_id,
601 ssl->getColor(id, MAX_PLAYERS), Player::AI_DUMMY);
602
603 // now fill in some map information
604 creator.setMapTiles(g.tile_theme);
605 creator.setShieldset(g.shield_theme);
606 creator.setCityset(g.city_theme);
607 creator.setNoCities(g.map.cities);
608 creator.setNoRuins(g.map.ruins);
609 creator.setNoTemples(g.map.temples);
610 int num_signposts = g.map.signposts;
611 if (num_signposts == -1)
612 num_signposts = CreateScenario::calculateNumberOfSignposts(g.map.width,
613 g.map.height,
614 g.map.grass);
615 creator.setNoSignposts(num_signposts);
616
617 // terrain: the scenario generator also accepts input with a sum of
618 // more than 100%, so the thing is rather easy here
619 creator.setPercentages(g.map.grass, g.map.water, g.map.forest, g.map.swamp,
620 g.map.hills, g.map.mountains);
621
622 // now create the map and dump the created map
623 Glib::ustring path = File::getSaveFile(file);
624
625 if (pulse)
626 creator.progress.connect(*pulse);
627
628 creator.create(g);
629 creator.dump(path);
630 random.cleanup();
631 return path;
632 }
633
on_accept_clicked()634 void NewRandomMapDialog::on_accept_clicked()
635 {
636 dialog_vbox->set_sensitive(false);
637 progress_treeview->show_all();
638
639 while (g_main_context_iteration(NULL, FALSE)); //doEvents
640 GameParameters g = getParams();
641
642 sigc::slot<void> progress = method(pulse);
643 g.difficulty = GameScenarioOptions::calculate_difficulty_rating(g);
644 d_filename = create_and_dump_scenario("random.map", g, &progress);
645
646 //finish off the progressbar
647 while (row[progress_columns.perc] < 100)
648 {
649 row[progress_columns.perc] = row[progress_columns.perc] + 1;
650 while (g_main_context_iteration(NULL, FALSE)); //doEvents
651 Glib::usleep (10000);
652 }
653 row[progress_columns.perc] = 100;
654
655 dialog_response = Gtk::RESPONSE_ACCEPT;
656 dialog->hide();
657 }
658
on_cancel_clicked()659 void NewRandomMapDialog::on_cancel_clicked()
660 {
661 dialog_response = Gtk::RESPONSE_CANCEL;
662 dialog->hide();
663 }
pulse()664 void NewRandomMapDialog::pulse()
665 {
666 if (row[progress_columns.perc] < 98)
667 {
668 row[progress_columns.perc] = row[progress_columns.perc] + 3;
669 while (g_main_context_iteration(NULL, FALSE)); //doEvents
670 }
671 }
672
take_percentages()673 void NewRandomMapDialog::take_percentages ()
674 {
675 percentages[GRASS] = grass_scale->get_value();
676 percentages[WATER] = water_scale->get_value();
677 percentages[FOREST] = forest_scale->get_value();
678 percentages[HILLS] = hills_scale->get_value();
679 percentages[MOUNTAINS] = mountains_scale->get_value();
680 percentages[SWAMP] = swamp_scale->get_value();
681 }
682
alter_grass()683 void NewRandomMapDialog::alter_grass ()
684 {
685 double excess = 100.0 - grass_scale->get_value() - water_scale->get_value() -
686 forest_scale->get_value() - hills_scale->get_value() -
687 swamp_scale->get_value() - mountains_scale->get_value();
688
689 std::map<int,double> per;
690 //go get the sum
691 double sum = 0;
692 for (int i = GRASS + 1; i < MAX_TERRAINS; i++)
693 sum += percentages[i];
694
695 // how much is each of the other terrains of the whole, multiplied by excess
696 for (int i = GRASS + 1; i < MAX_TERRAINS; i++)
697 {
698 if (percentages[i] > 0)
699 per[i] = (double)percentages[i] / sum * excess;
700 }
701
702 //we can't sort the map, so we load a copy of it into a vector.
703 std::vector<std::pair<int, double> > percopy(per.begin(), per.end());
704
705 std::sort(percopy.begin(), percopy.end(), cmp);
706
707 sum = 0;
708 for (auto p : percopy)
709 {
710 p.second = round (p.second);
711 sum += p.second;
712 }
713
714 if (sum > excess)
715 {
716 //decrement from the bottom
717 int extra = sum - excess;
718 for (std::vector<std::pair<int, double> >::reverse_iterator it = percopy.rbegin();
719 it != percopy.rend(); ++it)
720 {
721 if ((*it).second == 0)
722 continue;
723 (*it).second -= 1;
724 extra--;
725 if (extra <= 0)
726 break;
727 }
728 }
729 else if (sum < excess)
730 {
731 int extra = excess - sum;
732 //add to the top.
733 for (auto it : percopy)
734 {
735 it.second++;
736 extra--;
737 if (extra <= 0)
738 break;
739 }
740 }
741 for (auto p : percopy)
742 augment_scale_value_by_type (ActiveTerrainType(p.first), p.second);
743 }
744
augment_scale_value_by_type(ActiveTerrainType type,double amt)745 void NewRandomMapDialog::augment_scale_value_by_type (ActiveTerrainType type, double amt)
746 {
747 switch (type)
748 {
749 case GRASS:
750 grass_scale->set_value(grass_scale->get_value() + amt);
751 break;
752 case WATER:
753 water_scale->set_value(water_scale->get_value() + amt);
754 break;
755 case FOREST:
756 forest_scale->set_value(forest_scale->get_value() + amt);
757 break;
758 case HILLS:
759 hills_scale->set_value(hills_scale->get_value() + amt);
760 break;
761 case SWAMP:
762 swamp_scale->set_value(swamp_scale->get_value() + amt);
763 break;
764 case MOUNTAINS:
765 mountains_scale->set_value(mountains_scale->get_value() + amt);
766 break;
767 default:
768 break;
769 }
770 }
771
cmp(std::pair<int,double> const & a,std::pair<int,double> const & b)772 int NewRandomMapDialog::cmp (std::pair<int,double> const &a, std::pair<int,double> const &b)
773 {
774 return a.second != b.second ? fabs(a.second) > fabs(b.second) : a.first > b.first;
775 }
776
alter_terrain(ActiveTerrainType type)777 void NewRandomMapDialog::alter_terrain (ActiveTerrainType type)
778 {
779 double grass = 100.0 - water_scale->get_value() - forest_scale->get_value() -
780 hills_scale->get_value() - swamp_scale->get_value() -
781 mountains_scale->get_value();
782 int excess = 0;
783 if (grass < 0)
784 {
785 excess = int(grass) * -1;
786 grass = 0;
787 }
788 grass_scale->set_value (grass);
789 if (!excess)
790 return;
791 //okay we have EXCESS to take away from every other terrain that isn't TYPE
792 //and isn't grass.
793 std::map<int,double> per;
794 //go get the sum
795 double sum = 0;
796 for (int i = GRASS + 1; i < MAX_TERRAINS; i++)
797 {
798 if (ActiveTerrainType(i) == type)
799 continue;
800 sum += percentages[i];
801 }
802
803 // how much is each of the other terrains of the whole, multiplied by excess
804 for (int i = GRASS + 1; i < MAX_TERRAINS; i++)
805 {
806 if (ActiveTerrainType (i) == type)
807 continue;
808 if (percentages[i] > 0)
809 per[i] = (double)percentages[i] / sum * excess;
810 }
811
812 //we can't sort the map, so we load a copy of it into a vector.
813 std::vector<std::pair<int, double> > percopy(per.begin(), per.end());
814
815 std::sort(percopy.begin(), percopy.end(), cmp);
816
817 sum = 0;
818 for (auto p : percopy)
819 {
820 p.second = round (p.second);
821 sum += p.second;
822 }
823 if (sum > excess)
824 {
825 //decrement from the bottom
826 int extra = sum - excess;
827 for (std::vector<std::pair<int, double> >::reverse_iterator it = percopy.rbegin();
828 it != percopy.rend(); ++it)
829 {
830 if ((*it).second == 0)
831 continue;
832 (*it).second -= 1;
833 extra--;
834 if (extra <= 0)
835 break;
836 }
837 }
838 else if (sum < excess)
839 {
840 int extra = excess - sum;
841 //add to the top.
842 for (auto it : percopy)
843 {
844 it.second++;
845 extra--;
846 if (extra <= 0)
847 break;
848 }
849 }
850 for (auto p : percopy)
851 augment_scale_value_by_type (ActiveTerrainType(p.first), -p.second);
852 }
853
on_value_changed(ActiveTerrainType type)854 void NewRandomMapDialog::on_value_changed (ActiveTerrainType type)
855 {
856 if (d_inhibit_scales)
857 return;
858 if (type != d_active_terrain)
859 {
860 take_percentages ();
861 d_active_terrain = type;
862 }
863 switch (type)
864 {
865 case GRASS:
866 d_inhibit_scales = true;
867 alter_grass ();
868 d_inhibit_scales = false;
869 break;
870 case WATER:
871 case FOREST:
872 case HILLS:
873 case MOUNTAINS:
874 case SWAMP:
875 d_inhibit_scales = true;
876 alter_terrain (type);
877 d_inhibit_scales = false;
878 break;
879 default:
880 break;
881 }
882 }
883
~NewRandomMapDialog()884 NewRandomMapDialog::~NewRandomMapDialog()
885 {
886 notebook->property_show_tabs () = false;
887 }
888