made the game more interactive during the AI's turn

This commit is contained in:
Dave White 2004-04-02 23:42:19 +00:00
parent 8ae1c59ae2
commit 36a20a3a1e
12 changed files with 82 additions and 28 deletions

View file

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

View file

@ -498,7 +498,7 @@ void attack(display& gui, const gamemap& map,
const game_data& info, bool player_is_attacker)
{
//stop the user from issuing any commands while the units are fighting
const command_disabler disable_commands;
const command_disabler disable_commands(&gui);
std::map<gamemap::location,unit>::iterator a = units.find(attacker);
std::map<gamemap::location,unit>::iterator d = units.find(defender);
@ -1403,7 +1403,7 @@ size_t move_unit(display* disp, const game_data& gamedata,
replay* move_recorder, undo_list* undo_stack, gamemap::location *next_unit)
{
//stop the user from issuing any commands while the unit is moving
const command_disabler disable_commands;
const command_disabler disable_commands(disp);
assert(!route.empty());

View file

@ -114,6 +114,22 @@ bool ai_interface::recruit(const std::string& unit_name, location loc)
}
}
void ai_interface::user_interact()
{
const int interact_time = 30;
const int time_since_interact = SDL_GetTicks() - last_interact_;
if(time_since_interact < interact_time) {
return;
}
const int ncommand = recorder.ncommands();
info_.turn_data_.turn_slice();
info_.turn_data_.send_data(ncommand);
info_.disp.draw();
last_interact_ = SDL_GetTicks();
}
team& ai_interface::current_team()
{
return info_.teams[info_.team_num-1];
@ -127,6 +143,9 @@ const team& ai_interface::current_team() const
gamemap::location ai_interface::move_unit(location from, location to, std::map<location,paths>& possible_moves)
{
//stop the user from issuing any commands while the unit is moving
const command_disabler disable_commands(&info_.disp);
assert(info_.units.find(to) == info_.units.end() || from == to);
info_.disp.select_hex(from);
@ -307,6 +326,8 @@ void ai::do_move()
{
log_scope("doing ai move");
user_interact();
typedef paths::route route;
typedef std::map<location,paths> moves_map;
@ -458,6 +479,9 @@ bool ai::do_combat(std::map<gamemap::location,paths>& possible_moves, const move
void ai_interface::attack_enemy(const location& u, const location& target, int weapon)
{
//stop the user from issuing any commands while the unit is attacking
const command_disabler disable_commands(&info_.disp);
if(info_.units.count(u) && info_.units.count(target)) {
if(info_.units.find(target)->second.stone()) {
std::cerr << "ERROR: attempt to attack unit that is turned to stone\n";

View file

@ -35,9 +35,9 @@ public:
///that an AI might need access to in order to make and implement its decisions
struct info {
info(display& disp, const gamemap& map, const game_data& gameinfo, unit_map& units,
std::vector<team>& teams, int team_num, const gamestatus& state)
std::vector<team>& teams, int team_num, const gamestatus& state, class turn_info& turn_data)
: disp(disp), map(map), gameinfo(gameinfo), units(units), teams(teams),
team_num(team_num), state(state)
team_num(team_num), state(state), turn_data_(turn_data)
{}
///the display object, used to draw the moves the AI makes.
@ -61,11 +61,15 @@ public:
///information about what turn it is, and what time of day
const gamestatus& state;
///the object that allows the player to interact with the game.
///should not be used outside of ai_interface
class turn_info& turn_data_;
};
///the constructor. All derived classes should take an argument of type info& which
///they should pass to this constructor
ai_interface(info& arg) : info_(arg) {}
ai_interface(info& arg) : info_(arg), last_interact_(0) {}
virtual ~ai_interface() {}
///the function that is called when the AI must play its turn. Derived classes should
@ -118,8 +122,14 @@ protected:
info& get_info() { return info_; }
const info& get_info() const { return info_; }
///function which should be called frequently to allow the user to interact with
///the interface. This function will make sure that interaction doesn't occur
///too often, so there is no problem with calling it very regularly
void user_interact();
private:
info info_;
int last_interact_;
};
///this function is used to create a new AI object with the specified algorithm name

View file

@ -13,7 +13,6 @@
#include "actions.hpp"
#include "ai_attack.hpp"
#include "events.hpp"
#include "game_config.hpp"
#include "log.hpp"
#include "pathfind.hpp"
@ -38,11 +37,12 @@ void ai::do_attack_analysis(
attack_analysis& cur_analysis
)
{
//this function is called fairly frequently, so interact with the user here.
user_interact();
if(cur_analysis.movements.size() >= 4)
return;
events::pump();
static double best_results[6];
if(result.empty()) {
for(int i = 0; i != 6; ++i) {

View file

@ -193,6 +193,8 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
{
log_scope("choosing move");
user_interact();
std::vector<target>::const_iterator ittg;
for(ittg = targets.begin(); ittg != targets.end(); ++ittg) {
assert(map_.on_board(ittg->loc));
@ -227,6 +229,8 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
//choose the best target for that unit
for(std::vector<target>::iterator tg = targets.begin(); tg != targets.end(); ++tg) {
user_interact();
assert(map_.on_board(tg->loc));
const paths::route cur_route = a_star_search(u->first,tg->loc,
minimum(tg->value/best_rating,500.0),cost_calc);
@ -253,6 +257,8 @@ std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<targe
continue;
}
user_interact();
const move_cost_calculator calc(u->second,map_,gameinfo_,units_,u->first,dstsrc);
const paths::route cur_route = a_star_search(u->first,best_target->loc,
minimum(best_target->value/best_rating,100.0),calc);

View file

@ -167,12 +167,12 @@ void change_hotkey(hotkey_item& item)
}
}
basic_handler::basic_handler(display& disp) : disp_(disp) {}
basic_handler::basic_handler(display* disp) : disp_(disp) {}
void basic_handler::handle_event(const SDL_Event& event)
{
if(event.type == SDL_KEYDOWN && !gui::in_dialog()) {
key_event(disp_,event.key,NULL);
if(event.type == SDL_KEYDOWN && !gui::in_dialog() && disp_ != NULL) {
key_event(*disp_,event.key,NULL);
}
}

View file

@ -113,12 +113,12 @@ void execute_command(display& disp, HOTKEY_COMMAND command, command_executor* ex
//object which will ensure that basic keyboard events like escape
//are handled properly for the duration of its lifetime
struct basic_handler : public events::handler {
basic_handler(display& disp);
basic_handler(display* disp);
void handle_event(const SDL_Event& event);
private:
display& disp_;
display* disp_;
};
}

View file

@ -338,17 +338,20 @@ void show_map_scene(display& screen, config& data)
if(key[SDLK_RETURN] || key[SDLK_SPACE] || mouse_flags) {
break;
}
screen.video().flip();
}
if(key[SDLK_ESCAPE]) {
break;
}
screen.video().flip();
}
if(!key[SDLK_ESCAPE]) {
SDL_Delay(500);
for(int i = 0; i != 50; ++i) {
SDL_Delay(10);
screen.video().flip();
}
}
static const SDL_Rect area = {0,0,screen.x(),screen.y()};
@ -374,6 +377,7 @@ void show_map_scene(display& screen, config& data)
SDL_Delay(20);
events::pump();
screen.video().flip();
}
//clear the screen

View file

@ -322,7 +322,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, const config& game_config,
try {
if(first_time) {
const hotkey::basic_handler key_events_handler(gui);
const hotkey::basic_handler key_events_handler(&gui);
std::cerr << "first_time..." << (recorder.skipping() ? "skipping" : "no skip") << "\n";
update_locker lock_display(gui,recorder.skipping());
@ -383,12 +383,12 @@ LEVEL_RESULT play_level(game_data& gameinfo, const config& game_config,
const unit_map::iterator leader = find_leader(units,player_number);
if(leader != units.end() && !recorder.skipping()) {
const hotkey::basic_handler key_events_handler(gui);
const hotkey::basic_handler key_events_handler(&gui);
gui.scroll_to_tile(leader->first.x,leader->first.y);
}
if(replaying) {
const hotkey::basic_handler key_events_handler(gui);
const hotkey::basic_handler key_events_handler(&gui);
std::cerr << "doing replay " << player_number << "\n";
try {
replaying = do_replay(gui,map,gameinfo,units,teams,
@ -431,14 +431,17 @@ redo_turn:
std::cerr << "is ai...\n";
gui.recalculate_minimap();
const hotkey::basic_handler key_events_handler(gui);
const cursor::setter cursor_setter(cursor::WAIT);
const int start_command = recorder.ncommands();
update_locker lock(gui,!preferences::show_ai_moves());
ai_interface::info ai_info(gui,map,gameinfo,units,teams,player_number,status);
turn_info turn_data(gameinfo,state_of_game,status,
game_config,level,key,gui,
map,teams,player_number,units,true);
ai_interface::info ai_info(gui,map,gameinfo,units,teams,player_number,status,turn_data);
util::scoped_ptr<ai_interface> ai_obj(create_ai(team_it->ai_algorithm(),ai_info));
ai_obj->play_turn();

View file

@ -38,8 +38,15 @@ namespace {
int commands_disabled = 0;
}
command_disabler::command_disabler() { ++commands_disabled; }
command_disabler::~command_disabler() { --commands_disabled; }
command_disabler::command_disabler(display* disp) : hotkey::basic_handler(disp)
{
++commands_disabled;
}
command_disabler::~command_disabler()
{
--commands_disabled;
}
void play_turn(game_data& gameinfo, game_state& state_of_game,
gamestatus& status, const config& terrain_config, config* level,
@ -1040,7 +1047,7 @@ void turn_info::undo()
if(undo_stack_.empty())
return;
const command_disabler disable_commands;
const command_disabler disable_commands(&gui_);
const int starting_moves = undo_stack_.back().starting_moves;
std::vector<gamemap::location> route = undo_stack_.back().route;
@ -1093,7 +1100,7 @@ void turn_info::redo()
if(redo_stack_.empty())
return;
const command_disabler disable_commands;
const command_disabler disable_commands(&gui_);
//clear routes, selected hex, etc
gui_.set_paths(NULL);

View file

@ -46,9 +46,9 @@ private:
display& gui_;
};
struct command_disabler
struct command_disabler : private hotkey::basic_handler
{
command_disabler();
command_disabler(display* disp);
~command_disabler();
};