ETH Price: $2,102.29 (+0.45%)

Transaction Decoder

Block:
6983503 at Dec-31-2018 03:09:12 AM +UTC
Transaction Fee:
0.001009865 ETH $2.12
Gas Used:
201,973 Gas / 5 Gwei

Emitted Events:

98 EtheremonAdventureItem.Transfer( _from=0x00000000...000000000, _to=[Sender] 0x06f175e6ebeb0982b61c1c17ab43c30a8e6ac29a, _tokenId=17400 )
99 EtheremonAdventure.ClaimExplore( from=[Sender] 0x06f175e6ebeb0982b61c1c17ab43c30a8e6ac29a, exploreId=22202, itemType=1, itemClass=321, itemId=17400 )

Account State Difference:

  Address   Before After State Difference Code
0x06f175E6...A8E6aC29A
0.972335859 Eth
Nonce: 574
0.966325994 Eth
Nonce: 575
0.006009865
(MiningPoolHub: Old Address)
15,222.300085289708326618 Eth15,222.301095154708326618 Eth0.001009865
0xBfdE6246...d2B60393C
0xcdF7CfC9...87fC878e1
(Etheremon: Adventure 2)
66.335 Eth66.34 Eth0.005
0xf3bB445b...51C902B00

Execution Trace

ETH 0.005 EtheremonAdventure.claimExploreItem( _exploreId=22202 )
  • EtheremonAdventureData.getExploreData( _exploreId=22202 ) => ( _sender=0x06f175E6EBEB0982b61c1C17Ab43c30A8E6aC29A, _typeId=0, _monsterId=46795, _siteId=15, _itemSeed=0, _startAt=6983496 )
  • EtheremonAdventureSetting.getSiteItem( _siteId=15, _seed=26092 ) => ( _monsterClassId=0, _tokenClassId=321, _value=0 )
  • EtheremonAdventureData.removePendingExplore( _exploreId=22202, _itemSeed=26092 )
  • EtheremonAdventureItem.spawnItem( _classId=321, _value=0, _owner=0x06f175E6EBEB0982b61c1C17Ab43c30A8E6aC29A ) => ( 17400 )
    File 1 of 4: EtheremonAdventure
    pragma solidity ^0.4.16;
    
    library AddressUtils {
        function isContract(address addr) internal view returns (bool) {
            uint256 size;
            assembly { size := extcodesize(addr) }
            return size > 0;
        }
    }
    
    contract BasicAccessControl {
        address public owner;
        // address[] public moderators;
        uint16 public totalModerators = 0;
        mapping (address => bool) public moderators;
        bool public isMaintaining = false;
    
        function BasicAccessControl() public {
            owner = msg.sender;
        }
    
        modifier onlyOwner {
            require(msg.sender == owner);
            _;
        }
    
        modifier onlyModerators() {
            require(msg.sender == owner || moderators[msg.sender] == true);
            _;
        }
    
        modifier isActive {
            require(!isMaintaining);
            _;
        }
    
        function ChangeOwner(address _newOwner) onlyOwner public {
            if (_newOwner != address(0)) {
                owner = _newOwner;
            }
        }
    
    
        function AddModerator(address _newModerator) onlyOwner public {
            if (moderators[_newModerator] == false) {
                moderators[_newModerator] = true;
                totalModerators += 1;
            }
        }
        
        function RemoveModerator(address _oldModerator) onlyOwner public {
            if (moderators[_oldModerator] == true) {
                moderators[_oldModerator] = false;
                totalModerators -= 1;
            }
        }
    
        function UpdateMaintaining(bool _isMaintaining) onlyOwner public {
            isMaintaining = _isMaintaining;
        }
    }
    
    contract EtheremonEnum {
    
        enum ResultCode {
            SUCCESS,
            ERROR_CLASS_NOT_FOUND,
            ERROR_LOW_BALANCE,
            ERROR_SEND_FAIL,
            ERROR_NOT_TRAINER,
            ERROR_NOT_ENOUGH_MONEY,
            ERROR_INVALID_AMOUNT
        }
        
        enum ArrayType {
            CLASS_TYPE,
            STAT_STEP,
            STAT_START,
            STAT_BASE,
            OBJ_SKILL
        }
        
        enum PropertyType {
            ANCESTOR,
            XFACTOR
        }
    }
    
    interface EtheremonDataBase {
        // read
        function getMonsterClass(uint32 _classId) constant external returns(uint32 classId, uint256 price, uint256 returnPrice, uint32 total, bool catchable);
        function getMonsterObj(uint64 _objId) constant external returns(uint64 objId, uint32 classId, address trainer, uint32 exp, uint32 createIndex, uint32 lastClaimIndex, uint createTime);
        function getElementInArrayType(EtheremonEnum.ArrayType _type, uint64 _id, uint _index) constant external returns(uint8);
        
        function addMonsterObj(uint32 _classId, address _trainer, string _name) external returns(uint64);
        function addElementToArrayType(EtheremonEnum.ArrayType _type, uint64 _id, uint8 _value) external returns(uint);
    }
    
    contract ERC20Interface {
        function totalSupply() public constant returns (uint);
        function balanceOf(address tokenOwner) public constant returns (uint balance);
        function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
        function transfer(address to, uint tokens) public returns (bool success);
        function approve(address spender, uint tokens) public returns (bool success);
        function transferFrom(address from, address to, uint tokens) public returns (bool success);
    }
    
    interface ERC721Interface {
        function ownerOf(uint256 _tokenId) external view returns (address owner);
    }
    
    interface EtheremonAdventureItem {
        function ownerOf(uint256 _tokenId) external view returns (address);
        function getItemInfo(uint _tokenId) constant external returns(uint classId, uint value);
        function spawnItem(uint _classId, uint _value, address _owner) external returns(uint);
    }
    
    interface EtheremonAdventureSetting {
        function getSiteItem(uint _siteId, uint _seed) constant external returns(uint _monsterClassId, uint _tokenClassId, uint _value);
        function getSiteId(uint _classId, uint _seed) constant external returns(uint);
    }
    
    interface EtheremonMonsterNFT {
        function mintMonster(uint32 _classId, address _trainer, string _name) external returns(uint);
    }
    
    contract EtheremonAdventureData {
        
        function addLandRevenue(uint _siteId, uint _emontAmount, uint _etherAmount) external;
        function addTokenClaim(uint _tokenId, uint _emontAmount, uint _etherAmount) external;
        function addExploreData(address _sender, uint _typeId, uint _monsterId, uint _siteId, uint _startAt, uint _emontAmount, uint _etherAmount) external returns(uint);
        function removePendingExplore(uint _exploreId, uint _itemSeed) external;
        
        // public function
        function getLandRevenue(uint _classId) constant public returns(uint _emontAmount, uint _etherAmount);
        
        function getTokenClaim(uint _tokenId) constant public returns(uint _emontAmount, uint _etherAmount);
        
        function getExploreData(uint _exploreId) constant public returns(address _sender, uint _typeId, uint _monsterId, uint _siteId, uint _itemSeed, uint _startAt);
        
        function getPendingExplore(address _player) constant public returns(uint);
        
        function getPendingExploreData(address _player) constant public returns(uint _exploreId, uint _typeId, uint _monsterId, uint _siteId, uint _itemSeed, uint _startAt);
    }
    
    contract EtheremonAdventure is EtheremonEnum, BasicAccessControl {
        
        using AddressUtils for address;
        
        uint8 constant public STAT_COUNT = 6;
        uint8 constant public STAT_MAX = 32;
    
        struct MonsterObjAcc {
            uint64 monsterId;
            uint32 classId;
            address trainer;
            string name;
            uint32 exp;
            uint32 createIndex;
            uint32 lastClaimIndex;
            uint createTime;
        }
        
        struct ExploreData {
            address sender;
            uint monsterType;
            uint monsterId;
            uint siteId;
            uint itemSeed;
            uint startAt; // blocknumber
        }
        
        struct ExploreReward {
            uint monsterClassId;
            uint itemClassId;
            uint value;
            uint temp;
        }
        
        address public dataContract;
        address public monsterNFT;
        address public adventureDataContract;
        address public adventureSettingContract;
        address public adventureItemContract;
        address public tokenContract;
        address public kittiesContract;
        
        uint public exploreETHFee = 0.01 ether;
        uint public exploreEMONTFee = 1500000000;
        uint public exploreFastenETHFee = 0.005 ether;
        uint public exploreFastenEMONTFee = 750000000;
        uint public minBlockGap = 240;
        uint public totalSite = 54;
        
        uint seed = 0;
        
        event SendExplore(address indexed from, uint monsterType, uint monsterId, uint exploreId);
        event ClaimExplore(address indexed from, uint exploreId, uint itemType, uint itemClass, uint itemId);
        
        modifier requireDataContract {
            require(dataContract != address(0));
            _;
        }
        
        modifier requireAdventureDataContract {
            require(adventureDataContract != address(0));
            _;
        }
        
        modifier requireAdventureSettingContract {
            require(adventureSettingContract != address(0));
            _;
        }
        
        modifier requireTokenContract {
            require(tokenContract != address(0));
            _;
        }
        
        modifier requireKittiesContract {
            require(kittiesContract != address(0));
            _;
        }
        
        function setContract(address _dataContract, address _monsterNFT, address _adventureDataContract, address _adventureSettingContract, address _adventureItemContract, address _tokenContract, address _kittiesContract) onlyOwner public {
            dataContract = _dataContract;
            monsterNFT = _monsterNFT;
            adventureDataContract = _adventureDataContract;
            adventureSettingContract = _adventureSettingContract;
            adventureItemContract = _adventureItemContract;
            tokenContract = _tokenContract;
            kittiesContract = _kittiesContract;
        }
    
        function setFeeConfig(uint _exploreETHFee, uint _exploreEMONTFee, uint _exploreFastenETHFee, uint _exploreFastenEMONTFee) onlyOwner public {
            exploreETHFee = _exploreETHFee;
            exploreEMONTFee = _exploreEMONTFee;
            exploreFastenEMONTFee = _exploreFastenEMONTFee;
            exploreFastenETHFee = _exploreFastenETHFee;
        }
    
        function setConfig( uint _minBlockGap, uint _totalSite) onlyOwner public {
            minBlockGap = _minBlockGap;
            totalSite = _totalSite;
        }
        
        function withdrawEther(address _sendTo, uint _amount) onlyOwner public {
            // it is used in case we need to upgrade the smartcontract
            if (_amount > address(this).balance) {
                revert();
            }
            _sendTo.transfer(_amount);
        }
        
        function withdrawToken(address _sendTo, uint _amount) onlyOwner requireTokenContract external {
            ERC20Interface token = ERC20Interface(tokenContract);
            if (_amount > token.balanceOf(address(this))) {
                revert();
            }
            token.transfer(_sendTo, _amount);
        }
        
        function adventureByToken(address _player, uint _token, uint _param1, uint _param2, uint64 _param3, uint64 _param4) isActive onlyModerators external {
            // param1 = 1 -> explore, param1 = 2 -> claim 
            if (_param1 == 1) {
                _exploreUsingEmont(_player, _param2, _param3, _token);
            } else {
                _claimExploreItemUsingEMont(_param2, _token);
            }
        }
        
        function _exploreUsingEmont(address _sender, uint _monsterType, uint _monsterId, uint _token) internal {
            if (_token < exploreEMONTFee) revert();
            seed = getRandom(_sender, block.number - 1, seed, _monsterId);
            uint siteId = getTargetSite(_sender, _monsterType, _monsterId, seed);
            if (siteId == 0) revert();
            
            EtheremonAdventureData adventureData = EtheremonAdventureData(adventureDataContract);
            uint exploreId = adventureData.addExploreData(_sender, _monsterType, _monsterId, siteId, block.number, _token, 0);
            SendExplore(_sender, _monsterType, _monsterId, exploreId);
        }
        
        function _claimExploreItemUsingEMont(uint _exploreId, uint _token) internal {
            if (_token < exploreFastenEMONTFee) revert();
            
            EtheremonAdventureData adventureData = EtheremonAdventureData(adventureDataContract);
            ExploreData memory exploreData;
            (exploreData.sender, exploreData.monsterType, exploreData.monsterId, exploreData.siteId, exploreData.itemSeed, exploreData.startAt) = adventureData.getExploreData(_exploreId);
            
            if (exploreData.itemSeed != 0)
                revert();
            
            // min 2 blocks
            if (block.number < exploreData.startAt + 2)
                revert();
            
            exploreData.itemSeed = getRandom(exploreData.sender, exploreData.startAt + 1, exploreData.monsterId, _exploreId) % 100000;
            ExploreReward memory reward;
            (reward.monsterClassId, reward.itemClassId, reward.value) = EtheremonAdventureSetting(adventureSettingContract).getSiteItem(exploreData.siteId, exploreData.itemSeed);
            
            adventureData.removePendingExplore(_exploreId, exploreData.itemSeed);
            
            if (reward.monsterClassId > 0) {
                EtheremonMonsterNFT monsterContract = EtheremonMonsterNFT(monsterNFT);
                reward.temp = monsterContract.mintMonster(uint32(reward.monsterClassId), exploreData.sender,  "..name me..");
                ClaimExplore(exploreData.sender, _exploreId, 0, reward.monsterClassId, reward.temp);
            } else if (reward.itemClassId > 0) {
                // give new adventure item 
                EtheremonAdventureItem item = EtheremonAdventureItem(adventureItemContract);
                reward.temp = item.spawnItem(reward.itemClassId, reward.value, exploreData.sender);
                ClaimExplore(exploreData.sender, _exploreId, 1, reward.itemClassId, reward.temp);
            } else if (reward.value > 0) {
                // send token contract
                ERC20Interface token = ERC20Interface(tokenContract);
                token.transfer(exploreData.sender, reward.value);
                ClaimExplore(exploreData.sender, _exploreId, 2, 0, reward.value);
            } else {
                revert();
            }
        }
        
        // public
        
        function getRandom(address _player, uint _block, uint _seed, uint _count) constant public returns(uint) {
            return uint(keccak256(block.blockhash(_block), _player, _seed, _count));
        }
        
        function getTargetSite(address _sender, uint _monsterType, uint _monsterId, uint _seed) constant public returns(uint) {
            if (_monsterType == 0) {
                // Etheremon 
                MonsterObjAcc memory obj;
                (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = EtheremonDataBase(dataContract).getMonsterObj(uint64(_monsterId));
                if (obj.trainer != _sender) revert();
                return EtheremonAdventureSetting(adventureSettingContract).getSiteId(obj.classId, _seed);
            } else if (_monsterType == 1) {
                // Cryptokitties
                if (_sender != ERC721Interface(kittiesContract).ownerOf(_monsterId)) revert();
                return EtheremonAdventureSetting(adventureSettingContract).getSiteId(_seed % totalSite, _seed);
            }
            return 0;
        }
        
        function exploreUsingETH(uint _monsterType, uint _monsterId) isActive public payable {
            // not allow contract to make txn
            if (msg.sender.isContract()) revert();
            
            if (msg.value < exploreETHFee) revert();
            seed = getRandom(msg.sender, block.number - 1, seed, _monsterId);
            uint siteId = getTargetSite(msg.sender, _monsterType, _monsterId, seed);
            if (siteId == 0) revert();
            EtheremonAdventureData adventureData = EtheremonAdventureData(adventureDataContract);
            uint exploreId = adventureData.addExploreData(msg.sender, _monsterType, _monsterId, siteId, block.number, 0, msg.value);
            SendExplore(msg.sender, _monsterType, _monsterId, exploreId);
        }
        
        function claimExploreItem(uint _exploreId) isActive public payable {
            EtheremonAdventureData adventureData = EtheremonAdventureData(adventureDataContract);
            ExploreData memory exploreData;
            (exploreData.sender, exploreData.monsterType, exploreData.monsterId, exploreData.siteId, exploreData.itemSeed, exploreData.startAt) = adventureData.getExploreData(_exploreId);
            
            if (exploreData.itemSeed != 0)
                revert();
            
            // min 2 blocks
            if (block.number < exploreData.startAt + 2)
                revert();
            
            exploreData.itemSeed = getRandom(exploreData.sender, exploreData.startAt + 1, exploreData.monsterId, _exploreId) % 100000;
            if (msg.value < exploreFastenETHFee) {
                if (block.number < exploreData.startAt + minBlockGap + exploreData.startAt % minBlockGap)
                    revert();
            }
            
            ExploreReward memory reward;
            (reward.monsterClassId, reward.itemClassId, reward.value) = EtheremonAdventureSetting(adventureSettingContract).getSiteItem(exploreData.siteId, exploreData.itemSeed);
            
            adventureData.removePendingExplore(_exploreId, exploreData.itemSeed);
            
            if (reward.monsterClassId > 0) {
                EtheremonMonsterNFT monsterContract = EtheremonMonsterNFT(monsterNFT);
                reward.temp = monsterContract.mintMonster(uint32(reward.monsterClassId), exploreData.sender,  "..name me..");
                ClaimExplore(exploreData.sender, _exploreId, 0, reward.monsterClassId, reward.temp);
            } else if (reward.itemClassId > 0) {
                // give new adventure item 
                EtheremonAdventureItem item = EtheremonAdventureItem(adventureItemContract);
                reward.temp = item.spawnItem(reward.itemClassId, reward.value, exploreData.sender);
                ClaimExplore(exploreData.sender, _exploreId, 1, reward.itemClassId, reward.temp);
            } else if (reward.value > 0) {
                // send token contract
                ERC20Interface token = ERC20Interface(tokenContract);
                token.transfer(exploreData.sender, reward.value);
                ClaimExplore(exploreData.sender, _exploreId, 2, 0, reward.value);
            } else {
                revert();
            }
        }
        
        // public
        
        function predictExploreReward(uint _exploreId) constant external returns(uint itemSeed, uint rewardMonsterClass, uint rewardItemCLass, uint rewardValue) {
            EtheremonAdventureData adventureData = EtheremonAdventureData(adventureDataContract);
            ExploreData memory exploreData;
            (exploreData.sender, exploreData.monsterType, exploreData.monsterId, exploreData.siteId, exploreData.itemSeed, exploreData.startAt) = adventureData.getExploreData(_exploreId);
            
            if (exploreData.itemSeed != 0) {
                itemSeed = exploreData.itemSeed;
            } else {
                if (block.number < exploreData.startAt + 2)
                    return (0, 0, 0, 0);
                itemSeed = getRandom(exploreData.sender, exploreData.startAt + 1, exploreData.monsterId, _exploreId) % 100000;
            }
            (rewardMonsterClass, rewardItemCLass, rewardValue) = EtheremonAdventureSetting(adventureSettingContract).getSiteItem(exploreData.siteId, itemSeed);
        }
        
        function getExploreItem(uint _exploreId) constant external returns(address trainer, uint monsterType, uint monsterId, uint siteId, uint startBlock, uint rewardMonsterClass, uint rewardItemClass, uint rewardValue) {
            EtheremonAdventureData adventureData = EtheremonAdventureData(adventureDataContract);
            (trainer, monsterType, monsterId, siteId, rewardMonsterClass, startBlock) = adventureData.getExploreData(_exploreId);
            
            if (rewardMonsterClass > 0) {
                (rewardMonsterClass, rewardItemClass, rewardValue) = EtheremonAdventureSetting(adventureSettingContract).getSiteItem(siteId, rewardMonsterClass);
            }
            
        }
        
        function getPendingExploreItem(address _trainer) constant external returns(uint exploreId, uint monsterType, uint monsterId, uint siteId, uint startBlock, uint endBlock) {
            EtheremonAdventureData adventureData = EtheremonAdventureData(adventureDataContract);
            (exploreId, monsterType, monsterId, siteId, endBlock, startBlock) = adventureData.getPendingExploreData(_trainer);
            if (exploreId > 0) {
                endBlock = startBlock + minBlockGap + startBlock % minBlockGap;
            }
        }
    
    }

    File 2 of 4: EtheremonAdventureItem
    pragma solidity ^0.4.23;
    
    /**
     * @title SafeMath
     * @dev Math operations with safety checks that throw on error
     */
    library SafeMath {
    
      /**
      * @dev Multiplies two numbers, throws on overflow.
      */
      function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
        if (a == 0) {
          return 0;
        }
        c = a * b;
        assert(c / a == b);
        return c;
      }
    
      /**
      * @dev Integer division of two numbers, truncating the quotient.
      */
      function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // assert(b > 0); // Solidity automatically throws when dividing by 0
        // uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return a / b;
      }
    
      /**
      * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
      */
      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);
        return a - b;
      }
    
      /**
      * @dev Adds two numbers, throws on overflow.
      */
      function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
        c = a + b;
        assert(c >= a);
        return c;
      }
    }
    
    /**
     * Utility library of inline functions on addresses
     */
    library AddressUtils {
    
      /**
       * Returns whether the target address is a contract
       * @dev This function will return false if invoked during the constructor of a contract,
       *  as the code is not actually created until after the constructor finishes.
       * @param addr address to check
       * @return whether the target address is a contract
       */
      function isContract(address addr) internal view returns (bool) {
        uint256 size;
        // XXX Currently there is no better way to check if there is a contract in an address
        // than to check the size of the code at that address.
        // See https://ethereum.stackexchange.com/a/14016/36603
        // for more details about how this works.
        // TODO Check this again before the Serenity release, because all addresses will be
        // contracts then.
        // solium-disable-next-line security/no-inline-assembly
        assembly { size := extcodesize(addr) }
        return size > 0;
      }
    
    }
    
    interface ERC165 {
        function supportsInterface(bytes4 _interfaceID) external view returns (bool);
    }
    
    contract SupportsInterface is ERC165 {
        
        mapping(bytes4 => bool) internal supportedInterfaces;
    
        constructor() public {
            supportedInterfaces[0x01ffc9a7] = true; // ERC165
        }
    
        function supportsInterface(bytes4 _interfaceID) external view returns (bool) {
            return supportedInterfaces[_interfaceID];
        }
    }
    
    interface ERC721 {
        event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
        event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
        event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
        
        function balanceOf(address _owner) external view returns (uint256);
        function ownerOf(uint256 _tokenId) external view returns (address);
        function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes _data) external;
        function safeTransferFrom(address _from, address _to, uint256 _tokenId) external;
        
        function transferFrom(address _from, address _to, uint256 _tokenId) external;
        function transfer(address _to, uint256 _tokenId) external;
        function approve(address _approved, uint256 _tokenId) external;
        function setApprovalForAll(address _operator, bool _approved) external;
        
        function getApproved(uint256 _tokenId) external view returns (address);
        function isApprovedForAll(address _owner, address _operator) external view returns (bool);
    }
    
    interface ERC721Enumerable {
        function totalSupply() external view returns (uint256);
        function tokenByIndex(uint256 _index) external view returns (uint256);
        function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
    }
    
    interface ERC721Metadata {
        function name() external view returns (string _name);
        function symbol() external view returns (string _symbol);
        function tokenURI(uint256 _tokenId) external view returns (string);
    }
    
    interface ERC721TokenReceiver {
      function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4);
    }
    
    contract NFToken is ERC721, SupportsInterface {
    
        using SafeMath for uint256;
        using AddressUtils for address;
        
        // A mapping from NFT ID to the address that owns it.
        mapping (uint256 => address) internal idToOwner;
        
        // Mapping from NFT ID to approved address.
        mapping (uint256 => address) internal idToApprovals;
        
        // Mapping from owner address to count of his tokens.
        mapping (address => uint256) internal ownerToNFTokenCount;
        
        // Mapping from owner address to mapping of operator addresses.
        mapping (address => mapping (address => bool)) internal ownerToOperators;
        
        /**
        * @dev Magic value of a smart contract that can recieve NFT.
        * Equal to: bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")).
        */
        bytes4 constant MAGIC_ON_ERC721_RECEIVED = 0x150b7a02;
    
        event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
        event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
        event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
    
        modifier canOperate(uint256 _tokenId) {
            address tokenOwner = idToOwner[_tokenId];
            require(tokenOwner == msg.sender || ownerToOperators[tokenOwner][msg.sender]);
            _;
        }
    
    
        modifier canTransfer(uint256 _tokenId) {
            address tokenOwner = idToOwner[_tokenId];
            require(tokenOwner == msg.sender || getApproved(_tokenId) == msg.sender || ownerToOperators[tokenOwner][msg.sender]);
            _;
        }
    
        modifier validNFToken(uint256 _tokenId) {
            require(idToOwner[_tokenId] != address(0));
            _;
        }
    
        constructor() public {
            supportedInterfaces[0x80ac58cd] = true; // ERC721
        }
    
    
        function balanceOf(address _owner) external view returns (uint256) {
            require(_owner != address(0));
            return ownerToNFTokenCount[_owner];
        }
    
        function ownerOf(uint256 _tokenId) external view returns (address _owner) {
            _owner = idToOwner[_tokenId];
            require(_owner != address(0));
        }
    
    
        function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes _data) external {
            _safeTransferFrom(_from, _to, _tokenId, _data);
        }
    
        function safeTransferFrom(address _from, address _to, uint256 _tokenId) external {
            _safeTransferFrom(_from, _to, _tokenId, "");
        }
    
        function transferFrom(address _from, address _to, uint256 _tokenId) external canTransfer(_tokenId) validNFToken(_tokenId) {
            address tokenOwner = idToOwner[_tokenId];
            require(tokenOwner == _from);
            require(_to != address(0));
            _transfer(_to, _tokenId);
        }
        
        function transfer(address _to, uint256 _tokenId) external canTransfer(_tokenId) validNFToken(_tokenId) {
            address tokenOwner = idToOwner[_tokenId];
            require(tokenOwner == msg.sender);
            require(_to != address(0));
            _transfer(_to, _tokenId);
        }
    
        function approve(address _approved, uint256 _tokenId) external canOperate(_tokenId) validNFToken(_tokenId) {
            address tokenOwner = idToOwner[_tokenId];
            require(_approved != tokenOwner);
    
            idToApprovals[_tokenId] = _approved;
            emit Approval(tokenOwner, _approved, _tokenId);
        }
    
        function setApprovalForAll(address _operator, bool _approved) external {
            require(_operator != address(0));
            ownerToOperators[msg.sender][_operator] = _approved;
            emit ApprovalForAll(msg.sender, _operator, _approved);
        }
    
        function getApproved(uint256 _tokenId) public view validNFToken(_tokenId) returns (address) {
            return idToApprovals[_tokenId];
        }
    
        function isApprovedForAll(address _owner, address _operator) external view returns (bool) {
            require(_owner != address(0));
            require(_operator != address(0));
            return ownerToOperators[_owner][_operator];
        }
    
        function _safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes _data) internal canTransfer(_tokenId) validNFToken(_tokenId) {
            address tokenOwner = idToOwner[_tokenId];
            require(tokenOwner == _from);
            require(_to != address(0));
    
            _transfer(_to, _tokenId);
    
            if (_to.isContract()) {
                bytes4 retval = ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data);
                require(retval == MAGIC_ON_ERC721_RECEIVED);
            }
        }
    
        function _transfer(address _to, uint256 _tokenId) private {
            address from = idToOwner[_tokenId];
            clearApproval(_tokenId);
            removeNFToken(from, _tokenId);
            addNFToken(_to, _tokenId);
            emit Transfer(from, _to, _tokenId);
        }
       
    
        function _mint(address _to, uint256 _tokenId) internal {
            require(_to != address(0));
            require(_tokenId != 0);
            require(idToOwner[_tokenId] == address(0));
    
            addNFToken(_to, _tokenId);
    
            emit Transfer(address(0), _to, _tokenId);
        }
    
        function _burn(address _owner, uint256 _tokenId) validNFToken(_tokenId) internal { 
            clearApproval(_tokenId);
            removeNFToken(_owner, _tokenId);
            emit Transfer(_owner, address(0), _tokenId);
        }
    
        function clearApproval(uint256 _tokenId) private {
            if(idToApprovals[_tokenId] != 0) {
                delete idToApprovals[_tokenId];
            }
        }
    
        function removeNFToken(address _from, uint256 _tokenId) internal {
            require(idToOwner[_tokenId] == _from);
            assert(ownerToNFTokenCount[_from] > 0);
            ownerToNFTokenCount[_from] = ownerToNFTokenCount[_from] - 1;
            delete idToOwner[_tokenId];
        }
    
        function addNFToken(address _to, uint256 _tokenId) internal {
            require(idToOwner[_tokenId] == address(0));
    
            idToOwner[_tokenId] = _to;
            ownerToNFTokenCount[_to] = ownerToNFTokenCount[_to].add(1);
        }
    }
    
    
    contract NFTokenEnumerable is NFToken, ERC721Enumerable {
    
        // Array of all NFT IDs.
        uint256[] internal tokens;
    
        // Mapping from token ID its index in global tokens array.
        mapping(uint256 => uint256) internal idToIndex;
    
        // Mapping from owner to list of owned NFT IDs.
        mapping(address => uint256[]) internal ownerToIds;
    
        // Mapping from NFT ID to its index in the owner tokens list.
        mapping(uint256 => uint256) internal idToOwnerIndex;
    
        constructor() public {
            supportedInterfaces[0x780e9d63] = true; // ERC721Enumerable
        }
    
        function _mint(address _to, uint256 _tokenId) internal {
            super._mint(_to, _tokenId);
            uint256 length = tokens.push(_tokenId);
            idToIndex[_tokenId] = length - 1;
        }
    
        function _burn(address _owner, uint256 _tokenId) internal {
            super._burn(_owner, _tokenId);
            assert(tokens.length > 0);
    
            uint256 tokenIndex = idToIndex[_tokenId];
            // Sanity check. This could be removed in the future.
            assert(tokens[tokenIndex] == _tokenId);
            uint256 lastTokenIndex = tokens.length - 1;
            uint256 lastToken = tokens[lastTokenIndex];
    
            tokens[tokenIndex] = lastToken;
    
            tokens.length--;
            // Consider adding a conditional check for the last token in order to save GAS.
            idToIndex[lastToken] = tokenIndex;
            idToIndex[_tokenId] = 0;
        }
    
        function removeNFToken(address _from, uint256 _tokenId) internal
        {
            super.removeNFToken(_from, _tokenId);
            assert(ownerToIds[_from].length > 0);
    
            uint256 tokenToRemoveIndex = idToOwnerIndex[_tokenId];
            uint256 lastTokenIndex = ownerToIds[_from].length - 1;
            uint256 lastToken = ownerToIds[_from][lastTokenIndex];
    
            ownerToIds[_from][tokenToRemoveIndex] = lastToken;
    
            ownerToIds[_from].length--;
            // Consider adding a conditional check for the last token in order to save GAS.
            idToOwnerIndex[lastToken] = tokenToRemoveIndex;
            idToOwnerIndex[_tokenId] = 0;
        }
    
        function addNFToken(address _to, uint256 _tokenId) internal {
            super.addNFToken(_to, _tokenId);
    
            uint256 length = ownerToIds[_to].push(_tokenId);
            idToOwnerIndex[_tokenId] = length - 1;
        }
    
        function totalSupply() external view returns (uint256) {
            return tokens.length;
        }
    
        function tokenByIndex(uint256 _index) external view returns (uint256) {
            require(_index < tokens.length);
            // Sanity check. This could be removed in the future.
            assert(idToIndex[tokens[_index]] == _index);
            return tokens[_index];
        }
    
        function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256) {
            require(_index < ownerToIds[_owner].length);
            return ownerToIds[_owner][_index];
        }
    
    }
    
    contract NFTStandard is NFTokenEnumerable, ERC721Metadata {
        string internal nftName;
        string internal nftSymbol;
        
        mapping (uint256 => string) internal idToUri;
        
        constructor(string _name, string _symbol) public {
            nftName = _name;
            nftSymbol = _symbol;
            supportedInterfaces[0x5b5e139f] = true; // ERC721Metadata
        }
        
        function _burn(address _owner, uint256 _tokenId) internal {
            super._burn(_owner, _tokenId);
            if (bytes(idToUri[_tokenId]).length != 0) {
            delete idToUri[_tokenId];
            }
        }
        
        function _setTokenUri(uint256 _tokenId, string _uri) validNFToken(_tokenId) internal {
            idToUri[_tokenId] = _uri;
        }
        
        function name() external view returns (string _name) {
            _name = nftName;
        }
        
        function symbol() external view returns (string _symbol) {
            _symbol = nftSymbol;
        }
        
        function tokenURI(uint256 _tokenId) validNFToken(_tokenId) external view returns (string) {
            return idToUri[_tokenId];
        }
    }
    
    contract BasicAccessControl {
        address public owner;
        // address[] public moderators;
        uint16 public totalModerators = 0;
        mapping (address => bool) public moderators;
        bool public isMaintaining = false;
    
        constructor() public {
            owner = msg.sender;
        }
    
        modifier onlyOwner {
            require(msg.sender == owner);
            _;
        }
    
        modifier onlyModerators() {
            require(msg.sender == owner || moderators[msg.sender] == true);
            _;
        }
    
        modifier isActive {
            require(!isMaintaining);
            _;
        }
    
        function ChangeOwner(address _newOwner) onlyOwner public {
            if (_newOwner != address(0)) {
                owner = _newOwner;
            }
        }
    
    
        function AddModerator(address _newModerator) onlyOwner public {
            if (moderators[_newModerator] == false) {
                moderators[_newModerator] = true;
                totalModerators += 1;
            }
        }
        
        function RemoveModerator(address _oldModerator) onlyOwner public {
            if (moderators[_oldModerator] == true) {
                moderators[_oldModerator] = false;
                totalModerators -= 1;
            }
        }
    
        function UpdateMaintaining(bool _isMaintaining) onlyOwner public {
            isMaintaining = _isMaintaining;
        }
    }
    
    interface EtheremonAdventureHandler {
        function handleSingleItem(address _sender, uint _classId, uint _value, uint _target, uint _param) external;
        function handleMultipleItems(address _sender, uint _classId1, uint _classId2, uint _classId3, uint _target, uint _param) external;
    }
    
    contract EtheremonAdventureItem is NFTStandard("EtheremonAdventure", "EMOND"), BasicAccessControl {
        uint constant public MAX_OWNER_PERS_SITE = 10;
        uint constant public MAX_SITE_ID = 108;
        uint constant public MAX_SITE_TOKEN_ID = 1080;
        
        // smartcontract
        address public adventureHandler;
        
        // class sites: 1 -> 108
        // shard: 109 - 126
        // level, exp
        struct Item {
            uint classId;
            uint value;
        }
        
        uint public totalItem = MAX_SITE_TOKEN_ID;
        mapping (uint => Item) public items; // token id => info
        
        modifier requireAdventureHandler {
            require(adventureHandler != address(0));
            _;        
        }
        
        function setAdventureHandler(address _adventureHandler) onlyModerators external {
            adventureHandler = _adventureHandler;
        }
        
        function setTokenURI(uint256 _tokenId, string _uri) onlyModerators external {
            _setTokenUri(_tokenId, _uri);
        }
        
        function spawnSite(uint _classId, uint _tokenId, address _owner) onlyModerators external {
            if (_owner == address(0)) revert();
            if (_classId > MAX_SITE_ID || _classId == 0 || _tokenId > MAX_SITE_TOKEN_ID || _tokenId == 0) revert();
            
            Item storage item = items[_tokenId];
            if (item.classId != 0) revert(); // token existed
            item.classId = _classId;
            
            _mint(_owner, _tokenId);
        }
        
        function spawnItem(uint _classId, uint _value, address _owner) onlyModerators external returns(uint) {
            if (_owner == address(0)) revert();
            if (_classId <= MAX_SITE_ID) revert();
            
            totalItem += 1;
            Item storage item = items[totalItem];
            item.classId = _classId;
            item.value = _value;
            
            _mint(_owner, totalItem);
            return totalItem;
        }
        
        
        // public write 
        function useSingleItem(uint _tokenId, uint _target, uint _param) isActive requireAdventureHandler public {
            // check ownership
            if (_tokenId == 0 || idToOwner[_tokenId] != msg.sender) revert();
            Item storage item = items[_tokenId];
            
            EtheremonAdventureHandler handler = EtheremonAdventureHandler(adventureHandler);
            handler.handleSingleItem(msg.sender, item.classId, item.value, _target, _param);
            
            _burn(msg.sender, _tokenId);
        }
        
        function useMultipleItem(uint _token1, uint _token2, uint _token3, uint _target, uint _param) isActive requireAdventureHandler public {
            if (_token1 > 0 && idToOwner[_token1] != msg.sender) revert();
            if (_token2 > 0 && idToOwner[_token2] != msg.sender) revert();
            if (_token3 > 0 && idToOwner[_token3] != msg.sender) revert();
            
            Item storage item1 = items[_token1];
            Item storage item2 = items[_token2];
            Item storage item3 = items[_token3];
            
            EtheremonAdventureHandler handler = EtheremonAdventureHandler(adventureHandler);
            handler.handleMultipleItems(msg.sender, item1.classId, item2.classId, item3.classId, _target, _param);
            
            if (_token1 > 0) _burn(msg.sender, _token1);
            if (_token2 > 0) _burn(msg.sender, _token2);
            if (_token3 > 0) _burn(msg.sender, _token3);
        }
        
        
        // public read 
        function getItemInfo(uint _tokenId) constant public returns(uint classId, uint value) {
            Item storage item = items[_tokenId];
            classId = item.classId;
            value = item.value;
        }
    
    }

    File 3 of 4: EtheremonAdventureData
    pragma solidity ^0.4.23;
    
    /**
     * @title SafeMath
     * @dev Math operations with safety checks that throw on error
     */
    library SafeMath {
    
      /**
      * @dev Multiplies two numbers, throws on overflow.
      */
      function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
        if (a == 0) {
          return 0;
        }
        c = a * b;
        assert(c / a == b);
        return c;
      }
    
      /**
      * @dev Integer division of two numbers, truncating the quotient.
      */
      function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // assert(b > 0); // Solidity automatically throws when dividing by 0
        // uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return a / b;
      }
    
      /**
      * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
      */
      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);
        return a - b;
      }
    
      /**
      * @dev Adds two numbers, throws on overflow.
      */
      function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
        c = a + b;
        assert(c >= a);
        return c;
      }
    }
    
    contract BasicAccessControl {
        address public owner;
        // address[] public moderators;
        uint16 public totalModerators = 0;
        mapping (address => bool) public moderators;
        bool public isMaintaining = false;
    
        constructor() public {
            owner = msg.sender;
        }
    
        modifier onlyOwner {
            require(msg.sender == owner);
            _;
        }
    
        modifier onlyModerators() {
            require(msg.sender == owner || moderators[msg.sender] == true);
            _;
        }
    
        modifier isActive {
            require(!isMaintaining);
            _;
        }
    
        function ChangeOwner(address _newOwner) onlyOwner public {
            if (_newOwner != address(0)) {
                owner = _newOwner;
            }
        }
    
    
        function AddModerator(address _newModerator) onlyOwner public {
            if (moderators[_newModerator] == false) {
                moderators[_newModerator] = true;
                totalModerators += 1;
            }
        }
        
        function RemoveModerator(address _oldModerator) onlyOwner public {
            if (moderators[_oldModerator] == true) {
                moderators[_oldModerator] = false;
                totalModerators -= 1;
            }
        }
    
        function UpdateMaintaining(bool _isMaintaining) onlyOwner public {
            isMaintaining = _isMaintaining;
        }
    }
    
    contract EtheremonAdventureData is BasicAccessControl {
        
        using SafeMath for uint;
        
        struct LandTokenClaim {
            uint emontAmount;
            uint etherAmount;
        }
        
        // total revenue 
        struct LandRevenue {
            uint emontAmount;
            uint etherAmount;
        }
        
        struct ExploreData {
            address sender;
            uint typeId;
            uint monsterId;
            uint siteId;
            uint itemSeed;
            uint startAt; // blocknumber
        }
        
        uint public exploreCount = 0;
        mapping(uint => ExploreData) public exploreData; // explore count => data
        mapping(address => uint) public explorePending; // address => explore id
        
        mapping(uint => LandTokenClaim) public claimData; // tokenid => claim info
        mapping(uint => LandRevenue) public siteData; // class id => amount 
        
        function addLandRevenue(uint _siteId, uint _emontAmount, uint _etherAmount) onlyModerators external {
            LandRevenue storage revenue = siteData[_siteId];
            revenue.emontAmount = revenue.emontAmount.add(_emontAmount);
            revenue.etherAmount = revenue.etherAmount.add(_etherAmount);
        }
        
        function addTokenClaim(uint _tokenId, uint _emontAmount, uint _etherAmount) onlyModerators external {
            LandTokenClaim storage claim = claimData[_tokenId];
            claim.emontAmount = claim.emontAmount.add(_emontAmount);
            claim.etherAmount = claim.etherAmount.add(_etherAmount);
        }
        
        function addExploreData(address _sender, uint _typeId, uint _monsterId, uint _siteId, uint _startAt, uint _emontAmount, uint _etherAmount) onlyModerators external returns(uint){
            if (explorePending[_sender] > 0) revert();
            exploreCount += 1;
            ExploreData storage data = exploreData[exploreCount];
            data.sender = _sender;
            data.typeId = _typeId;
            data.monsterId = _monsterId;
            data.siteId = _siteId;
            data.itemSeed = 0;
            data.startAt = _startAt;
            explorePending[_sender] = exploreCount;
            
            LandRevenue storage revenue = siteData[_siteId];
            revenue.emontAmount = revenue.emontAmount.add(_emontAmount);
            revenue.etherAmount = revenue.etherAmount.add(_etherAmount);
            return exploreCount;
        }
        
        function removePendingExplore(uint _exploreId, uint _itemSeed) onlyModerators external {
            ExploreData storage data = exploreData[_exploreId];
            if (explorePending[data.sender] != _exploreId)
                revert();
            explorePending[data.sender] = 0;
            data.itemSeed = _itemSeed;
        }
        
        // public function
        function getLandRevenue(uint _classId) constant public returns(uint _emontAmount, uint _etherAmount) {
            LandRevenue storage revenue = siteData[_classId];
            return (revenue.emontAmount, revenue.etherAmount);
        }
        
        function getTokenClaim(uint _tokenId) constant public returns(uint _emontAmount, uint _etherAmount) {
            LandTokenClaim storage claim = claimData[_tokenId];
            return (claim.emontAmount, claim.etherAmount);
        }
        
        function getExploreData(uint _exploreId) constant public returns(address _sender, uint _typeId, uint _monsterId, uint _siteId, uint _itemSeed, uint _startAt) {
            ExploreData storage data = exploreData[_exploreId];
            return (data.sender, data.typeId, data.monsterId, data.siteId, data.itemSeed, data.startAt);
        }
        
        function getPendingExplore(address _player) constant public returns(uint) {
            return explorePending[_player];
        }
        
        function getPendingExploreData(address _player) constant public returns(uint _exploreId, uint _typeId, uint _monsterId, uint _siteId, uint _itemSeed, uint _startAt) {
            _exploreId = explorePending[_player];
            if (_exploreId > 0) {
                ExploreData storage data = exploreData[_exploreId];
                return (_exploreId, data.typeId, data.monsterId, data.siteId, data.itemSeed, data.startAt);
            }
            
        }
    }

    File 4 of 4: EtheremonAdventureSetting
    pragma solidity ^0.4.23;
    
    contract BasicAccessControl {
        address public owner;
        // address[] public moderators;
        uint16 public totalModerators = 0;
        mapping (address => bool) public moderators;
        bool public isMaintaining = false;
    
        constructor() public {
            owner = msg.sender;
        }
    
        modifier onlyOwner {
            require(msg.sender == owner);
            _;
        }
    
        modifier onlyModerators() {
            require(msg.sender == owner || moderators[msg.sender] == true);
            _;
        }
    
        modifier isActive {
            require(!isMaintaining);
            _;
        }
    
        function ChangeOwner(address _newOwner) onlyOwner public {
            if (_newOwner != address(0)) {
                owner = _newOwner;
            }
        }
    
    
        function AddModerator(address _newModerator) onlyOwner public {
            if (moderators[_newModerator] == false) {
                moderators[_newModerator] = true;
                totalModerators += 1;
            }
        }
        
        function RemoveModerator(address _oldModerator) onlyOwner public {
            if (moderators[_oldModerator] == true) {
                moderators[_oldModerator] = false;
                totalModerators -= 1;
            }
        }
    
        function UpdateMaintaining(bool _isMaintaining) onlyOwner public {
            isMaintaining = _isMaintaining;
        }
    }
    
    contract EtheremonAdventureSetting is BasicAccessControl {
        struct RewardData {
            uint monster_rate;
            uint monster_id;
            uint shard_rate;
            uint shard_id;
            uint level_rate;
            uint exp_rate;
            uint emont_rate;
        }
        mapping(uint => uint[]) public siteSet; // monster class -> site id
        mapping(uint => uint) public monsterClassSiteSet;
        mapping(uint => RewardData) public siteRewards; // site id => rewards (monster_rate, monster_id, shard_rate, shard_id, level_rate, exp_rate, emont_rate)
        uint public levelItemClass = 200;
        uint public expItemClass = 201;
        uint[4] public levelRewards = [1, 1, 1, 2];
        uint[11] public expRewards = [50, 50, 50, 50, 100, 100, 100, 100, 200, 200, 500];
        uint[6] public emontRewards = [300000000, 300000000, 500000000, 500000000, 1000000000, 150000000];
        
        function setConfig(uint _levelItemClass, uint _expItemClass) onlyModerators public {
            levelItemClass = _levelItemClass;
            expItemClass = _expItemClass;
        }
        
        function addSiteSet(uint _setId, uint _siteId) onlyModerators public {
            uint[] storage siteList = siteSet[_setId];
            for (uint index = 0; index < siteList.length; index++) {
                if (siteList[index] == _siteId) {
                    return;
                }
            }
            siteList.push(_siteId);
        }
        
        function removeSiteSet(uint _setId, uint _siteId) onlyModerators public {
            uint[] storage siteList = siteSet[_setId];
            uint foundIndex = 0;
            for (; foundIndex < siteList.length; foundIndex++) {
                if (siteList[foundIndex] == _siteId) {
                    break;
                }
            }
            if (foundIndex < siteList.length) {
                siteList[foundIndex] = siteList[siteList.length-1];
                delete siteList[siteList.length-1];
                siteList.length--;
            }
        }
        
        function setMonsterClassSiteSet(uint _monsterId, uint _siteSetId) onlyModerators public {
            monsterClassSiteSet[_monsterId] = _siteSetId;
        }
        
        function setSiteRewards(uint _siteId, uint _monster_rate, uint _monster_id, uint _shard_rate, uint _shard_id, uint _level_rate, uint _exp_rate, uint _emont_rate) onlyModerators public {
            RewardData storage reward = siteRewards[_siteId];
            reward.monster_rate = _monster_rate;
            reward.monster_id = _monster_id;
            reward.shard_rate = _shard_rate;
            reward.shard_id = _shard_id;
            reward.level_rate = _level_rate;
            reward.exp_rate = _exp_rate;
            reward.emont_rate = _emont_rate;
        }
        
        function setLevelRewards(uint _index, uint _value) onlyModerators public {
            levelRewards[_index] = _value;
        }
        
        function setExpRewards(uint _index, uint _value) onlyModerators public {
            expRewards[_index] = _value;
        }
        
        function setEmontRewards(uint _index, uint _value) onlyModerators public {
            emontRewards[_index] = _value;
        }
        
        function initSiteSet(uint _turn) onlyModerators public {
            if (_turn == 1) {
                siteSet[1] = [35, 3, 4, 37, 51, 8, 41, 11, 45, 47, 15, 16, 19, 52, 23, 36, 27, 30, 31];
                siteSet[2] = [35, 3, 4, 49, 39, 8, 41, 11, 13, 15, 48, 43, 18, 19, 53, 23, 27, 30, 31];
                siteSet[3] = [2, 4, 39, 40, 9, 47, 12, 14, 44, 16, 49, 20, 46, 54, 24, 25, 27, 36, 29, 31];
                siteSet[4] = [51, 3, 5, 38, 7, 40, 11, 12, 45, 14, 47, 16, 35, 52, 21, 22, 26, 30, 31];
                siteSet[5] = [33, 3, 4, 54, 38, 8, 10, 43, 45, 14, 50, 18, 35, 21, 22, 46, 26, 28, 42];
                siteSet[6] = [51, 3, 36, 5, 7, 44, 42, 12, 13, 47, 17, 37, 19, 52, 24, 26, 28, 29, 31];
                siteSet[7] = [32, 48, 2, 43, 4, 38, 7, 9, 42, 11, 34, 15, 16, 49, 21, 23, 25, 30, 53];
                siteSet[8] = [1, 34, 54, 6, 33, 8, 44, 39, 12, 13, 46, 17, 50, 20, 22, 40, 24, 25, 29];
                siteSet[9] = [32, 2, 6, 7, 40, 10, 39, 44, 34, 15, 48, 17, 50, 20, 21, 24, 25, 29, 52];
                siteSet[10] = [32, 1, 36, 5, 38, 48, 9, 11, 45, 15, 16, 49, 19, 41, 23, 27, 28, 53, 37];
            } else {
                siteSet[11] = [2, 35, 37, 6, 7, 10, 46, 44, 50, 14, 18, 51, 21, 22, 26, 53, 42, 30, 31];
                siteSet[12] = [1, 34, 5, 51, 33, 9, 10, 45, 14, 47, 16, 18, 19, 52, 41, 23, 27, 29, 37];
                siteSet[13] = [32, 2, 35, 4, 5, 38, 49, 9, 42, 43, 12, 13, 48, 17, 21, 24, 25, 28, 53];
                siteSet[14] = [1, 34, 3, 37, 6, 33, 8, 41, 10, 45, 46, 15, 17, 50, 20, 54, 24, 25, 29];
                siteSet[15] = [33, 2, 34, 6, 7, 40, 42, 11, 13, 47, 50, 43, 18, 20, 22, 39, 26, 30, 52];
                siteSet[16] = [32, 1, 36, 5, 39, 54, 9, 10, 43, 14, 18, 51, 20, 46, 22, 41, 27, 28, 53];
                siteSet[17] = [32, 1, 49, 36, 38, 6, 33, 8, 44, 12, 13, 48, 17, 19, 40, 54, 23, 26, 28];
            }
        }
        
        function initMonsterClassSiteSet() onlyModerators public {
                monsterClassSiteSet[1] = 1;
                monsterClassSiteSet[2] = 2;
                monsterClassSiteSet[3] = 3;
                monsterClassSiteSet[4] = 4;
                monsterClassSiteSet[5] = 5;
                monsterClassSiteSet[6] = 6;
                monsterClassSiteSet[7] = 7;
                monsterClassSiteSet[8] = 8;
                monsterClassSiteSet[9] = 8;
                monsterClassSiteSet[10] = 2;
                monsterClassSiteSet[11] = 9;
                monsterClassSiteSet[12] = 10;
                monsterClassSiteSet[13] = 11;
                monsterClassSiteSet[14] = 12;
                monsterClassSiteSet[15] = 3;
                monsterClassSiteSet[16] = 13;
                monsterClassSiteSet[17] = 3;
                monsterClassSiteSet[18] = 8;
                monsterClassSiteSet[19] = 8;
                monsterClassSiteSet[20] = 14;
                monsterClassSiteSet[21] = 13;
                monsterClassSiteSet[22] = 4;
                monsterClassSiteSet[23] = 9;
                monsterClassSiteSet[24] = 1;
                monsterClassSiteSet[25] = 1;
                monsterClassSiteSet[26] = 3;
                monsterClassSiteSet[27] = 2;
                monsterClassSiteSet[28] = 6;
                monsterClassSiteSet[29] = 4;
                monsterClassSiteSet[30] = 14;
                monsterClassSiteSet[31] = 10;
                monsterClassSiteSet[32] = 1;
                monsterClassSiteSet[33] = 15;
                monsterClassSiteSet[34] = 3;
                monsterClassSiteSet[35] = 3;
                monsterClassSiteSet[36] = 2;
                monsterClassSiteSet[37] = 8;
                monsterClassSiteSet[38] = 1;
                monsterClassSiteSet[39] = 2;
                monsterClassSiteSet[40] = 3;
                monsterClassSiteSet[41] = 4;
                monsterClassSiteSet[42] = 5;
                monsterClassSiteSet[43] = 6;
                monsterClassSiteSet[44] = 7;
                monsterClassSiteSet[45] = 8;
                monsterClassSiteSet[46] = 8;
                monsterClassSiteSet[47] = 2;
                monsterClassSiteSet[48] = 9;
                monsterClassSiteSet[49] = 10;
                monsterClassSiteSet[50] = 8;
                monsterClassSiteSet[51] = 14;
                monsterClassSiteSet[52] = 1;
                monsterClassSiteSet[53] = 3;
                monsterClassSiteSet[54] = 2;
                monsterClassSiteSet[55] = 6;
                monsterClassSiteSet[56] = 4;
                monsterClassSiteSet[57] = 14;
                monsterClassSiteSet[58] = 10;
                monsterClassSiteSet[59] = 1;
                monsterClassSiteSet[60] = 15;
                monsterClassSiteSet[61] = 3;
                monsterClassSiteSet[62] = 8;
                monsterClassSiteSet[63] = 8;
                monsterClassSiteSet[64] = 1;
                monsterClassSiteSet[65] = 2;
                monsterClassSiteSet[66] = 4;
                monsterClassSiteSet[67] = 5;
                monsterClassSiteSet[68] = 14;
                monsterClassSiteSet[69] = 1;
                monsterClassSiteSet[70] = 3;
                monsterClassSiteSet[71] = 3;
                monsterClassSiteSet[72] = 16;
                monsterClassSiteSet[73] = 17;
                monsterClassSiteSet[74] = 5;
                monsterClassSiteSet[75] = 7;
                monsterClassSiteSet[76] = 1;
                monsterClassSiteSet[77] = 17;
                monsterClassSiteSet[78] = 10;
                monsterClassSiteSet[79] = 1;
                monsterClassSiteSet[80] = 13;
                monsterClassSiteSet[81] = 4;
                monsterClassSiteSet[82] = 17;
                monsterClassSiteSet[83] = 10;
                monsterClassSiteSet[84] = 1;
                monsterClassSiteSet[85] = 13;
                monsterClassSiteSet[86] = 4;
                monsterClassSiteSet[87] = 1;
                monsterClassSiteSet[88] = 4;
                monsterClassSiteSet[89] = 1;
                monsterClassSiteSet[90] = 2;
                monsterClassSiteSet[91] = 2;
                monsterClassSiteSet[92] = 2;
                monsterClassSiteSet[93] = 15;
                monsterClassSiteSet[94] = 15;
                monsterClassSiteSet[95] = 15;
                monsterClassSiteSet[96] = 12;
                monsterClassSiteSet[97] = 12;
                monsterClassSiteSet[98] = 12;
                monsterClassSiteSet[99] = 5;
                monsterClassSiteSet[100] = 5;
                monsterClassSiteSet[101] = 8;
                monsterClassSiteSet[102] = 8;
                monsterClassSiteSet[103] = 2;
                monsterClassSiteSet[104] = 2;
                monsterClassSiteSet[105] = 15;
                monsterClassSiteSet[106] = 1;
                monsterClassSiteSet[107] = 1;
                monsterClassSiteSet[108] = 1;
                monsterClassSiteSet[109] = 9;
                monsterClassSiteSet[110] = 10;
                monsterClassSiteSet[111] = 13;
                monsterClassSiteSet[112] = 11;
                monsterClassSiteSet[113] = 14;
                monsterClassSiteSet[114] = 6;
                monsterClassSiteSet[115] = 8;
                monsterClassSiteSet[116] = 3;
                monsterClassSiteSet[117] = 3;
                monsterClassSiteSet[118] = 3;
                monsterClassSiteSet[119] = 13;
                monsterClassSiteSet[120] = 13;
                monsterClassSiteSet[121] = 13;
                monsterClassSiteSet[122] = 5;
                monsterClassSiteSet[123] = 5;
                monsterClassSiteSet[124] = 5;
                monsterClassSiteSet[125] = 15;
                monsterClassSiteSet[126] = 15;
                monsterClassSiteSet[127] = 15;
                monsterClassSiteSet[128] = 1;
                monsterClassSiteSet[129] = 1;
                monsterClassSiteSet[130] = 1;
                monsterClassSiteSet[131] = 14;
                monsterClassSiteSet[132] = 14;
                monsterClassSiteSet[133] = 14;
                monsterClassSiteSet[134] = 16;
                monsterClassSiteSet[135] = 16;
                monsterClassSiteSet[136] = 13;
                monsterClassSiteSet[137] = 13;
                monsterClassSiteSet[138] = 4;
                monsterClassSiteSet[139] = 4;
                monsterClassSiteSet[140] = 7;
                monsterClassSiteSet[141] = 7;
                monsterClassSiteSet[142] = 4;
                monsterClassSiteSet[143] = 4;
                monsterClassSiteSet[144] = 13;
                monsterClassSiteSet[145] = 13;
                monsterClassSiteSet[146] = 9;
                monsterClassSiteSet[147] = 9;
                monsterClassSiteSet[148] = 14;
                monsterClassSiteSet[149] = 14;
                monsterClassSiteSet[150] = 14;
                monsterClassSiteSet[151] = 1;
                monsterClassSiteSet[152] = 1;
                monsterClassSiteSet[153] = 12;
                monsterClassSiteSet[154] = 9;
                monsterClassSiteSet[155] = 14;
                monsterClassSiteSet[156] = 16;
                monsterClassSiteSet[157] = 16;
                monsterClassSiteSet[158] = 8;
        }
        
        function initSiteRewards(uint _turn) onlyModerators public {
            if (_turn == 1) {
                siteRewards[1] = RewardData(25, 116, 350, 350, 50, 350, 225);
                siteRewards[2] = RewardData(25, 119, 350, 350, 50, 350, 225);
                siteRewards[3] = RewardData(25, 122, 350, 350, 50, 350, 225);
                siteRewards[4] = RewardData(25, 116, 350, 351, 50, 350, 225);
                siteRewards[5] = RewardData(25, 119, 350, 351, 50, 350, 225);
                siteRewards[6] = RewardData(25, 122, 350, 351, 50, 350, 225);
                siteRewards[7] = RewardData(25, 116, 350, 352, 50, 350, 225);
                siteRewards[8] = RewardData(25, 119, 350, 352, 50, 350, 225);
                siteRewards[9] = RewardData(25, 122, 350, 352, 50, 350, 225);
                siteRewards[10] = RewardData(25, 125, 350, 320, 50, 350, 225);
                siteRewards[11] = RewardData(25, 128, 350, 320, 50, 350, 225);
                siteRewards[12] = RewardData(25, 131, 350, 320, 50, 350, 225);
                siteRewards[13] = RewardData(25, 125, 350, 321, 50, 350, 225);
                siteRewards[14] = RewardData(25, 128, 350, 321, 50, 350, 225);
                siteRewards[15] = RewardData(25, 131, 350, 321, 50, 350, 225);
                siteRewards[16] = RewardData(25, 125, 350, 322, 50, 350, 225);
                siteRewards[17] = RewardData(25, 128, 350, 322, 50, 350, 225);
                siteRewards[18] = RewardData(25, 131, 350, 322, 50, 350, 225);
                siteRewards[19] = RewardData(25, 134, 350, 340, 50, 350, 225);
                siteRewards[20] = RewardData(25, 136, 350, 340, 50, 350, 225);
                siteRewards[21] = RewardData(25, 138, 350, 340, 50, 350, 225);
                siteRewards[22] = RewardData(25, 134, 350, 341, 50, 350, 225);
                siteRewards[23] = RewardData(25, 136, 350, 341, 50, 350, 225);
                siteRewards[24] = RewardData(25, 138, 350, 341, 50, 350, 225);
                siteRewards[25] = RewardData(25, 134, 350, 342, 50, 350, 225);
                siteRewards[26] = RewardData(25, 136, 350, 342, 50, 350, 225);
                siteRewards[27] = RewardData(25, 138, 350, 342, 50, 350, 225);
            } else {
                siteRewards[28] = RewardData(25, 140, 350, 300, 50, 350, 225);
                siteRewards[29] = RewardData(25, 142, 350, 300, 50, 350, 225);
                siteRewards[30] = RewardData(25, 144, 350, 300, 50, 350, 225);
                siteRewards[31] = RewardData(25, 140, 350, 301, 50, 350, 225);
                siteRewards[32] = RewardData(25, 142, 350, 301, 50, 350, 225);
                siteRewards[33] = RewardData(25, 144, 350, 301, 50, 350, 225);
                siteRewards[34] = RewardData(25, 140, 350, 302, 50, 350, 225);
                siteRewards[35] = RewardData(25, 142, 350, 302, 50, 350, 225);
                siteRewards[36] = RewardData(25, 144, 350, 302, 50, 350, 225);
                siteRewards[37] = RewardData(25, 153, 350, 310, 50, 350, 225);
                siteRewards[38] = RewardData(25, 154, 350, 310, 50, 350, 225);
                siteRewards[39] = RewardData(25, 155, 350, 310, 50, 350, 225);
                siteRewards[40] = RewardData(25, 146, 350, 311, 50, 350, 225);
                siteRewards[41] = RewardData(25, 148, 350, 311, 50, 350, 225);
                siteRewards[42] = RewardData(25, 151, 350, 311, 50, 350, 225);
                siteRewards[43] = RewardData(25, 146, 350, 312, 50, 350, 225);
                siteRewards[44] = RewardData(25, 148, 350, 312, 50, 350, 225);
                siteRewards[45] = RewardData(25, 151, 350, 312, 50, 350, 225);
                siteRewards[46] = RewardData(25, 151, 350, 330, 50, 350, 225);
                siteRewards[47] = RewardData(25, 146, 350, 330, 50, 350, 225);
                siteRewards[48] = RewardData(25, 148, 350, 330, 50, 350, 225);
                siteRewards[49] = RewardData(5, 153, 350, 331, 50, 350, 245);
                siteRewards[50] = RewardData(5, 154, 350, 331, 50, 350, 245);
                siteRewards[51] = RewardData(5, 155, 350, 331, 50, 350, 245);
                siteRewards[52] = RewardData(25, 151, 350, 332, 50, 350, 225);
                siteRewards[53] = RewardData(25, 146, 350, 332, 50, 350, 225);
                siteRewards[54] = RewardData(25, 148, 350, 332, 50, 350, 225);
            } 
        }
        
        function getSiteRewards(uint _siteId) constant public returns(uint monster_rate, uint monster_id, uint shard_rate, uint shard_id, uint level_rate, uint exp_rate, uint emont_rate) {
            RewardData storage reward = siteRewards[_siteId];
            return (reward.monster_rate, reward.monster_id, reward.shard_rate, reward.shard_id, reward.level_rate, reward.exp_rate, reward.emont_rate);
        }
        
        function getSiteId(uint _classId, uint _seed) constant public returns(uint) {
            uint[] storage siteList = siteSet[monsterClassSiteSet[_classId]];
            if (siteList.length == 0) return 0;
            return siteList[_seed % siteList.length];
        }
        
        function getSiteItem(uint _siteId, uint _seed) constant public returns(uint _monsterClassId, uint _tokenClassId, uint _value) {
            uint value = _seed % 1000;
            RewardData storage reward = siteRewards[_siteId];
            // assign monster
            if (value < reward.monster_rate) {
                return (reward.monster_id, 0, 0);
            }
            value -= reward.monster_rate;
            // shard
            if (value < reward.shard_rate) {
                return (0, reward.shard_id, 0);
            }
            value -= reward.shard_rate;
            // level 
            if (value < reward.level_rate) {
                return (0, levelItemClass, levelRewards[value%4]);
            }
            value -= reward.level_rate;
            // exp
            if (value < reward.exp_rate) {
                return (0, expItemClass, expRewards[value%11]);
            }
            value -= reward.exp_rate;
            return (0, 0, emontRewards[value%6]);
        }
    }