[[Editor and AI improvements]]

- some editor improvements

- made AI not recruit units that don't have a suitable movement type for the map
This commit is contained in:
Dave White 2004-04-23 15:48:24 +00:00
parent 17d1e484bd
commit 4fd5afc631
12 changed files with 1106 additions and 395 deletions

View file

@ -1,6 +1,6 @@
SSSSSSShhmmmmmmmmmhhhhhhmmmmmmmmmmmmmm
SCCCSSVhmmmmmmmmhhhSShSShhmmmmmmmmmmmm
SC2CSSSSmmmmmmmhhSShhmhhVhmmmmmmmmmmmm
SC2CSSSScmmmmmmhhSShhmhhVhmmmmmmmmmmmm
SSChhhSSSmmmmShSSVShmmmmhmmmmhmhmmmmmm
ShhmmmSSSSmSSSShhhShmmmmmmmmhSSShSSSmm
VmmmmmmmSVSSSmmmmhShmmmmmhhSSSSSSSVSmm

View file

@ -52,7 +52,7 @@ Defeat:
side=2
canrecruit=1
recruit=Vampire Bat,Naga
recruitment_pattern=scout,swimmer
recruitment_pattern=scout,fighter
team_name=orcs
#ifdef EASY
gold=60

337
data/themes/editor.cfg Normal file
View file

@ -0,0 +1,337 @@
[theme]
name=null
[resolution]
width=1
height=1
[/resolution]
[/theme]
[theme]
name=editor
[resolution]
width=800
height=600
[main_map]
rect=0,26,887,768
xanchor=left
yanchor=top
[/main_map]
[menu]
title=main_menu
image=lite
items=save,quit
rect=3,1,107,22
xanchor=fixed
yanchor=fixed
[/menu]
#[menu]
#title=game_menu
#image=lite
#items=undo,redo,save,preferences,quit
#rect=110,1,215,22
#xanchor=fixed
#yanchor=fixed
# [menu]
# is_context_menu=true
# items=undo,redo,cycle,describeunit,speak,recruit,recall,createunit,renameunit,labelterrain,showenemymoves,bestenemymoves,endturn
# [/menu]
# top panel
[panel]
image=misc/top-bg.png
rect=0,0,1024,26
xanchor=top
yanchor=fixed
[/panel]
#[menu]
#title=action_preferences
#items=preferences
#rect=5,1
#xanchor=left
#yanchor=top
#[/menu]
# # rightside panel
# [panel]
# image=misc/rightside.png
# rect=887,24,1024,284
# xanchor=right
# yanchor=fixed
# [/panel]
[mini_map]
rect=900,32,1016,177
xanchor=right
yanchor=fixed
[/mini_map]
# [panel]
# image=misc/rightside-bg.png
# rect=887,284,1024,768
# xanchor=right
# yanchor=top
# [/panel]
# [panel]
# image=misc/rightside-bottom.png
# rect=887,713,0,768
# xanchor=right
# yanchor=bottom
# [/panel]
# [menu]
# title=action_endturn
# items=endturn
# rect=904,736
# xanchor=right
# yanchor=bottom
# [/menu]
# [panel]
# image=misc/status-bg.png
# rect=175,2,280,21
# xanchor=proportional
# yanchor=fixed
# [/panel]
# [panel]
# image=misc/status-bg.png
# rect=285,2,390,21
# xanchor=proportional
# yanchor=fixed
# [/panel]
# [panel]
# image=misc/status-bg.png
# rect=395,2,495,21
# xanchor=proportional
# yanchor=fixed
# [/panel]
# [panel]
# image=misc/status-bg.png
# rect=500,2,600,21
# xanchor=proportional
# yanchor=fixed
# [/panel]
# [panel]
# image=misc/status-bg.png
# rect=605,2,705,21
# xanchor=proportional
# yanchor=fixed
# [/panel]
# [panel]
# image=misc/status-bg.png
# rect=710,2,810,21
# xanchor=proportional
# yanchor=fixed
# [/panel]
# # gold icon
# [label]
# icon=misc/gold.png
# text=gold
# rect=290,3,306,19
# xanchor=proportional
# yanchor=fixed
# [/label]
# # villages icon
# [label]
# icon=misc/villages.png
# text=villages
# rect=400,3,416,19
# xanchor=proportional
# yanchor=fixed
# [/label]
# # units icon
# [label]
# icon=misc/units.png
# text=units
# rect=505,3,521,19
# xanchor=proportional
# yanchor=fixed
# [/label]
# # upkeep icon
# [label]
# icon=misc/upkeep.png
# text=upkeep
# rect=610,3,642,19
# xanchor=proportional
# yanchor=fixed
# [/label]
# # income icon
# [label]
# icon=misc/income.png
# text=income
# rect=715,3,747,19
# xanchor=proportional
# yanchor=fixed
# [/label]
# [status]
# # the time of day image
# [time_of_day]
# rect=900,185,1017,225
# xanchor=right
# yanchor=fixed
# [/time_of_day]
# [observers]
# font_size=12
# rect=156,4,172,20
# xanchor=proportional
# yanchor=fixed
# [/observers]
# #put the side playing indicator next to the turn indicator
# [side_playing]
# rect=178,4,193,20
# xanchor=proportional
# yanchor=fixed
# [/side_playing]
# # the game status
# [turn]
# font_size=12
# rect=200,4,275,20
# xanchor=proportional
# yanchor=fixed
# prefix=
# prefix_literal=""
# [/turn]
# [gold]
# font_size=12
# rect=310,4,385,20
# xanchor=proportional
# yanchor=fixed
# prefix=
# prefix_literal=""
# [/gold]
# [villages]
# font_size=12
# rect=420,4,490,20
# xanchor=proportional
# yanchor=fixed
# prefix=
# prefix_literal=""
# [/villages]
# [num_units]
# font_size=12
# rect=525,4,595,20
# xanchor=proportional
# yanchor=fixed
# prefix=
# prefix_literal=""
# [/num_units]
# [upkeep]
# font_size=12
# rect=647,4,700,20
# xanchor=proportional
# yanchor=fixed
# prefix=
# prefix_literal=""
# [/upkeep]
# [income]
# font_size=12
# rect=752,4,805,20
# xanchor=proportional
# yanchor=fixed
# prefix=
# prefix_literal=""
# [/income]
# [terrain]
# font_size=12
# rect=820,4,920,20
# xanchor=proportional
# yanchor=fixed
# [/terrain]
# [position]
# font_size=12
# rect=925,4,1020,20
# xanchor=proportional
# yanchor=fixed
# [/position]
# #unit stats here
# [unit_image]
# rect=900,235,946,283
# xanchor=right
# yanchor=fixed
# [/unit_image]
# [unit_description]
# font_size=14
# rect=900,290,1020,308
# xanchor=right
# yanchor=fixed
# [/unit_description]
# [unit_type]
# font_size=12
# rect=900,308,1020,324
# xanchor=right
# yanchor=fixed
# [/unit_type]
# [unit_level]
# font_size=12
# rect=900,324,1020,340
# prefix=level
# prefix_literal=" "
# xanchor=right
# yanchor=fixed
# [/unit_level]
# [unit_alignment]
# font_size=12
# rect=900,340,1020,356
# xanchor=right
# yanchor=fixed
# [/unit_alignment]
# [unit_traits]
# font_size=12
# rect=900,356,1020,372
# xanchor=right
# yanchor=fixed
# [/unit_traits]
# [unit_abilities]
# font_size=12
# rect=900,372,1020,388
# xanchor=right
# yanchor=fixed
# [/unit_abilities]
# [unit_status]
# font_size=12
# rect=958,241,1008,291
# xanchor=right
# yanchor=fixed
# [/unit_status]
# [unit_moves]
# font_size=12
# rect=900,404,1020,420
# prefix=movement
# prefix_literal=": "
# xanchor=right
# yanchor=fixed
# [/unit_moves]
# [unit_hp]
# font_size=12
# rect=900,420,1020,436
# prefix=hp
# prefix_literal=": "
# xanchor=right
# yanchor=fixed
# [/unit_hp]
# [unit_xp]
# font_size=12
# rect=900,436,1020,452
# prefix=xp
# prefix_literal=": "
# xanchor=right
# yanchor=fixed
# [/unit_xp]
# [unit_weapons]
# font_size=12
# rect=900,452,1020,680
# xanchor=right
# yanchor=fixed
# [/unit_weapons]
# [/status]
[/resolution]
[/theme]

