contract Army is ERC721Enumerable, ReentrancyGuard, Ownable {

    ERC721 loot = ERC721(0xFF9C1b15B16263C61d017ee9F65C50e4AE0113D7);

    uint256 public price = 20000000000000000; //0.02 ETH

    
    // mirror a dice roll
    function random(string memory input) internal pure returns (uint256) {
        return (uint256(keccak256(abi.encodePacked(input))) % 7) + 1;
    }
    
    function getSwordsmen(uint256 tokenId) public pure returns (string memory) {
        return pluck(tokenId, "Swordsmen", 10000);
    }
    
    function getHorses(uint256 tokenId) public pure returns (string memory) {
        return pluck(tokenId, "Horses", 100);
    }
    
    function getElephants(uint256 tokenId) public pure returns (string memory) {
        return pluck(tokenId, "Elephants", 10);
    }
    
    function getDragons(uint256 tokenId) public pure returns (string memory) {
        return pluck(tokenId, "Dragons", 1);
    }

    function getArchers(uint256 tokenId) public pure returns (string memory) {
        return pluck(tokenId, "Archers", 1000);
    }
    
    function getWizards(uint256 tokenId) public pure returns (string memory) {
        return pluck(tokenId, "Wizards", 1);
    }
    
    
    function pluck(uint256 tokenId, string memory keyPrefix, uint multiplier) internal pure returns (string memory) {
        uint256 roll1 = random(string(abi.encodePacked(keyPrefix, toString(tokenId), "1")));
        uint256 min = roll1;
        uint256 roll2 = random(string(abi.encodePacked(keyPrefix, toString(tokenId), "2")));
        min = min > roll2 ? roll2 : min;
        uint256 roll3 = random(string(abi.encodePacked(keyPrefix, toString(tokenId), "3")));
        min = min > roll3 ? roll3 : min;
        uint256 roll4 = random(string(abi.encodePacked(keyPrefix, toString(tokenId), "4")));
        min = min > roll4 ? roll4 : min;
        
        // get 3 highest dice rolls
        uint256 stat = (roll1 + roll2 + roll3 + roll4 - min) * multiplier;
        
        string memory output = string(abi.encodePacked(keyPrefix, ": ", toString(stat)));

        return output;
    }

    function tokenURI(uint256 tokenId) override public pure returns (string memory) {
        string[13] memory parts;
        parts[0] = '<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350"><style>.base { fill: white; font-family: serif; font-size: 14px; }</style><rect width="100%" height="100%" fill="black" /><text x="10" y="20" class="base">';

        parts[1] = getSwordsmen(tokenId);

        parts[2] = '</text><text x="10" y="40" class="base">';

        parts[3] = getArchers(tokenId);

        parts[4] = '</text><text x="10" y="60" class="base">';

        parts[5] = getHorses(tokenId);

        parts[6] = '</text><text x="10" y="80" class="base">';

        parts[7] = getElephants(tokenId);

        parts[8] = '</text><text x="10" y="100" class="base">';

        parts[9] = getDragons(tokenId);

        parts[10] = '</text><text x="10" y="120" class="base">';

        parts[11] = getWizards(tokenId);

        parts[12] = '</text></svg>';

        string memory output = string(abi.encodePacked(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8]));
        output = string(abi.encodePacked(output, parts[9], parts[10], parts[11], parts[12]));
        
        string memory json = Base64.encode(bytes(string(abi.encodePacked('{"name": "Sheet #', toString(tokenId), '", "description": "Army is randomized table top RPG style stats generated and stored on chain. Feel free to use Army in any way you want.", "image": "data:image/svg+xml;base64,', Base64.encode(bytes(output)), '"}'))));
        output = string(abi.encodePacked('data:application/json;base64,', json));

        return output;
    }

    function claim(uint256 tokenId) public payable nonReentrant {
        require(price <= msg.value, "Ether value sent is not correct");
        require(tokenId > 8000 && tokenId < 11976, "Token ID invalid");
        _safeMint(_msgSender(), tokenId);
    }
    
    function claimForLoot(uint256 tokenId) public nonReentrant {
        require(tokenId > 0 && tokenId < 8001, "Token ID invalid");
        require(loot.ownerOf(tokenId) == msg.sender, "Not Loot owner");
        _safeMint(_msgSender(), tokenId);
    }
    
    function ownerClaim(uint256 tokenId) public nonReentrant onlyOwner {
        require(tokenId > 11975 && tokenId < 12001, "Token ID invalid");
        _safeMint(owner(), tokenId);
    }
    
    function withdraw() public onlyOwner {
        payable(owner()).transfer(address(this).balance);
    }    
    
    function toString(uint256 value) internal pure returns (string memory) {
    // Inspired by OraclizeAPI's implementation - MIT license
    // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }
    
    constructor() ERC721("Army Loot", "ARMY") Ownable() {}
}
function random(string memory input) internal pure returns (uint256) {
    return (uint256(keccak256(abi.encodePacked(input))) % 7) + 1;
}

//0.02 ETH
// mirror a dice roll