00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "global.hpp"
00018
00019 #include "actions.hpp"
00020 #include "game_display.hpp"
00021 #include "game_preferences.hpp"
00022 #include "events.hpp"
00023 #include "game_config.hpp"
00024 #include "gamestatus.hpp"
00025 #include "halo.hpp"
00026 #include "image.hpp"
00027 #include "log.hpp"
00028 #include "scoped_resource.hpp"
00029 #include "sound.hpp"
00030 #include "unit_display.hpp"
00031 #include "util.hpp"
00032 #include "mouse_events.hpp"
00033
00034 #include <cassert>
00035 #include <climits>
00036
00037 #define LOG_DP LOG_STREAM(info, display)
00038
00039 static void teleport_unit_between( const gamemap::location& a, const gamemap::location& b, unit& temp_unit)
00040 {
00041 game_display* disp = game_display::get_singleton();
00042 if(!disp || disp->video().update_locked() || (disp->fogged(a) && disp->fogged(b))) {
00043 return;
00044 }
00045 disp->scroll_to_tiles(a,b,game_display::ONSCREEN,true);
00046
00047 if (!disp->fogged(a)) {
00048 disp->place_temporary_unit(temp_unit,a);
00049 unit_animator animator;
00050 animator.add_animation(&temp_unit,"pre_teleport",a);
00051 animator.start_animations();
00052 animator.wait_for_end();
00053 }
00054 if (!disp->fogged(b)) {
00055 disp->place_temporary_unit(temp_unit,b);
00056 disp->scroll_to_tiles(b,a,game_display::ONSCREEN,true);
00057 unit_animator animator;
00058 animator.add_animation(&temp_unit,"post_teleport",b);
00059 animator.start_animations();
00060 animator.wait_for_end();
00061 }
00062 temp_unit.set_standing(b);
00063 disp->update_display();
00064 events::pump();
00065 }
00066
00067 static void move_unit_between(const gamemap::location& a, const gamemap::location& b, unit& temp_unit)
00068 {
00069 game_display* disp = game_display::get_singleton();
00070 if(!disp || disp->video().update_locked() || (disp->fogged(a) && disp->fogged(b))) {
00071 return;
00072 }
00073
00074
00075 disp->place_temporary_unit(temp_unit,a);
00076 temp_unit.set_facing(a.get_relative_dir(b));
00077 unit_animator animator;
00078 animator.replace_anim_if_invalid(&temp_unit,"movement",a);
00079 animator.start_animations();
00080 animator.pause_animation();
00081 disp->scroll_to_tiles(a,b,game_display::ONSCREEN);
00082 animator.restart_animation();
00083 int target_time = animator.get_animation_time_potential();
00084 target_time += 150;
00085 target_time -= target_time%150;
00086 if( target_time - animator.get_animation_time_potential() < 100 ) target_time +=150;
00087 animator.wait_until(target_time);
00088 gamemap::location arr[6];
00089 get_adjacent_tiles(a, arr);
00090 unsigned int i;
00091 for (i = 0; i < 6; i++) {
00092 disp->invalidate(arr[i]);
00093 }
00094 get_adjacent_tiles(b, arr);
00095 for (i = 0; i < 6; i++) {
00096 disp->invalidate(arr[i]);
00097 }
00098 }
00099
00100 namespace unit_display
00101 {
00102
00103 bool unit_visible_on_path( const std::vector<gamemap::location>& path, const unit& u, const unit_map& units, const std::vector<team>& teams)
00104 {
00105 game_display* disp = game_display::get_singleton();
00106 assert(disp);
00107 for(size_t i = 0; i+1 < path.size(); ++i) {
00108 const bool invisible = teams[u.side()-1].is_enemy(int(disp->viewing_team()+1)) &&
00109 u.invisible(path[i],units,teams) &&
00110 u.invisible(path[i+1],units,teams);
00111 if(!invisible) {
00112 return true;
00113 }
00114 }
00115
00116 return false;
00117 }
00118
00119 void move_unit(const std::vector<gamemap::location>& path, unit& u, const std::vector<team>& teams)
00120 {
00121 game_display* disp = game_display::get_singleton();
00122 assert(!path.empty());
00123 assert(disp);
00124
00125 if (path.size()==1) return;
00126
00127 const unit_map& units = disp->get_units();
00128
00129 bool invisible = teams[u.side()-1].is_enemy(int(disp->viewing_team()+1)) &&
00130 u.invisible(path[0],units,teams);
00131
00132 if(!invisible) {
00133
00134
00135 disp->scroll_to_tiles(path, game_display::ONSCREEN, true, true);
00136 }
00137
00138 bool was_hidden = u.get_hidden();
00139
00140 unit temp_unit = u;
00141 u.set_hidden(true);
00142 temp_unit.set_hidden(false);
00143 disp->draw();
00144 for(size_t i = 0; i+1 < path.size(); ++i) {
00145
00146 invisible = teams[temp_unit.side()-1].is_enemy(int(disp->viewing_team()+1)) &&
00147 temp_unit.invisible(path[i],units,teams) &&
00148 temp_unit.invisible(path[i+1],units,teams);
00149
00150 if(!invisible) {
00151 if (!disp->tile_on_screen(path[i]) || !disp->tile_on_screen(path[i+1])) {
00152
00153 disp->place_temporary_unit(temp_unit,path[i]);
00154
00155 std::vector<gamemap::location> remaining_path;
00156 for(size_t j = i; j < path.size(); j++) {
00157 remaining_path.push_back(path[j]);
00158 }
00159 disp->scroll_to_tiles(remaining_path);
00160 }
00161
00162 if( !tiles_adjacent(path[i], path[i+1])) {
00163 teleport_unit_between(path[i],path[i+1],temp_unit);
00164 } else {
00165 move_unit_between(path[i],path[i+1],temp_unit);
00166 }
00167 }
00168 }
00169 disp->remove_temporary_unit();
00170 u.set_facing(path[path.size()-2].get_relative_dir(path[path.size()-1]));
00171 u.set_standing(path[path.size()-1]);
00172
00173 u.set_hidden(was_hidden);
00174 disp->invalidate_unit_after_move(path[0], path[path.size()-1]);
00175
00176 events::mouse_handler* mousehandler = events::mouse_handler::get_singleton();
00177 if (mousehandler) {
00178 mousehandler->invalidate_reachmap();
00179 }
00180 }
00181
00182 void unit_die(const gamemap::location& loc, unit& loser,
00183 const attack_type* attack,const attack_type* secondary_attack, unit* winner)
00184 {
00185 game_display* disp = game_display::get_singleton();
00186 if(!disp ||disp->video().update_locked() || disp->fogged(loc) || preferences::show_combat() == false) {
00187 return;
00188 }
00189 unit_animator animator;
00190
00191 animator.add_animation(&loser,"death",loc,0,false,false,"",0,unit_animation::KILL,attack,secondary_attack,0);
00192
00193 animator.add_animation(winner,"victory",loc.get_direction(loser.facing()),0,true,false,"",0,
00194 unit_animation::KILL,secondary_attack,attack,0);
00195 animator.start_animations();
00196 animator.wait_for_end();
00197
00198 events::mouse_handler* mousehandler = events::mouse_handler::get_singleton();
00199 if (mousehandler) {
00200 mousehandler->invalidate_reachmap();
00201 }
00202 }
00203
00204
00205 void unit_attack(
00206 const gamemap::location& a, const gamemap::location& b, int damage,
00207 const attack_type& attack, const attack_type* secondary_attack,
00208 int swing,std::string hit_text,bool drain,std::string att_text)
00209 {
00210 game_display* disp = game_display::get_singleton();
00211 if(!disp || preferences::show_combat() == false) return;
00212 unit_map& units = disp->get_units();
00213 disp->select_hex(gamemap::location::null_location);
00214 const bool hide = disp->video().update_locked() || (disp->fogged(a) && disp->fogged(b));
00215
00216 if(!hide) {
00217
00218 disp->scroll_to_tiles(a,b,game_display::ONSCREEN,true,0.5);
00219 }
00220
00221 log_scope("unit_attack");
00222
00223 const unit_map::iterator att = units.find(a);
00224 assert(att != units.end());
00225 unit& attacker = att->second;
00226
00227 const unit_map::iterator def = units.find(b);
00228 assert(def != units.end());
00229 unit& defender = def->second;
00230
00231 att->second.set_facing(a.get_relative_dir(b));
00232 def->second.set_facing(b.get_relative_dir(a));
00233
00234
00235 unit_animator animator;
00236 const gamemap::location leader_loc = under_leadership(units,a);
00237 unit_map::iterator leader = units.end();
00238
00239 {
00240 std::string text ;
00241 if(damage) text = lexical_cast<std::string>(damage);
00242 if(!hit_text.empty()) {
00243 text.insert(text.begin(),hit_text.size()/2,' ');
00244 text = text + "\n" + hit_text;
00245 }
00246
00247 std::string text_2 ;
00248 if(drain && damage) text_2 = lexical_cast<std::string>(minimum<int>(damage,defender.hitpoints())/2);
00249 if(!att_text.empty()) {
00250 text_2.insert(text_2.begin(),att_text.size()/2,' ');
00251 text_2 = text_2 + "\n" + att_text;
00252 }
00253
00254 unit_animation::hit_type hit_type;
00255 if(damage >= defender.hitpoints()) {
00256 hit_type = unit_animation::KILL;
00257 } else if(damage > 0) {
00258 hit_type = unit_animation::HIT;
00259 }else {
00260 hit_type = unit_animation::MISS;
00261 }
00262 animator.add_animation(&attacker,"attack",att->first,damage,true,false,text_2,display::rgb(0,255,0),hit_type,&attack,secondary_attack,swing);
00263 animator.add_animation(&defender,"defend",def->first,damage,true,false,text ,display::rgb(255,0,0),hit_type,&attack,secondary_attack,swing);
00264
00265 if(leader_loc.valid() && leader_loc != att->first && leader_loc != def->first){
00266 leader = units.find(leader_loc);
00267 leader->second.set_facing(leader_loc.get_relative_dir(a));
00268 assert(leader != units.end());
00269 animator.add_animation(&leader->second,"leading",leader_loc,damage,true,false,"",0,hit_type,&attack,secondary_attack,swing);
00270 }
00271 }
00272
00273 animator.start_animations();
00274 animator.wait_for_end();
00275
00276 if(leader_loc.valid() && leader_loc != att->first && leader_loc != def->first) leader->second.set_standing(leader_loc);
00277 att->second.set_standing(a);
00278 def->second.set_standing(b);
00279 }
00280
00281
00282 void unit_recruited(gamemap::location& loc)
00283 {
00284 game_display* disp = game_display::get_singleton();
00285 if(!disp || disp->video().update_locked() ||disp->fogged(loc)) return;
00286 unit_map::iterator u = disp->get_units().find(loc);
00287 if(u == disp->get_units().end()) return;
00288
00289 u->second.set_hidden(true);
00290 disp->scroll_to_tile(loc,game_display::ONSCREEN);
00291 disp->draw();
00292 u->second.set_hidden(false);
00293 u->second.set_facing(static_cast<gamemap::location::DIRECTION>(rand()%gamemap::location::NDIRECTIONS));
00294 unit_animator animator;
00295 animator.add_animation(&u->second,"recruited",loc);
00296 animator.start_animations();
00297 animator.wait_for_end();
00298 u->second.set_standing(loc);
00299 if (loc==disp->mouseover_hex()) disp->invalidate_unit();
00300 }
00301
00302 void unit_healing(unit& healed,gamemap::location& healed_loc, std::vector<unit_map::iterator> healers, int healing)
00303 {
00304 game_display* disp = game_display::get_singleton();
00305 if(!disp || disp->video().update_locked() || disp->fogged(healed_loc)) return;
00306 if(healing==0) return;
00307
00308 disp->scroll_to_tile(healed_loc, game_display::ONSCREEN);
00309 disp->display_unit_hex(healed_loc);
00310 unit_animator animator;
00311
00312 for(std::vector<unit_map::iterator>::iterator heal_anim_it = healers.begin(); heal_anim_it != healers.end(); ++heal_anim_it) {
00313 (*heal_anim_it)->second.set_facing((*heal_anim_it)->first.get_relative_dir(healed_loc));
00314 animator.add_animation(&(*heal_anim_it)->second,"healing",(*heal_anim_it)->first,healing);
00315 }
00316 if (healing < 0) {
00317 animator.add_animation(&healed,"poisoned",healed_loc,-healing,false,false,lexical_cast<std::string>(-healing), display::rgb(255,0,0));
00318 } else {
00319 animator.add_animation(&healed,"healed",healed_loc,healing,false,false,lexical_cast<std::string>(healing), display::rgb(0,255,0));
00320 }
00321 animator.start_animations();
00322 animator.wait_for_end();
00323
00324 healed.set_standing(healed_loc);
00325 for(std::vector<unit_map::iterator>::iterator heal_sanim_it = healers.begin(); heal_sanim_it != healers.end(); ++heal_sanim_it) {
00326 (*heal_sanim_it)->second.set_standing((*heal_sanim_it)->first);
00327 }
00328
00329 }
00330
00331 }