contract DungeonBase is EjectableOwnable, Pausable, PullPayment, DungeonStructs {

    /* ======== TOKEN CONTRACTS ======== */

    /**
     * @dev The address of the ERC721 token contract managing all Dungeon tokens.
     */
    DungeonToken public dungeonTokenContract;

    /**
     * @dev The address of the ERC721 token contract managing all Hero tokens.
     */
    HeroToken public heroTokenContract;


    /* ======== CLOSED SOURCE CONTRACTS ======== */

    /**
     * @dev The address of the ChallengeScience contract that handles the floor generation mechanics after challenge success.
     */
    ChallengeScienceInterface challengeScienceContract;

    /**
     * @dev The address of the TrainingScience contract that handles the hero training mechanics.
     */
    TrainingScienceInterface trainingScienceContract;


    /* ======== SETTER FUNCTIONS ======== */

    /**
     * @dev Set the address of the dungeon token contract.
     * @param _newDungeonTokenContract An address of a DungeonToken contract.
     */
    function setDungeonTokenContract(address _newDungeonTokenContract) onlyOwner external {
        dungeonTokenContract = DungeonToken(_newDungeonTokenContract);
    }

    /**
     * @dev Set the address of the hero token contract.
     * @param _newHeroTokenContract An address of a HeroToken contract.
     */
    function setHeroTokenContract(address _newHeroTokenContract) onlyOwner external {
        heroTokenContract = HeroToken(_newHeroTokenContract);
    }

    /**
     * @dev Set the address of the secret dungeon challenge formula contract.
     * @param _newChallengeScienceAddress An address of a ChallengeScience contract.
     */
    function setChallengeScienceContract(address _newChallengeScienceAddress) onlyOwner external {
        challengeScienceContract = ChallengeScienceInterface(_newChallengeScienceAddress);
    }

    /**
     * @dev Set the address of the secret hero training formula contract.
     * @param _newTrainingScienceAddress An address of a TrainingScience contract.
     */
    function setTrainingScienceContract(address _newTrainingScienceAddress) onlyOwner external {
        trainingScienceContract = TrainingScienceInterface(_newTrainingScienceAddress);
    }


    /* ======== MODIFIERS ======== */
    /**
     * @dev Throws if _dungeonId is not created yet.
     */
    modifier dungeonExists(uint _dungeonId) {
        require(_dungeonId < dungeonTokenContract.totalSupply());
        _;
    }

    /**
     * @dev Throws if dungeon status do not allow challenge, also check for dungeon existence.
     */
    modifier canChallenge(uint _dungeonId) {
        require(_dungeonId < dungeonTokenContract.totalSupply());
        uint status;
        (,status,,,,,,) = dungeonTokenContract.dungeons(_dungeonId);
        require(status == 0 || status == 1);
        _;
    }

    /**
     * @dev Throws if dungeon status do not allow training, also check for dungeon existence.
     */
    modifier canTrain(uint _dungeonId) {
        require(_dungeonId < dungeonTokenContract.totalSupply());
        uint status;
        (,status,,,,,,) = dungeonTokenContract.dungeons(_dungeonId);
        require(status == 0 || status == 2);
        _;
    }


    /* ======== HELPER FUNCTIONS ======== */

    /**
     * @dev An internal function to calculate the power of player, or difficulty of a dungeon floor,
     *  if the total heroes power is larger than the current dungeon floor difficulty, the heroes win the challenge.
     */
    function _getGenesPower(uint _genes) internal pure returns (uint) {
        // Calculate total stats power.
        uint statsPower;

        for (uint i = 0; i < 4; i++) {
            statsPower += _genes % 32;
            _genes /= 32 ** 4;
        }

        // Calculate total stats power.
        uint equipmentPower;
        bool isSuper = true;

        for (uint j = 4; j < 12; j++) {
            uint curGene = _genes % 32;
            equipmentPower += curGene;
            _genes /= 32 ** 4;

            if (equipmentPower != curGene * (j - 3)) {
                isSuper = false;
            }
        }

        // Calculate super power
        if (isSuper) {
            equipmentPower *= 2;
        }

        return statsPower + equipmentPower + 12;
    }

}
/**
 * @title DungeonBase
 * @dev Base contract for Ether Dungeon. It implements all necessary sub-classes,
 * holds all the base storage variables, and some commonly used functions.
 */
function setHeroTokenContract(address _newHeroTokenContract) onlyOwner external {
    heroTokenContract = HeroToken(_newHeroTokenContract);
}

/**
 * @dev Set the address of the hero token contract.
 * @param _newHeroTokenContract An address of a HeroToken contract.
 */