文件 1 的 11:Combo721Base.sol
pragma solidity 0.8.11;
import "../Interfaces/IERC721.sol";
import "../Interfaces/IERC721Receiver.sol";
import "../Interfaces/IERC721Metadata.sol";
import "../Interfaces/IERC721Enumerable.sol";
import "../Interfaces/IERC165.sol";
abstract contract Combo721Base is IERC165, IERC721, IERC721Metadata, IERC721Enumerable {
mapping(uint256 => address) private _owners;
mapping(address => uint256) private _balances;
mapping(uint256 => address) private _approvals;
mapping(address => mapping(address => bool)) private _operators;
string private _name;
string private _symbol;
mapping(address => mapping(uint256 => uint256)) private _ownedTokens;
mapping(uint256 => uint256) private _ownedTokensIndex;
uint256[] private _allTokens;
mapping(uint256 => uint256) private _allTokensIndex;
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId ||
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
interfaceId == type(IERC721Enumerable).interfaceId;
}
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _owners[tokenId] != address(0);
}
function balanceOf(address owner) public view returns (uint256) {
require(owner != address(0), "ERC721: balance query for the zero address");
return _balances[owner];
}
function ownerOf(uint256 tokenId) public view returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "ERC721: owner query for nonexistent token");
return owner;
}
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
address owner = ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
function approve(address to, uint256 tokenId) public {
address owner = ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(
msg.sender == owner || isApprovedForAll(owner, msg.sender),
"ERC721: approve caller is not owner nor approved for all"
);
_approvals[tokenId] = to;
emit Approval(owner, to, tokenId);
}
function getApproved(uint256 tokenId) public view returns (address) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _approvals[tokenId];
}
function setApprovalForAll(address operator, bool approved) public {
_operators[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function isApprovedForAll(address owner, address operator) public view returns (bool) {
return _operators[owner][operator];
}
function safeTransferFrom( address from, address to, uint256 tokenId) public {
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory _data) public {
require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransfer(from, to, tokenId, _data);
}
function transferFrom(address from, address to, uint256 tokenId) public {
require( _isApprovedOrOwner(msg.sender, tokenId), "ERC721: transfer caller is not owner nor approved");
_transfer(from, to, tokenId);
}
function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal {
_transfer(from, to, tokenId);
if (to.code.length > 0) {
bytes4 ret = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data);
require(ret == IERC721Receiver.onERC721Received.selector, "receiver");
}
}
function _transfer( address from, address to, uint256 tokenId) internal {
require(ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
require(to != address(0), "ERC721: transfer to the zero address");
_innerTransfer(from, to, tokenId);
_balances[from] -= 1;
_approvals[tokenId] = address(0x0);
}
function _innerTransfer(address from, address to, uint256 tokenId) internal {
_beforeTokenTransfer(from, to, tokenId);
if (from == address(0)) {
_addTokenToAllTokensEnumeration(tokenId);
} else if (from != to) {
_removeTokenFromOwnerEnumeration(from, tokenId);
}
if (to == address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId);
} else if (to != from) {
_addTokenToOwnerEnumeration(to, tokenId);
}
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual { }
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_innerTransfer(address(0), to, tokenId);
}
function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) {
require(index < balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
return _ownedTokens[owner][index];
}
function totalSupply() public view returns (uint256) {
return _allTokens.length;
}
function tokenByIndex(uint256 index) public view returns (uint256) {
require(index < totalSupply(), "ERC721Enumerable: global index out of bounds");
return _allTokens[index];
}
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
uint256 length = balanceOf(to);
_ownedTokens[to][length] = tokenId;
_ownedTokensIndex[tokenId] = length;
}
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
uint256 lastTokenIndex = balanceOf(from) - 1;
uint256 tokenIndex = _ownedTokensIndex[tokenId];
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId;
_ownedTokensIndex[lastTokenId] = tokenIndex;
}
delete _ownedTokensIndex[tokenId];
delete _ownedTokens[from][lastTokenIndex];
}
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
uint256 lastTokenIndex = _allTokens.length - 1;
uint256 tokenIndex = _allTokensIndex[tokenId];
uint256 lastTokenId = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenId;
_allTokensIndex[lastTokenId] = tokenIndex;
delete _allTokensIndex[tokenId];
_allTokens.pop();
}
}
文件 2 的 11:CoreMimic.sol
pragma solidity 0.8.11;
import { ILore } from "../Interfaces/ILore.sol";
import { Combo721Base } from "./Combo721Base.sol";
import { MimicMeta } from "./MimicMeta.sol";
import { CoreShield } from "./CoreShield.sol";
abstract contract CoreMimic is Combo721Base {
MimicMeta cMeta;
CoreShield cShield;
address aGuild;
mapping(uint256 => address) POKED_CONTRACTS;
mapping(uint256 => uint256) POKED_IDS;
mapping(uint256 => uint256) MATURITIES;
mapping(uint256 => bool) SKIP_ID_REPLACEMENT;
uint256 guildGenesis;
uint256 guildPrice;
uint256 guildRate18;
event Poke(uint256 indexed _mimicId, address _targetContract, uint256 _targetId);
event Rite(uint256 indexed _mimicId);
event SkipIdReplace(uint256 indexed _mimicId, bool _trueOrFalse);
function init(address _guild, address _shield, address _meta) external {
require(aGuild == address(0x0), "already initialized");
aGuild = _guild;
cShield = CoreShield(_shield);
cMeta = MimicMeta(_meta);
}
function maturityHash(address _targetContract, uint256 _targetId) internal pure returns (uint) {
return uint(keccak256(abi.encodePacked("MH", _targetContract, _targetId)));
}
function maturityHashForMimic(uint256 _mimicId) internal view returns (uint) {
return maturityHash(POKED_CONTRACTS[_mimicId], POKED_IDS[_mimicId]);
}
function _pokeShared(uint256 _mimicId, address _targetContract, uint256 _targetId) internal {
require(_isApprovedOrOwner(msg.sender, _mimicId), "*SLAP*, not your mimic!");
require(_targetContract != address(0x0), "that's not poking, that's pointing");
require(_targetContract != address(this), "this would cause poor mimic to explode");
require(_targetContract != address(cShield), "this is essence-ally a bad idea");
uint256 mimicMatHashMimicId = MATURITIES[maturityHashForMimic(_mimicId)];
require(mimicMatHashMimicId != _mimicId, "mature mimics won't poke");
uint256 targetMatHashMimicId = MATURITIES[maturityHash(_targetContract, _targetId)];
require(targetMatHashMimicId == 0x0, "mimic honor code violation");
POKED_CONTRACTS[_mimicId] = _targetContract;
POKED_IDS[_mimicId] = _targetId;
emit Poke(_mimicId, _targetContract, _targetId);
}
function _riteShared(uint256 _mimicId) internal view returns (address pokedContract, uint256 matHash) {
require(_isApprovedOrOwner(msg.sender, _mimicId), "*SLAP*, not your mimic!");
pokedContract = POKED_CONTRACTS[_mimicId];
require(pokedContract != address(0x0), "need to poke first");
matHash = maturityHashForMimic(_mimicId);
uint256 matHashMimicId = MATURITIES[matHash];
require(matHashMimicId != _mimicId, "mimic is already mature");
require(matHashMimicId == 0x0, "mimic honor code violation");
}
function mimic_IsAdult(uint256 _mimicId) external view returns (bool) {
if (_exists(_mimicId) && (MATURITIES[maturityHashForMimic(_mimicId)] == _mimicId)) {
return true;
}
return false;
}
function mimic_Poke721(uint256 _mimicId, address _pokeNftContract, uint256 _pokeNftId) external {
(bool success, bytes memory ownerResult) = _pokeNftContract.staticcall(abi.encodeWithSignature("ownerOf(uint256)", _pokeNftId));
require(success, "not a valid 721");
address owner721 = abi.decode(ownerResult, (address));
uint256 auraCount = cShield.activeCount(owner721);
require(auraCount == 0, "blocked by active shield");
_pokeShared(_mimicId, _pokeNftContract, _pokeNftId);
}
function mimic_Poke1155(uint256 _mimicId, address _pokeNftContract, uint256 _pokeNftId, address _ownerOf1155) external {
(bool success, bytes memory countResult) = _pokeNftContract.staticcall(abi.encodeWithSignature("balanceOf(address,uint256)", _ownerOf1155, _pokeNftId));
require(success, "not a valid 1155");
require(abi.decode(countResult, (uint256)) > 0, "not a valid owner of the NFT");
require(cShield.activeCount(_ownerOf1155) == 0, "blocked by active shield");
_pokeShared(_mimicId, _pokeNftContract, _pokeNftId);
}
function mimic_Relax(uint256 _mimicId) external {
require(_isApprovedOrOwner(msg.sender, _mimicId), "*SLAP*, not your mimic!");
require(MATURITIES[maturityHashForMimic(_mimicId)] != _mimicId, "adult mimics can never relax");
delete POKED_CONTRACTS[_mimicId];
delete POKED_IDS[_mimicId];
emit Poke(_mimicId, address(0x0), 0x0);
}
function mimic_RiteOf721(uint256 _mimicId) external {
(address pokedContract, uint256 matHash) = _riteShared(_mimicId);
(bool success, bytes memory ownerResult) = pokedContract.staticcall(abi.encodeWithSignature("ownerOf(uint256)", POKED_IDS[_mimicId]));
require(success, "rite of 721 failed");
MATURITIES[matHash] = _mimicId;
cShield.cMimic_Mint(abi.decode(ownerResult, (address)), _mimicId);
emit Rite(_mimicId);
}
function mimic_RiteOf1155(uint256 _mimicId, address _ownerOf1155) external {
require(_ownerOf1155 != address(0x0), "nowner!");
(address pokedContract, uint256 matHash) = _riteShared(_mimicId);
(bool success, bytes memory ownershipCountResult) = pokedContract.staticcall(abi.encodeWithSignature("balanceOf(address,uint256)", _ownerOf1155, POKED_IDS[_mimicId]));
require(success, "rite of 1155 failed");
require(abi.decode(ownershipCountResult, (uint256)) > 0, "not the owner you're looking for");
MATURITIES[matHash] = _mimicId;
cShield.cMimic_Mint(_ownerOf1155, _mimicId);
emit Rite(_mimicId);
}
function mimic_SkipIdReplacement(uint256 _mimicId, bool _trueOrFalse) external {
require(_isApprovedOrOwner(msg.sender, _mimicId), "*SLAP*, not your mimic!");
SKIP_ID_REPLACEMENT[_mimicId] = _trueOrFalse;
emit SkipIdReplace(_mimicId, _trueOrFalse);
}
function tokenURI(uint256 _mimicId) public view override returns (string memory) {
require(msg.sender.code.length == 0, "nah!");
require(_exists(_mimicId), "no such mimic");
address pokedContract = POKED_CONTRACTS[_mimicId];
if (pokedContract == address(0x0)) {
return cMeta.mimicNative(_mimicId, "");
}
uint256 pokedId = POKED_IDS[_mimicId];
uint256 matHash = maturityHash(pokedContract, pokedId);
uint256 matHashMimicId = MATURITIES[matHash];
if ( (matHashMimicId != _mimicId) && (matHashMimicId != 0x0) ) {
return cMeta.mimicNative(_mimicId, "");
}
(bool success, bytes memory uriBytes) = pokedContract.staticcall(abi.encodeWithSignature("tokenURI(uint256)", pokedId));
if (success) {
if (SKIP_ID_REPLACEMENT[_mimicId]) {
return abi.decode(uriBytes, (string));
}
return uriIdReplace(abi.decode(uriBytes, (string)), pokedId);
}
(success, uriBytes) = pokedContract.staticcall(abi.encodeWithSignature("uri(uint256)", pokedId));
if (success) {
if (SKIP_ID_REPLACEMENT[_mimicId]) {
return abi.decode(uriBytes, (string));
}
return uriIdReplace(abi.decode(uriBytes, (string)), pokedId);
}
if (matHashMimicId == _mimicId) {
return cMeta.mimicNative(_mimicId, "X");
}
return cMeta.mimicNative(_mimicId, "x");
}
function cGuild_Mint(address _owner) external {
require(msg.sender == aGuild);
_mint(_owner, totalSupply() + 1);
}
function lore() external view returns (string memory) {
return ILore(aGuild).lore();
}
function uriIdReplace(string memory uri, uint tokenId) internal pure returns (string memory) {
bytes memory s = bytes(uri);
uint sLen = s.length;
if (sLen < 4) {
return uri;
}
bytes memory t = uint256ToPaddedBytesHex(tokenId);
uint sLenM3 = sLen - 3;
bytes memory o = bytes(uri);
uint si = 0;
uint oi = 0;
while (si < sLenM3) {
if (s[si] == "{" && s[si+1] == "i" && s[si+2] == "d" && s[si+3] == "}") {
o = bytes.concat(o, new bytes(60));
for (uint ti = 0; ti < 64; ti++) {
o[oi++] = t[ti];
}
si += 4;
break;
} else {
oi++;
si++;
}
}
while (si < sLenM3) {
if (s[si] == "{" && s[si+1] == "i" && s[si+2] == "d" && s[si+3] == "}") {
o = bytes.concat(o, new bytes(60));
for (uint ti = 0; ti < 64; ti++) {
o[oi++] = t[ti];
}
si += 4;
} else {
o[oi++] = s[si++];
}
}
while (si < sLen) {
o[oi++] = s[si++];
}
return string(o);
}
function uint256ToPaddedBytesHex(uint256 value) internal pure returns (bytes memory) {
bytes memory o = new bytes(64);
uint256 mask = 0xf;
uint i = 63;
while (true) {
uint8 end = uint8(value & mask);
if (end < 10) {
o[i] = bytes1(end + 48);
} else {
o[i] = bytes1(end + 87);
}
value >>= 4;
if (i == 0) {
break;
}
i--;
}
return o;
}
function d() external pure returns (string memory) {
return "Rm9yIG15IGZhdGhlciwgd2hvIG5ldmVyIGNvbXBsYWlucyBhYm91dCBteSBob25vcmFibGUgbWlzY2hpZWYu";
}
}
文件 10 的 11:MimicMeta.sol
pragma solidity 0.8.11;
contract MimicMeta {
address aMimic;
address aShield;
string constant COLOR = "COLORS";
string constant EYE = "EYE";
string constant MOUTH = "MOUTH";
string constant TOOTH = "TOOTH";
string[] private colors = [
"#abffbc",
"#abffbc",
"#abffbc",
"#abffbc",
"#abffbc",
"#abfff5",
"#abfff5",
"#abfff5",
"#abfff5",
"#abfff5",
"#aaddff",
"#aaddff",
"#aaddff",
"#aaddff",
"#aaddff",
"#abb2ff",
"#abb2ff",
"#abb2ff",
"#abb2ff",
"#abb2ff",
"#ffa8a8",
"#ffa8a8",
"#ffa8a8",
"#ffa8a8",
"#ffa8a8",
"#ffd2aa",
"#ffd2aa",
"#ffd2aa",
"#ffd2aa",
"#ffd2aa",
"#ffaafa",
"#ffaafa",
"#ffaafa",
"#ffaafa",
"#ffaafa",
"#f72585",
"#f72585",
"#a025f7",
"#a025f7",
"#2538f7",
"#2538f7",
"#f5f725",
"#f5f725",
"#27fb6b",
"#27fb6b",
"#f51000",
"#f51000",
"#edc531",
"#dee2e6",
"#33333a"
];
string[] private eyes = [
"0",
"0",
"0",
"0",
"0",
"0",
"O",
"O",
"O",
"O",
"O",
"O",
"^",
"^",
"^",
"^",
"^",
"^",
"'",
"'",
"'",
"'",
"'",
"'",
"~",
"~",
"~",
"~",
"~",
"~",
"-",
"-",
"-",
"-",
"-",
"-",
"o",
"o",
"o",
"o",
"o",
"o",
"#",
"@",
"$"
];
string[] private left_mouths = [
"[",
"[",
"(",
"(",
"{",
"{",
"\\",
":"
];
string[] private right_mouths = [
"]",
"]",
")",
")",
"}",
"}",
"/",
":"
];
string[] private teeth = [
"=",
"_",
"."
];
function init(address _mimic, address _shield) external {
require(aMimic == address(0x0));
aMimic = _mimic;
aShield = _shield;
}
function randomUS(uint256 input, string memory input2) internal pure returns (uint) {
return uint256(keccak256(abi.encodePacked(input, input2)));
}
function pluck(uint256 tokenId, string memory keyPrefix, string[] memory sourceArray) internal pure returns (string memory) {
uint256 rand = randomUS(tokenId, keyPrefix);
string memory output = sourceArray[rand % sourceArray.length];
return output;
}
function mimicNative(uint256 _tokenId, string calldata _eye) external view returns (string memory output) {
require(msg.sender == aMimic);
string memory tidString = uintToString(_tokenId);
string memory json = Base64.encodeNew(bytes(string(abi.encodePacked(
'{',
'"name": "Mimic #',
tidString,
'",'
'"description": "Mimic #',
tidString,
'\\n\\n'
'Mimics are mischeivous but honorable digital creatures that live deep within the ethereum blockchain.'
'\\n\\n'
'They are known to interact in interesting ways with other NFTs from throughout the ethereum ecosystem.'
'",'
'"image": "data:image/svg+xml;base64,',
Base64.encodeNew(bytes(imageFace(_tokenId, _eye))),
'"'
'}'
))));
output = string(abi.encodePacked('data:application/json;base64,', json));
}
function imageFace(uint256 _mimicId, string memory _eye) internal view returns (string memory) {
string memory color = pluck(_mimicId, COLOR, colors);
if (bytes(_eye).length == 0) {
_eye = pluck(_mimicId, EYE, eyes);
}
string memory tooth = pluck(_mimicId, TOOTH, teeth);
uint256 rand_mouth = randomUS(_mimicId, MOUTH) % left_mouths.length;
return string(abi.encodePacked(
'<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350">'
'<style>'
'.base { fill: ', color, '; font-family: monospace; text-anchor: middle; font-size: 80px; } '
'@keyframes glow { 0% { opacity: 0.2; } 3% { opacity: 0.9; } 30% { opacity: 0.2 } 70% {opacity: 0.9} } '
'.face { animation: glow 3s linear infinite alternate } '
'.f1 { animation-delay: 0.5s } '
'.f2 { animation-delay: 1.5s } '
'.f3 { animation-delay: 0.7s } '
'.f4 { animation-delay: 2.5s } '
'.f5 { animation-delay: 0.3s } '
'.f6 { animation-delay: 2.2s } '
'.d1 { animation-duration: 2.7s } '
'.d2 { animation-duration: 2.8s } '
'.d3 { animation-duration: 2.9s } '
'.d4 { animation-duration: 3.0s } '
'.d5 { animation-duration: 3.1s } '
'.d6 { animation-duration: 3.2s } '
'.d7 { animation-duration: 3.3s } '
'</style>'
'<rect width="100%" height="100%" fill="black" />'
'<text x="100" y="130" class="base face f1 d1">',
_eye,
'</text>'
'<text x="250" y="130" class="base face f2 d2">',
_eye,
'</text>'
'<text x="100" y="260" class="base face f3 d3">',
left_mouths[rand_mouth],
'</text>'
'<text x="150" y="260" class="base face f4 d4">',
tooth,
'</text>'
'<text x="200" y="260" class="base face f5 d5">',
tooth,
'</text>'
'<text x="250" y="260" class="base face f6 d6">',
right_mouths[rand_mouth],
'</text>'
'<rect class="face d7" width="100%" height="100%" fill="#000000ee" />'
'</svg>'
));
}
function shieldNative(uint256 _tokenId, bool _active) external view returns (string memory output) {
require(msg.sender == aShield);
string memory tidString = uintToString(_tokenId);
string memory aura;
if (_active) {
aura = "Active";
} else {
aura = "Inactive";
}
string memory json = Base64.encodeNew(bytes(string(abi.encodePacked(
'{',
'"name": "Mimic Shield #',
tidString,
'",'
'"description": "Mimic Shield #',
tidString,
'\\n\\n'
'A Mimic Shield is the reified character of a mimic that has undertaken a sacred rite to become an adult.'
'\\n\\n'
"The aura of a shield is of great significance to mimics and their ritual practice."
'",'
'"attributes": [{ "trait_type": "Aura", "value": "',
aura,
'"}],'
'"image": "data:image/svg+xml;base64,',
Base64.encodeNew(bytes(imageShield(_tokenId, _active))),
'"'
'}'
))));
output = string(abi.encodePacked('data:application/json;base64,', json));
}
function imageShield(uint256 _mimicId, bool _active) internal view returns (string memory) {
string memory color = pluck(_mimicId, COLOR, colors);
string memory aura = shieldAura(_active);
return string(abi.encodePacked(
'<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350">'
'<style>'
'.base { fill: ', color, '; font-family: monospace; text-anchor: middle; font-size: 30px; }'
'@keyframes glow { 0% { opacity: 0.4; } 3% { opacity: 0.9; } 30% { opacity: 0.4 } 70% {opacity: 0.9} }'
'@keyframes rx {0% { transform: translateX(11px) } 2% { transform: translateX(83px) } 3% { transform: translateX(227px) } 4% { transform: translateX(19px) } 5% { transform: translateX(160px) } 6% { transform: translateX(252px) } 7% { transform: translateX(177px) } 8% { transform: translateX(64px) } 9% { transform: translateX(317px) } 10% { transform: translateX(192px) } 11% { transform: translateX(310px) } 12% { transform: translateX(92px) } 13% { transform: translateX(184px) } 14% { transform: translateX(248px) } 15% { transform: translateX(64px) } 16% { transform: translateX(205px) } 17% { transform: translateX(243px) } 18% { transform: translateX(11px) } 19% { transform: translateX(348px) } 20% { transform: translateX(232px) } 21% { transform: translateX(191px) } 22% { transform: translateX(313px) } 23% { transform: translateX(154px) } 24% { transform: translateX(4px) } 25% { transform: translateX(105px) } 26% { transform: translateX(140px) } 27% { transform: translateX(229px) } 28% { transform: translateX(262px) } 29% { transform: translateX(200px) } 30% { transform: translateX(107px) } 31% { transform: translateX(30px) } 32% { transform: translateX(193px) } 33% { transform: translateX(105px) } 34% { transform: translateX(222px) } 35% { transform: translateX(64px) } 36% { transform: translateX(285px) } 37% { transform: translateX(224px) } 38% { transform: translateX(96px) } 39% { transform: translateX(284px) } 40% { transform: translateX(32px) } 41% { transform: translateX(216px) } 42% { transform: translateX(273px) } 43% { transform: translateX(28px) } 44% { transform: translateX(6px) } 45% { transform: translateX(303px) } 46% { transform: translateX(177px) } 47% { transform: translateX(145px) } 48% { transform: translateX(103px) } 49% { transform: translateX(85px) } 50% { transform: translateX(342px) } 51% { transform: translateX(201px) } 52% { transform: translateX(321px) } 53% { transform: translateX(152px) } 54% { transform: translateX(204px) } 55% { transform: translateX(267px) } 56% { transform: translateX(19px) } 57% { transform: translateX(137px) } 58% { transform: translateX(1px) } 59% { transform: translateX(314px) } 60% { transform: translateX(174px) } 61% { transform: translateX(143px) } 62% { transform: translateX(132px) } 63% { transform: translateX(130px) } 64% { transform: translateX(219px) } 65% { transform: translateX(281px) } 66% { transform: translateX(272px) } 67% { transform: translateX(244px) } 68% { transform: translateX(311px) } 69% { transform: translateX(110px) } 70% { transform: translateX(59px) } 71% { transform: translateX(72px) } 72% { transform: translateX(285px) } 73% { transform: translateX(296px) } 74% { transform: translateX(319px) } 75% { transform: translateX(96px) } 76% { transform: translateX(192px) } 77% { transform: translateX(293px) } 78% { transform: translateX(26px) } 79% { transform: translateX(174px) } 80% { transform: translateX(246px) } 81% { transform: translateX(276px) } 82% { transform: translateX(255px) } 83% { transform: translateX(298px) } 84% { transform: translateX(137px) } 85% { transform: translateX(296px) } 86% { transform: translateX(112px) } 87% { transform: translateX(32px) } 88% { transform: translateX(66px) } 89% { transform: translateX(288px) } 90% { transform: translateX(76px) } 91% { transform: translateX(116px) } 92% { transform: translateX(158px) } 93% { transform: translateX(280px) } 94% { transform: translateX(161px) } 95% { transform: translateX(81px) } 96% { transform: translateX(260px) } 97% { transform: translateX(185px) } 98% { transform: translateX(213px) } 99% { transform: translateX(102px) } 100% { transform: translateX(160px) }}'
'@keyframes ry {0% { transform: translateY(41px) } 1% { transform: translateY(320px) } 2% { transform: translateY(239px) } 3% { transform: translateY(220px) } 4% { transform: translateY(158px) } 5% { transform: translateY(301px) } 6% { transform: translateY(335px) } 8% { transform: translateY(39px) } 9% { transform: translateY(171px) } 10% { transform: translateY(305px) } 11% { transform: translateY(148px) } 12% { transform: translateY(152px) } 13% { transform: translateY(168px) } 14% { transform: translateY(178px) } 15% { transform: translateY(57px) } 16% { transform: translateY(94px) } 17% { transform: translateY(307px) } 18% { transform: translateY(19px) } 19% { transform: translateY(249px) } 20% { transform: translateY(48px) } 21% { transform: translateY(332px) } 22% { transform: translateY(234px) } 23% { transform: translateY(302px) } 24% { transform: translateY(139px) } 25% { transform: translateY(255px) } 26% { transform: translateY(80px) } 27% { transform: translateY(184px) } 28% { transform: translateY(87px) } 29% { transform: translateY(337px) } 30% { transform: translateY(83px) } 31% { transform: translateY(204px) } 32% { transform: translateY(182px) } 33% { transform: translateY(348px) } 34% { transform: translateY(285px) } 35% { transform: translateY(273px) } 36% { transform: translateY(273px) } 37% { transform: translateY(99px) } 38% { transform: translateY(206px) } 39% { transform: translateY(217px) } 40% { transform: translateY(345px) } 41% { transform: translateY(329px) } 42% { transform: translateY(128px) } 43% { transform: translateY(61px) } 44% { transform: translateY(79px) } 45% { transform: translateY(302px) } 46% { transform: translateY(153px) } 47% { transform: translateY(98px) } 48% { transform: translateY(294px) } 49% { transform: translateY(189px) } 50% { transform: translateY(347px) } 51% { transform: translateY(20px) } 52% { transform: translateY(300px) } 53% { transform: translateY(216px) } 54% { transform: translateY(285px) } 55% { transform: translateY(72px) } 56% { transform: translateY(53px) } 57% { transform: translateY(178px) } 58% { transform: translateY(292px) } 59% { transform: translateY(340px) } 60% { transform: translateY(273px) } 61% { transform: translateY(197px) } 62% { transform: translateY(71px) } 63% { transform: translateY(279px) } 64% { transform: translateY(247px) } 65% { transform: translateY(120px) } 66% { transform: translateY(22px) } 67% { transform: translateY(20px) } 68% { transform: translateY(217px) } 69% { transform: translateY(12px) } 70% { transform: translateY(246px) } 71% { transform: translateY(219px) } 72% { transform: translateY(347px) } 73% { transform: translateY(252px) } 74% { transform: translateY(155px) } 75% { transform: translateY(290px) } 76% { transform: translateY(163px) } 77% { transform: translateY(132px) } 78% { transform: translateY(146px) } 79% { transform: translateY(121px) } 80% { transform: translateY(227px) } 81% { transform: translateY(189px) } 82% { transform: translateY(311px) } 83% { transform: translateY(243px) } 84% { transform: translateY(83px) } 85% { transform: translateY(59px) } 86% { transform: translateY(44px) } 87% { transform: translateY(75px) } 88% { transform: translateY(312px) } 89% { transform: translateY(161px) } 90% { transform: translateY(31px) } 91% { transform: translateY(310px) } 92% { transform: translateY(119px) } 93% { transform: translateY(292px) } 94% { transform: translateY(187px) } 95% { transform: translateY(176px) } 96% { transform: translateY(20px) } 97% { transform: translateY(312px) } 98% { transform: translateY(342px) } 99% { transform: translateY(47px) } 100% { transform: translateY(336px) }}'
'.aura { animation: glow 5s ease infinite alternate-reverse }'
'.shield { opacity: 0.6 }'
'.xv { animation-name: rx; animation-timing-function: step-end; animation-iteration-count: infinite; }'
'.yv { animation: ry 87s step-end infinite }'
'.t { transform: rotateY(260deg) }'
'.f1 { animation-delay: -0.5s }'
'.f2 { animation-delay: -10.5s }'
'.f3 { animation-delay: -15.7s }'
'.f4 { animation-delay: -32.5s }'
'.f5 { animation-delay: -37.3s }'
'.f6 { animation-delay: -32.2s }'
'.a1 { animation-duration: 31.11s }'
'.a2 { animation-duration: 37.91s }'
'.a3 { animation-duration: 42.31s }'
'.a4 { animation-duration: 47.71s }'
'.a5 { animation-duration: 131.11s }'
'.a6 { animation-duration: 141.01s }'
'</style>'
'<defs>'
'<radialGradient id="rgaura">'
'<stop offset="30%" stop-color="transparent" />'
'<stop offset="70%" stop-color="',
color,
'" stop-opacity="0.30" />'
'</radialGradient>'
'</defs>'
'<rect width="100%" height="100%" fill="111111" />',
shieldFeatures(_mimicId),
'<rect class="aura a4" x="0%" y="0" width="100%" height="100%" fill="#aaddff11" />',
aura,
'<g transform="translate(175, 175)">', shield(_mimicId, color), '</g>'
'</svg>'
));
}
function shieldFeatures(uint256 _mimicId) internal view returns (string memory) {
string memory eye = pluck(_mimicId, EYE, eyes);
string memory tooth = pluck(_mimicId, TOOTH, teeth);
uint256 rand_mouth = randomUS(_mimicId, MOUTH) % left_mouths.length;
return string(abi.encodePacked(
'<g class="xv f2 a1"><g class="yv f1 a3"><text class="base aura f1">', eye, '</text></g></g>'
'<g class="xv f4 a2"><g class="yv f3 a4"><text class="base aura f3">', eye, '</text></g></g>'
'<g class="xv f3 a3"><g class="yv f4 a5"><text class="base aura f2">', left_mouths[rand_mouth], '</text></g></g>'
'<g class="xv f1 a4"><g class="yv f2 a6"><text class="base aura f4">', tooth, '</text></g></g>'
'<g class="xv f5 a5"><g class="yv f2 a1"><text class="base aura f2">', tooth, '</text></g></g>'
'<g class="xv f2 a6"><g class="yv f5 a2"><text class="base aura f5">', right_mouths[rand_mouth], '</text></g></g>'
));
}
function shieldAura(bool _active) internal pure returns (string memory) {
if (_active) {
return '<rect width="200%" height="200%" x="-175" y="-175" fill="url(#rgaura)" />';
}
return "";
}
function shield(uint256 _mimicId, string memory _color) internal pure returns (string memory) {
string memory vdx = uintToString((randomUS(_mimicId, "VDX") % 100)+25);
string memory vdy = uintToString((randomUS(_mimicId, "VDY") % 100)+25);
string memory vvx = uintToString((randomUS(_mimicId, "VVX") % 100)+25);
string memory hdx = uintToString((randomUS(_mimicId, "HDX") % 100)+25);
string memory hdy = uintToString((randomUS(_mimicId, "HDY") % 100)+25);
string memory hhy = uintToString((randomUS(_mimicId, "HHY") % 100)+25);
return string(abi.encodePacked(
poly1(_color, vdx, vdy, vvx),
poly2(_color, vdx, vdy, vvx),
poly3(_color, hdx, hdy, hhy),
poly4(_color, hdx, hdy, hhy)
));
}
function poly1(string memory _color, string memory _x, string memory _y, string memory _z) internal pure returns (string memory) {
return string(abi.encodePacked(
'<polygon fill="', _color, '" class="shield aura f2 a1" points="0,0 ', _x, ',-', _y, ' 0,-', _z, ' -', _x, ',-', _y, '" />'
));
}
function poly2(string memory _color, string memory _x, string memory _y, string memory _z) internal pure returns (string memory) {
return string(abi.encodePacked(
'<polygon fill="', _color, '" class="shield aura f3 a2" points="0,0 ', _x, ',', _y, ' 0,', _z, ' -', _x, ',', _y, '" />'
));
}
function poly3(string memory _color, string memory _x, string memory _y, string memory _z) internal pure returns (string memory) {
return string(abi.encodePacked(
'<polygon fill="', _color, '" class="shield aura f4 a3" points="0,0 ', _x, ',', _y, ' ', _z, ',0 ', _x, ',-', _y, '" />'
));
}
function poly4(string memory _color, string memory _x, string memory _y, string memory _z) internal pure returns (string memory) {
return string(abi.encodePacked(
'<polygon fill="', _color, '" class="shield aura f5 a4" points="0,0 -', _x, ',', _y, ' -', _z, ',0 -', _x, ',-', _y, '" />'
));
}
function uintToString(uint256 value) internal pure returns (string memory) {
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);
}
}
library Base64 {
string internal constant TABLE_ENCODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
function encodeNew(bytes memory data) internal pure returns (string memory) {
if (data.length == 0) return '';
string memory table = TABLE_ENCODE;
uint256 encodedLen = 4 * ((data.length + 2) / 3);
string memory result = new string(encodedLen + 32);
assembly {
mstore(result, encodedLen)
let tablePtr := add(table, 1)
let dataPtr := data
let endPtr := add(dataPtr, mload(data))
let resultPtr := add(result, 32)
for {} lt(dataPtr, endPtr) {}
{
dataPtr := add(dataPtr, 3)
let input := mload(dataPtr)
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and(shr( 6, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and( input, 0x3F))))
resultPtr := add(resultPtr, 1)
}
switch mod(mload(data), 3)
case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) }
case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) }
}
return result;
}
}