View file

@ -11,7 +11,7 @@ level=1
alignment=lawful
advanceto=Triton
cost=12
usage=swimmer
usage=fighter
unit_description="Skilled creatures of the sea, Mermen are powerful and quick in any watery environment, but struggle greatly to move on land."
get_hit_sound=mermen-hit.wav
[attack]

View file

@ -10,7 +10,7 @@ level=2
alignment=lawful
advanceto=null
cost=28
usage=swimmer
usage=fighter
unit_description="Merman Lords are masters of the sea. Skilled in use of the trident, Merman Lords easily defeat any enemy foolish enough to wander into their preferred environment."
get_hit_sound=mermen-hit.wav
[attack]

View file

@ -11,7 +11,7 @@ level=1
alignment=neutral
advanceto=Sea Hag
cost=11
usage=swimmer
usage=fighter
unit_description="Like the Mermen, Nagas are inhabitants of the seas. Smaller and more nimble than their counterparts, they share a distaste for dry land."
get_hit_sound=mermen-hit.wav
[attack]

View file

@ -11,7 +11,7 @@ level=2
alignment=neutral
advanceto=null
cost=31
usage=swimmer
usage=fighter
unit_description="Sea Hags are older and more experienced Nagas who have learned to control the water magic."
get_hit_sound=mermen-hit.wav
[attack]

View file

@ -11,7 +11,7 @@ level=2
alignment=lawful
advanceto=null
cost=28
usage=swimmer
usage=fighter
unit_description="Tritons are masters of the sea. Skilled in use of the trident, Tritons easily defeat any enemy foolish enough to wander into their preferred environment."
get_hit_sound=mermen-hit.wav
[attack]
@ -40,7 +40,7 @@ level=2
alignment=lawful
advanceto=null
cost=28
usage=swimmer
usage=fighter
unit_description="Merman Lords are masters of the sea. Skilled in use of the trident, Merman Lords easily defeat any enemy foolish enough to wander into their preferred environment."
get_hit_sound=mermen-hit.wav
[attack]

View file

