-
Notifications
You must be signed in to change notification settings - Fork 21
/
CryptoBeauty.sol
177 lines (139 loc) · 5.17 KB
/
CryptoBeauty.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
pragma solidity ^0.4.25;
import { SafeMath } from "github.com/OpenZeppelin/zeppelin-solidity/contracts/math/SafeMath.sol";
contract Randomness {
address owner;
modifier onlyOwner(){
require(msg.sender == owner);
_;
}
constructor() public{
owner = msg.sender;
}
bytes32 private seed = "hi";
function rand(bytes32 key) public onlyOwner returns (bytes32) {
seed ^= key;
return keccak256(abi.encodePacked(key, seed, now, block.difficulty, "台灣きन्दी한حَNo.1 :) "));
}
}
contract CryptoBeauty {
using SafeMath for uint256;
struct Card {
uint256 id;
uint256 birthTime;
uint256 modelId; // from 1 to 2^256-1, 0 is unspecified
}
address public owner;
uint256 public drawCardCost = 1;
uint256 public totalCardCount;
uint256 public totalModelCount;
uint256 public totalRareScore;
uint256 internal lastDrawCardId;
address internal randContractAddr;
// modelId map to card
mapping (uint256 => Card[]) public URcards;
mapping (uint256 => Card[]) public SSRcards;
mapping (uint256 => Card[]) public SRcards;
mapping (uint256 => Card[]) public Rcards;
mapping (uint256 => Card[]) public Ncards;
mapping (uint256 => address) public cardIndexToHolder;
mapping (address => uint256) public holdCardCount;
mapping (address => uint256) public playerDeposit;
mapping (address => uint256) public playerRareScore;
mapping (address => bool) public hasPlayed;
mapping (uint256 => uint256) public cardIndexToRareScore;
mapping (uint256 => bool) public modelCardHasCreated;
mapping (uint256 => uint256) public modelIdToURcardCount;
mapping (uint256 => uint256) public modelIdToSSRcardCount;
mapping (uint256 => uint256) public modelIdToSRcardCount;
mapping (uint256 => uint256) public modelIdToRcardCount;
mapping (uint256 => uint256) public modelIdToNcardCount;
modifier onlyOwner(){
require(msg.sender == owner);
_;
}
constructor() public {
owner = msg.sender;
}
// internal functions
// transfer card holder
function _transferHolder(address _to, uint256 _cardId) internal {
address _from = cardIndexToHolder[_cardId];
uint256 _rareScore = cardIndexToRareScore[_cardId];
holdCardCount[_from].sub(1);
cardIndexToHolder[_cardId] = _to;
holdCardCount[_to].add(1);
playerRareScore[_from].sub(_rareScore);
playerRareScore[_to].add(_rareScore);
}
function random(uint256 seed) internal returns (uint) {
return uint(keccak256(abi.encodePacked(block.difficulty, block.timestamp, seed, Randomness(randContractAddr).rand(bytes32(seed)))));
}
function randNumToCardIndexByModel(uint randNum, uint modelId) internal returns (uint) {
uint256 newRandNum = random(randNum.add(uint256(msg.sender).div(1000)));
uint rareScore = randNum.mod(1000);
if(rareScore == 0) return URcards[modelId][newRandNum.mod(URcards[modelId].length)].id;
else if(rareScore > 0 && rareScore <= 20) return SSRcards[modelId][newRandNum.mod(SSRcards[modelId].length)].id;
else if(rareScore > 20 && rareScore <= 120) return SRcards[modelId][newRandNum.mod(SRcards[modelId].length)].id;
else if(rareScore > 120 && rareScore <= 370) return Rcards[modelId][newRandNum.mod(Rcards[modelId].length)].id;
else return Ncards[modelId][newRandNum.mod(Ncards[modelId].length)].id;
}
// public functions
function createNewCard (
uint _rareScore,
uint _modelId,
address _holder
)
public
onlyOwner
returns (uint)
{
uint256 newCardId = totalCardCount;
Card memory _card = Card({
id: newCardId,
modelId: _modelId,
birthTime: uint256(block.timestamp)
});
if(_rareScore == 1000) URcards[_modelId].push(_card);
else if(_rareScore == 50) SSRcards[_modelId].push(_card);
else if(_rareScore == 10) SRcards[_modelId].push(_card);
else if(_rareScore == 4) Rcards[_modelId].push(_card);
else if(_rareScore == 1) Ncards[_modelId].push(_card);
else revert("Invalid card rare score!");
cardIndexToRareScore[newCardId] = _rareScore;
// increment total
totalRareScore.add(_rareScore);
totalCardCount.add(1);
if(!modelCardHasCreated[_modelId]) {
modelCardHasCreated[_modelId] = true;
totalModelCount.add(1);
}
_transferHolder(_holder, newCardId);
return newCardId;
}
function drawCard(address _to, uint _modelId) public onlyOwner returns (uint256 rareScore) {
// first visit -> draw card for free
if(hasPlayed[_to])
playerDeposit[_to].sub(drawCardCost);
else hasPlayed[_to] = true;
// rand draw a model if the given id is 0
uint modelId;
if(_modelId == 0){
modelId = random((lastDrawCardId).mod(totalModelCount)).add(1);
}
lastDrawCardId = index;
uint index = randNumToCardIndexByModel(random(modelId), modelId);
_transferHolder(_to, index);
// return how rare the card is
return cardIndexToRareScore[index];
}
function deposit() public payable {
playerDeposit[msg.sender].add(msg.value);
}
function withdrawDeposit(uint amount) public {
playerDeposit[msg.sender].sub(amount);
msg.sender.transfer(amount);
}
function setRandContractAddr(address _addr) public onlyOwner {
randContractAddr = _addr;
}
}