patch to map editor for proper key handling
This commit is contained in:
parent
8d400665a8
commit
0bec75d1b9
20 changed files with 420 additions and 183 deletions
|
@ -1,9 +1,9 @@
|
|||
sscssscccccccsssssssssscccggg
|
||||
ccgcccccmmmcmccssssssssscgRRg
|
||||
cgtggggggmmmmccssssssssssggRg
|
||||
fgfgCCCggtmmmffccccssssssssgs
|
||||
fgfgCCCgctmmmffccccssssssssgs
|
||||
cfffC3Cggmmmmfffftcscssscssss
|
||||
sccffCggmmmmfffffffcccccpccss
|
||||
sccffCggmmmmfffffffccccccpcss
|
||||
sscffrrmmmmmffrffffffccccgtcc
|
||||
sscccfrffmfffrrrfffffccccgggc
|
||||
sssscffrrftfrrrrfffffgtccgCgd
|
||||
|
@ -15,10 +15,10 @@ ccgftfrfffffffrrfffrrfrfffffc
|
|||
gcgffffrrgffffrtfffffrfrrrffc
|
||||
gccggfffrggfggrffffffrffrtfcc
|
||||
ggcccccfdgggggrffffffrrrffccs
|
||||
gcsssccddddgdgrggggfgfffcccss
|
||||
ccssscpccdcdcddgddcgcgccccsss
|
||||
gpsssccddddgdgrggggfgfffcccss
|
||||
ccsssccccdcdcddgddcgcgccccsss
|
||||
sssssccddcdccdddddcccccccccss
|
||||
ssssccccddddcdddccscscccpcdcc
|
||||
ssssccccddddcdddccscscccccdcc
|
||||
gggggccccdddcdccccssssccddfdd
|
||||
gtfffggccddddccccssssscdfftfd
|
||||
fgfffggccccddcccsssssscddfffd
|
||||
|
|
|
@ -45,6 +45,7 @@ submerge=0.4
|
|||
unit_height_adjust=-4
|
||||
heals=true
|
||||
gives_income=true
|
||||
no_overlay=true
|
||||
[/terrain]
|
||||
|
||||
[terrain]
|
||||
|
|
|
@ -513,6 +513,14 @@ attacks="attacks"
|
|||
damage="damage"
|
||||
hexes="hexes"
|
||||
|
||||
#on-screen messages for ambush and enemy unit sightings
|
||||
ambushed="Ambushed!"
|
||||
enemy_unit_sighted="Enemy unit sighted!"
|
||||
friendly_unit_sighted="Friendly unit sighted"
|
||||
enemy_units_sighted="%enemies Enemy units sighted!"
|
||||
friendly_units_sighted="%friends Friendly units sighted"
|
||||
units_sighted="Units sighted! (%friends friendly, %enemies enemy)"
|
||||
|
||||
# Weapon special effect descriptions
|
||||
weapon_special_backstab_description="Backstab:
|
||||
This attack deals double damage if a friendly unit is on the opposite side of the target."
|
||||
|
|
|
@ -19,7 +19,7 @@ usage=fighter
|
|||
fire=90
|
||||
cold=80
|
||||
[/resistance]
|
||||
unit_description="Dwarvish Lords are kings under the mountains. Their skill with the battle axe is unparalled, and they are able to hit even enemies that are far away. Their fine armor is made of the strong alloys crafted by their kin."
|
||||
unit_description="Dwarvish Lords are kings under the mountains. Their skill with the battle axe is unmatched, and they are able to hit even enemies that are far away. Their fine armor is made of the strong alloys crafted by their kin."
|
||||
get_hit_sound=groan.wav
|
||||
[attack]
|
||||
name=battle axe
|
||||
|
|
115
src/actions.cpp
115
src/actions.cpp
|
@ -1320,18 +1320,16 @@ bool clear_shroud_loc(const gamemap& map, team& tm,
|
|||
}
|
||||
|
||||
//returns true iff some shroud is cleared
|
||||
//returns true/false in seen_unit if new units has/has not been seen
|
||||
//if known_units is NULL, seen_unit can be NULL and seen_unit is undefined
|
||||
//seen_units will return new units that have been seen by this unit
|
||||
//if known_units is NULL, seen_units can be NULL and will not be changed
|
||||
bool clear_shroud_unit(const gamemap& map,
|
||||
const gamestatus& status,
|
||||
const game_data& gamedata,
|
||||
const unit_map& units, const gamemap::location& loc,
|
||||
std::vector<team>& teams, int team,
|
||||
const std::set<gamemap::location>* known_units,
|
||||
bool* seen_unit)
|
||||
std::set<gamemap::location>* seen_units)
|
||||
{
|
||||
bool res;
|
||||
|
||||
std::vector<gamemap::location> cleared_locations;
|
||||
|
||||
paths p(map,status,gamedata,units,loc,teams,true,false);
|
||||
|
@ -1342,26 +1340,20 @@ bool clear_shroud_unit(const gamemap& map,
|
|||
|
||||
//clear the location the unit is at
|
||||
clear_shroud_loc(map,teams[team],loc,&cleared_locations);
|
||||
|
||||
res = (cleared_locations.empty() == false);
|
||||
|
||||
for(std::vector<gamemap::location>::const_iterator it =
|
||||
cleared_locations.begin(); it != cleared_locations.end(); ++it) {
|
||||
if(units.count(*it)) {
|
||||
if(seen_unit == NULL) {
|
||||
if(seen_units == NULL || known_units == NULL) {
|
||||
static const std::string sighted("sighted");
|
||||
game_events::fire(sighted,*it,loc);
|
||||
} else if(known_units->count(*it) == 0) {
|
||||
*seen_unit = true;
|
||||
return res;
|
||||
seen_units->insert(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(seen_unit != NULL) {
|
||||
*seen_unit = false;
|
||||
}
|
||||
return res;
|
||||
return cleared_locations.empty() == false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1438,11 +1430,11 @@ size_t move_unit(display* disp, const game_data& gamedata,
|
|||
const bool skirmisher = u.type().is_skirmisher();
|
||||
|
||||
//if we use shroud/fog of war, count out the units we can currently see
|
||||
std::set<gamemap::location> seen_units;
|
||||
std::set<gamemap::location> known_units;
|
||||
if(teams[team_num].uses_shroud() || teams[team_num].uses_fog()) {
|
||||
for(unit_map::const_iterator u = units.begin(); u != units.end(); ++u) {
|
||||
if(teams[team_num].fogged(u->first.x,u->first.y) == false) {
|
||||
seen_units.insert(u->first);
|
||||
known_units.insert(u->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1450,7 +1442,7 @@ size_t move_unit(display* disp, const game_data& gamedata,
|
|||
//see how far along the given path we can move
|
||||
const int starting_moves = u.movement_left();
|
||||
int moves_left = starting_moves;
|
||||
bool seen_unit = false;
|
||||
std::set<gamemap::location> seen_units;
|
||||
bool discovered_unit = false;
|
||||
bool should_clear_stack = false;
|
||||
std::vector<gamemap::location>::const_iterator step;
|
||||
|
@ -1460,35 +1452,33 @@ size_t move_unit(display* disp, const game_data& gamedata,
|
|||
const unit_map::const_iterator enemy_unit = units.find(*step);
|
||||
|
||||
const int mv = u.movement_cost(map,terrain);
|
||||
if(discovered_unit || seen_unit || mv > moves_left || enemy_unit != units.end() &&
|
||||
if(discovered_unit || seen_units.empty() == false || mv > moves_left || enemy_unit != units.end() &&
|
||||
teams[team_num].is_enemy(enemy_unit->second.side())) {
|
||||
break;
|
||||
} else {
|
||||
moves_left -= mv;
|
||||
}
|
||||
|
||||
if(!skirmisher && enemy_zoc(map,status,units,teams,*step,teams[team_num],
|
||||
u.side())) {
|
||||
if(!skirmisher && enemy_zoc(map,status,units,teams,*step,teams[team_num],u.side())) {
|
||||
moves_left = 0;
|
||||
}
|
||||
|
||||
//if we use fog or shroud, see if we have sighted an enemy unit, in
|
||||
//which case we should stop immediately.
|
||||
if(teams[team_num].uses_shroud() || teams[team_num].uses_fog()) {
|
||||
|
||||
if(units.count(*step) == 0 && !map.is_village(*step)) {
|
||||
units.insert(std::pair<gamemap::location,unit>(*step,ui->second));
|
||||
|
||||
bool res;
|
||||
std::cerr << "checking for units from " << (step->x+1) << "," << (step->y+1) << "\n";
|
||||
|
||||
should_clear_stack |=
|
||||
clear_shroud_unit(map,status,gamedata,units,*step,teams,
|
||||
ui->second.side()-1,&seen_units,&res);
|
||||
units.erase(*step);
|
||||
//temporarily reset the unit's moves to full
|
||||
const unit_movement_resetter move_resetter(ui->second);
|
||||
|
||||
//we've seen a new unit. Stop on the next iteration
|
||||
if(res) {
|
||||
seen_unit = true;
|
||||
}
|
||||
//we have to swap out any unit that is already in the hex, so we can put our
|
||||
//unit there, then we'll swap back at the end.
|
||||
const temporary_unit_placer unit_placer(units,*step,ui->second);
|
||||
|
||||
should_clear_stack |= clear_shroud_unit(map,status,gamedata,units,*step,teams,
|
||||
ui->second.side()-1,&known_units,&seen_units);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1526,7 +1516,7 @@ size_t move_unit(display* disp, const game_data& gamedata,
|
|||
|
||||
//if we can't get all the way there and have to set a go-to,
|
||||
//unless we stop early because of sighting a unit
|
||||
if(steps.size() != route.size() && !seen_unit) {
|
||||
if(steps.size() != route.size() && seen_units.empty()) {
|
||||
ui->second.set_goto(route.back());
|
||||
u.set_goto(route.back());
|
||||
}
|
||||
|
@ -1572,6 +1562,67 @@ size_t move_unit(display* disp, const game_data& gamedata,
|
|||
|
||||
if(disp != NULL) {
|
||||
disp->set_route(NULL);
|
||||
|
||||
//show messages on the screen here
|
||||
if(discovered_unit) {
|
||||
//we've been ambushed, so display an appropriate message
|
||||
font::add_floating_label(string_table["ambushed"],24,font::BAD_COLOUR,
|
||||
disp->map_area().w/2,disp->map_area().h/3,
|
||||
0.0,0.0,100,disp->map_area(),font::CENTER_ALIGN);
|
||||
}
|
||||
|
||||
if(seen_units.empty() == false) {
|
||||
//the message depends on how many units have been sighted, and whether
|
||||
//they are allies or enemies, so calculate that out here
|
||||
int nfriends = 0, nenemies = 0;
|
||||
for(std::set<gamemap::location>::const_iterator i = seen_units.begin(); i != seen_units.end(); ++i) {
|
||||
std::cerr << "processing unit at " << (i->x+1) << "," << (i->y+1) << "\n";
|
||||
const unit_map::const_iterator u = units.find(*i);
|
||||
assert(u != units.end());
|
||||
if(teams[team_num].is_enemy(u->second.side())) {
|
||||
++nenemies;
|
||||
} else {
|
||||
++nfriends;
|
||||
}
|
||||
|
||||
std::cerr << "processed...\n";
|
||||
}
|
||||
|
||||
std::string msg_id;
|
||||
|
||||
//the message we display is different depending on whether units sighted
|
||||
//were enemies or friends, and whether there is one or more
|
||||
if(seen_units.size() == 1) {
|
||||
if(nfriends == 1) {
|
||||
msg_id = "friendly_unit_sighted";
|
||||
} else {
|
||||
msg_id = "enemy_unit_sighted";
|
||||
}
|
||||
}
|
||||
else if(nfriends == 0 || nenemies == 0) {
|
||||
if(nfriends > 0) {
|
||||
msg_id = "friendly_units_sighted";
|
||||
} else {
|
||||
msg_id = "enemy_units_sighted";
|
||||
}
|
||||
}
|
||||
else {
|
||||
msg_id = "units_sighted";
|
||||
}
|
||||
|
||||
string_map symbols;
|
||||
symbols["friends"] = lexical_cast<std::string>(nfriends);
|
||||
symbols["enemies"] = lexical_cast<std::string>(nenemies);
|
||||
|
||||
std::cerr << "formatting string...\n";
|
||||
const std::string message = format_string(msg_id,symbols);
|
||||
|
||||
std::cerr << "displaying label...\n";
|
||||
font::add_floating_label(message,24,font::BAD_COLOUR,
|
||||
disp->map_area().w/2,disp->map_area().h/3,
|
||||
0.0,0.0,100,disp->map_area(),font::CENTER_ALIGN);
|
||||
}
|
||||
|
||||
disp->draw();
|
||||
disp->recalculate_minimap();
|
||||
}
|
||||
|
|
|
@ -67,7 +67,12 @@ struct close_FILE
|
|||
|
||||
void read_file_internal(const std::string& fname, std::string& res)
|
||||
{
|
||||
res.resize(0);
|
||||
const int size = file_size(fname);
|
||||
if(size == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
res.resize(size);
|
||||
|
||||
const util::scoped_resource<FILE*,close_FILE> file(fopen(fname.c_str(),"rb"));
|
||||
if(file == NULL) {
|
||||
|
@ -77,12 +82,26 @@ void read_file_internal(const std::string& fname, std::string& res)
|
|||
const int block_size = 4096;
|
||||
char buf[block_size];
|
||||
|
||||
std::string::iterator i = res.begin();
|
||||
|
||||
for(;;) {
|
||||
size_t nbytes = fread(buf,1,block_size,file);
|
||||
res.resize(res.size()+nbytes);
|
||||
std::copy(buf,buf+nbytes,res.end()-nbytes);
|
||||
const size_t nbytes = fread(buf,1,block_size,file);
|
||||
|
||||
//make sure the string is big enough
|
||||
const int size_diff = (res.end() - i) - nbytes;
|
||||
if(size_diff < 0) {
|
||||
res.resize(res.size() - size_diff);
|
||||
i = res.end() - nbytes;
|
||||
}
|
||||
|
||||
std::copy(buf,buf+nbytes,i);
|
||||
i += nbytes;
|
||||
|
||||
if(nbytes < block_size) {
|
||||
if(i != res.end()) {
|
||||
res.erase(i,res.end());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1292,7 +1292,7 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image, double alpha, Uin
|
|||
|
||||
SDL_Rect clip_rect = map_area();
|
||||
|
||||
if(xpos > clip_rect.x + clip_rect.w || ypos > clip_rect.y + clip_rect.h ||
|
||||
if(xpos >= clip_rect.x + clip_rect.w || ypos >= clip_rect.y + clip_rect.h ||
|
||||
xpos + static_cast<int>(zoom_) < clip_rect.x || ypos + static_cast<int>(zoom_) < clip_rect.y) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "../unit_types.hpp"
|
||||
#include "../unit.hpp"
|
||||
#include "../video.hpp"
|
||||
#include "../events.hpp"
|
||||
|
||||
#include <cctype>
|
||||
#include <iostream>
|
||||
|
@ -71,6 +72,83 @@ void drawbar(display& disp);
|
|||
bool drawterrainpalette(display& disp, int start, gamemap::TERRAIN selected, gamemap map);
|
||||
int tileselected(int x, int y, display& disp);
|
||||
|
||||
// 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_;
|
||||
};
|
||||
|
||||
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) {}
|
||||
|
||||
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_);
|
||||
|
||||
if(sym == SDLK_x)
|
||||
gui_.zoom(-zoom_amount_);
|
||||
|
||||
if(sym == SDLK_d)
|
||||
gui_.default_zoom();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
|
@ -82,7 +160,6 @@ int main(int argc, char** argv)
|
|||
}
|
||||
|
||||
const double scroll_speed = preferences::scroll_speed();
|
||||
const double zoom_amount = 5.0;
|
||||
|
||||
CVideo video;
|
||||
|
||||
|
@ -183,6 +260,8 @@ int main(int argc, char** argv)
|
|||
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])
|
||||
|
@ -205,61 +284,7 @@ int main(int argc, char** argv)
|
|||
if(key[SDLK_RIGHT] || mousex == gui.x()-1)
|
||||
gui.scroll(scroll_speed,0.0);
|
||||
|
||||
if(key[SDLK_z])
|
||||
gui.zoom(zoom_amount);
|
||||
|
||||
if(key[SDLK_x])
|
||||
gui.zoom(-zoom_amount);
|
||||
|
||||
if(key[SDLK_d])
|
||||
gui.default_zoom();
|
||||
|
||||
if(key[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(key[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const gamemap::location cur_hex = gui.hex_clicked_on(mousex,mousey);
|
||||
for(int num_key = SDLK_1; num_key != SDLK_9; ++num_key) {
|
||||
if(key[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();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gui.highlight_hex(cur_hex);
|
||||
if(new_left_button) {
|
||||
|
||||
|
@ -399,7 +424,7 @@ int tileselected(int x, int y, display& disp)
|
|||
{
|
||||
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*terrain_space/2;
|
||||
const int py = palette_y + (i/2)*terrain_space;
|
||||
const int pw = terrain_space;
|
||||
const int ph = terrain_space;
|
||||
|
||||
|
|
|
@ -266,3 +266,12 @@ time_t file_create_time(const std::string& fname)
|
|||
|
||||
return buf.st_mtime;
|
||||
}
|
||||
|
||||
int file_size(const std::string& fname)
|
||||
{
|
||||
struct stat buf;
|
||||
if(::stat(fname.c_str(),&buf) == -1)
|
||||
return -1;
|
||||
|
||||
return buf.st_size;
|
||||
}
|
|
@ -44,4 +44,7 @@ bool file_exists(const std::string& name);
|
|||
|
||||
time_t file_create_time(const std::string& fname);
|
||||
|
||||
//returns the size of a file, or -1 if the file doesn't exist
|
||||
int file_size(const std::string& fname);
|
||||
|
||||
#endif
|
||||
|
|
151
src/font.cpp
151
src/font.cpp
|
@ -61,11 +61,15 @@ TTF_Font* open_font(const std::string& fname, int size)
|
|||
}
|
||||
}
|
||||
|
||||
std::cerr << "opening font '" << name << "' " << size << "\n";
|
||||
|
||||
TTF_Font* font = TTF_OpenFont(name.c_str(),size);
|
||||
if(font == NULL) {
|
||||
std::cerr << "Could not open font file: " << name << '\n';
|
||||
}
|
||||
|
||||
std::cerr << "opened font okay\n";
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
|
@ -178,6 +182,55 @@ SDL_Surface* render_text(TTF_Font* font,const std::string& str,
|
|||
}
|
||||
}
|
||||
|
||||
//function which will parse the markup tags at the front of a string
|
||||
std::string::const_iterator parse_markup(std::string::const_iterator i1, std::string::const_iterator i2,
|
||||
int* font_size, SDL_Color* colour)
|
||||
{
|
||||
if(font_size == NULL || colour == NULL) {
|
||||
return i1;
|
||||
}
|
||||
|
||||
while(i1 != i2) {
|
||||
switch(*i1) {
|
||||
case '\\':
|
||||
// this must either be a quoted special character or a
|
||||
// quoted backslash - either way, remove leading backslash
|
||||
break;
|
||||
case BAD_TEXT:
|
||||
*colour = BAD_COLOUR;
|
||||
break;
|
||||
case GOOD_TEXT:
|
||||
*colour = GOOD_COLOUR;
|
||||
break;
|
||||
case NORMAL_TEXT:
|
||||
*colour = NORMAL_COLOUR;
|
||||
break;
|
||||
case BLACK_TEXT:
|
||||
*colour = BLACK_COLOUR;
|
||||
break;
|
||||
case LARGE_TEXT:
|
||||
*font_size += 2;
|
||||
break;
|
||||
case SMALL_TEXT:
|
||||
*font_size -= 2;
|
||||
break;
|
||||
case NULL_MARKUP:
|
||||
return i1+1;
|
||||
default:
|
||||
if(*i1 >= 1 && *i1 <= 9) {
|
||||
*colour = get_side_colour(*i1);
|
||||
break;
|
||||
}
|
||||
|
||||
return i1;
|
||||
}
|
||||
|
||||
++i1;
|
||||
}
|
||||
|
||||
return i1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SDL_Rect draw_text_line(display* gui, const SDL_Rect& area, int size,
|
||||
|
@ -247,7 +300,6 @@ SDL_Rect draw_text_line(display* gui, const SDL_Rect& area, int size,
|
|||
return dest;
|
||||
}
|
||||
|
||||
|
||||
SDL_Rect draw_text(display* gui, const SDL_Rect& area, int size,
|
||||
const SDL_Color& colour, const std::string& txt,
|
||||
int x, int y, SDL_Surface* bg, bool use_tooltips,
|
||||
|
@ -266,64 +318,26 @@ SDL_Rect draw_text(display* gui, const SDL_Rect& area, int size,
|
|||
|
||||
std::string::const_iterator i1 = text.begin();
|
||||
std::string::const_iterator i2 = std::find(i1,text.end(),'\n');
|
||||
SDL_Color col = colour;
|
||||
int sz = size;
|
||||
for(;;) {
|
||||
SDL_Color col = colour;
|
||||
int sz = size;
|
||||
|
||||
i1 = parse_markup(i1,i2,&sz,&col);
|
||||
|
||||
if(i1 != i2) {
|
||||
if(use_markup == USE_MARKUP) {
|
||||
if(*i1 == '\\') {
|
||||
// this must either be a quoted special character or a
|
||||
// quoted backslash - either way, remove leading backslash
|
||||
++i1;
|
||||
} else if(*i1 == BAD_TEXT) {
|
||||
col = BAD_COLOUR;
|
||||
++i1;
|
||||
} else if(*i1 == GOOD_TEXT) {
|
||||
col = GOOD_COLOUR;
|
||||
++i1;
|
||||
} else if(*i1 == NORMAL_TEXT) {
|
||||
col = NORMAL_COLOUR;
|
||||
++i1;
|
||||
continue;
|
||||
} else if(*i1 == BLACK_TEXT) {
|
||||
col = BLACK_COLOUR;
|
||||
++i1;
|
||||
continue;
|
||||
} else if(*i1 == LARGE_TEXT) {
|
||||
sz += 2;
|
||||
++i1;
|
||||
continue;
|
||||
} else if(*i1 == SMALL_TEXT) {
|
||||
sz -= 2;
|
||||
++i1;
|
||||
continue;
|
||||
} else if(*i1 == NULL_MARKUP) {
|
||||
++i1;
|
||||
} else if(*i1 >= 1 && *i1 <= 9) {
|
||||
col = get_side_colour(*i1);
|
||||
++i1;
|
||||
continue;
|
||||
}
|
||||
std::string new_string(i1,i2);
|
||||
|
||||
config::unescape(new_string);
|
||||
|
||||
const SDL_Rect rect = draw_text_line(gui,area,sz,col,new_string,x,y,bg,use_tooltips);
|
||||
if(rect.w > res.w) {
|
||||
res.w = rect.w;
|
||||
}
|
||||
|
||||
if(i1 != i2) {
|
||||
std::string new_string(i1,i2);
|
||||
|
||||
config::unescape(new_string);
|
||||
|
||||
const SDL_Rect rect =
|
||||
draw_text_line(gui,area,sz,col,new_string,x,y,bg,
|
||||
use_tooltips);
|
||||
if(rect.w > res.w)
|
||||
res.w = rect.w;
|
||||
res.h += rect.h;
|
||||
y += rect.h;
|
||||
}
|
||||
res.h += rect.h;
|
||||
y += rect.h;
|
||||
}
|
||||
|
||||
col = colour;
|
||||
sz = size;
|
||||
|
||||
if(i2 == text.end()) {
|
||||
break;
|
||||
}
|
||||
|
@ -537,15 +551,20 @@ SDL_Surface* floating_label::create_surface()
|
|||
{
|
||||
if(surf_ == NULL) {
|
||||
std::cerr << "creating surface...\n";
|
||||
TTF_Font* const font = get_font(font_size_);
|
||||
if(font == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const std::vector<std::string> lines = config::split(text_,'\n');
|
||||
std::vector<shared_sdl_surface> surfaces;
|
||||
for(std::vector<std::string>::const_iterator ln = lines.begin(); ln != lines.end(); ++ln) {
|
||||
surfaces.push_back(shared_sdl_surface(font::render_text(font,*ln,colour_)));
|
||||
SDL_Color colour = colour_;
|
||||
int size = font_size_;
|
||||
const std::string::const_iterator i1 = font::parse_markup(ln->begin(),ln->end(),&size,&colour);
|
||||
const std::string str(i1,ln->end());
|
||||
|
||||
TTF_Font* const font = get_font(size);
|
||||
|
||||
if(str != "" && font != NULL) {
|
||||
surfaces.push_back(shared_sdl_surface(font::render_text(font,str,colour)));
|
||||
}
|
||||
}
|
||||
|
||||
if(surfaces.empty()) {
|
||||
|
@ -659,7 +678,7 @@ void floating_label::undraw(SDL_Surface* screen)
|
|||
move(xmove_,ymove_);
|
||||
if(lifetime_ > 0) {
|
||||
--lifetime_;
|
||||
if(surf_ != NULL && alpha_change_ != 0) {
|
||||
if(surf_ != NULL && alpha_change_ != 0 && (xmove_ != 0.0 || ymove_ != 0.0)) {
|
||||
surf_.assign(adjust_surface_alpha_add(surf_,alpha_change_));
|
||||
}
|
||||
}
|
||||
|
@ -776,9 +795,9 @@ void draw_floating_labels(SDL_Surface* screen)
|
|||
return;
|
||||
}
|
||||
|
||||
//draw the labels in reverse order, so we can clear them in-order
|
||||
//to make sure the draw-undraw order is LIFO
|
||||
for(label_map::reverse_iterator i = labels.rbegin(); i != labels.rend(); ++i) {
|
||||
//draw the labels in the order they were added, so later added labels (likely to be tooltips)
|
||||
//are displayed over earlier added labels.
|
||||
for(label_map::iterator i = labels.begin(); i != labels.end(); ++i) {
|
||||
i->second.draw(screen);
|
||||
}
|
||||
}
|
||||
|
@ -789,10 +808,14 @@ void undraw_floating_labels(SDL_Surface* screen)
|
|||
return;
|
||||
}
|
||||
|
||||
for(label_map::iterator i = labels.begin(); i != labels.end(); ) {
|
||||
//undraw labels in reverse order, so that a LIFO process occurs, and the screen is restored
|
||||
//into the exact state it started in.
|
||||
for(label_map::reverse_iterator i = labels.rbegin(); i != labels.rend(); ) {
|
||||
i->second.undraw(screen);
|
||||
if(i->second.expired()) {
|
||||
labels.erase(i++);
|
||||
//we want to erase element i, which is (i+1).base()
|
||||
++i;
|
||||
labels.erase(i.base());
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
|
|
|
@ -638,6 +638,7 @@ int play_game(int argc, char** argv)
|
|||
config starting_pos;
|
||||
if(recorder.at_end()) {
|
||||
starting_pos = state.snapshot;
|
||||
state.gold = -100000;
|
||||
} else {
|
||||
starting_pos = state.starting_pos;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,44 @@ const std::string& translate_string_default(const std::string& str, const std::s
|
|||
return default_val;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool not_id(char c)
|
||||
{
|
||||
return !isalpha(c);
|
||||
}
|
||||
|
||||
void do_formatting(std::string& res, size_t npos, const string_map& m)
|
||||
{
|
||||
const std::string::iterator i = std::find(res.begin()+npos,res.end(),'%');
|
||||
if(i == res.end() || i+1 == res.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
npos = i - res.begin() + 1;
|
||||
|
||||
const std::string::iterator end = std::find_if(i+1,res.end(),not_id);
|
||||
|
||||
const std::string key(i+1,end);
|
||||
res.erase(i,end);
|
||||
|
||||
const string_map::const_iterator itor = m.find(key);
|
||||
if(itor != m.end()) {
|
||||
res.insert(npos-1,itor->second);
|
||||
}
|
||||
|
||||
do_formatting(res,npos,m);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string format_string(const std::string& key, const string_map& m)
|
||||
{
|
||||
std::string res = string_table[key];
|
||||
do_formatting(res,0,m);
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<std::string> get_languages()
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
|
|
|
@ -34,6 +34,11 @@ const std::string& translate_string(const std::string& str);
|
|||
//and otherwise returns default_val
|
||||
const std::string& translate_string_default(const std::string& key, const std::string& default_val);
|
||||
|
||||
//a function which can take an id to a string in the string table, and a
|
||||
//map of key/value pairs. Any token in the string of the form %identifier
|
||||
//will be substituted with m["identifier"]
|
||||
std::string format_string(const std::string& key, const string_map& m);
|
||||
|
||||
//function which, given the main configuration object, will return
|
||||
//a list of the translations of the game available.
|
||||
std::vector<std::string> get_languages();
|
||||
|
|
|
@ -148,7 +148,8 @@ int mp_connect::load_map(const std::string& era, int map, int num_turns, int vil
|
|||
} else {
|
||||
//Load a new map
|
||||
save_ = false;
|
||||
level_ptr = levels[map];
|
||||
loaded_level_ = *levels[map];
|
||||
level_ptr = &loaded_level_;
|
||||
|
||||
//set the number of turns here
|
||||
std::stringstream turns;
|
||||
|
@ -196,12 +197,14 @@ int mp_connect::load_map(const std::string& era, int map, int num_turns, int vil
|
|||
|
||||
bool first = true;
|
||||
for(sd = sides.first; sd != sides.second; ++sd) {
|
||||
config& side = (**sd);
|
||||
|
||||
if(save_ == false)
|
||||
{
|
||||
std::stringstream svillage_gold;
|
||||
svillage_gold << village_gold;
|
||||
(**sd)["village_gold"] = svillage_gold.str();
|
||||
(**sd)["gold"] = "100";
|
||||
side["village_gold"] = svillage_gold.str();
|
||||
side["gold"] = "100";
|
||||
if (first == true) {
|
||||
(**sd)["controller"] = "human";
|
||||
(**sd)["description"] = preferences::login();
|
||||
|
@ -212,27 +215,26 @@ int mp_connect::load_map(const std::string& era, int map, int num_turns, int vil
|
|||
}
|
||||
}
|
||||
|
||||
if((**sd)["fog"].empty())
|
||||
(**sd)["fog"] = fog_game ? "yes" : "no";
|
||||
if(side["fog"].empty())
|
||||
side["fog"] = fog_game ? "yes" : "no";
|
||||
|
||||
if((**sd)["shroud"].empty())
|
||||
(**sd)["shroud"] = shroud_game ? "yes" : "no";
|
||||
if(side["shroud"].empty())
|
||||
side["shroud"] = shroud_game ? "yes" : "no";
|
||||
|
||||
if((**sd)["name"].empty())
|
||||
(**sd)["name"] = (*possible_sides.front())["name"];
|
||||
if(side["name"].empty())
|
||||
side["name"] = (*possible_sides.front())["name"];
|
||||
|
||||
if((**sd)["type"].empty())
|
||||
(**sd)["type"] = (*possible_sides.front())["type"];
|
||||
if(side["type"].empty())
|
||||
side["type"] = (*possible_sides.front())["type"];
|
||||
|
||||
if((**sd)["recruit"].empty())
|
||||
(**sd)["recruit"] = (*possible_sides.front())["recruit"];
|
||||
if(side["recruit"].empty())
|
||||
side["recruit"] = (*possible_sides.front())["recruit"];
|
||||
|
||||
if((**sd)["music"].empty())
|
||||
(**sd)["music"] = (*possible_sides.front())["music"];
|
||||
if(side["music"].empty())
|
||||
side["music"] = (*possible_sides.front())["music"];
|
||||
|
||||
if((**sd)["recruitment_pattern"].empty())
|
||||
(**sd)["recruitment_pattern"] =
|
||||
possible_sides.front()->values["recruitment_pattern"];
|
||||
if(side["recruitment_pattern"].empty())
|
||||
side["recruitment_pattern"] = possible_sides.front()->values["recruitment_pattern"];
|
||||
}
|
||||
|
||||
if ((*level_)["objectives"] == "")
|
||||
|
|
|
@ -1075,7 +1075,8 @@ void turn_info::end_turn()
|
|||
} catch(gamestatus::save_game_failed& e) {
|
||||
gui::show_dialog(gui_,NULL,"",string_table["auto_save_game_failed"],gui::MESSAGE);
|
||||
//do not bother retrying, since the user can just save the game
|
||||
};
|
||||
}
|
||||
|
||||
recorder.end_turn();
|
||||
}
|
||||
|
||||
|
|
|
@ -568,6 +568,12 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
|
|||
advance_unit(gameinfo,units,advancing_units.front(),options[val]);
|
||||
|
||||
advancing_units.pop_front();
|
||||
|
||||
//if there are no more advancing units, then we check for victory,
|
||||
//in case the battle that led to advancement caused the end of scenario
|
||||
if(advancing_units.empty()) {
|
||||
check_victory(units,teams);
|
||||
}
|
||||
}
|
||||
|
||||
//if there is nothing more in the records
|
||||
|
@ -764,7 +770,6 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
|
|||
|
||||
if(u != units.end() && tgt != units.end()) {
|
||||
attack(disp,map,teams,src,dst,weapon_num,units,state,gameinfo,false);
|
||||
check_victory(units,teams);
|
||||
}
|
||||
|
||||
u = units.find(src);
|
||||
|
@ -779,6 +784,12 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
|
|||
tgt->second.type().advances_to().empty() == false) {
|
||||
advancing_units.push_back(tgt->first);
|
||||
}
|
||||
|
||||
//check victory now if we don't have any advancements. If we do have advancements,
|
||||
//we don't check until the advancements are processed.
|
||||
if(advancing_units.empty()) {
|
||||
check_victory(units,teams);
|
||||
}
|
||||
} else if((child = cfg->child("speak")) != NULL) {
|
||||
const std::string& team_name = (*child)["team_name"];
|
||||
if(team_name == "" || teams[disp.viewing_team()].team_name() == team_name) {
|
||||
|
|
18
src/unit.cpp
18
src/unit.cpp
|
@ -1087,3 +1087,21 @@ std::string get_team_name(int side, const unit_map& units)
|
|||
|
||||
return "-";
|
||||
}
|
||||
|
||||
temporary_unit_placer::temporary_unit_placer(unit_map& m, const gamemap::location& loc, const unit& u)
|
||||
: m_(m), loc_(loc), temp_(m.count(loc) == 1 ? m.find(loc)->second : u), use_temp_(m.count(loc) == 1)
|
||||
{
|
||||
if(use_temp_) {
|
||||
m.erase(loc);
|
||||
}
|
||||
|
||||
m.insert(std::pair<gamemap::location,unit>(loc,u));
|
||||
}
|
||||
|
||||
temporary_unit_placer::~temporary_unit_placer()
|
||||
{
|
||||
m_.erase(loc_);
|
||||
if(use_temp_) {
|
||||
m_.insert(std::pair<gamemap::location,unit>(loc_,temp_));
|
||||
}
|
||||
}
|
14
src/unit.hpp
14
src/unit.hpp
|
@ -237,4 +237,18 @@ std::string get_team_name(int side, const unit_map& units);
|
|||
|
||||
const std::set<gamemap::location> vacant_towers(const std::set<gamemap::location>& towers, const unit_map& units);
|
||||
|
||||
//this object is used to temporary place a unit in the unit map, swapping out any unit
|
||||
//that is already there. On destruction, it restores the unit map to its original state.
|
||||
struct temporary_unit_placer
|
||||
{
|
||||
temporary_unit_placer(unit_map& m, const gamemap::location& loc, const unit& u);
|
||||
~temporary_unit_placer();
|
||||
|
||||
private:
|
||||
unit_map& m_;
|
||||
const gamemap::location& loc_;
|
||||
const unit temp_;
|
||||
bool use_temp_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -111,6 +111,10 @@ SOURCE=.\src\ai_move.cpp
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\builder.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\widgets\button.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -347,6 +351,10 @@ SOURCE=.\src\ai_move.hpp
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\builder.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\widgets\button.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
Loading…
Add table
Reference in a new issue