Пример #1
0
bool Game_Character::MakeWay(int x, int y, int d) const {
	if (d > 3) {
		int dx = (d == UpRight || d == DownRight) - (d == DownLeft || d == UpLeft);
		int dy = (d == DownRight || d == DownLeft) - (d == UpRight || d == UpLeft);
		return ((MakeWay(x, y, dy + 1) && MakeWay(x, y + dy, -dx + 2)) ||
			(MakeWay(x, y, -dx + 2) && MakeWay(x + dx, y, dy + 1)));
	}

	return Game_Map::MakeWay(x, y, d, *this);
}
Пример #2
0
void Game_Character::Move(int dir) {
	int dx = (dir == Right || dir == UpRight || dir == DownRight) - (dir == Left || dir == DownLeft || dir == UpLeft);
	int dy = (dir == Down || dir == DownRight || dir == DownLeft) - (dir == Up || dir == UpRight || dir == UpLeft);

	SetDirection(dir);
	if (!(IsDirectionFixed() || IsFacingLocked() || IsSpinning())) {
		if (dir > 3) // Diagonal
			SetSpriteDirection(GetSpriteDirection() % 2 ? -dx + 2 : dy + 1);
		else
			SetSpriteDirection(dir);
	}

	if (jumping) {
		jump_plus_x += dx;
		jump_plus_y += dy;
		return;
	}

	move_failed = !MakeWay(GetX(), GetY(), dir);
	if (move_failed) {
		if (!CheckEventTriggerTouch(Game_Map::RoundX(GetX() + dx), Game_Map::RoundY(GetY() + dy)))
			return;
	} else {
		SetX(Game_Map::RoundX(GetX() + dx));
		SetY(Game_Map::RoundY(GetY() + dy));
		remaining_step = SCREEN_TILE_WIDTH;
		BeginMove();
	}

	stop_count = 0;
	max_stop_count = (GetMoveFrequency() > 7) ? 0 : pow(2.0, 9 - GetMoveFrequency());
}
Пример #3
0
bool Game_Map::MakeWay(const Game_Character& self, int x, int y) {
	// Moving to same tile (used for jumps) always succeeds
	if (x == self.GetX() && y == self.GetY()) {
		return true;
	}
	if (!self.IsJumping() && x != self.GetX() && y != self.GetY()) {
		// Handle diagonal stepping.
		// Must be able to step on at least one of the 2 adjacent tiles and also the target tile.
		// Verified behavior: Always checks vertical first, only checks horizontal if vertical fails.
		bool vertical_ok = MakeWay(self, self.GetX(), y);
		if (!vertical_ok) {
			bool horizontal_ok = MakeWay(self, x, self.GetY());
			if (!horizontal_ok) {
				return false;
			}
		}
	}

	// Infer directions before we do any rounding.
	const auto bit_from = GetPassableMask(self.GetX(), self.GetY(), x, y);
	const auto bit_to = GetPassableMask(x, y, self.GetX(), self.GetY());

	// Now round for looping maps.
	x = Game_Map::RoundX(x);
	y = Game_Map::RoundY(y);

	// Note, even for diagonal, if the tile is invalid we still check vertical/horizontal first!
	if (!Game_Map::IsValid(x, y)) {
		return false;
	}

	if (self.GetThrough()) {
		return true;
	}

	const auto vehicle_type = static_cast<Game_Vehicle::Type>(self.GetVehicleType());

	bool self_conflict = false;
	if (!self.IsJumping()) {
		// Check for self conflict.
		// If this event has a tile graphic and the tile itself has passage blocked in the direction
		// we want to move, flag it as "self conflicting" for use later.
		if (self.GetLayer() == RPG::EventPage::Layers_below && self.GetTileId() != 0) {
			int tile_id = self.GetTileId();
			if ((passages_up[tile_id] & bit_from) == 0) {
				self_conflict = true;
			}
		}

		if (vehicle_type == Game_Vehicle::None) {
			// Check that we are allowed to step off of the current tile.
			// Note: Vehicles can always step off a tile.
			if (!IsPassableTile(&self, bit_from, self.GetX(), self.GetY())) {
				return false;
			}
		}
	}

	if (vehicle_type != Game_Vehicle::Airship) {
		// Check for collision with events on the target tile.
		for (auto& other: GetEvents()) {
			if (MakeWayCollideEvent(x, y, self, other, self_conflict)) {
				return false;
			}
		}
		auto& player = Main_Data::game_player;
		if (player->GetVehicleType() == Game_Vehicle::None) {
			if (MakeWayCollideEvent(x, y, self, *Main_Data::game_player, self_conflict)) {
				return false;
			}
		}
		for (auto vid: { Game_Vehicle::Boat, Game_Vehicle::Ship}) {
			auto& other = vehicles[vid - 1];
			if (other->IsInCurrentMap()) {
				if (MakeWayCollideEvent(x, y, self, *other, self_conflict)) {
					return false;
				}
			}
		}
		auto& airship = vehicles[Game_Vehicle::Airship - 1];
		if (airship->IsInCurrentMap() && self.GetType() != Game_Character::Player) {
			if (MakeWayCollideEvent(x, y, self, *airship, self_conflict)) {
				return false;
			}
		}
	}

	int bit = bit_to;
	if (self.IsJumping()) {
		bit = Passable::Down | Passable::Up | Passable::Left | Passable::Right;
	}

	return IsPassableTile(&self, bit, x, y);
}