feat: 重构任务奖励系统并增加宠物技能和皮肤奖励
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
将任务奖励逻辑重构到单独的文件中,增加对宠物技能和皮肤奖励的支持,优化任务完成处理流程
This commit is contained in:
@@ -71,6 +71,10 @@ func roundFloat32(val float32, decimals int) float32 {
|
||||
return float32(math.Round(float64(val*shift))) / shift
|
||||
}
|
||||
|
||||
func randomFloat32Range(r *rand.Rand, min, max float32) float32 {
|
||||
return min + float32(r.Float64())*(max-min)
|
||||
}
|
||||
|
||||
// 预处理矩阵:自动修正越界参数,确保合规
|
||||
func ProcessOffspringMatrix(mat [4][5]float32) [4][5]float32 {
|
||||
var processedMat [4][5]float32
|
||||
@@ -118,71 +122,62 @@ func calculateMatrixHash(mm MonsterMatrix) string {
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// GenerateRandomParentMatrix 调整随机参数范围,解决暗色问题,贴合你的示例
|
||||
// GenerateRandomParentMatrix 生成色域更大的父矩阵,同时抬高黑场避免整只精灵发黑
|
||||
func GenerateRandomParentMatrix() MonsterMatrix {
|
||||
// 1. 保留高熵种子逻辑(确保唯一性,不变)
|
||||
salt := "player-matrix-random-seed"
|
||||
now := time.Now().UnixNano()
|
||||
randomNum := rand.Int63()
|
||||
seed := now ^ randomNum ^ int64(hashString(salt))
|
||||
r := rand.New(rand.NewSource(seed))
|
||||
|
||||
// 2. 调整随机参数范围(贴合你的示例,解决暗色问题)
|
||||
// 对比你的示例:亮度大多在[-30,30],对比度[0.7,1.7],饱和度[0.4,1.4],偏移[-10,10]
|
||||
params := struct {
|
||||
brightness float32 // 从[-125,125]调整为[-30,60],避免过低亮度
|
||||
contrast float32 // 从[0.4,2.2]调整为[0.7,1.7],贴合你的示例
|
||||
saturation float32 // 从[0.1,2.0]调整为[0.4,1.4],避免低饱和度灰暗
|
||||
hueRotate float32 // 从[-180,180]调整为[-50,50],减少极端色相导致的暗沉
|
||||
rOffset float32 // 从[-50,50]调整为[-10,10],避免亮度偏移过大
|
||||
gOffset float32 // 同上
|
||||
bOffset float32 // 同上
|
||||
}{
|
||||
brightness: float32(r.Float64()*90 - 30), // [-30, 60](贴合示例亮度范围,减少暗色)
|
||||
contrast: float32(r.Float64()*1.0 + 0.7), // [0.7, 1.7](与你的示例完全匹配)
|
||||
saturation: float32(r.Float64()*1.0 + 0.4), // [0.4, 1.4](与你的示例完全匹配)
|
||||
hueRotate: float32(r.Float64()*100 - 50), // [-50, 50](避免极端色相)
|
||||
rOffset: float32(r.Float64()*20 - 10), // [-10, 10](小幅亮度偏移,贴合示例)
|
||||
gOffset: float32(r.Float64()*20 - 10), // 同上
|
||||
bOffset: float32(r.Float64()*20 - 10), // 同上
|
||||
matrix := newIdentityMatrix()
|
||||
dominant := r.Intn(3)
|
||||
accent := (dominant + 1 + r.Intn(2)) % 3
|
||||
baseLift := randomFloat32Range(r, 10, 24)
|
||||
|
||||
for row := 0; row < 3; row++ {
|
||||
for col := 0; col < 3; col++ {
|
||||
value := randomFloat32Range(r, -0.22, 0.22)
|
||||
if row == col {
|
||||
value = randomFloat32Range(r, 0.8, 1.45)
|
||||
}
|
||||
if row == dominant && col == dominant {
|
||||
value += randomFloat32Range(r, 0.35, 0.7)
|
||||
}
|
||||
if row == accent && col == accent {
|
||||
value += randomFloat32Range(r, 0.1, 0.3)
|
||||
}
|
||||
if row == dominant && col != row {
|
||||
value += randomFloat32Range(r, -0.12, 0.28)
|
||||
}
|
||||
matrix[row][col] = clampFloat32(roundFloat32(value, FloatPrecision), MatrixMinVal, MatrixMaxVal)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 矩阵计算逻辑不变(确保与你的示例参数分布一致)
|
||||
matrix := newIdentityMatrix()
|
||||
contrast := params.contrast
|
||||
matrix[0][0] *= contrast
|
||||
matrix[1][1] *= contrast
|
||||
matrix[2][2] *= contrast
|
||||
matrix[0][4] = baseLift + randomFloat32Range(r, -5, 10)
|
||||
matrix[1][4] = baseLift + randomFloat32Range(r, -5, 10)
|
||||
matrix[2][4] = baseLift + randomFloat32Range(r, -5, 10)
|
||||
matrix[dominant][4] += randomFloat32Range(r, 8, 18)
|
||||
matrix[accent][4] += randomFloat32Range(r, 2, 8)
|
||||
|
||||
sat := params.saturation
|
||||
grayR, grayG, grayB := float32(0.299)*(1-sat), float32(0.587)*(1-sat), float32(0.114)*(1-sat)
|
||||
matrix[0][0] = grayR + sat*matrix[0][0]
|
||||
matrix[0][1], matrix[0][2] = grayG, grayB
|
||||
matrix[1][0] = grayR
|
||||
matrix[1][1] = grayG + sat*matrix[1][1]
|
||||
matrix[1][2] = grayB
|
||||
matrix[2][0] = grayR
|
||||
matrix[2][1] = grayG
|
||||
matrix[2][2] = grayB + sat*matrix[2][2]
|
||||
avgBrightness := (matrix[0][4] + matrix[1][4] + matrix[2][4]) / 3
|
||||
if avgBrightness < 12 {
|
||||
lift := 12 - avgBrightness + randomFloat32Range(r, 0, 6)
|
||||
for row := 0; row < 3; row++ {
|
||||
matrix[row][4] += lift
|
||||
}
|
||||
}
|
||||
if matrix[dominant][4] < 16 {
|
||||
matrix[dominant][4] = 16 + randomFloat32Range(r, 0, 10)
|
||||
}
|
||||
|
||||
angle := params.hueRotate * float32(math.Pi) / 180
|
||||
cos, sin := float32(math.Cos(float64(angle))), float32(math.Sin(float64(angle)))
|
||||
r1, g1, b1 := matrix[0][0], matrix[0][1], matrix[0][2]
|
||||
r2, g2, b2 := matrix[1][0], matrix[1][1], matrix[1][2]
|
||||
for row := 0; row < 3; row++ {
|
||||
for col := 0; col < 3; col++ {
|
||||
matrix[row][col] = clampFloat32(roundFloat32(matrix[row][col], FloatPrecision), MatrixMinVal, MatrixMaxVal)
|
||||
}
|
||||
matrix[row][4] = clampFloat32(roundFloat32(matrix[row][4], FloatPrecision), BrightnessMinVal, BrightnessMaxVal)
|
||||
}
|
||||
|
||||
matrix[0][0] = r1*cos - r2*sin
|
||||
matrix[0][1] = r1*sin + r2*cos
|
||||
matrix[1][0] = g1*cos - g2*sin
|
||||
matrix[1][1] = g1*sin + g2*cos
|
||||
matrix[2][0] = b1*cos - b2*sin
|
||||
matrix[2][1] = b1*sin + b2*cos
|
||||
|
||||
// 亮度偏移:范围缩小后,避免过暗/过亮
|
||||
matrix[0][4] = params.brightness + params.rOffset
|
||||
matrix[1][4] = params.brightness + params.gOffset
|
||||
matrix[2][4] = params.brightness + params.bOffset
|
||||
|
||||
// 4. 封装为MonsterMatrix(不变)
|
||||
parent := MonsterMatrix{
|
||||
Matrix: matrix,
|
||||
Hash: "",
|
||||
|
||||
@@ -32,6 +32,7 @@ type MapNode struct {
|
||||
IsBroadcast uint32 `gorm:"type:int;default:0;comment:'广播模型ID(0表示不广播)'" json:"is_broadcast"`
|
||||
|
||||
IsGroupBoss uint32 `gorm:"type:int;default:0;comment:'是否为组队Boss(0否1是)'" json:"is_group_boss" description:"是否为组队Boss"`
|
||||
PkFlag uint32 `gorm:"type:int;default:0;comment:'是否单精灵对战(0否1是)'" json:"pk_flag" description:"是否单精灵对战"`
|
||||
|
||||
TriggerPlotID uint32 `gorm:"default:0;comment:'触发剧情ID(0表示无剧情)'" json:"trigger_plot_id" description:"触发剧情ID"`
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@ type TaskConfig struct {
|
||||
// 奖励配置
|
||||
ItemRewardIds []uint32 `gorm:"not null;type:jsonb;default:'[]';comment:'绑定奖励物品ID数组,关联item_gift表主键'" json:"item_reward_ids" description:"奖励物品数组"`
|
||||
ElfRewardIds uint32 `gorm:"not null;default:0;comment:'绑定奖励精灵ID,关联elf_gift表主键'" json:"elf_reward_ids" description:"绑定奖励精灵ID"`
|
||||
RewardPetID uint32 `gorm:"not null;default:0;comment:'宠物相关奖励生效的目标精灵ID,0表示不对已有精灵发放'" json:"reward_pet_id" description:"目标精灵ID"`
|
||||
TrainSkillIDs []uint32 `gorm:"not null;type:jsonb;default:'[]';comment:'任务奖励的特训技能ID数组'" json:"train_skill_ids" description:"特训技能奖励数组"`
|
||||
SkinIDs []uint32 `gorm:"not null;type:jsonb;default:'[]';comment:'任务奖励的皮肤ID数组'" json:"skin_ids" description:"皮肤奖励数组"`
|
||||
|
||||
//绑定奖励
|
||||
TitleRewardIds uint32 `gorm:"not null;default:0;comment:'绑定奖励称号'" json:"title_reward_ids" description:"绑定奖励称号"`
|
||||
|
||||
@@ -2,7 +2,6 @@ package service
|
||||
|
||||
import (
|
||||
"blazing/common/data"
|
||||
"blazing/common/utils"
|
||||
"blazing/cool"
|
||||
"blazing/modules/config/model"
|
||||
"context"
|
||||
@@ -43,18 +42,52 @@ func (s *ShinyService) ModifyBefore(ctx context.Context, method string, param g.
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (s *ShinyService) RandShiny(id uint32) *data.GlowFilter {
|
||||
|
||||
func (s *ShinyService) listByPetID(id uint32) []model.ColorfulSkin {
|
||||
var ret []model.ColorfulSkin
|
||||
|
||||
// 执行 Raw SQL 并扫描返回值
|
||||
dbm_enable(s.Model).
|
||||
Wheref(`bind_elf_ids @> ?::jsonb`, id).
|
||||
Wheref(`jsonb_typeof(bind_elf_ids) = ?`, "array").Scan(&ret)
|
||||
Wheref(`jsonb_typeof(bind_elf_ids) = ?`, "array").
|
||||
Scan(&ret)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func pickColorfulSkinByWeight(items []model.ColorfulSkin) *model.ColorfulSkin {
|
||||
if len(items) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
totalWeight := 0
|
||||
for _, item := range items {
|
||||
if item.ElfProbability > 0 {
|
||||
totalWeight += int(item.ElfProbability)
|
||||
}
|
||||
}
|
||||
if totalWeight <= 0 {
|
||||
return &items[grand.Intn(len(items))]
|
||||
}
|
||||
|
||||
randomValue := grand.Intn(totalWeight)
|
||||
for i := range items {
|
||||
weight := int(items[i].ElfProbability)
|
||||
if weight <= 0 {
|
||||
continue
|
||||
}
|
||||
if randomValue < weight {
|
||||
return &items[i]
|
||||
}
|
||||
randomValue -= weight
|
||||
}
|
||||
|
||||
return &items[0]
|
||||
}
|
||||
|
||||
func (s *ShinyService) RandShiny(id uint32) *data.GlowFilter {
|
||||
ret := s.listByPetID(id)
|
||||
|
||||
for _, v := range ret {
|
||||
//print(v.ID)
|
||||
|
||||
id := v.ID
|
||||
|
||||
if grand.Meet(int(v.ElfProbability), 1000) {
|
||||
@@ -74,32 +107,16 @@ func (s *ShinyService) RandShiny(id uint32) *data.GlowFilter {
|
||||
|
||||
var t = data.GetDef()
|
||||
|
||||
t.ColorMatrixFilter = model.GenerateRandomOffspringMatrix().Get()
|
||||
t.ColorMatrixFilter = model.GenerateRandomParentMatrix().Get()
|
||||
|
||||
return &t
|
||||
}
|
||||
|
||||
func (s *ShinyService) RandomByWeightShiny(id uint32) *data.GlowFilter {
|
||||
|
||||
var ret []model.ColorfulSkin
|
||||
|
||||
// 执行 Raw SQL 并扫描返回值
|
||||
dbm_enable(s.Model).
|
||||
Wheref(`bind_elf_ids @> ?::jsonb`, id).
|
||||
Wheref(`jsonb_typeof(bind_elf_ids) = ?`, "array").Scan(&ret)
|
||||
if len(ret) == 0 {
|
||||
r := pickColorfulSkinByWeight(s.listByPetID(id))
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
var rets []model.ColorfulSkin
|
||||
var props []int
|
||||
|
||||
for _, v := range ret {
|
||||
rets = append(rets, v)
|
||||
props = append(props, int(v.ElfProbability))
|
||||
|
||||
}
|
||||
|
||||
r, _ := utils.RandomByWeight(rets, props)
|
||||
if cool.Config.ServerInfo.IsVip == 0 {
|
||||
m := cool.DBM(s.Model).Where("id", r.ID)
|
||||
m.Increment("refresh_count", 1)
|
||||
|
||||
BIN
modules/model.test
Executable file
BIN
modules/model.test
Executable file
Binary file not shown.
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"blazing/common/utils"
|
||||
"blazing/cool"
|
||||
configmodel "blazing/modules/config/model"
|
||||
config "blazing/modules/config/service"
|
||||
"blazing/modules/player/model"
|
||||
|
||||
@@ -27,54 +28,58 @@ func (s *TalkService) reset(flag int) {
|
||||
s.dbm(s.Model).Where("talk_id", flag).Data("count", 0, "last_reset_time", gtime.Now()).Update()
|
||||
}
|
||||
|
||||
//实现挖矿次数确认
|
||||
|
||||
func (s *TalkService) Cheak(mapid uint32, flag int) (int, bool) {
|
||||
|
||||
m1 := s.dbm(s.Model)
|
||||
|
||||
func (s *TalkService) progress(flag int) (uint32, *model.Talk, *configmodel.MineralCollectionConfig, bool) {
|
||||
var talks *model.Talk
|
||||
m1.Where("talk_id", flag).Scan(&talks)
|
||||
s.dbm(s.Model).Where("talk_id", flag).Scan(&talks)
|
||||
|
||||
cfg := config.NewTalkConfigService().GetCache(flag)
|
||||
if cfg == nil {
|
||||
return 0, talks, nil, false
|
||||
}
|
||||
if talks == nil {
|
||||
|
||||
return 0, true //如果表里没有记载数据,那么就可以直接挖矿
|
||||
return 0, nil, cfg, true
|
||||
}
|
||||
|
||||
c := config.NewTalkConfigService().GetCache(flag)
|
||||
|
||||
//因为这个是挖一次更新一次,而且是实时更新的,如果更新日期是今天,那么就可以确认不用再重置,否则就需要重置挖矿记录
|
||||
if c == nil {
|
||||
return 0, false //没在地图
|
||||
}
|
||||
switch c.Limit {
|
||||
switch cfg.Limit {
|
||||
case 0:
|
||||
if !utils.IsToday(talks.LastResetTime) {
|
||||
|
||||
s.reset(flag)
|
||||
return int(0), true
|
||||
return 0, talks, cfg, true
|
||||
}
|
||||
|
||||
case 1:
|
||||
if !utils.IsWEEK(talks.LastResetTime) {
|
||||
|
||||
s.reset(flag)
|
||||
return int(0), true
|
||||
return 0, talks, cfg, true
|
||||
}
|
||||
case 2:
|
||||
if !utils.IsMon(talks.LastResetTime) {
|
||||
|
||||
s.reset(flag)
|
||||
return int(0), true
|
||||
return 0, talks, cfg, true
|
||||
}
|
||||
}
|
||||
|
||||
if uint32(mapid) != c.MapID {
|
||||
return talks.Count, talks, cfg, true
|
||||
}
|
||||
|
||||
func (s *TalkService) Progress(flag int) (uint32, bool) {
|
||||
count, _, _, ok := s.progress(flag)
|
||||
return count, ok
|
||||
}
|
||||
|
||||
//实现挖矿次数确认
|
||||
|
||||
func (s *TalkService) Cheak(mapid uint32, flag int) (int, bool) {
|
||||
count, _, cfg, ok := s.progress(flag)
|
||||
if !ok || cfg == nil {
|
||||
return 0, false //没在地图
|
||||
}
|
||||
if talks.Count >= c.DailyCollectCount {
|
||||
if uint32(mapid) != cfg.MapID {
|
||||
return 0, false //没在地图
|
||||
}
|
||||
if count >= cfg.DailyCollectCount {
|
||||
return 0, false
|
||||
}
|
||||
return int(talks.Count), true //int(config.MaxDailyCnt - talks.Count)
|
||||
return int(count), true //int(config.MaxDailyCnt - talks.Count)
|
||||
|
||||
}
|
||||
|
||||
|
||||
BIN
modules/service.test
Executable file
BIN
modules/service.test
Executable file
Binary file not shown.
Reference in New Issue
Block a user