made the game more interactive during the AI's turn
This commit is contained in:
parent
8ae1c59ae2
commit
36a20a3a1e
12 changed files with 82 additions and 28 deletions
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
24
src/ai.cpp
24
src/ai.cpp
|
@ -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";
|
||||
|
|
16
src/ai.hpp
16
src/ai.hpp
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue