Ejemplo n.º 1
0
/**
 * Initiates the display of movement for the supplied unit.
 * This should be called before attempting to display moving to a new hex.
 */
void unit_mover::start(unit_ptr u)
{
	// Nothing to do here if there is nothing to animate.
	if ( !can_draw_ )
		return;
	// If no animation then hide unit until end of movement
	if ( !animate_ ) {
		was_hidden_ = u->get_hidden();
		u->set_hidden(true);
		return;
	}

	// This normally does nothing, but just in case...
	wait_for_anims();

	// Visually replace the original unit with the temporary.
	// (Original unit is left on the map, so the unit count is correct.)
	replace_temporary(u);

	// Initialize our temporary unit for the move.
	temp_unit_ptr_->set_location(path_[0]);
	temp_unit_ptr_->set_facing(path_[0].get_relative_dir(path_[1]));
	temp_unit_ptr_->anim_comp().set_standing(false);
	disp_->invalidate(path_[0]);

	// If the unit can be seen here by the viewing side:
	if ( !is_enemy_ || !temp_unit_ptr_->invisible(path_[0]) ) {
		// Scroll to the path, but only if it fully fits on screen.
		// If it does not fit we might be able to do a better scroll later.
		disp_->scroll_to_tiles(path_, game_display::ONSCREEN, true, true, 0.0, false);
	}
	// We need to clear big invalidation before the move and have a smooth animation
	// (mainly black stripes and invalidation after canceling attack dialog).
	// Two draw calls are needed to also redraw the previously invalidated hexes.
	// We use update=false because we don't need delay here (no time wasted)
	// and no screen refresh (will be done by last 3rd draw() and it optimizes
	// the double blitting done by these invalidations).
	disp_->draw(false);
	disp_->draw(false);

	// The last draw() was still slow, and its initial new_animation_frame() call
	// is now old, so we do another draw() to get a fresh one
	// TODO: replace that by a new_animation_frame() before starting anims
	//       don't forget to change the previous draw(false) to true
	disp_->draw(true);

	// extra immobile movement animation for take-off
	animator_.add_animation(temp_unit_ptr_.get(), "pre_movement", path_[0], path_[1]);
	animator_.start_animations();
	animator_.wait_for_end();
	animator_.clear();

	// Switch the display back to the real unit.
	u->set_facing(temp_unit_ptr_->facing());
	u->anim_comp().set_standing(false);	// Need to reset u's animation so the new facing takes effect.
	u->set_hidden(was_hidden_);
	temp_unit_ptr_->set_hidden(true);
}
Ejemplo n.º 2
0
/**
 * Finishes the display of movement for the supplied unit.
 * If called before showing the unit reach the end of the path, it will be
 * assumed that the movement ended early.
 * If @a dir is not supplied, the final direction will be determined by (the
 * last two traversed hexes of) the path.
 */
void unit_mover::finish(unit_ptr u, map_location::DIRECTION dir)
{
	// Nothing to do here if the display is not valid.
	if ( !can_draw_ ) {
		// Make sure to reset the unit's animation to deal with a quirk in the
		// action engine where it leaves it to us to reenable bars even if the
		// display is initially locked.
		u->anim_comp().set_standing(true);
		return;
	}

	const map_location & end_loc = path_[current_];
	const map_location::DIRECTION final_dir = current_ == 0 ?
		path_[0].get_relative_dir(path_[1]) :
		path_[current_-1].get_relative_dir(end_loc);

	if ( animate_ )
	{
		wait_for_anims(); // In case proceed_to() did not wait for the last animation.

		// Make sure the displayed unit is correct.
		replace_temporary(u);
		temp_unit_ptr_->set_location(end_loc);
		temp_unit_ptr_->set_facing(final_dir);

		// Animation
		animator_.add_animation(temp_unit_ptr_.get(), "post_movement", end_loc);
		animator_.start_animations();
		animator_.wait_for_end();
		animator_.clear();

		// Switch the display back to the real unit.
		u->set_hidden(was_hidden_);
		temp_unit_ptr_->set_hidden(true);

		events::mouse_handler* mousehandler = events::mouse_handler::get_singleton();
		if ( mousehandler ) {
			mousehandler->invalidate_reachmap();
		}
	}
	else
	{
		// Show the unit at end of skipped animation
		u->set_hidden(was_hidden_);
	}

	// Facing gets set even when not animating.
	u->set_facing(dir == map_location::NDIRECTIONS ? final_dir : dir);
	u->anim_comp().set_standing(true);	// Need to reset u's animation so the new facing takes effect.

	// Redraw path ends (even if not animating).
	disp_->invalidate(path_.front());
	disp_->invalidate(end_loc);
}
Ejemplo n.º 3
0
/* Note: Hide the unit in its current location; do not actually remove it.
 * Otherwise the status displays will be wrong during the movement.
 */
