forked from fluofoxxo/outrun
-
Notifications
You must be signed in to change notification settings - Fork 2
/
randomChaoWheelChoice.go
273 lines (259 loc) · 7.27 KB
/
randomChaoWheelChoice.go
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
package roulette
import (
"errors"
"math/rand"
"strconv"
"github.com/fluofoxxo/outrun/consts"
"github.com/fluofoxxo/outrun/enums"
)
type LogicChao struct { // TODO: Find a better way to replace this!
ID string `json:"chaoId"`
Rarity int64 `json:"rarity"`
Hidden int64 `json:"hidden"` // this value is required, but is never really used in game... Best to keep at "1"
Status int64 `json:"status"` // enums.ChaoStatus*
Level int64 `json:"level"`
Dealing int64 `json:"setStatus"` // enums.ChaoDealing*
Acquired int64 `json:"acquired"` // flag
}
func GetRandomChaoWheelCharacter(count int, oldCharacters bool) ([]string, error) {
// Reference: https://eli.thegreenplace.net/2010/01/22/weighted-random-generation-in-python/
totalWeights := []float64{}
charList := []string{}
runningTotal := float64(0)
prizes := consts.RandomChaoWheelCharacterPrizes
if oldCharacters {
prizes = consts.RandomChaoWheelCharacterPrizes114
}
for cid, weight := range prizes {
charList = append(charList, cid)
runningTotal += weight
totalWeights = append(totalWeights, runningTotal)
}
finalCharList := []string{}
for count > 0 {
count--
gotChar := false
rnd := rand.Float64() * runningTotal
for i, total := range totalWeights {
if rnd < total {
finalCharList = append(finalCharList, charList[i])
gotChar = true
break
}
}
if !gotChar {
return []string{}, errors.New("should not have gotten here")
}
}
return finalCharList, nil
}
func GetRandomChaoWheelChao(rarity int64, count int, oldChao bool) ([]string, error) {
// Reference: https://eli.thegreenplace.net/2010/01/22/weighted-random-generation-in-python/
totalWeights := []float64{}
chaoList := []string{}
runningTotal := float64(0)
prizes := consts.RandomChaoWheelChaoPrizes
if oldChao {
prizes = consts.RandomChaoWheelChaoPrizes114
}
for chid, weight := range prizes {
if string(chid[2]) == strconv.Itoa(int(rarity)) {
chaoList = append(chaoList, chid)
runningTotal += weight
totalWeights = append(totalWeights, runningTotal)
}
}
finalChaoList := []string{}
for count > 0 {
count--
gotChao := false
rnd := rand.Float64() * runningTotal
for i, total := range totalWeights {
if rnd < total {
finalChaoList = append(finalChaoList, chaoList[i])
gotChao = true
break
}
}
if !gotChao {
return []string{}, errors.New("should not have gotten here")
}
}
return finalChaoList, nil
}
func GetRandomChaoRouletteItems(rarities []int64, allowedCharacters, allowedChao []string, oldCharacters bool) ([]string, []int64, error) { // TODO: Possibly rename to GetRandomChaoWheelItems?
//failsafeTimeout := int64(3) // seconds, used to break in case of infinite loop
//debugOriginalTime := time.Now().Unix()
/*dprint := func(a ...interface{}) {
if config.CFile.DebugPrints {
log.Println(a...)
}
}*/
allowedRarity := func(x int) bool {
/*
if x == 100 { // character
return len(allowedCharacters) != 0 // if any characters allowed, return true
}
searchingForRarity := strconv.Itoa(x)[0] // get byte
for _, chao := range allowedChao {
if chao[2] == searchingForRarity {
return true
}
}
return false
*/
return true // Don't check for duplicate Chao
}
//chaoAllowed := func(chid string) bool {
_ = func(chid string) bool {
// Checks if chid is in allowedChao
for _, chao := range allowedChao {
if chao == chid {
return true
}
}
return false
}
//characterAllowed := func(cid string) bool {
_ = func(cid string) bool {
// Checks if cid is in allowedCharacters
/*
for _, char := range allowedCharacters {
if char == cid {
return true
}
}
return false
*/
return true // Don't check for duplicate characters
}
getUnusedChao := func(rarity int64) (string, error) {
// Implies that there is a Chao of the given rarity allowed! Check with allowedRarity.
chao, err := GetRandomChaoWheelChao(rarity, 1, oldCharacters)
// Don't check for unused Chao
return chao[0], err
/*
if err != nil {
return "", err
}
for !chaoAllowed(chao[0]) { // get allowed Chao
if time.Now().Unix()-failsafeTimeout > debugOriginalTime { // break out of long loop (debug)
return enums.ChaoIDStrHeroChao, nil
}
dprint("searching for allowed chao ", chao[0])
chao, err = GetRandomChaoWheelChao(rarity, 1)
if err != nil {
return "", err
}
}
return chao[0], nil
*/
}
getUnusedCharacter := func() (string, error) {
// Implies that there are characters available! Check with len(allowedCharacters) != 0 or allowedRarity.
char, err := GetRandomChaoWheelCharacter(1, oldCharacters)
// Don't check for unused characters
return char[0], err
/*
if err != nil {
return "", err
}
for !characterAllowed(char[0]) {
if time.Now().Unix()-failsafeTimeout > debugOriginalTime { // break out of long loop (debug)
return enums.CTStrTails, nil
}
dprint("searching for allowed character ", char)
char, err = GetRandomChaoWheelCharacter(1)
if err != nil {
return "", err
}
}
return char[0], nil
*/
}
newRarities := rarities
items := []string{}
for i, rarity := range rarities {
if rarity == 100 { // Character
if !allowedRarity(100) { // if character not possible
rarity = 2 // degrade to rarity 2 Chao
} else {
char, err := getUnusedCharacter()
if err != nil {
return []string{}, []int64{}, err
}
items = append(items, char)
}
}
if rarity == 2 { // Rarity 2 Chao
if !allowedRarity(2) { // if impossible
rarity = 1 // degrade
} else {
chao, err := getUnusedChao(2)
if err != nil {
return []string{}, []int64{}, err
}
items = append(items, chao)
}
}
if rarity == 1 { // Rarity 1 Chao
if !allowedRarity(1) { // if impossible
rarity = 0
} else {
chao, err := getUnusedChao(1)
if err != nil {
return []string{}, []int64{}, err
}
items = append(items, chao)
}
}
if rarity == 0 { // Rarity 1 Chao
if !allowedRarity(0) { // if impossible
// TODO: what do we do now?
items = append(items, enums.ChaoIDStrHeroChao)
} else {
chao, err := getUnusedChao(0)
if err != nil {
return []string{}, []int64{}, err
}
items = append(items, chao)
}
}
newRarities[i] = rarity
}
return items, newRarities, nil
}
func ChooseChaoRouletteItem(items []string, weights []int64) (string, error) {
index, err := ChooseChaoRouletteItemIndex(items, weights)
if err != nil {
return "", err
}
return items[index], nil
}
func ChooseChaoRouletteItemIndex(items []string, weights []int64) (int, error) {
// TODO: Remake! This is probably the worst way to do weighted selection!
if len(items) != len(weights) { // Vibe check
return -1, errors.New("'items' and 'weights' lengths do not match")
}
possibilities := []string{}
appendXTimes := func(s string, t int64) {
for t > 0 {
possibilities = append(possibilities, s)
t--
}
}
for i, item := range items {
weight := weights[i]
appendXTimes(item, weight)
}
// select randomly from possibilities
posIndex := rand.Intn(len(possibilities))
selection := possibilities[posIndex]
// return index of selection from items
for i, item := range items {
if selection == item {
return i, nil
}
}
return -1, errors.New("selection not found in 'items'") // This should never, ever happen
}