function explore(uint256 _shipTokenId, uint256 _sectorTokenId, uint256 _crewTokenId) payable external whenNotPaused {
        
        require(msg.value >= sectorToOwnerCut[_sectorTokenId]);

        
        require(ethernautsStorage.isCategory(_shipTokenId, uint8(AssetCategory.Ship)));

        
        require(ethernautsStorage.isCategory(_sectorTokenId, uint8(AssetCategory.Sector)));

        
        require(ethernautsStorage.isState(_shipTokenId, uint8(AssetState.Available)));

        
        require(!isExploring(_shipTokenId));

        
        require(msg.sender == ethernautsStorage.ownerOf(_shipTokenId));

        
        address sectorOwner = ethernautsStorage.ownerOf(_sectorTokenId);
        require(sectorOwner != address(0));

        
        if (_crewTokenId > 0) {
            
            require(!isExploring(_crewTokenId));

            
            require(ethernautsStorage.isCategory(_crewTokenId, uint8(AssetCategory.CrewMember)));

            
            require(msg.sender == ethernautsStorage.ownerOf(_crewTokenId));
        }

        
        tokenIndexToExplore[_shipTokenId] = explorers.push(_shipTokenId) - 1;
        tokenIndexToSector[_shipTokenId] = _sectorTokenId;

        uint8[STATS_SIZE] memory _shipStats = ethernautsStorage.getStats(_shipTokenId);
        uint8[STATS_SIZE] memory _sectorStats = ethernautsStorage.getStats(_sectorTokenId);

        
        if (_crewTokenId > 0) {
            
            exploreIndexToCrew[tokenIndexToExplore[_shipTokenId]] = _crewTokenId;
            missions[_crewTokenId]++;

            
            uint8[STATS_SIZE] memory _crewStats = ethernautsStorage.getStats(_crewTokenId);
            _shipStats[uint256(ShipStats.Range)] += _crewStats[uint256(ShipStats.Range)];
            _shipStats[uint256(ShipStats.Speed)] += _crewStats[uint256(ShipStats.Speed)];

            if (_shipStats[uint256(ShipStats.Range)] > STATS_CAPOUT) {
                _shipStats[uint256(ShipStats.Range)] = STATS_CAPOUT;
            }
            if (_shipStats[uint256(ShipStats.Speed)] > STATS_CAPOUT) {
                _shipStats[uint256(ShipStats.Speed)] = STATS_CAPOUT;
            }
        }

        
        uint256 time = uint256(_explorationTime(
                _shipStats[uint256(ShipStats.Range)],
                _shipStats[uint256(ShipStats.Speed)],
                _sectorStats[uint256(SectorStats.Size)]
            ));
        
        time *= 60;

        uint64 _cooldownEndBlock = uint64((time/secondsPerBlock) + block.number);
        ethernautsStorage.setAssetCooldown(_shipTokenId, now + time, _cooldownEndBlock);

        
        if (_crewTokenId > 0) {
            
            ethernautsStorage.setAssetCooldown(_crewTokenId, now + time, _cooldownEndBlock);
        }

        
        uint256 feeExcess = SafeMath.sub(msg.value, sectorToOwnerCut[_sectorTokenId]);
        uint256 payment = uint256(SafeMath.div(SafeMath.mul(msg.value, percentageCut), 100)) - sectorToOracleFee[_sectorTokenId];

        
        Explore(_shipTokenId, _sectorTokenId, _crewTokenId, now + time);

        
        oracleAddress.transfer(sectorToOracleFee[_sectorTokenId]);

        
        sectorOwner.transfer(payment);

        
        msg.sender.transfer(feeExcess);
    }