@ -61,10 +61,12 @@ bool ai::recruit_usage(const std::string& usage)
for(std::map<std::string,unit_type>::const_iterator i =
gameinfo_.unit_types.begin(); i != gameinfo_.unit_types.end(); ++i) {
if(i->second.usage() == usage && recruits.count(i->second.name())
&& current_team().gold() - i->second.cost() > min_gold) {
const std::string& name = i->second.name();
options.push_back(i->second.name());
if(i->second.usage() == usage && recruits.count(name)
&& current_team().gold() - i->second.cost() > min_gold
&& not_recommended_units_.count(name) == 0) {
options.push_back(name);
}
}
@ -771,23 +773,206 @@ bool ai::move_to_targets(std::map<gamemap::location,paths>& possible_moves, move
return false;
}
int ai::average_resistance_against(const unit_type& a, const unit_type& b) const
{
int sum = 0, weight_sum = 0;
const std::vector<attack_type>& attacks = b.attacks();
for(std::vector<attack_type>::const_iterator i = attacks.begin(); i != attacks.end(); ++i) {
const int resistance = a.movement_type().resistance_against(*i);
const int weight = i->damage()*i->num_attacks();
sum += resistance*weight;
weight_sum += weight;
}
return sum/weight_sum;
}
int ai::compare_unit_types(const unit_type& a, const unit_type& b) const
{
const int a_effectiveness_vs_b = average_resistance_against(b,a);
const int b_effectiveness_vs_a = average_resistance_against(a,b);
std::cerr << "comparison of '" << a.name() << " vs " << b.name() << ": "
<< a_effectiveness_vs_b << " - " << b_effectiveness_vs_a << " = "
<< (a_effectiveness_vs_b - b_effectiveness_vs_a) << "\n";
return a_effectiveness_vs_b - b_effectiveness_vs_a;
}
void ai::analyze_potential_recruit_combat()
{
if(unit_combat_scores_.empty() == false) {
return;
}
log_scope("analyze_potential_recruit_combat()");
const std::set<std::string>& recruits = current_team().recruits();
for(std::set<std::string>::const_iterator i = recruits.begin(); i != recruits.end(); ++i) {
const game_data::unit_type_map::const_iterator info = gameinfo_.unit_types.find(*i);
if(info == gameinfo_.unit_types.end()) {
continue;
}
int score = 0;
for(unit_map::const_iterator j = units_.begin(); j != units_.end(); ++j) {
if(j->second.can_recruit() || current_team().is_enemy(j->second.side()) == false) {
continue;
}
score += compare_unit_types(info->second,j->second.type());
}
std::cerr << "combat score of '" << *i << "': " << score << "\n";
unit_combat_scores_[*i] = score;
}
}
namespace {
struct target_comparer_distance {
target_comparer_distance(const gamemap::location& loc) : loc_(loc) {}
bool operator()(const ai::target& a, const ai::target& b) const {
return distance_between(a.loc,loc_) < distance_between(b.loc,loc_);
}
private:
gamemap::location loc_;
};
}
void ai::analyze_potential_recruit_movements()
{
if(unit_movement_scores_.empty() == false) {
return;
}
const location& start = map_.starting_position(team_num_);
if(map_.on_board(start) == false) {
return;
}
log_scope("analyze_potential_recruit_movements()");
const unit_map::const_iterator leader = units_.find(start);
const int max_targets = 5;
const move_map srcdst, dstsrc;
std::vector<target> targets = find_targets(leader,srcdst,dstsrc);
if(targets.size() > max_targets) {
std::sort(targets.begin(),targets.end(),target_comparer_distance(start));
targets.erase(targets.begin()+max_targets,targets.end());
}
const std::set<std::string>& recruits = current_team().recruits();
std::cerr << "targets: " << targets.size() << "\n";
int best_score = -1;
for(std::set<std::string>::const_iterator i = recruits.begin(); i != recruits.end(); ++i) {
const game_data::unit_type_map::const_iterator info = gameinfo_.unit_types.find(*i);
if(info == gameinfo_.unit_types.end()) {
continue;
}
const unit temp_unit(&info->second,team_num_);
unit_map units;
const temporary_unit_placer placer(units,start,temp_unit);
int cost = 0;
int targets_reached = 0;
int targets_missed = 0;
const shortest_path_calculator calc(temp_unit,current_team(),units,teams_,map_,state_);
for(std::vector<target>::const_iterator t = targets.begin(); t != targets.end(); ++t) {
std::cerr << "analyzing '" << *i << "' getting to target...\n";
const paths::route& route = a_star_search(start,t->loc,100.0,calc);
if(route.steps.empty() == false) {
std::cerr << "made it: " << route.move_left << "\n";
cost += route.move_left;
++targets_reached;
} else {
std::cerr << "failed\n";
++targets_missed;
}
}
if(targets_reached == 0 || targets_missed >= targets_reached*2) {
unit_movement_scores_[*i] = 100000;
not_recommended_units_.insert(*i);
} else {
const int average_cost = cost/targets_reached;
const int score = (average_cost * (targets_reached+targets_missed))/targets_reached;
unit_movement_scores_[*i] = score;
if(best_score == -1 || score < best_score) {
best_score = score;
}
}
}
for(std::map<std::string,int>::iterator j = unit_movement_scores_.begin(); j != unit_movement_scores_.end(); ++j) {
if(best_score > 0) {
j->second = (j->second*10)/best_score;
if(j->second > 15) {
std::cerr << "recommending against recruiting '" << j->first << "' (score: " << j->second << ")\n";
not_recommended_units_.insert(j->first);
} else {
std::cerr << "recommending recruit of '" << j->first << "' (score: " << j->second << ")\n";
}
}
}
if(not_recommended_units_.size() == unit_movement_scores_.size()) {
not_recommended_units_.clear();
}
}
void ai::do_recruitment()
{
analyze_potential_recruit_movements();
analyze_potential_recruit_combat();
//currently just spend all the gold we can!
const int min_gold = 0;
const int villages = map_.villages().size();
int taken_villages = 0;
for(size_t j = 0; j != teams_.size(); ++j) {
taken_villages += teams_[j].villages().size();
size_t neutral_villages = 0;
//we recruit the initial allocation of scouts based on how many neutral villages
//there are that are closer to us than to other keeps.
const std::vector<location>& villages = map_.villages();
for(std::vector<location>::const_iterator v = villages.begin(); v != villages.end(); ++v) {
const int owner = village_owner(*v,teams_);
if(owner == -1) {
const size_t distance = distance_between(map_.starting_position(team_num_),*v);
bool closest = true;
for(std::vector<team>::const_iterator i = teams_.begin(); i != teams_.end(); ++i) {
const int index = i - teams_.begin() + 1;
if(team_num_ != index) {
const gamemap::location& loc = map_.starting_position(index);
if(distance_between(loc,*v) < distance) {
closest = false;
break;
}
}
}
if(closest) {
++neutral_villages;
}
}
}
const int neutral_villages = villages - taken_villages;
//the villages per scout parameter is assumed to be based on a 2-side battle.
//in a greater than 2 side battle, we want to recruit less scouts, since the villages
//are going to be taken more quickly, and we will need combat units faster.
const int villages_per_scout = (current_team().villages_per_scout()*teams_.size())/2;
//the villages per scout is for a two-side battle, accounting for all neutral villages
//on the map. We only look at villages closer to us, so we halve it, making us get
//twice as many scouts
const int villages_per_scout = current_team().villages_per_scout()/2;
//get scouts depending on how many neutral villages there are
int scouts_wanted = villages_per_scout > 0 ? neutral_villages/villages_per_scout : 0;
@ -947,7 +1132,7 @@ int ai::rate_terrain(const unit& u, const gamemap::location& loc)
if(map_.is_village(terrain)) {
const int owner = village_owner(loc,teams_);
if(owner == team_num_) {
if(owner+1 == team_num_) {
rating += friendly_village_value;
} else if(owner == -1) {
rating += neutral_village_value;

View file

@ -362,13 +362,6 @@ public:
int choose_weapon(const location& att, const location& def,
battle_stats& cur_stats, gamemap::TERRAIN terrain);
private:
std::vector<attack_analysis> analyze_targets(
const move_map& srcdst, const move_map& dstsrc,
const move_map& enemy_srcdst, const move_map& enemy_dstsrc
);
struct target {
target(const location& pos, double val) : loc(pos), value(val)
{}
@ -376,6 +369,13 @@ private:
double value;
};
private:
std::vector<attack_analysis> analyze_targets(
const move_map& srcdst, const move_map& dstsrc,
const move_map& enemy_srcdst, const move_map& enemy_dstsrc
);
std::vector<target> find_targets(unit_map::const_iterator leader, const move_map& enemy_srcdst, const move_map& enemy_dstsrc);
std::pair<location,location> choose_move(std::vector<target>& targets,const move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc);
@ -392,6 +392,32 @@ private:
const gamestatus& state_;
bool consider_combat_;
std::vector<target> additional_targets_;
//function which will analyze all the units that this side can recruit and rate
//their movement types. Ratings will be placed in 'unit_movement_scores_', with
//lower scores being better, and the lowest possible rating being '10'.
void analyze_potential_recruit_movements();
std::map<std::string,int> unit_movement_scores_;
std::set<std::string> not_recommended_units_;
//function which will analyze all the units that this side can recruit and rate
//their fighting suitability against enemy units. Ratings will be placed in
//'unit_combat_scores_' with a '0' rating indicating that the unit is 'average'
//against enemy units, negative ratings meaning they are poorly suited, and
//positive ratings meaning they are well suited
void analyze_potential_recruit_combat();
std::map<std::string,int> unit_combat_scores_;
//function which rates two unit types for their suitability against each other.
//returns 0 if the units are equally matched, a positive number if a is suited
//against b, and a negative number if b is suited against a.
int compare_unit_types(const unit_type& a, const unit_type& b) const;
//function which calculates the average resistance unit type a has against
//the attacks of unit type b.
int average_resistance_against(const unit_type& a, const unit_type& b) const;
};
#endif

View file

@ -540,7 +540,7 @@ void draw_label(display& disp, SDL_Surface* target, const theme::label& label)
void display::draw(bool update,bool force)
{
if(!panelsDrawn_ && !teams_.empty()) {
if(!panelsDrawn_) {
SDL_Surface* const screen = screen_.getSurface();
const std::vector<theme::panel>& panels = theme_.panels();

View file

@ -1,15 +1,14 @@
/*
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
Copyright (C) 2003 by David Whire <davidnwhite@optusnet.com.au>
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
See the COPYING file for more details.
*/
#include "SDL.h"
#include "SDL_keysym.h"
@ -18,7 +17,6 @@
#include "../config.hpp"
#include "../cursor.hpp"
#include "../dialogs.hpp"
#include "../display.hpp"
#include "../filesystem.hpp"
#include "../font.hpp"
#include "../game_config.hpp"
@ -30,11 +28,14 @@
#include "../pathfind.hpp"
#include "../playlevel.hpp"
#include "../preferences.hpp"
#include "../sdl_utils.hpp"
#include "../team.hpp"
#include "../unit_types.hpp"
#include "../unit.hpp"
#include "../util.hpp"
#include "../video.hpp"
#include "../events.hpp"
#include "editor.hpp"
#include <cctype>
#include <iostream>
@ -42,397 +43,559 @@
#include <string>
namespace {
const size_t nterrains = 24;
const size_t terrain_size = 35;
const size_t terrain_padding = 2;
const size_t terrain_space = terrain_size + terrain_padding;
const size_t button_x = 50;
const size_t top_button_y = 200;
const size_t palette_x = 40;
const size_t palette_y = top_button_y + 40;
const size_t bot_button_y = palette_y + terrain_space*nterrains/2;
bool is_invalid_terrain(char c) { return c == ' ' || c == '~'; }
const int undo_limit = 20;
const unsigned int undo_limit = 100;
const double zoom_amount = 5.0;
// Milliseconds to sleep in every iteration of the main loop.
const unsigned int sdl_delay = 20;
const size_t default_terrain_size = 35;
}
struct map_undo_action {
map_undo_action(const gamemap::TERRAIN& old_tr,
const gamemap::TERRAIN& new_tr,
const gamemap::location& lc)
: old_terrain(old_tr), new_terrain(new_tr), location(lc) {}
gamemap::TERRAIN old_terrain;
gamemap::TERRAIN new_terrain;
gamemap::location location;
};
typedef std::deque<map_undo_action> map_undo_list;
namespace map_editor {
void drawbar(display& disp);
bool drawterrainpalette(display& disp, int start, gamemap::TERRAIN selected, gamemap map);
int tileselected(int x, int y, display& disp);
editor_event_handler::editor_event_handler(map_editor &editor)
: editor_(editor) {}
// A handler that intercepts key events.
class editor_key_handler : public events::handler {
public:
editor_key_handler(display &gui, map_undo_list &undo_stack, map_undo_list &redo_stack, gamemap &map);
virtual void handle_event(const SDL_Event &event);
private:
map_undo_list &undo_stack_, &redo_stack_;
display &gui_;
gamemap &map_;
const double zoom_amount_;
};
void editor_event_handler::handle_event(const SDL_Event &event) {
int mousex, mousey;
SDL_GetMouseState(&mousex,&mousey);
const SDL_KeyboardEvent keyboard_event = event.key;
handle_keyboard_event(keyboard_event, mousex, mousey);
editor_key_handler::editor_key_handler(display &gui, map_undo_list &undo_stack, map_undo_list &redo_stack, gamemap &map)
: gui_(gui), undo_stack_(undo_stack), redo_stack_(redo_stack), map_(map), zoom_amount_(5.0) {}
const SDL_MouseButtonEvent mouse_button_event = event.button;
handle_mouse_button_event(mouse_button_event, mousex, mousey);
}
void editor_key_handler::handle_event(const SDL_Event &event) {
const SDL_KeyboardEvent keyboard_event = event.key;
if (keyboard_event.type == SDL_KEYDOWN) {
const SDLKey sym = keyboard_event.keysym.sym;
if(sym == SDLK_z)
gui_.zoom(zoom_amount_);
void editor_event_handler::handle_keyboard_event(const SDL_KeyboardEvent &event,
const int mousex, const int mousey) {
if (event.type == SDL_KEYDOWN) {
const SDLKey sym = event.keysym.sym;
if (sym == SDLK_z) {
editor_.zoom_in();
}
if (sym == SDLK_x) {
editor_.zoom_out();
}
if (sym == SDLK_d) {
editor_.zoom_default();
}
if (sym == SDLK_u) {
editor_.undo();
}
if (sym == SDLK_r) {
editor_.redo();
}
if (sym == SDLK_s) {
editor_.save_map("", true);
}
if(sym == SDLK_ESCAPE) {
editor_.set_abort(ABORT_NORMALLY);
}
// Check if a number key was pressed.
for(int num_key = SDLK_1; num_key != SDLK_9; ++num_key) {
if(sym == num_key) {
const unsigned int number_pressed = num_key + 1 - SDLK_1;
editor_.set_starting_position(number_pressed, mousex, mousey);
break;
}
}
}
}
if(sym == SDLK_x)
gui_.zoom(-zoom_amount_);
void editor_event_handler::handle_mouse_button_event(const SDL_MouseButtonEvent &event,
const int mousex, const int mousey) {
if (event.type == SDL_MOUSEBUTTONDOWN) {
const Uint8 button = event.button;
if (button == SDL_BUTTON_WHEELUP) {
editor_.scroll_palette_up();
}
if (button == SDL_BUTTON_WHEELDOWN) {
editor_.scroll_palette_down();
}
}
}
if(sym == SDLK_d)
gui_.default_zoom();
map_editor::map_editor(display &gui, gamemap &map)
: gui_(gui), map_(map), tup_(gui, "", gui::button::TYPE_PRESS, "uparrow-button"),
tdown_(gui, "", gui::button::TYPE_PRESS, "downarrow-button"), abort_(DONT_ABORT),
tstart_(0), num_operations_since_save_(0) {
if(sym == SDLK_u) {
if(!undo_stack_.empty()) {
map_undo_action action = undo_stack_.back();
map_.set_terrain(action.location,action.old_terrain);
undo_stack_.pop_back();
redo_stack_.push_back(action);
if(redo_stack_.size() > undo_limit)
redo_stack_.pop_front();
gamemap::location locs[7];
locs[0] = action.location;
get_adjacent_tiles(action.location,locs+1);
for(int i = 0; i != 7; ++i) {
gui_.draw_tile(locs[i].x,locs[i].y);
terrains_ = map_.get_terrain_precedence();
terrains_.erase(std::remove_if(terrains_.begin(), terrains_.end(), is_invalid_terrain),
terrains_.end());
if(terrains_.empty()) {
std::cerr << "No terrain found.\n";
abort_ = ABORT_HARD;
}
selected_terrain_ = terrains_[1];
// Set size specs.
adjust_sizes(gui_);
tup_.set_xy(gui.mapx() + size_specs_.button_x, size_specs_.top_button_y);
tdown_.set_xy(gui.mapx() + size_specs_.button_x, size_specs_.bot_button_y);
}
void map_editor::adjust_sizes(const display &disp) {
size_specs_.terrain_size = default_terrain_size;
size_specs_.terrain_padding = 2;
size_specs_.terrain_space = size_specs_.terrain_size + size_specs_.terrain_padding;
size_specs_.palette_x = 40;
size_specs_.button_x = size_specs_.palette_x + size_specs_.terrain_space - 12;
size_specs_.top_button_y = 200;
size_specs_.palette_y = size_specs_.top_button_y + 40;
size_specs_.bot_button_y = disp.y() - 20 - 24;
size_t space_for_terrains = size_specs_.bot_button_y -
(size_specs_.top_button_y + 24);
space_for_terrains = space_for_terrains / size_specs_.terrain_space % 2 == 0 ?
space_for_terrains : space_for_terrains - size_specs_.terrain_space;
size_specs_.nterrains = minimum((space_for_terrains / size_specs_.terrain_space) * 2,
terrains_.size());
}
void map_editor::undo() {
if(!undo_stack_.empty()) {
--num_operations_since_save_;
map_undo_action action = undo_stack_.back();
map_.set_terrain(action.location,action.old_terrain);
undo_stack_.pop_back();
redo_stack_.push_back(action);
if(redo_stack_.size() > undo_limit)
redo_stack_.pop_front();
gamemap::location locs[7];
locs[0] = action.location;
get_adjacent_tiles(action.location,locs+1);
for(int i = 0; i != 7; ++i) {
gui_.draw_tile(locs[i].x,locs[i].y);
}
}
}
void map_editor::redo() {
if(!redo_stack_.empty()) {
++num_operations_since_save_;
map_undo_action action = redo_stack_.back();
map_.set_terrain(action.location,action.new_terrain);
redo_stack_.pop_back();
undo_stack_.push_back(action);
if(undo_stack_.size() > undo_limit)
undo_stack_.pop_front();
gamemap::location locs[7];
locs[0] = action.location;
get_adjacent_tiles(action.location,locs+1);
for(int i = 0; i != 7; ++i) {
gui_.draw_tile(locs[i].x,locs[i].y);
}
}
}
void map_editor::zoom_in() {
gui_.zoom(zoom_amount);
}
void map_editor::zoom_out() {
gui_.zoom(-zoom_amount);
}
void map_editor::zoom_default() {
gui_.default_zoom();
}
void map_editor::set_starting_position(const int player, const int x, const int y) {
const gamemap::location loc = gui_.hex_clicked_on(x, y);
if(map_.on_board(loc)) {
map_.set_terrain(loc, gamemap::CASTLE);
}
else {
std::cerr << "Warning: Set starting position to a hex not on the board." << std::endl;
}
map_.set_starting_position(player, loc);
gui_.invalidate_all();
}
void map_editor::set_abort(const ABORT_MODE abort) {
abort_ = abort;
}
void map_editor::set_file_to_save_as(const std::string filename) {
filename_ = filename;
}
void map_editor::left_button_down_(const int mousex, const int mousey) {
const gamemap::location& loc = gui_.minimap_location_on(mousex,mousey);
if (loc.valid()) {
gui_.scroll_to_tile(loc.x,loc.y,display::WARP,false);
}
else {
const gamemap::location hex = gui_.hex_clicked_on(mousex,mousey);
if(map_.on_board(hex)) {
const gamemap::TERRAIN terrain = map_[hex.x][hex.y];
if(selected_terrain_ != terrain) {
if(key_[SDLK_RCTRL] || key_[SDLK_LCTRL]) {
selected_terrain_ = terrain;
} else {
++num_operations_since_save_;
undo_stack_.push_back(map_undo_action(terrain,selected_terrain_,hex));
if(undo_stack_.size() > undo_limit)
undo_stack_.pop_front();
map_.set_terrain(hex,selected_terrain_);
gamemap::location locs[7];
locs[0] = hex;
get_adjacent_tiles(hex,locs+1);
for(int i = 0; i != 7; ++i) {
gui_.draw_tile(locs[i].x,locs[i].y);
}
gui_.draw();
gui_.recalculate_minimap();
}
}
} else {
int tselect = tile_selected(mousex, mousey, gui_, size_specs_);
if(tselect >= 0)
selected_terrain_ = terrains_[tstart_+tselect];
}
}
}
void map_editor::right_button_down_(const int mousex, const int mousey) {
}
void map_editor::middle_button_down_(const int mousex, const int mousey) {
}
void map_editor::scroll_palette_down() {
if(tstart_ + size_specs_.nterrains + 2 <= terrains_.size()) {
tstart_ += 2;
}
}
void map_editor::scroll_palette_up() {
if(tstart_ >= 2) {
tstart_ -= 2;
}
}
bool map_editor::confirm_exit_and_save_() {
int exitRes = gui::show_dialog(gui_, NULL, "Exit?",
"Do you want to exit the map editor?", gui::YES_NO);
if (exitRes != 0) {
return false;
}
if (num_operations_since_save_ > 0) {
int saveRes = gui::show_dialog(gui_, NULL, "Save?",
"Do you want to save before exiting?", gui::YES_NO);
if(saveRes == 0) {
if (!save_map("", false)) {
return false;
}
}
}
return true;
}
bool map_editor::save_map(const std::string fn, const bool display_confirmation) {
std::string filename = fn;
if (filename == "") {
filename = filename_;
}
try {
write_file(filename,map_.write());
num_operations_since_save_ = 0;
if (display_confirmation) {
gui::show_dialog(gui_, NULL, "Saved", "Map saved.", gui::OK_ONLY);
}
}
catch (io_exception) {
gui::show_dialog(gui_, NULL, "Save Failed", "Could not save the map.", gui::OK_ONLY);
return false;
}
return true;
}
void map_editor::main_loop() {
events::event_context ec;
editor_event_handler event_handler(*this);
const double scroll_speed = preferences::scroll_speed();
while (abort_ == DONT_ABORT) {
int mousex, mousey;
const int mouse_flags = SDL_GetMouseState(&mousex,&mousey);
const bool left_button_down = mouse_flags & SDL_BUTTON_LMASK;
const bool right_button_down = mouse_flags & SDL_BUTTON_RMASK;
const bool middle_button_down = mouse_flags & SDL_BUTTON_MMASK;
const gamemap::location cur_hex = gui_.hex_clicked_on(mousex,mousey);
gui_.highlight_hex(cur_hex);
const theme::menu* const m = gui_.menu_pressed(mousex,mousey,mouse_flags&SDL_BUTTON_LMASK);
if(m != NULL) {
std::cerr << "menu pressed\n";
const SDL_Rect& menu_loc = m->location(gui_.screen_area());
static const std::string style = "menu2";
const int res = gui::show_dialog(gui_,NULL,"","",
gui::MESSAGE,&m->items(),
NULL,"",NULL,NULL,NULL,
menu_loc.x+1,menu_loc.y,
&style);
if(0 <= res && res < m->items().size()) {
if(m->items()[res] == "save") {
try {
write_file(filename_,map_.write());
} catch(io_exception&) {
gui::show_dialog(gui_,NULL,"",
"Save failed",gui::MESSAGE);
}
}
}
if(sym == SDLK_r) {
if(!redo_stack_.empty()) {
map_undo_action action = redo_stack_.back();
map_.set_terrain(action.location,action.new_terrain);
redo_stack_.pop_back();
undo_stack_.push_back(action);
if(undo_stack_.size() > undo_limit)
undo_stack_.pop_front();
gamemap::location locs[7];
locs[0] = action.location;
get_adjacent_tiles(action.location,locs+1);
for(int i = 0; i != 7; ++i) {
gui_.draw_tile(locs[i].x,locs[i].y);
}
}
}
int mousex, mousey;
const int mouse_flags = SDL_GetMouseState(&mousex,&mousey);
const gamemap::location cur_hex = gui_.hex_clicked_on(mousex,mousey);
for(int num_key = SDLK_1; num_key != SDLK_9; ++num_key) {
if(sym == num_key) {
if(map_.on_board(cur_hex)) {
map_.set_terrain(cur_hex,gamemap::CASTLE);
}
map_.set_starting_position(num_key+1-SDLK_1,cur_hex);
gui_.invalidate_all();
else if(m->items()[res] == "quit")
break;
}
}
}
if(key_[SDLK_UP] || mousey == 0) {
gui_.scroll(0.0,-scroll_speed);
}
if(key_[SDLK_DOWN] || mousey == gui_.y()-1) {
gui_.scroll(0.0,scroll_speed);
}
if(key_[SDLK_LEFT] || mousex == 0) {
gui_.scroll(-scroll_speed,0.0);
}
if(key_[SDLK_RIGHT] || mousex == gui_.x()-1) {
gui_.scroll(scroll_speed,0.0);
}
if (left_button_down) {
left_button_down_(mousex, mousey);
}
if (right_button_down) {
right_button_down_(mousex, mousey);
}
if (middle_button_down) {
middle_button_down_(mousex, mousey);
}
gui_.draw(false);
if(drawterrainpalette(gui_, tstart_, selected_terrain_, map_, size_specs_) == false)
scroll_palette_down();
if(tup_.process(mousex,mousey,left_button_down)) {
scroll_palette_up();
}
if(tdown_.process(mousex,mousey,left_button_down)) {
scroll_palette_down();
}
gui_.update_display();
SDL_Delay(sdl_delay);
events::pump();
if (abort_ == ABORT_NORMALLY) {
if (!confirm_exit_and_save_()) {
set_abort(DONT_ABORT);
}
}
}
}
int main(int argc, char** argv)
{
game_config::editor = true;
if(argc > 2) {
std::cout << "usage: " << argv[0] << " map-name\n";
return 0;
}
const double scroll_speed = preferences::scroll_speed();
CVideo video;
video.setMode(1024,768,16,0);
const font::manager font_manager;
const preferences::manager prefs_manager;
const image::manager image_manager;
preproc_map defines_map;
defines_map["MEDIUM"] = preproc_define();
defines_map["NORMAL"] = preproc_define();
config cfg(preprocess_file("data/game.cfg",&defines_map));
set_language("English");
std::string filename;
if(argc == 1) {
const std::string path = "data/maps/";
display::unit_map u_map;
config dummy_cfg("");
config dummy_theme;
display disp(u_map,video,gamemap(dummy_cfg,"1"),gamestatus(dummy_cfg,0),
std::vector<team>(), dummy_theme, cfg);
std::vector<std::string> files;
get_files_in_dir(path,&files);
files.push_back("New Map...");
const int res = gui::show_dialog(disp,NULL,"","Choose map to edit:",gui::OK_CANCEL,&files);
if(res < 0) {
return 0;
}
if(res == int(files.size()-1)) {
filename = "new-map";
gui::show_dialog(disp,NULL,"","Create new map",gui::OK_ONLY,NULL,NULL,"",&filename);
if(filename == "")
return 0;
} else {
filename = files[res];
}
filename = path + filename;
} else if(argc == 2) {
filename = argv[1];
}
std::cout << "a\n";
std::string mapdata = read_file(filename);
if(mapdata.empty()) {
for(int i = 0; i != 30; ++i) {
mapdata = mapdata + "gggggggggggggggggggggggggggggggggggggg\n";
}
}
std::cout << "b\n";
gamemap map(cfg,mapdata);
CKey key;
gamestatus status(cfg,0);
std::vector<team> teams;
const config* const theme_cfg = cfg.find_child("theme","name",preferences::theme());
config dummy_theme;
std::map<gamemap::location,unit> units;
display gui(units,video,map,status,teams,theme_cfg ? *theme_cfg : dummy_theme, cfg);
std::vector<std::string> terrain_names;
std::vector<gamemap::TERRAIN> terrains = map.get_terrain_precedence();
terrains.erase(std::remove_if(terrains.begin(),terrains.end(),is_invalid_terrain),terrains.end());
if(terrains.empty()) {
std::cerr << "No terrain found\n";
return 0;
}
for(std::vector<gamemap::TERRAIN>::const_iterator t = terrains.begin(); t != terrains.end(); ++t) {
terrain_names.push_back(map.terrain_name(*t));
}
gui::button tup(gui, "", gui::button::TYPE_PRESS,"uparrow-button");
gui::button tdown(gui, "", gui::button::TYPE_PRESS,"downarrow-button");
tup.set_xy(gui.mapx() + button_x, top_button_y);
tdown.set_xy(gui.mapx() + button_x, bot_button_y);
gamemap::TERRAIN selected_terrain = terrains[1];
int tstart = 0;
//Draw the nice background bar
drawbar(gui);
map_undo_list undo_stack;
map_undo_list redo_stack;
events::event_context ec;
editor_key_handler key_handler(gui, undo_stack, redo_stack, map);
std::cerr << "starting for(;;)\n";
for(;;) {
if(key[SDLK_ESCAPE])
break;
int mousex, mousey;
const int mouse_flags = SDL_GetMouseState(&mousex,&mousey);
const bool new_left_button = mouse_flags & SDL_BUTTON_LMASK;
const bool new_right_button = mouse_flags & SDL_BUTTON_RMASK;
if(key[SDLK_UP] || mousey == 0)
gui.scroll(0.0,-scroll_speed);
if(key[SDLK_DOWN] || mousey == gui.y()-1)
gui.scroll(0.0,scroll_speed);
if(key[SDLK_LEFT] || mousex == 0)
gui.scroll(-scroll_speed,0.0);
if(key[SDLK_RIGHT] || mousex == gui.x()-1)
gui.scroll(scroll_speed,0.0);
const gamemap::location cur_hex = gui.hex_clicked_on(mousex,mousey);
gui.highlight_hex(cur_hex);
if(new_left_button) {
const gamemap::location& loc = gui.minimap_location_on(mousex,mousey);
if (loc.valid()) {
gui.scroll_to_tile(loc.x,loc.y,display::WARP,false);
continue;
}
const gamemap::location hex = gui.hex_clicked_on(mousex,mousey);
if(map.on_board(hex)) {
const gamemap::TERRAIN terrain = map[hex.x][hex.y];
if(selected_terrain != terrain) {
if(key[SDLK_RCTRL] || key[SDLK_LCTRL]) {
selected_terrain = terrain;
} else {
undo_stack.push_back(map_undo_action(terrain,selected_terrain,hex));
if(undo_stack.size() > undo_limit)
undo_stack.pop_front();
map.set_terrain(hex,selected_terrain);
gamemap::location locs[7];
locs[0] = hex;
get_adjacent_tiles(hex,locs+1);
for(int i = 0; i != 7; ++i) {
gui.draw_tile(locs[i].x,locs[i].y);
}
gui.draw();
gui.recalculate_minimap();
}
}
}else{
int tselect = tileselected(mousex,mousey,gui);
if(tselect >= 0)
selected_terrain = terrains[tstart+tselect];
}
}
gui.draw(false);
if(drawterrainpalette(gui, tstart, selected_terrain, map)==false)
tstart += 2;
if(tup.process(mousex,mousey,new_left_button)) {
tstart -= 2;
if(tstart<0)
tstart=0;
}
if(tdown.process(mousex,mousey,new_left_button)) {
tstart += 2;
if(tstart+nterrains>terrains.size())
tstart-=2;
}
gui.update_display();
SDL_Delay(20);
events::pump();
}
int res = gui::show_dialog(gui,NULL,"Save?","Do you want to save changes?",
gui::YES_NO);
if(res == 0) {
write_file(filename,map.write());
}
return 0;
std::string get_filename_from_dialog(CVideo &video, config &cfg) {
const std::string path = "data/maps/";
display::unit_map u_map;
config dummy_cfg("");
config dummy_theme;
display disp(u_map, video, gamemap(dummy_cfg,"1"), gamestatus(dummy_cfg,0),
std::vector<team>(), dummy_theme, cfg);
std::vector<std::string> files;
get_files_in_dir(path,&files);
files.push_back("New Map...");
const int res = gui::show_dialog(disp, NULL, "",
"Choose map to edit:", gui::OK_CANCEL, &files);
if(res < 0) {
return "";
}
std::string filename;
if(res == int(files.size()-1)) {
filename = "new-map";
gui::show_dialog(disp, NULL, "", "Create new map",
gui::OK_ONLY, NULL, NULL, "", &filename);
if (filename == "") {
// If no name was given, return the empty filename; don't add
// the path.
return filename;
}
} else {
filename = files[res];
}
filename = path + filename;
return filename;
}
void drawbar(display& disp)
{
SDL_Surface* const screen = disp.video().getSurface();
SDL_Rect dst = {disp.mapx(),0,disp.x()-disp.mapx(),disp.y()};
SDL_FillRect(screen,&dst,0);
update_rect(dst);
SDL_Surface* const screen = disp.video().getSurface();
SDL_Rect dst = {disp.mapx(), 0, disp.x() - disp.mapx(), disp.y()};
SDL_FillRect(screen,&dst,0);
update_rect(dst);
}
bool drawterrainpalette(display& disp, int start, gamemap::TERRAIN selected, gamemap map)
bool drawterrainpalette(display& disp, int start, gamemap::TERRAIN selected, gamemap map,
size_specs specs)
{
int x = disp.mapx() + palette_x;
int y = palette_y;
size_t x = disp.mapx() + specs.palette_x;
size_t y = specs.palette_y;
int starting = start;
int ending = starting+nterrains;
unsigned int starting = start;
unsigned int ending = starting+specs.nterrains;
bool status = true;
bool status = true;
SDL_Rect invalid_rect;
invalid_rect.x = x;
invalid_rect.y = y;
invalid_rect.w = 0;
SDL_Rect invalid_rect;
invalid_rect.x = x;
invalid_rect.y = y;
invalid_rect.w = 0;
SDL_Surface* const screen = disp.video().getSurface();
SDL_Surface* const screen = disp.video().getSurface();
std::vector<gamemap::TERRAIN> terrains = map.get_terrain_precedence();
terrains.erase(std::remove_if(terrains.begin(),terrains.end(),is_invalid_terrain),terrains.end());
if(ending > terrains.size()){
ending = terrains.size();
starting = ending - nterrains;
status = false;
}
std::vector<gamemap::TERRAIN> terrains = map.get_terrain_precedence();
terrains.erase(std::remove_if(terrains.begin(), terrains.end(), is_invalid_terrain),
terrains.end());
if(ending > terrains.size()){
ending = terrains.size();
starting = ending - specs.nterrains;
status = false;
}
for(int counter = starting; counter < ending; counter++){
const gamemap::TERRAIN terrain = terrains[counter];
scoped_sdl_surface image(image::get_image("terrain/" + map.get_terrain_info(terrain).default_image() + ".png",image::UNSCALED));
if(image->w != terrain_size || image->h != terrain_size) {
image.assign(scale_surface(image,terrain_size,terrain_size));
}
for(unsigned int counter = starting; counter < ending; counter++){
const gamemap::TERRAIN terrain = terrains[counter];
const std::string filename = "terrain/" +
map.get_terrain_info(terrain).default_image() + ".png";
scoped_sdl_surface image(image::get_image(filename, image::UNSCALED));
if(image->w != specs.terrain_size || image->h != specs.terrain_size) {
image.assign(scale_surface(image, specs.terrain_size, specs.terrain_size));
}
if(image == NULL) {
std::cerr << "image for terrain '" << counter << "' not found\n";
return status;
}
if(image == NULL) {
std::cerr << "image for terrain '" << counter << "' not found\n";
return status;
}
SDL_Rect dstrect;
dstrect.x = x + (counter % 2 != 0 ? 0 : terrain_space);
dstrect.y = y;
dstrect.w = image->w;
dstrect.h = image->h;
SDL_Rect dstrect;
dstrect.x = x + (counter % 2 != 0 ? 0 : specs.terrain_space);
dstrect.y = y;
dstrect.w = image->w;
dstrect.h = image->h;
SDL_BlitSurface(image,NULL,screen,&dstrect);
gui::draw_rectangle(dstrect.x,dstrect.y,image->w,image->h,
terrain == selected?0xF000:0,screen);
if (counter % 2 != 0)
y += terrain_space;
}
invalid_rect.w = terrain_space * 2;
invalid_rect.h = y - invalid_rect.y;
update_rect(invalid_rect);
return status;
SDL_BlitSurface(image, NULL, screen, &dstrect);
gui::draw_rectangle(dstrect.x, dstrect.y, image->w, image->h,
terrain == selected ? 0xF000:0 , screen);
if (counter % 2 != 0)
y += specs.terrain_space;
}
invalid_rect.w = specs.terrain_space * 2;
invalid_rect.h = y - invalid_rect.y;
update_rect(invalid_rect);
return status;
}
int tileselected(int x, int y, display& disp)
int tile_selected(const unsigned int x, const unsigned int y,
const display& disp, const size_specs specs)
{
for(int i = 0; i != nterrains; i++) {
const int px = disp.mapx() + palette_x + (i % 2 != 0 ? 0 : terrain_space);
const int py = palette_y + (i/2)*terrain_space;
const int pw = terrain_space;
const int ph = terrain_space;
for(unsigned int i = 0; i != specs.nterrains; i++) {
const unsigned int px = disp.mapx() + specs.palette_x + (i % 2 != 0 ? 0 : specs.terrain_space);
const unsigned int py = specs.palette_y + (i / 2) * specs.terrain_space;
const unsigned int pw = specs.terrain_space;
const unsigned int ph = specs.terrain_space;
if(x>px && x<px+pw && y>py && y<py+ph) {
return i;
}
}
return -1;
if(x > px && x < px + pw && y > py && y < py + ph) {
return i;
}
}
return -1;
}
bool is_invalid_terrain(char c) {
return c == ' ' || c == '~';
}
}
int main(int argc, char** argv)
{
game_config::editor = true;
if(argc > 2) {
std::cout << "usage: " << argv[0] << " [map-name]" << std::endl;
return 0;
}
CVideo video;
const font::manager font_manager;
const preferences::manager prefs_manager;
const image::manager image_manager;
std::pair<int, int> desiredResolution = preferences::resolution();
video.setMode(desiredResolution.first,desiredResolution.second,16,0);
preproc_map defines_map;
defines_map["MEDIUM"] = preproc_define();
defines_map["NORMAL"] = preproc_define();
config cfg(preprocess_file("data/game.cfg",&defines_map));
set_language("English");
std::string filename;
if(argc == 1) {
filename = map_editor::get_filename_from_dialog(video, cfg);
if (filename == "") {
return 0;
}
} else if(argc == 2) {
filename = argv[1];
}
std::string mapdata;
try {
mapdata = read_file(filename);
}
catch (io_exception) {
std::cerr << "Could not read the map file, sorry." << std::endl;
return 1;
}
if(mapdata.empty()) {
for(int i = 0; i != 30; ++i) {
mapdata = mapdata + "gggggggggggggggggggggggggggggggggggggg\n";
}
}
try {
gamemap map(cfg, mapdata);
gamestatus status(cfg, 0);
std::vector<team> teams;
const config* const theme_cfg = cfg.find_child("theme", "name", "editor");
config dummy_theme;
std::map<gamemap::location,unit> units;
display gui(units, video, map, status, teams,
theme_cfg ? *theme_cfg : dummy_theme, cfg);
//Draw the nice background bar
map_editor::drawbar(gui);
map_editor::map_editor editor(gui, map);
editor.set_file_to_save_as(filename);
editor.main_loop();
}
catch (gamemap::incorrect_format_exception) {
std::cerr << "The map is not in a correct format, sorry." << std::endl;
return 1;
}
return 0;
}