life.gno
3.43 Kb · 174 lines
1package fish
2
3import (
4 "chain/runtime"
5 "crypto/sha256"
6 "strconv"
7 "time"
8)
9
10func Register(cur realm, id int, stake int64) {
11 caller := requireUser(cur)
12 body := must(id)
13 if body.owner != caller {
14 panic("fish: owner")
15 }
16 if body.inMatch {
17 panic("fish: match")
18 }
19 if body.mustHeal {
20 panic("fish: heal")
21 }
22 guardMovable(body)
23 if tooHurt(body) {
24 panic("fish: hp")
25 }
26 if walletInSea(caller) {
27 panic("fish: one")
28 }
29 if !arenaStake(stake) {
30 panic("fish: stake")
31 }
32 takeExact(stake)
33 now := time.Now().Unix()
34 body.pool = stake
35 body.inMatch = true
36 body.boutPaid = false
37 body.startUnix = now
38 body.endUnix = 0
39 body.lastCombatMilli = -1
40 body.nextMoveMilli = 0
41 body.burstUntil = 0
42 body.nextBurstAt = 0
43 body.springBorn = -1
44 placeSwimmer(body)
45 clearDamage(id)
46}
47
48func Leave(cur realm, id int) {
49 caller := requireUser(cur)
50 takeExact(0)
51 body := must(id)
52 if body.owner != caller {
53 panic("fish: owner")
54 }
55 if !body.inMatch {
56 panic("fish: match")
57 }
58 nowMs := time.Now().UnixMilli()
59 if body.lastCombatMilli >= 0 && nowMs < body.lastCombatMilli+combatLockMs {
60 panic("fish: stay")
61 }
62 returnCheers(body, cur)
63 stake := body.pool
64 body.pool = 0
65 body.inMatch = false
66 body.boutPaid = false
67 clearDamage(id)
68 send(caller, stake, cur)
69}
70
71func SettleMatch(cur realm, id int) {
72 requireUser(cur)
73 takeExact(0)
74 body := must(id)
75 if !body.inMatch {
76 panic("fish: match")
77 }
78 _ = body
79 panic("fish: sea")
80}
81
82func CommitLay(cur realm, id int) {
83 caller := requireUser(cur)
84 body := must(id)
85 if body.owner != caller {
86 panic("fish: owner")
87 }
88 guardMovable(body)
89 left := body.bouts - body.layBoutsUsed
90 if left < 3 {
91 panic("fish: bouts")
92 }
93 takeExact(layFee)
94 payMint(layFee, cur)
95 body.layBoutsUsed = body.bouts
96 body.layOpen = true
97 body.layHeight = runtime.ChainHeight()
98}
99
100func SettleLay(cur realm, id int) int {
101 requireUser(cur)
102 takeExact(0)
103 body := must(id)
104 if !body.layOpen {
105 panic("fish: lay")
106 }
107 height := runtime.ChainHeight()
108 if height < body.layHeight+layBlocks {
109 panic("fish: early")
110 }
111 trait := traitFrom(body.id, body.layHeight, height, time.Now().Unix())
112 body.layOpen = false
113 return issue(body.owner, body.name+" fry", body.rarity, body.size, trait)
114}
115
116func Upgrade(cur realm, keep, food int) int {
117 caller := requireUser(cur)
118 if keep == food {
119 panic("fish: upgrade")
120 }
121 a := must(keep)
122 b := must(food)
123 if a.owner != caller || b.owner != caller {
124 panic("fish: owner")
125 }
126 guardMovable(a)
127 guardMovable(b)
128 if a.rarity != b.rarity || a.size != b.size || a.trait != b.trait {
129 panic("fish: pair")
130 }
131 if a.rarity != "common" {
132 panic("fish: roll")
133 }
134 if a.bouts < 1 || b.bouts < 1 {
135 panic("fish: bouts")
136 }
137 takeExact(upgradeFee)
138 send(upgradeSink, upgradeFee, cur)
139 name := a.name
140 size := a.size
141 trait := a.trait
142 burnBody(a)
143 burnBody(b)
144 return issue(caller, name, "uncommon", size, trait)
145}
146
147func burnBody(body *fishBody) {
148 burnGRC(body.id)
149 body.burned = true
150 body.owner = address("")
151 body.seller = address("")
152 body.price = 0
153 body.listed = false
154 body.pool = 0
155 body.inMatch = false
156 body.layOpen = false
157}
158
159func traitFrom(id int, commitHeight, settleHeight, unix int64) string {
160 raw := strconv.Itoa(id) + ":" + strconv.FormatInt(commitHeight, 10) + ":" + strconv.FormatInt(settleHeight, 10) + ":" + strconv.FormatInt(unix, 10)
161 sum := sha256.Sum256([]byte(raw))
162 var n int64
163 for i := 0; i < len(sum); i++ {
164 n = (n*256 + int64(sum[i])) % 3
165 }
166 switch n {
167 case 0:
168 return "swift"
169 case 1:
170 return "fang"
171 default:
172 return "hide"
173 }
174}