void unit_mover::replace_temporary(unit_ptr u)
{
	if ( disp_ == nullptr )
		// No point in creating a temp unit with no way to display it.
		return;

	// Save the hidden state of the unit.
	was_hidden_ = u->get_hidden();

	// Make our temporary unit mostly match u...
	temp_unit_ptr_ = fake_unit_ptr(unit_ptr(new unit(*u)), resources::fake_units);

	// ... but keep the temporary unhidden and hide the original.
	temp_unit_ptr_->set_hidden(false);
	u->set_hidden(true);

	// Update cached data.
	is_enemy_ =	(*resources::teams)[u->side()-1].is_enemy(disp_->viewing_side());
}
Ejemplo n.º 4
0
/**
 * Visually moves a unit from the last hex we drew to the one specified by
 * @a path_index. If @a path_index points to an earlier hex, we do nothing.
 * The moving unit will only be updated if update is set to true; otherwise,
 * the provided unit is merely hidden during the movement and re-shown after.
 * (Not updating the unit can produce smoother animations in some cases.)
 * If @a wait is set to false, this returns without waiting for the final
 * animation to finish. Call wait_for_anims() to explicitly get this final
 * wait (another call to proceed_to() or finish() will implicitly wait). The
 * unit must remain valid until the wait is finished.
 */
void unit_mover::proceed_to(unit_ptr u, size_t path_index, bool update, bool wait)
{
	// Nothing to do here if animations cannot be shown.
	if ( !can_draw_ || !animate_ )
		return;

	// Handle pending visibility issues before introducing new ones.
	wait_for_anims();

	if ( update  ||  !temp_unit_ptr_ )
		// Replace the temp unit (which also hides u and shows our temporary).
		replace_temporary(u);
	else
	{
		// Just switch the display from the real unit to our fake one.
		temp_unit_ptr_->set_hidden(false);
		u->set_hidden(true);
	}

	// Safety check.
	path_index = std::min(path_index, path_.size()-1);

	for ( ; current_ < path_index; ++current_ )
		// If the unit can be seen by the viewing side while making this step:
		if ( !is_enemy_ || !temp_unit_ptr_->invisible(path_[current_]) ||
		     !temp_unit_ptr_->invisible(path_[current_+1]) )
		{
			// Wait for the previous step to complete before drawing the next one.
			wait_for_anims();

			if ( !disp_->tile_fully_on_screen(path_[current_]) ||
			     !disp_->tile_fully_on_screen(path_[current_+1]))
			{
				// prevent the unit from disappearing if we scroll here with i == 0
				temp_unit_ptr_->set_location(path_[current_]);
				disp_->invalidate(path_[current_]);
				// scroll in as much of the remaining path as possible
				if ( temp_unit_ptr_->anim_comp().get_animation() )
					temp_unit_ptr_->anim_comp().get_animation()->pause_animation();
				disp_->scroll_to_tiles(path_.begin() + current_,
				                       path_.end(), game_display::ONSCREEN,
				                       true, false, 0.0, force_scroll_);
				if ( temp_unit_ptr_->anim_comp().get_animation() )
					temp_unit_ptr_->anim_comp().get_animation()->restart_animation();
			}

			if ( tiles_adjacent(path_[current_], path_[current_+1]) )
				wait_until_ =
					move_unit_between(path_[current_], path_[current_+1],
					                  temp_unit_ptr_.get_unit_ptr(), current_,
					                  path_.size() - (current_+2), animator_,
					                  *disp_);
			else if ( path_[current_] != path_[current_+1] )
				teleport_unit_between(path_[current_], path_[current_+1],
				                      *temp_unit_ptr_, *disp_);
		}

	// Update the unit's facing.
	u->set_facing(temp_unit_ptr_->facing());
	u->anim_comp().set_standing(false);	// Need to reset u's animation so the new facing takes effect.
	// Remember the unit to unhide when the animation finishes.
	shown_unit_ = u;
	if ( wait )
		wait_for_anims();
}