Added the ability to move units on fog/shroud maps without ...

...updating the fog/shroud, so the moves can be undone. The player can
commit the moves, forcing the fog/shroud to update, but then the moves
can no longer be undone.  Useful to make fog/shroud maps behave more
like normal maps, with respect to move undoing.
This commit is contained in:
John B. Messerly 2004-04-25 18:50:42 +00:00
parent 5021410e72
commit 8a80955b83
10 changed files with 121 additions and 13 deletions

View file

@ -39,7 +39,7 @@ height=600
[menu]
is_context_menu=true
items=undo,redo,cycle,describeunit,speak,recruit,recall,createunit,renameunit,labelterrain,showenemymoves,bestenemymoves,endturn
items=undo,redo,cycle,describeunit,speak,recruit,recall,createunit,renameunit,labelterrain,showenemymoves,bestenemymoves,toggleshroud,updateshroud,endturn
[/menu]
# top panel

View file

@ -125,6 +125,16 @@ language="English"
ctrl=yes
[/hotkey]
[hotkey]
command=toggleshroud
key=k
alt=yes
[/hotkey]
[hotkey]
command=updateshroud
key=k
ctrl=yes
[/hotkey]
[hotkey]
command=speak
key=m
[/hotkey]
@ -450,6 +460,8 @@ action_mute="Mute"
action_labelterrain="Set Label"
action_showenemymoves="Show Enemy Moves"
action_bestenemymoves="Best Possible Enemy Moves"
action_toggleshroud="Toggle Shroud Updates"
action_updateshroud="Update Shroud Now"
action_editnewmap="New Map"
action_editloadmap="Load Map"
action_editsavemap="Save Map"

View file

