contract DungeonToken is DungeonTokenInterface, ERC721Token, JointOwnable {


    /* ======== EVENTS ======== */

    /**
     * @dev The Mint event is fired whenever a new dungeon is created.
     */
    event Mint(address indexed owner, uint newTokenId, uint difficulty, uint capacity, uint seedGenes);


    /* ======== PUBLIC/EXTERNAL FUNCTIONS ======== */

    /**
     * @dev Returns the total number of tokens currently in existence.
     */
    function totalSupply() public view returns (uint) {
        return dungeons.length;
    }

    /**
     * @dev The external function that creates a new dungeon and stores it, only contract owners
     *  can create new token, and will be restricted by the DUNGEON_CREATION_LIMIT.
     *  Will generate a Mint event, a  NewDungeonFloor event, and a Transfer event.
     * @param _difficulty The difficulty of the new dungeon.
     * @param _capacity The capacity of the new dungeon.
     * @param _floorNumber The initial floor number of the new dungeon.
     * @param _seedGenes The seed genes of the new dungeon.
     * @param _floorGenes The initial genes of the dungeon floor.
     * @return The dungeon ID of the new dungeon.
     */
    function createDungeon(uint _difficulty, uint _capacity, uint _floorNumber, uint _seedGenes, uint _floorGenes, address _owner) eitherOwner external returns (uint) {
        return _createDungeon(_difficulty, _capacity, _floorNumber, 0, _seedGenes, _floorGenes, _owner);
    }

    /**
     * @dev The external function to set dungeon status by its ID,
     *  refer to DungeonStructs for more information about dungeon status.
     *  Only contract owners can alter dungeon state.
     */
    function setDungeonStatus(uint _id, uint _newStatus) eitherOwner tokenExists(_id) external {
        dungeons[_id].status = uint8(_newStatus);
    }

    /**
     * @dev The external function to add additional dungeon rewards by its ID,
     *  only contract owners can alter dungeon state.
     */
    function addDungeonRewards(uint _id, uint _additinalRewards) eitherOwner tokenExists(_id) external {
        dungeons[_id].rewards += uint128(_additinalRewards);
    }

    /**
     * @dev The external function to add another dungeon floor by its ID,
     *  only contract owners can alter dungeon state.
     */
    function addDungeonNewFloor(uint _id, uint _newRewards, uint _newFloorGenes) eitherOwner tokenExists(_id) external {
        Dungeon storage dungeon = dungeons[_id];

        dungeon.floorNumber++;
        dungeon.floorCreationTime = uint32(now);
        dungeon.rewards = uint128(_newRewards);
        dungeon.floorGenes = _newFloorGenes;
    }


    /* ======== PRIVATE/INTERNAL FUNCTIONS ======== */

    function _createDungeon(uint _difficulty, uint _capacity, uint _floorNumber, uint _rewards, uint _seedGenes, uint _floorGenes, address _owner) private returns (uint) {
        // Ensure the total supply is within the fixed limit.
        require(totalSupply() < DUNGEON_CREATION_LIMIT);

        // ** STORAGE UPDATE **
        // Create a new dungeon.
        dungeons.push(Dungeon(uint32(now), 0, uint8(_difficulty), uint16(_capacity), uint32(_floorNumber), uint32(now), uint128(_rewards), _seedGenes, _floorGenes));

        // Token id is the index in the storage array.
        uint newTokenId = dungeons.length - 1;

        // Emit the token mint event.
        Mint(_owner, newTokenId, _difficulty, _capacity, _seedGenes);

        // This will assign ownership, and also emit the Transfer event.
        _transfer(0, _owner, newTokenId);

        return newTokenId;
    }


    /* ======== MIGRATION FUNCTIONS ======== */


    /**
     * @dev Since the DungeonToken contract is re-deployed due to optimization.
     *  We need to migrate all dungeons from Beta token contract to Version 1.
     */
    function migrateDungeon(uint _difficulty, uint _capacity, uint _floorNumber, uint _rewards, uint _seedGenes, uint _floorGenes, address _owner) external {
        // Migration will be finished before maintenance period ends, tx.origin is used within a short period only.
        require(now < 1520694000 && tx.origin == 0x47169f78750Be1e6ec2DEb2974458ac4F8751714);

        _createDungeon(_difficulty, _capacity, _floorNumber, _rewards, _seedGenes, _floorGenes, _owner);
    }

}
/**
 * @title The ERC-721 compliance token contract for the Dungeon tokens.
 * @dev See the DungeonStructs contract to see the details of the Dungeon token data structure.
 */
function addDungeonRewards(uint _id, uint _additinalRewards) eitherOwner tokenExists(_id) external {
    dungeons[_id].rewards += uint128(_additinalRewards);
}

/**
 * @dev The external function to add additional dungeon rewards by its ID,
 *  only contract owners can alter dungeon state.
 */