Ejemplo n.º 1
0
void mapbuilder::pre_build()
{
    for (team& t : resources::gameboard->teams()) {
        //Reset spent gold to zero, it'll be recalculated during the map building
        t.get_side_actions()->reset_gold_spent();
    }

    int current_side = resources::controller->current_side();
    for (unit& u : *resources::units) {
        bool on_current_side = (u.side() == current_side);

        //Remove any unit the current side cannot see to avoid their detection by planning
        //Units will be restored to the unit map by destruction of removers_

        if(!on_current_side && !u.is_visible_to_team(resources::gameboard->teams()[viewer_team()], *resources::gameboard, false)) {
            removers_.push_back(new temporary_unit_remover(*resources::units, u.get_location()));

            //Don't do anything else to the removed unit!
            continue;
        }

        //Reset movement points, to be restored by destruction of resetters_

        //restore movement points only to units not on the current side
        resetters_.push_back(new unit_movement_resetter(u,!on_current_side));
        //make sure current side's units are not reset to full moves on first turn
        if(on_current_side) {
            acted_this_turn_.insert(&u);
        }
    }
}
Ejemplo n.º 2
0
action::error move::check_validity() const
{
	// Used to deal with multiple return paths.
	class arrow_texture_setter {
	public:
		arrow_texture_setter(const move *target, move::ARROW_TEXTURE current_texture, move::ARROW_TEXTURE setting_texture):
			target(target),
			current_texture(current_texture),
			setting_texture(setting_texture) {}

		~arrow_texture_setter() {
			if(current_texture!=setting_texture) {
				target->set_arrow_texture(setting_texture);
			}
		}

		void set_texture(move::ARROW_TEXTURE texture) { setting_texture=texture; }

	private:
		const move *target;
		move::ARROW_TEXTURE current_texture, setting_texture;
	};

	arrow_texture_setter setter(this, arrow_texture_, ARROW_TEXTURE_INVALID);

	if(!(get_source_hex().valid() && get_dest_hex().valid())) {
		return INVALID_LOCATION;
	}

	//Check that the unit still exists in the source hex
	unit_map::iterator unit_it;
	unit_it = resources::units->find(get_source_hex());
	if(unit_it == resources::units->end()) {
		return NO_UNIT;
	}

	//check if the unit in the source hex has the same unit id as before,
	//i.e. that it's the same unit
	if(unit_id_ != unit_it->id() || unit_underlying_id_ != unit_it->underlying_id()) {
		return UNIT_CHANGED;
	}

	//If the path has at least two hexes (it can have less with the attack subclass), ensure destination hex is free
	if(get_route().steps.size() >= 2 && get_visible_unit(get_dest_hex(),resources::teams->at(viewer_team())) != NULL) {
		return LOCATION_OCCUPIED;
	}

	//check that the path is good
	if(get_source_hex() != get_dest_hex()) { //skip zero-hex move used by attack subclass
		// Mark the plain route to see if the move can still be done in one turn,
		// which is always the case for planned moves
		pathfind::marked_route checked_route = pathfind::mark_route(get_route().route);

		if(checked_route.marks[checked_route.steps.back()].turns != 1) {
			return TOO_FAR;
		}
	}

	// The move is valid, so correct the setter.
	setter.set_texture(ARROW_TEXTURE_VALID);

	return OK;
}
Ejemplo n.º 3
0
void move::execute(bool& success, bool& complete)
{
	if (!valid_) {
		success = complete = false;
		return;
	}

	if (get_source_hex() == get_dest_hex()) {
		//zero-hex move, used by attack subclass
		success = complete = true;
		return;
	}

	//Ensure destination hex is free
	if (get_visible_unit(get_dest_hex(),resources::teams->at(viewer_team())) != NULL) {
		success = complete = false;
		return;
	}

	LOG_WB << "Executing: " << shared_from_this() << "\n";

	set_arrow_brightness(ARROW_BRIGHTNESS_HIGHLIGHTED);
	hide_fake_unit();
	unghost_owner_unit(get_unit());

	events::mouse_handler& mouse_handler = resources::controller->get_mouse_handler_base();
	std::set<map_location> adj_enemies = mouse_handler.get_adj_enemies(get_dest_hex(), side_number());

	map_location final_location;
	bool steps_finished;
	bool enemy_sighted;
	{
		team const& owner_team = resources::teams->at(team_index());
		try {
			steps_finished = mouse_handler.move_unit_along_route(*route_, &final_location, owner_team.auto_shroud_updates(), &enemy_sighted);
		} catch (end_turn_exception&) {
			set_arrow_brightness(ARROW_BRIGHTNESS_STANDARD);
			throw; // we rely on the caller to delete this action
		}
		// final_location now contains the final unit location
		// if that isn't needed, pass NULL rather than &final_location
		// Also, enemy_sighted now tells whether a unit was sighted during the move
	}
	if(mouse_handler.get_adj_enemies(final_location,side_number()) != adj_enemies)
		enemy_sighted = true; //< "ambushed" on last hex

	unit_map::const_iterator unit_it;

	if (final_location == route_->steps.front())
	{
		LOG_WB << "Move execution resulted in zero movement.\n";
		success = complete = false;
	}
	else if (final_location.valid() &&
			(unit_it = resources::units->find(final_location)) != resources::units->end()
			&& unit_it->id() == unit_id_)
	{
		if (steps_finished && route_->steps.back() == final_location) //reached destination
		{
			complete = true;

			//check if new enemies are now visible
			if(enemy_sighted)
			{
				LOG_WB << "Move completed, but interrupted on final hex. Halting.\n";
				//reset to a single-hex path, just in case *this is a wb::attack
				arrow_.reset();
				route_->steps = std::vector<map_location>(1,route_->steps.back());
				success = false;
			}
			else // Everything went smoothly
				success = true;
		}
		else // Move was interrupted, probably by enemy unit sighted
		{
			LOG_WB << "Move finished at (" << final_location << ") instead of at (" << get_dest_hex() << "), analyzing\n";
			std::vector<map_location>::iterator start_new_path;
			bool found = false;
			for (start_new_path = route_->steps.begin(); ((start_new_path != route_->steps.end()) && !found); ++start_new_path)
			{
				if (*start_new_path == final_location)
				{
					found = true;
				}
			}
			if (found)
			{
				--start_new_path; //since the for loop incremented the iterator once after we found the right one.
				std::vector<map_location> new_path(start_new_path, route_->steps.end());
				LOG_WB << "Setting new path for this move from (" << new_path.front()
						<< ") to (" << new_path.back() << ").\n";
				//FIXME: probably better to use the new calculate_new_route instead of doing this
				route_->steps = new_path;
				arrow_->set_path(new_path);
				success = complete = false;
			}
			else //Unit ended up in location outside path, likely due to a WML event
			{
				WRN_WB << "Unit ended up in location outside path during move execution.\n";
				success = complete = true;
			}
		}
	}
	else //Unit disappeared from the map, likely due to a WML event
	{
		WRN_WB << "Unit disappeared from map during move execution.\n";
		success = complete = true;
	}

	if(!complete)
	{
		set_arrow_brightness(ARROW_BRIGHTNESS_STANDARD);
		show_fake_unit();
		ghost_owner_unit(get_unit());
	}

	//if unit has other moves besides this one, set it back to ghosted visuals
	//@todo handle this in a more centralized fashion
	if (resources::teams->at(team_index()).get_side_actions()->count_actions_of(get_unit()) > 1) {
		ghost_owner_unit(get_unit());
	}
}