@ -1430,9 +1430,12 @@ size_t move_unit(display* disp, const game_data& gamedata,
const bool skirmisher = u.type().is_skirmisher();
const bool check_shroud = teams[team_num].auto_shroud_updates() &&
(teams[team_num].uses_shroud() || teams[team_num].uses_fog());
//if we use shroud/fog of war, count out the units we can currently see
std::set<gamemap::location> known_units;
if(teams[team_num].uses_shroud() || teams[team_num].uses_fog()) {
if(check_shroud) {
for(unit_map::const_iterator u = units.begin(); u != units.end(); ++u) {
if(teams[team_num].fogged(u->first.x,u->first.y) == false) {
known_units.insert(u->first);
@ -1466,8 +1469,7 @@ size_t move_unit(display* disp, const game_data& gamedata,
//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(check_shroud) {
if(units.count(*step) == 0 && !map.is_village(*step)) {
std::cerr << "checking for units from " << (step->x+1) << "," << (step->y+1) << "\n";
@ -1553,6 +1555,7 @@ size_t move_unit(display* disp, const game_data& gamedata,
if(undo_stack != NULL) {
if(event_mutated || should_clear_stack) {
apply_shroud_changes(*undo_stack,disp,status,map,gamedata,units,teams,team_num);
undo_stack->clear();
} else {
undo_stack->push_back(undo_action(steps,starting_moves,orig_village_owner));
@ -1671,3 +1674,42 @@ bool unit_can_move(const gamemap::location& loc, const unit_map& units,
return false;
}
void apply_shroud_changes(undo_list& undos, display* disp, const gamestatus& status, const gamemap& map,
const game_data& gamedata, const unit_map& units, std::vector<team>& teams, int team)
{
// No need to do this if the team isn't using fog or shroud.
if(!teams[team].uses_shroud() && !teams[team].uses_fog())
return;
/*
This function works thusly:
1. run through the list of undo_actions
2. for each one, play back the unit's move
3. for each location along the route, clear any "shrouded" squares that the unit can see
4. clear the undo_list
5. call clear_shroud to update the fog of war for each unit.
6. fix up associated display stuff (done in a similar way to turn_info::undo())
*/
for(undo_list::const_iterator un = undos.begin(); un != undos.end(); ++un) {
if(un->is_recall()) continue;
unit_map::const_iterator ui = units.find(un->route.back());
unit_map um;
assert(ui != units.end());
std::vector<gamemap::location>::const_iterator step;
for(step = un->route.begin(); step != un->route.end(); ++step) {
um.insert(std::pair<gamemap::location,unit>(*step,ui->second));
clear_shroud_unit(map,status,gamedata,um,*step,teams,team,NULL,NULL);
um.erase(*step);
}
}
if(disp != NULL) {
disp->invalidate_unit();
disp->invalidate_game_status();
clear_shroud(*disp,status,map,gamedata,units,teams,team);
disp->recalculate_minimap();
disp->set_paths(NULL);
disp->set_route(NULL);
} else {
recalculate_fog(map,status,gamedata,units,teams,team);
}
}

View file

@ -196,6 +196,11 @@ bool clear_shroud(display& disp, const gamestatus& status,
const gamemap& map, const game_data& gamedata,
const unit_map& units, std::vector<team>& teams, int team);
//function to apply pending shroud changes in the undo stack.
//it needs tons of parameters because it calls clear_shroud(...) (see above)
void apply_shroud_changes(undo_list& undos, display* disp, const gamestatus& status, const gamemap& map,
const game_data& gamedata, const unit_map& units, std::vector<team>& teams, int team);
//will return true iff the unit at 'loc' has any possible moves it can do
//(including attacking etc).
bool unit_can_move(const gamemap::location& loc, const unit_map& units,

View file

@ -73,6 +73,8 @@ HOTKEY_COMMAND string_to_command(const std::string& str)
m.insert(val("editsavemap",HOTKEY_EDIT_SAVE_MAP));
m.insert(val("editsaveas",HOTKEY_EDIT_SAVE_AS));
m.insert(val("editsetstartpos",HOTKEY_EDIT_SET_START_POS));
m.insert(val("toggleshroud",HOTKEY_TOGGLE_SHROUD));
m.insert(val("updateshroud",HOTKEY_UPDATE_SHROUD));
}
const std::map<std::string,HOTKEY_COMMAND>::const_iterator i = m.find(str);
@ -373,6 +375,12 @@ void execute_command(display& disp, HOTKEY_COMMAND command, command_executor* ex
if(executor)
executor->show_enemy_moves(true);
break;
case HOTKEY_TOGGLE_SHROUD:
if(executor) executor->toggle_shroud_updates();
break;
case HOTKEY_UPDATE_SHROUD:
if(executor) executor->update_shroud_now();
break;
case HOTKEY_QUIT_GAME: {
const int res = gui::show_dialog(disp,NULL,"",string_table["quit_message"],gui::YES_NO);
if(res == 0) {

View file

@ -34,6 +34,7 @@ enum HOTKEY_COMMAND { HOTKEY_CYCLE_UNITS, HOTKEY_END_UNIT_TURN, HOTKEY_LEADER,
HOTKEY_SPEAK, HOTKEY_CREATE_UNIT, HOTKEY_PREFERENCES,
HOTKEY_OBJECTIVES, HOTKEY_UNIT_LIST, HOTKEY_STATISTICS, HOTKEY_QUIT_GAME,
HOTKEY_LABEL_TERRAIN, HOTKEY_SHOW_ENEMY_MOVES, HOTKEY_BEST_ENEMY_MOVES,
HOTKEY_TOGGLE_SHROUD, HOTKEY_UPDATE_SHROUD,
//editing specific commands
HOTKEY_EDIT_SET_TERRAIN,
@ -106,6 +107,8 @@ public:
virtual void show_statistics() = 0;
virtual void label_terrain() = 0;
virtual void show_enemy_moves(bool ignore_units) = 0;
virtual void toggle_shroud_updates() = 0;
virtual void update_shroud_now() = 0;
// Map editor stuff.
virtual void edit_set_terrain() {}

View file

@ -675,7 +675,7 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
res = attacks_in_range[res];
u->second.set_goto(gamemap::location());
undo_stack_.clear();
clear_undo_stack();
redo_stack_.clear();
current_paths_ = paths();
@ -771,9 +771,7 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
gui_.set_paths(&current_paths_);
}
if(clear_shroud(gui_,status_,map_,gameinfo_,units_,teams_,team_num_-1)) {
undo_stack_.clear();
}
if(clear_shroud()) clear_undo_stack();
}
} else {
gui_.set_paths(NULL);
@ -893,6 +891,11 @@ bool turn_info::can_execute_command(hotkey::HOTKEY_COMMAND command) const
case hotkey::HOTKEY_UNDO:
return !browse_ && !undo_stack_.empty();
case hotkey::HOTKEY_TOGGLE_SHROUD:
return !browse_ && (teams_[team_num_-1].uses_fog() || teams_[team_num_-1].uses_shroud());
case hotkey::HOTKEY_UPDATE_SHROUD:
return !browse_ && !teams_[team_num_-1].auto_shroud_updates();
//commands we can only do if we are actually playing, not just viewing
case hotkey::HOTKEY_END_UNIT_TURN:
case hotkey::HOTKEY_RECRUIT:
@ -1070,6 +1073,8 @@ void turn_info::end_turn()
}
}
//force any pending fog updates
clear_undo_stack();
end_turn_ = true;
//auto-save
@ -1089,7 +1094,7 @@ void turn_info::goto_leader()
{
const unit_map::const_iterator i = team_leader(team_num_,units_);
if(i != units_.end()) {
clear_shroud(gui_,status_,map_,gameinfo_,units_,teams_,team_num_-1);
clear_shroud();
gui_.scroll_to_tile(i->first.x,i->first.y,display::WARP);
}
}
@ -1174,7 +1179,7 @@ void turn_info::undo()
recorder.undo();
const bool shroud_cleared = clear_shroud(gui_,status_,map_,gameinfo_,units_,teams_,team_num_-1);
const bool shroud_cleared = clear_shroud();
if(shroud_cleared) {
gui_.recalculate_minimap();
@ -1588,10 +1593,10 @@ void turn_info::do_recruit(const std::string& name)
gui::show_dialog(gui_,NULL,"",msg,gui::OK_ONLY);
}
undo_stack_.clear();
clear_undo_stack();
redo_stack_.clear();
clear_shroud(gui_,status_,map_,gameinfo_,units_,teams_,team_num_-1);
clear_shroud();
gui_.recalculate_minimap();
gui_.invalidate_game_status();
@ -1996,6 +2001,29 @@ void turn_info::show_enemy_moves(bool ignore_units)
gui_.set_paths(&all_paths_);
}
void turn_info::toggle_shroud_updates() {
bool auto_shroud = teams_[team_num_-1].auto_shroud_updates();
// If we're turning automatic shroud updates on, then commit all moves
if(auto_shroud == false) update_shroud_now();
teams_[team_num_-1].set_auto_shroud_updates(!auto_shroud);
}
void turn_info::update_shroud_now() {
clear_undo_stack();
}
bool turn_info::clear_shroud() {
return teams_[team_num_-1].auto_shroud_updates() &&
::clear_shroud(gui_,status_,map_,gameinfo_,units_,teams_,team_num_-1);
}
void turn_info::clear_undo_stack() {
if (teams_[team_num_-1].auto_shroud_updates() == false)
apply_shroud_changes(undo_stack_,&gui_,status_,map_,gameinfo_,units_,teams_,team_num_-1);
undo_stack_.clear();
}
unit_map::iterator turn_info::current_unit()
{
unit_map::iterator i = units_.end();

View file

@ -108,6 +108,8 @@ private:
void show_statistics();
void label_terrain();
void show_enemy_moves(bool ignore_units);
void toggle_shroud_updates();
void update_shroud_now();
void do_recruit(const std::string& name);
@ -120,6 +122,9 @@ private:
void show_attack_options(unit_map::const_iterator u);
bool clear_shroud();
void clear_undo_stack();
unit_map::iterator current_unit();
unit_map::const_iterator current_unit() const;

View file

@ -217,7 +217,7 @@ void team::team_info::write(config& cfg) const
cfg["music"] = music;
}
team::team(const config& cfg, int gold) : gold_(gold), info_(cfg)
team::team(const config& cfg, int gold) : gold_(gold), info_(cfg), auto_shroud_updates_(true)
{
//gold is the maximum of 'gold' and what is given in the config file
if(info_.gold.empty() == false)

View file

@ -120,6 +120,9 @@ public:
bool clear_fog(size_t x, size_t y);
void refog();
bool auto_shroud_updates() const { return auto_shroud_updates_; }
void set_auto_shroud_updates(bool value) { auto_shroud_updates_ = value; }
const std::string& music() const;
static int nteams();
@ -131,6 +134,8 @@ private:
typedef std::vector<std::vector<bool> > shroud_map;
shroud_map shroud_, fog_;
bool auto_shroud_updates_;
team_info info_;
};