Nightstalk ability added

This commit is contained in:
uid67456 2004-01-28 23:43:38 +00:00
parent d7cb1e3d97
commit f80e2924cf
13 changed files with 89 additions and 61 deletions

View file

@ -344,6 +344,8 @@ void attack(display& gui, const gamemap& map,
//if the attacker was invisible, she isn't anymore!
static const std::string forest_invisible("ambush");
a->second.remove_flag(forest_invisible);
static const std::string night_invisible("nightstalk");
a->second.remove_flag(night_invisible);
battle_stats stats = evaluate_battle_stats(map,attacker,defender,
attack_with,units,state,info);
@ -438,7 +440,7 @@ void attack(display& gui, const gamemap& map,
gui.draw_tile(loc.x,loc.y);
}
}
recalculate_fog(map, info, units, teams, d->second.side()-1);
recalculate_fog(map,state,info,units,teams,d->second.side()-1);
gui.recalculate_minimap();
gui.update_display();
break;
@ -554,7 +556,7 @@ void attack(display& gui, const gamemap& map,
}
gui.recalculate_minimap();
gui.update_display();
recalculate_fog(map, info, units, teams, a->second.side()-1);
recalculate_fog(map,state,info,units,teams,a->second.side()-1);
break;
} else if(hits) {
if(stats.defend_special == poison_string &&
@ -1032,7 +1034,9 @@ 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
bool clear_shroud_unit(const gamemap& map, const game_data& gamedata,
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,
@ -1042,7 +1046,7 @@ bool clear_shroud_unit(const gamemap& map, const game_data& gamedata,
std::vector<gamemap::location> cleared_locations;
paths p(map,gamedata,units,loc,teams,true,false);
paths p(map,status,gamedata,units,loc,teams,true,false);
for(paths::routes_map::const_iterator i = p.routes.begin();
i != p.routes.end(); ++i) {
clear_shroud_loc(map,teams[team],i->first,&cleared_locations);
@ -1074,8 +1078,9 @@ bool clear_shroud_unit(const gamemap& map, const game_data& gamedata,
}
void recalculate_fog(const gamemap& map, const game_data& gamedata,
const unit_map& units, std::vector<team>& teams, int team) {
void recalculate_fog(const gamemap& map, const gamestatus& status,
const game_data& gamedata, const unit_map& units,
std::vector<team>& teams, int team) {
teams[team].refog();
@ -1087,12 +1092,13 @@ void recalculate_fog(const gamemap& map, const game_data& gamedata,
unit& mutable_unit = const_cast<unit&>(i->second);
const unit_movement_resetter move_resetter(mutable_unit);
clear_shroud_unit(map,gamedata,units,i->first,teams,team,NULL,NULL);
clear_shroud_unit(map,status,gamedata,units,i->first,teams,team,NULL,NULL);
}
}
}
bool clear_shroud(display& disp, const gamemap& map, const game_data& gamedata,
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)
{
if(teams[team].uses_shroud() == false && teams[team].uses_fog() == false)
@ -1109,16 +1115,17 @@ bool clear_shroud(display& disp, const gamemap& map, const game_data& gamedata,
unit& mutable_unit = const_cast<unit&>(i->second);
const unit_movement_resetter move_resetter(mutable_unit);
result |= clear_shroud_unit(map,gamedata,units,i->first,teams,team,NULL,NULL);
result |= clear_shroud_unit(map,status,gamedata,units,i->first,teams,team,NULL,NULL);
}
}
recalculate_fog(map, gamedata, units, teams, team);
recalculate_fog(map,status,gamedata,units,teams,team);
return result;
}
size_t move_unit(display* disp, const game_data& gamedata, const gamemap& map,
size_t move_unit(display* disp, const game_data& gamedata,
const gamestatus& status, const gamemap& map,
unit_map& units, std::vector<team>& teams,
const std::vector<gamemap::location>& route,
replay* move_recorder, undo_list* undo_stack, gamemap::location *next_unit)
@ -1169,7 +1176,8 @@ size_t move_unit(display* disp, const game_data& gamedata, const gamemap& map,
moves_left -= mv;
}
if(!skirmisher && enemy_zoc(map,units,*step,teams[team_num],u.side())) {
if(!skirmisher && enemy_zoc(map,status,units,*step,teams[team_num],
u.side())) {
moves_left = 0;
}
@ -1182,7 +1190,7 @@ size_t move_unit(display* disp, const game_data& gamedata, const gamemap& map,
bool res;
should_clear_stack |=
clear_shroud_unit(map,gamedata,units,*step,teams,
clear_shroud_unit(map,status,gamedata,units,*step,teams,
ui->second.side()-1,&seen_units,&res);
units.erase(*step);

View file

@ -172,19 +172,22 @@ typedef std::deque<undo_action> undo_list;
//steps. If the unit cannot make it completely along the path this turn,
//a goto order will be set. If move_recorder is not NULL, the move will
//be recorded in it. If undos is not NULL, undo information will be added.
size_t move_unit(display* disp, const game_data& gamedata, const gamemap& map,
unit_map& units, std::vector<team>& teams,
const std::vector<gamemap::location>& steps,
replay* move_recorder, undo_list* undos,
size_t move_unit(display* disp, const game_data& gamedata,
const gamestatus& status, const gamemap& map,
unit_map& units, std::vector<team>& teams,
const std::vector<gamemap::location>& steps,
replay* move_recorder, undo_list* undos,
gamemap::location *next_unit = NULL);
//function which recalculates the fog
void recalculate_fog(const gamemap& map, const game_data& gamedata,
void recalculate_fog(const gamemap& map, const gamestatus& status,
const game_data& gamedata,
const unit_map& units, std::vector<team>& teams, int team);
//function which will clear shroud away for the given 0-based team based on
//current unit positions. Returns true if some shroud is actually cleared away.
bool clear_shroud(display& disp, const gamemap& map, const game_data& gamedata,
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);
//will return true iff the unit at 'loc' has any possible moves it can do

View file

@ -113,7 +113,7 @@ void ai::move_unit(const location& from, const location& to, std::map<location,p
const bool ignore_zocs = u_it->second.type().is_skirmisher();
const bool teleport = u_it->second.type().teleports();
paths current_paths = paths(map_,gameinfo_,units_,from,teams_,ignore_zocs,teleport);
paths current_paths = paths(map_,state_,gameinfo_,units_,from,teams_,ignore_zocs,teleport);
paths_wiper wiper(disp_);
if(!disp_.fogged(from.x,from.y))
@ -187,7 +187,7 @@ void ai::do_move()
const bool ignore_zocs = un_it->second.type().is_skirmisher();
const bool teleports = un_it->second.type().teleports();
const paths new_paths(map_,gameinfo_,units_,
const paths new_paths(map_,state_,gameinfo_,units_,
un_it->first,teams_,ignore_zocs,teleports);
for(paths::routes_map::const_iterator rt = new_paths.routes.begin();
rt != new_paths.routes.end(); ++rt) {
@ -218,7 +218,7 @@ void ai::do_move()
const bool ignore_zocs = un_it->second.type().is_skirmisher();
const bool teleports = un_it->second.type().teleports();
possible_moves.insert(std::pair<gamemap::location,paths>(
un_it->first,paths(map_,gameinfo_,units_,
un_it->first,paths(map_,state_,gameinfo_,units_,
un_it->first,teams_,ignore_zocs,teleports)));
}
@ -248,7 +248,7 @@ void ai::do_move()
}
//find where the leader can move
const paths leader_paths(map_,gameinfo_,units_,leader->first,teams_,false,false);
const paths leader_paths(map_,state_,gameinfo_,units_,leader->first,teams_,false,false);
const gamemap::location& start_pos = map_.starting_position(leader->second.side());
possible_moves.insert(std::pair<gamemap::location,paths>(leader->first,leader_paths));
@ -580,7 +580,8 @@ void ai::do_move()
const unit_map::iterator enemy = units_.find(adj[n]);
if(enemy != units_.end() &&
current_team().is_enemy(enemy->second.side()) &&
!enemy->second.invisible(map_[enemy->first.x][enemy->first.y])) {
!enemy->second.invisible(map_[enemy->first.x][enemy->first.y],
state_.get_time_of_day().lawful_bonus)) {
target = adj[n];
weapon = choose_weapon(move.first,target,bat_stats,
map_[move.second.x][move.second.y]);

View file

@ -423,7 +423,8 @@ std::vector<ai::attack_analysis> ai::analyze_targets(
//attack anyone who is on the enemy side, and who is not invisible
if(current_team().is_enemy(j->second.side()) &&
j->second.invisible(map_.underlying_terrain(map_[j->first.x][j->first.y])) == false) {
j->second.invisible(map_.underlying_terrain(map_[j->first.x][j->first.y]),
state_.get_time_of_day().lawful_bonus) == false) {
std::cerr << "analyzing attack on " << j->first.x+1 << "," << j->first.y+1 << "\n";
location adjacent[6];
get_adjacent_tiles(j->first,adjacent);
@ -547,4 +548,4 @@ double ai::power_projection(const gamemap::location& loc, const move_map& srcdst
}
return res;
}
}

View file

@ -754,7 +754,8 @@ void display::draw_unit_details(int x, int y, const gamemap::location& loc,
std::string status = string_table["healthy"];
if(map_.on_board(loc) &&
u.invisible(map_.underlying_terrain(map_[loc.x][loc.y]))) {
u.invisible(map_.underlying_terrain(map_[loc.x][loc.y]),
status_.get_time_of_day().lawful_bonus)) {
status = "@" + string_table["invisible"];
}
@ -1137,7 +1138,8 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image_override,
if(highlight_ratio == 1.0)
highlight_ratio = it->second.alpha();
if(it->second.invisible(map_.underlying_terrain(map_[x][y])) &&
if(it->second.invisible(map_.underlying_terrain(map_[x][y]),
status_.get_time_of_day().lawful_bonus) &&
highlight_ratio > 0.5) {
highlight_ratio = 0.5;
}

View file

@ -117,7 +117,8 @@ size_t distance_between(const gamemap::location& a, const gamemap::location& b)
return hdistance + vdistance - vsavings;
}
bool enemy_zoc(const gamemap& map,const std::map<gamemap::location,unit>& units,
bool enemy_zoc(const gamemap& map, const gamestatus& status,
const std::map<gamemap::location,unit>& units,
const gamemap::location& loc, const team& current_team, int side)
{
gamemap::location locs[6];
@ -128,7 +129,8 @@ bool enemy_zoc(const gamemap& map,const std::map<gamemap::location,unit>& units,
if(it != units.end() && it->second.side() != side &&
current_team.is_enemy(it->second.side()) &&
!it->second.invisible(map.underlying_terrain(
map[it->first.x][it->first.y]))) {
map[it->first.x][it->first.y]),
status.get_time_of_day().lawful_bonus)) {
return true;
}
}
@ -138,7 +140,8 @@ bool enemy_zoc(const gamemap& map,const std::map<gamemap::location,unit>& units,
namespace {
void find_routes(const gamemap& map, const game_data& gamedata,
void find_routes(const gamemap& map, const gamestatus& status,
const game_data& gamedata,
const std::map<gamemap::location,unit>& units,
const unit& u,
const gamemap::location& loc,
@ -209,7 +212,7 @@ void find_routes(const gamemap& map, const game_data& gamedata,
rtit->second.move_left >= total_movement)
continue;
const bool zoc = enemy_zoc(map,units,currentloc,
const bool zoc = enemy_zoc(map,status,units,currentloc,
current_team,u.side()) &&
!ignore_zocs;
paths::route new_route = routes[loc];
@ -221,7 +224,7 @@ void find_routes(const gamemap& map, const game_data& gamedata,
routes[currentloc] = new_route;
if(new_route.move_left > 0) {
find_routes(map,gamedata,units,u,currentloc,
find_routes(map,status,gamedata,units,u,currentloc,
zoc_move_left,routes,teams,ignore_zocs,
allow_teleport,new_turns_left);
}
@ -231,7 +234,8 @@ void find_routes(const gamemap& map, const game_data& gamedata,
} //end anon namespace
paths::paths(const gamemap& map, const game_data& gamedata,
paths::paths(const gamemap& map, const gamestatus& status,
const game_data& gamedata,
const std::map<gamemap::location,unit>& units,
const gamemap::location& loc,
std::vector<team>& teams,
@ -244,7 +248,7 @@ paths::paths(const gamemap& map, const game_data& gamedata,
}
routes[loc].move_left = i->second.movement_left();
find_routes(map,gamedata,units,i->second,loc,
find_routes(map,status,gamedata,units,i->second,loc,
i->second.movement_left(),routes,teams,
ignore_zocs,allow_teleport,additional_turns);
}

View file

@ -13,6 +13,7 @@
#ifndef PATHFIND_H_INCLUDED
#define PATHFIND_H_INCLUDED
#include "gamestatus.hpp"
#include "map.hpp"
#include "unit.hpp"
#include "unit_types.hpp"
@ -50,7 +51,8 @@ gamemap::location find_vacant_tile(const gamemap& map,
gamemap::TERRAIN terrain=0);
//function which determines if a given location is an enemy zone of control
bool enemy_zoc(const gamemap& map,const std::map<gamemap::location,unit>& units,
bool enemy_zoc(const gamemap& map,const gamestatus& status,
const std::map<gamemap::location,unit>& units,
const gamemap::location& loc,const team& current_team,int side);
//object which contains all the possible locations a unit can move to, with
@ -65,7 +67,8 @@ struct paths
//additional_turns: if 0, paths for how far the unit can move this turn
//will be calculated. If 1, paths for how far the unit can move by the
//end of next turn will be calculated, and so forth.
paths(const gamemap& map, const game_data& gamedata,
paths(const gamemap& map, const gamestatus& status,
const game_data& gamedata,
const std::map<gamemap::location,unit>& units,
const gamemap::location& loc, std::vector<team>& teams,
bool ignore_zocs, bool allow_teleport, int additional_turns=0);

View file

@ -283,7 +283,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& game_config,
if(first_time) {
const hotkey::basic_handler key_events_handler(gui);
clear_shroud(gui,map,gameinfo,units,teams,0);
clear_shroud(gui,status,map,gameinfo,units,teams,0);
std::cerr << "first_time..." << (recorder.skipping() ? "skipping" : "no skip") << "\n";
update_locker lock_display(gui,recorder.skipping());
@ -333,7 +333,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& game_config,
gui.set_playing_team(size_t(player_number-1));
clear_shroud(gui,map,gameinfo,units,teams,player_number-1);
clear_shroud(gui,status,map,gameinfo,units,teams,player_number-1);
//scroll the map to the leader
const unit_map::iterator leader = find_leader(units,player_number);

View file

@ -111,7 +111,7 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
route.move_left = route_turns_to_complete(ui->second,map,route);
gui.set_route(&route);
move_unit(&gui,gameinfo,map,units,teams,route.steps,
move_unit(&gui,gameinfo,status,map,units,teams,route.steps,
&recorder,&turn_data.undos());
gui.invalidate_game_status();
}
@ -225,7 +225,7 @@ void turn_info::handle_event(const SDL_Event& event)
if(u != units_.end()) {
const bool ignore_zocs = u->second.type().is_skirmisher();
const bool teleport = u->second.type().teleports();
current_paths_ = paths(map_,gameinfo_,units_,u->first,
current_paths_ = paths(map_,status_,gameinfo_,units_,u->first,
teams_,ignore_zocs,teleport,
path_turns_);
gui_.set_paths(&current_paths_);
@ -310,7 +310,7 @@ void turn_info::mouse_motion(const SDL_MouseMotionEvent& event)
const bool ignore_zocs = un->second.type().is_skirmisher();
const bool teleport = un->second.type().teleports();
current_paths_ = paths(map_,gameinfo_,units_,new_hex,teams_,
current_paths_ = paths(map_,status_,gameinfo_,units_,new_hex,teams_,
ignore_zocs,teleport,path_turns_);
gui_.set_paths(&current_paths_);
enemy_paths_ = true;
@ -542,7 +542,7 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
current_route_.steps.front() == selected_hex_) {
const size_t moves = move_unit(&gui_,gameinfo_,map_,units_,teams_,
const size_t moves = move_unit(&gui_,gameinfo_,status_,map_,units_,teams_,
current_route_.steps,&recorder,&undo_stack_, &next_unit_);
gui_.invalidate_game_status();
@ -579,7 +579,7 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
gui_.set_paths(&current_paths_);
}
if(clear_shroud(gui_,map_,gameinfo_,units_,teams_,team_num_-1)) {
if(clear_shroud(gui_,status_,map_,gameinfo_,units_,teams_,team_num_-1)) {
undo_stack_.clear();
}
}
@ -596,7 +596,7 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
if(it != units_.end() && it->second.side() == team_num_ && !gui_.fogged(it->first.x,it->first.y)) {
const bool ignore_zocs = it->second.type().is_skirmisher();
const bool teleport = it->second.type().teleports();
current_paths_ = paths(map_,gameinfo_,units_,hex,teams_,
current_paths_ = paths(map_,status_,gameinfo_,units_,hex,teams_,
ignore_zocs,teleport,path_turns_);
next_unit_ = it->first;
@ -766,7 +766,7 @@ void turn_info::cycle_units()
if(it != units_.end() && !gui_.fogged(it->first.x,it->first.y)) {
const bool ignore_zocs = it->second.type().is_skirmisher();
const bool teleport = it->second.type().teleports();
current_paths_ = paths(map_,gameinfo_,units_,
current_paths_ = paths(map_,status_,gameinfo_,units_,
it->first,teams_,ignore_zocs,teleport,path_turns_);
gui_.set_paths(&current_paths_);
@ -904,7 +904,7 @@ void turn_info::undo()
recorder.undo();
clear_shroud(gui_,map_,gameinfo_,units_,teams_,team_num_-1);
clear_shroud(gui_,status_,map_,gameinfo_,units_,teams_,team_num_-1);
gui_.recalculate_minimap();
}

View file

@ -376,7 +376,7 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
log_scope("do replay");
replay& replayer = (obj != NULL) ? *obj : recorder;
clear_shroud(disp,map,gameinfo,units,teams,team_num-1);
clear_shroud(disp,state,map,gameinfo,units,teams,team_num-1);
disp.recalculate_minimap();
const set_random_generator generator_setter(&replayer);
@ -498,7 +498,7 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
const bool ignore_zocs = u->second.type().is_skirmisher();
const bool teleport = u->second.type().teleports();
paths paths_list(map,gameinfo,units,src,teams,ignore_zocs,teleport);
paths paths_list(map,state,gameinfo,units,src,teams,ignore_zocs,teleport);
paths_wiper wiper(disp);
if(!replayer.skipping()) {
@ -549,7 +549,7 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
game_events::fire("sighted",dst);
}
clear_shroud(disp,map,gameinfo,units,teams,team_num-1);
clear_shroud(disp,state,map,gameinfo,units,teams,team_num-1);
}
else if((child = cfg->child("attack")) != NULL) {

View file

@ -67,20 +67,20 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
return res;
}
case UNIT_STATUS: {
std::string status = "healthy", prefix = "";
if(map.on_board(loc) && u->second.invisible(map.underlying_terrain(map[loc.x][loc.y]))) {
status = "invisible";
std::string unit_status = "healthy", prefix = "";
if(map.on_board(loc) && u->second.invisible(map.underlying_terrain(map[loc.x][loc.y]),status.get_time_of_day().lawful_bonus)) {
unit_status = "invisible";
prefix = "@";
} else if(u->second.has_flag("slowed")) {
status = "slowed";
unit_status = "slowed";
prefix = "#";
} else if(u->second.has_flag("poisoned")) {
status = "poisoned";
unit_status = "poisoned";
prefix = "#";
}
report res(prefix + string_table[status]);
res.tooltip = string_table[status + "_description"];
report res(prefix + string_table[unit_status]);
res.tooltip = string_table[unit_status + "_description"];
return res;
}
case UNIT_ALIGNMENT: {
@ -253,4 +253,4 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
return report(str.str());
}
}
}

View file

@ -228,6 +228,8 @@ void unit::new_turn()
moves_ = total_movement();
if(type().has_ability("ambush"))
set_flag("ambush");
if(type().has_ability("nightstalk"))
set_flag("nightstalk");
}
void unit::end_turn()
@ -315,10 +317,14 @@ void unit::heal_all()
hitpoints_ = max_hitpoints();
}
bool unit::invisible(gamemap::TERRAIN terrain) const
bool unit::invisible(gamemap::TERRAIN terrain, int lawful_bonus) const
{
static const std::string forest_invisible("ambush");
if(terrain == gamemap::FOREST && has_flag(forest_invisible)) {
if((terrain == gamemap::FOREST) && has_flag(forest_invisible)) {
return true;
}
static const std::string night_invisible("nightstalk");
if((lawful_bonus < 0) && has_flag(night_invisible)) {
return true;
}

View file

@ -63,7 +63,7 @@ public:
void heal(int amount);
void heal_all();
bool invisible(gamemap::TERRAIN terrain) const;
bool invisible(gamemap::TERRAIN terrain, int lawful_bonus) const;
bool matches_filter(const config& cfg) const;