mirror of
https://github.com/tiennm99/miti99bot.git
synced 2026-09-19 02:23:14 +00:00
173 lines
5.7 KiB
Go
173 lines
5.7 KiB
Go
package misc
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"image"
|
|
"image/color"
|
|
"image/draw"
|
|
"image/gif"
|
|
"math"
|
|
)
|
|
|
|
const (
|
|
wheelBetaSize = 320
|
|
wheelBetaRadius = 118
|
|
wheelBetaSpinDuration = 7
|
|
wheelBetaHoldDuration = 3
|
|
wheelBetaSpinDelay = 20
|
|
wheelBetaSpinFrames = wheelBetaSpinDuration * 100 / wheelBetaSpinDelay
|
|
wheelBetaHoldFrames = wheelBetaHoldDuration * 100 / wheelBetaSpinDelay
|
|
wheelBetaHoldDelay = wheelBetaSpinDelay
|
|
wheelBetaDuration = wheelBetaSpinDuration + wheelBetaHoldDuration
|
|
wheelBetaCelebrateFrames = 8
|
|
wheelBetaPointerAngle = 0.0
|
|
)
|
|
|
|
const (
|
|
wheelBetaBackgroundColorIndex byte = 0
|
|
wheelBetaInkColorIndex byte = 1
|
|
wheelBetaPaperColorIndex byte = 2
|
|
wheelBetaShadowColorIndex byte = 10
|
|
wheelBetaBevelColorIndex byte = 11
|
|
wheelBetaHighlightColorIndex byte = 12
|
|
wheelBetaSparkColorIndex byte = 13
|
|
)
|
|
|
|
var wheelBetaPalette = color.Palette{
|
|
color.RGBA{R: 250, G: 251, B: 252, A: 255},
|
|
color.RGBA{R: 30, G: 35, B: 42, A: 255},
|
|
color.RGBA{R: 255, G: 255, B: 255, A: 255},
|
|
color.RGBA{R: 221, G: 75, B: 75, A: 255},
|
|
color.RGBA{R: 245, G: 180, B: 64, A: 255},
|
|
color.RGBA{R: 76, G: 167, B: 120, A: 255},
|
|
color.RGBA{R: 78, G: 135, B: 206, A: 255},
|
|
color.RGBA{R: 147, G: 103, B: 196, A: 255},
|
|
color.RGBA{R: 52, G: 197, B: 197, A: 255},
|
|
color.RGBA{R: 235, G: 117, B: 164, A: 255},
|
|
color.RGBA{R: 204, G: 212, B: 224, A: 255},
|
|
color.RGBA{R: 82, G: 94, B: 111, A: 255},
|
|
color.RGBA{R: 255, G: 244, B: 206, A: 255},
|
|
color.RGBA{R: 255, G: 218, B: 89, A: 255},
|
|
}
|
|
|
|
var wheelBetaSliceColorIndexes = []byte{3, 4, 5, 6, 7, 8, 9}
|
|
|
|
func renderWheelOfNamesBetaGIF(options []string, winner int) ([]byte, error) {
|
|
if len(options) == 0 {
|
|
return nil, fmt.Errorf("no options")
|
|
}
|
|
if winner < 0 || winner >= len(options) {
|
|
return nil, fmt.Errorf("winner index %d out of range %d", winner, len(options))
|
|
}
|
|
|
|
frames := make([]*image.Paletted, 0, wheelBetaSpinFrames+wheelBetaHoldFrames)
|
|
delays := make([]int, 0, wheelBetaSpinFrames+wheelBetaHoldFrames)
|
|
profile := newWheelBetaSpinProfile(len(options), winner, nil)
|
|
for i := 0; i < wheelBetaSpinFrames; i++ {
|
|
t := float64(i) / float64(wheelBetaSpinFrames-1)
|
|
frames = append(frames, renderWheelBetaFrameWithStatus(options, winner, profile.rotationAt(t), false, profile.statusAt(t)))
|
|
delays = append(delays, wheelBetaSpinDelay)
|
|
}
|
|
for i := 0; i < wheelBetaHoldFrames; i++ {
|
|
celebrateStep := i
|
|
if celebrateStep >= wheelBetaCelebrateFrames {
|
|
celebrateStep = -1
|
|
}
|
|
frames = append(frames, renderWheelBetaFrameWithCelebration(options, winner, profile.finalRotation, true, "", celebrateStep))
|
|
delays = append(delays, wheelBetaHoldDelay)
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
err := gif.EncodeAll(&buf, &gif.GIF{
|
|
Image: frames,
|
|
Delay: delays,
|
|
LoopCount: -1,
|
|
Config: image.Config{
|
|
ColorModel: wheelBetaPalette,
|
|
Width: wheelBetaSize,
|
|
Height: wheelBetaSize,
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
func renderWheelBetaFrame(options []string, winner int, rotation float64, reveal bool) *image.Paletted {
|
|
return renderWheelBetaFrameWithStatus(options, winner, rotation, reveal, "")
|
|
}
|
|
|
|
func renderWheelBetaFrameWithStatus(options []string, winner int, rotation float64, reveal bool, status string) *image.Paletted {
|
|
return renderWheelBetaFrameWithCelebration(options, winner, rotation, reveal, status, -1)
|
|
}
|
|
|
|
func renderWheelBetaFrameWithCelebration(options []string, winner int, rotation float64, reveal bool, status string, celebrateStep int) *image.Paletted {
|
|
rect := image.Rect(0, 0, wheelBetaSize, wheelBetaSize)
|
|
img := image.NewPaletted(rect, wheelBetaPalette)
|
|
draw.Draw(img, rect, image.NewUniform(wheelBetaPalette[wheelBetaBackgroundColorIndex]), image.Point{}, draw.Src)
|
|
|
|
cx, cy := wheelBetaSize/2, wheelBetaSize/2
|
|
drawWheelDropShadow(img, cx, cy)
|
|
|
|
segment := 2 * math.Pi / float64(len(options))
|
|
r2 := wheelBetaRadius * wheelBetaRadius
|
|
for y := cy - wheelBetaRadius; y <= cy+wheelBetaRadius; y++ {
|
|
for x := cx - wheelBetaRadius; x <= cx+wheelBetaRadius; x++ {
|
|
dx, dy := x-cx, y-cy
|
|
if dx*dx+dy*dy > r2 {
|
|
continue
|
|
}
|
|
theta := normalizeAngle(math.Atan2(float64(dy), float64(dx)) - rotation)
|
|
idx := int(theta / segment)
|
|
colorIndex := wheelBetaSliceColorIndexes[idx%len(wheelBetaSliceColorIndexes)]
|
|
img.SetColorIndex(x, y, colorIndex)
|
|
}
|
|
}
|
|
|
|
currentIndex := currentWheelBetaIndex(len(options), rotation)
|
|
pointerColor := wheelBetaSliceColorIndexes[currentIndex%len(wheelBetaSliceColorIndexes)]
|
|
drawWheelLighting(img, cx, cy)
|
|
drawWheelRim(img, cx, cy)
|
|
drawWinnerCelebration(img, celebrateStep)
|
|
drawWheelSliceLabels(img, options, rotation)
|
|
drawCircle(img, cx, cy, 24, wheelBetaPaperColorIndex)
|
|
drawCircle(img, cx, cy, 18, wheelBetaInkColorIndex)
|
|
drawPointer(img, cx+wheelBetaRadius, cy, pointerColor)
|
|
drawCenteredText(img, "WHEELOFNAMES BETA", cy+wheelBetaRadius+34, wheelBetaInkColorIndex)
|
|
label := status
|
|
if label == "" {
|
|
label = "CURRENT"
|
|
}
|
|
value := wheelBetaDisplayText(options[currentIndex], 28)
|
|
if reveal {
|
|
label = "RESULT"
|
|
value = wheelBetaDisplayText(options[winner], 28)
|
|
}
|
|
drawStatusBand(img, label, value)
|
|
return img
|
|
}
|
|
|
|
func finalWheelRotation(optionCount, winner int) float64 {
|
|
return finalWheelRotationWithOffset(optionCount, winner, 0)
|
|
}
|
|
|
|
func finalWheelRotationWithOffset(optionCount, winner int, sliceOffset float64) float64 {
|
|
segment := 2 * math.Pi / float64(optionCount)
|
|
return wheelBetaPointerAngle - (float64(winner)+0.5+sliceOffset)*segment
|
|
}
|
|
|
|
func currentWheelBetaIndex(optionCount int, rotation float64) int {
|
|
segment := 2 * math.Pi / float64(optionCount)
|
|
return int(normalizeAngle(wheelBetaPointerAngle-rotation) / segment)
|
|
}
|
|
|
|
func normalizeAngle(theta float64) float64 {
|
|
theta = math.Mod(theta, 2*math.Pi)
|
|
if theta < 0 {
|
|
theta += 2 * math.Pi
|
|
}
|
|
return theta
|
|
}
|