Compare commits
3 Commits
97c8231b44
...
f6aa0c3339
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6aa0c3339 | ||
|
|
ecc483a11a | ||
|
|
5f5634d999 |
@@ -43,7 +43,7 @@ func (Controller) PlayerFightBoss(req *ChallengeBossInboundInfo, p *player.Playe
|
||||
}
|
||||
|
||||
p.Fightinfo.Status = fightinfo.BattleMode.FIGHT_WITH_NPC
|
||||
p.Fightinfo.Mode = fightinfo.BattleMode.MULTI_MODE
|
||||
p.Fightinfo.Mode = resolveMapNodeFightMode(mapNode)
|
||||
|
||||
ai := player.NewAI_player(monsterInfo)
|
||||
ai.CanCapture = resolveBossCaptureRate(bossConfigs[0].IsCapture, leadMonsterID)
|
||||
@@ -76,12 +76,23 @@ func startMapBossFight(
|
||||
oppPets := ai.GetPetInfo(0)
|
||||
if mapNode != nil && mapNode.IsGroupBoss != 0 {
|
||||
if len(ourPets) > 0 && len(oppPets) > 0 {
|
||||
return fight.NewLegacyGroupFightSingleController(p, ai, ourPets, oppPets, groupBossSlotLimit, fn)
|
||||
slotLimit := groupBossSlotLimit
|
||||
if mapNode.PkFlag != 0 {
|
||||
slotLimit = 1
|
||||
}
|
||||
return fight.NewLegacyGroupFightSingleController(p, ai, ourPets, oppPets, slotLimit, fn)
|
||||
}
|
||||
}
|
||||
return fight.NewFight(p, ai, ourPets, oppPets, fn)
|
||||
}
|
||||
|
||||
func resolveMapNodeFightMode(mapNode *configmodel.MapNode) uint32 {
|
||||
if mapNode != nil && mapNode.PkFlag != 0 {
|
||||
return fightinfo.BattleMode.SINGLE_MODE
|
||||
}
|
||||
return fightinfo.BattleMode.MULTI_MODE
|
||||
}
|
||||
|
||||
// OnPlayerFightNpcMonster 战斗野怪
|
||||
func (Controller) OnPlayerFightNpcMonster(req *FightNpcMonsterInboundInfo, p *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
|
||||
if err = p.CanFight(); err != 0 {
|
||||
|
||||
@@ -77,31 +77,16 @@ func (h Controller) CompleteTask(data1 *CompleteTaskInboundInfo, c *player.Playe
|
||||
// if service.NewTaskService().IsAcceptable(data1.TaskId) == nil {
|
||||
// return nil, errorcode.ErrorCodes.ErrSystemError
|
||||
// }
|
||||
c.Info.SetTask(int(data1.TaskId), model.Completed)
|
||||
|
||||
result = &task.CompleteTaskOutboundInfo{
|
||||
TaskId: data1.TaskId,
|
||||
ItemList: make([]data.ItemInfo, 0),
|
||||
}
|
||||
|
||||
taskInfo := task.GetTaskInfo(int(data1.TaskId), int(data1.OutState))
|
||||
if taskInfo == nil {
|
||||
return nil, errorcode.ErrorCodes.ErrNeedCompleteTaskForPrize
|
||||
if _, err = c.ApplyTaskCompletion(data1.TaskId, int(data1.OutState), result); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if taskInfo.Pet != nil {
|
||||
|
||||
c.Service.Pet.PetAdd(taskInfo.Pet, 0)
|
||||
result.CaptureTime = taskInfo.Pet.CatchTime
|
||||
result.PetTypeId = taskInfo.Pet.ID
|
||||
}
|
||||
|
||||
for _, item := range taskInfo.ItemList {
|
||||
success := c.ItemAdd(item.ItemId, item.ItemCnt)
|
||||
if success {
|
||||
result.ItemList = append(result.ItemList, item)
|
||||
}
|
||||
|
||||
if taskErr := c.Info.SetTask(int(data1.TaskId), model.Completed); taskErr != nil {
|
||||
return nil, errorcode.ErrorCodes.ErrSystemError
|
||||
}
|
||||
|
||||
return result, 0 //通过PUB/SUB回包
|
||||
|
||||
@@ -44,6 +44,7 @@ func (f *FightC) openActionWindow() {
|
||||
f.actionMu.Lock()
|
||||
f.acceptActions = true
|
||||
f.pendingActions = f.pendingActions[:0]
|
||||
f.pendingHead = 0
|
||||
f.actionRound.Store(uint32(f.Round))
|
||||
f.actionMu.Unlock()
|
||||
}
|
||||
@@ -52,6 +53,7 @@ func (f *FightC) closeActionWindow() {
|
||||
f.actionMu.Lock()
|
||||
f.acceptActions = false
|
||||
f.pendingActions = f.pendingActions[:0]
|
||||
f.pendingHead = 0
|
||||
f.actionRound.Store(0)
|
||||
f.actionMu.Unlock()
|
||||
|
||||
@@ -73,8 +75,10 @@ func (f *FightC) submitAction(act action.BattleActionI) {
|
||||
f.actionMu.Unlock()
|
||||
return
|
||||
}
|
||||
f.compactPendingActionsLocked()
|
||||
replaceIndex := -1
|
||||
for i, pending := range f.pendingActions {
|
||||
for i := f.pendingHead; i < len(f.pendingActions); i++ {
|
||||
pending := f.pendingActions[i]
|
||||
if pending == nil || actionSlotKeyFromAction(pending) != actionSlotKeyFromAction(act) {
|
||||
continue
|
||||
}
|
||||
@@ -105,15 +109,23 @@ func (f *FightC) submitAction(act action.BattleActionI) {
|
||||
|
||||
func (f *FightC) nextAction() action.BattleActionI {
|
||||
f.actionMu.Lock()
|
||||
if len(f.pendingActions) == 0 {
|
||||
if f.pendingHead >= len(f.pendingActions) {
|
||||
f.pendingActions = f.pendingActions[:0]
|
||||
f.pendingHead = 0
|
||||
f.actionMu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
act := f.pendingActions[0]
|
||||
copy(f.pendingActions, f.pendingActions[1:])
|
||||
f.pendingActions = f.pendingActions[:len(f.pendingActions)-1]
|
||||
hasMore := len(f.pendingActions) > 0
|
||||
act := f.pendingActions[f.pendingHead]
|
||||
f.pendingActions[f.pendingHead] = nil
|
||||
f.pendingHead++
|
||||
hasMore := f.pendingHead < len(f.pendingActions)
|
||||
if !hasMore {
|
||||
f.pendingActions = f.pendingActions[:0]
|
||||
f.pendingHead = 0
|
||||
} else {
|
||||
f.compactPendingActionsLocked()
|
||||
}
|
||||
notify := f.actionNotify
|
||||
f.actionMu.Unlock()
|
||||
|
||||
@@ -127,6 +139,22 @@ func (f *FightC) nextAction() action.BattleActionI {
|
||||
return act
|
||||
}
|
||||
|
||||
func (f *FightC) compactPendingActionsLocked() {
|
||||
if f.pendingHead == 0 {
|
||||
return
|
||||
}
|
||||
if f.pendingHead < len(f.pendingActions)/2 && len(f.pendingActions) < cap(f.pendingActions) {
|
||||
return
|
||||
}
|
||||
remaining := len(f.pendingActions) - f.pendingHead
|
||||
copy(f.pendingActions, f.pendingActions[f.pendingHead:])
|
||||
for i := remaining; i < len(f.pendingActions); i++ {
|
||||
f.pendingActions[i] = nil
|
||||
}
|
||||
f.pendingActions = f.pendingActions[:remaining]
|
||||
f.pendingHead = 0
|
||||
}
|
||||
|
||||
// 玩家逃跑/无响应/掉线
|
||||
func (f *FightC) Over(c common.PlayerI, res model.EnumBattleOverReason) {
|
||||
if f.closefight {
|
||||
|
||||
@@ -467,12 +467,7 @@ func (f *FightC) TURNOVER(cur *input.Input) {
|
||||
if cur == nil {
|
||||
return
|
||||
}
|
||||
for _, pet := range cur.BenchPets() {
|
||||
if pet != nil && pet.Info.Hp > 0 {
|
||||
_hasBackup = true
|
||||
break
|
||||
}
|
||||
}
|
||||
_hasBackup = cur.HasLivingBench()
|
||||
f.sendLegacySpriteDie(cur, _hasBackup)
|
||||
|
||||
f.Broadcast(func(ff *input.Input) {
|
||||
|
||||
@@ -39,6 +39,7 @@ type FightC struct {
|
||||
actionNotify chan struct{}
|
||||
acceptActions bool
|
||||
pendingActions []action.BattleActionI // 待处理动作队列,同一战斗位最多保留一个动作
|
||||
pendingHead int
|
||||
actionRound atomic.Uint32
|
||||
|
||||
quit chan struct{}
|
||||
@@ -250,20 +251,13 @@ func (f *FightC) sideHasActionableSlots(side int) bool {
|
||||
}
|
||||
|
||||
func (f *FightC) slotNeedsAction(in *input.Input) bool {
|
||||
var bench []*info.BattlePetEntity
|
||||
if in == nil {
|
||||
return false
|
||||
}
|
||||
if current := in.CurrentPet(); current != nil && current.Info.Hp > 0 {
|
||||
return true
|
||||
}
|
||||
bench = in.BenchPets()
|
||||
for _, pet := range bench {
|
||||
if pet != nil && pet.Info.Hp > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return in.HasLivingBench()
|
||||
}
|
||||
|
||||
func (f *FightC) setActionAttackValue(act action.BattleActionI) {
|
||||
|
||||
@@ -107,18 +107,14 @@ func (our *Input) GetProp(id int) alpacadecimal.Decimal {
|
||||
}
|
||||
|
||||
func (our *Input) GetEffect(etype EnumEffectType, id int) Effect {
|
||||
var ret []Effect
|
||||
pr := EffectIDCombiner{}
|
||||
pr.Combine(etype, 0, gconv.Uint16(id))
|
||||
|
||||
for _, v := range our.Effects {
|
||||
if v.ID().Base == pr.Base && v.Alive() {
|
||||
ret = append(ret, v)
|
||||
our.ensureEffectIndex()
|
||||
bucket := our.effectsByBase[pr.Base]
|
||||
for i := len(bucket) - 1; i >= 0; i-- {
|
||||
if bucket[i] != nil && bucket[i].Alive() {
|
||||
return bucket[i]
|
||||
}
|
||||
|
||||
}
|
||||
if len(ret) > 0 {
|
||||
return ret[len(ret)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -178,6 +174,7 @@ func (our *Input) AddEffect(in *Input, e Effect) Effect {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
our.ensureEffectIndex()
|
||||
ctx := e.Ctx()
|
||||
if ctx != nil {
|
||||
if ctx.Source == nil {
|
||||
@@ -204,7 +201,7 @@ func (our *Input) AddEffect(in *Input, e Effect) Effect {
|
||||
//TODO 先激活
|
||||
//fmt.Println("产生回合数", e.ID(), e.Duration())
|
||||
// 如果已有同 ID 的效果,尝试叠加
|
||||
for _, v := range our.Effects {
|
||||
for _, v := range our.effectsByBase[e.ID().Base] {
|
||||
if v == e {
|
||||
return nil //完全相同,跳过执行
|
||||
}
|
||||
@@ -219,7 +216,7 @@ func (our *Input) AddEffect(in *Input, e Effect) Effect {
|
||||
if !v.CanStack() { //说明进行了替换
|
||||
v.Alive(false) //不允许叠层,取消效果
|
||||
e.Duration(utils.Max(e.Duration(), v.Duration()))
|
||||
our.Effects = append(our.Effects, e)
|
||||
our.appendEffect(e)
|
||||
return v //这里把V替换掉了
|
||||
} else {
|
||||
//默认给叠一层
|
||||
@@ -237,7 +234,7 @@ func (our *Input) AddEffect(in *Input, e Effect) Effect {
|
||||
}
|
||||
//无限叠加,比如能力提升类buff
|
||||
// 如果没有同 ID 的效果,直接添加
|
||||
our.Effects = append(our.Effects, e)
|
||||
our.appendEffect(e)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -309,6 +306,34 @@ func (our *Input) CancelTurn(in *Input) {
|
||||
|
||||
}
|
||||
|
||||
func (our *Input) ensureEffectIndex() {
|
||||
if our == nil {
|
||||
return
|
||||
}
|
||||
if our.effectsByBase == nil {
|
||||
our.effectsByBase = make(map[int64][]Effect, len(our.Effects))
|
||||
}
|
||||
if our.indexedEffects > len(our.Effects) {
|
||||
our.effectsByBase = make(map[int64][]Effect, len(our.Effects))
|
||||
our.indexedEffects = 0
|
||||
}
|
||||
for our.indexedEffects < len(our.Effects) {
|
||||
effect := our.Effects[our.indexedEffects]
|
||||
if effect != nil {
|
||||
our.effectsByBase[effect.ID().Base] = append(our.effectsByBase[effect.ID().Base], effect)
|
||||
}
|
||||
our.indexedEffects++
|
||||
}
|
||||
}
|
||||
|
||||
func (our *Input) appendEffect(effect Effect) {
|
||||
if our == nil || effect == nil {
|
||||
return
|
||||
}
|
||||
our.Effects = append(our.Effects, effect)
|
||||
our.ensureEffectIndex()
|
||||
}
|
||||
|
||||
// // 消除全部 断回合效果,但是我放下场的时候应该断掉所有的回合类效果
|
||||
// func (our *Input) CancelAll() {
|
||||
// our.Effects = make([]Effect, 0)
|
||||
|
||||
@@ -15,6 +15,13 @@ import (
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
|
||||
var statusBonuses = map[info.EnumPetStatus]float64{
|
||||
info.PetStatus.Paralysis: 1.5,
|
||||
info.PetStatus.Poisoned: 1.5,
|
||||
info.PetStatus.Sleep: 2.0,
|
||||
// /info.BattleStatus.Frozen: 2.0,
|
||||
}
|
||||
|
||||
type Input struct {
|
||||
CanChange uint32 //是否可以死亡切换CanChange
|
||||
// CanAction bool //是否可以行动
|
||||
@@ -27,9 +34,11 @@ type Input struct {
|
||||
CanCapture int
|
||||
Finished bool //是否加载完成
|
||||
// info.BattleActionI
|
||||
Effects []Effect //effects 实际上全局就是effect无限回合 //effects容器 技能的
|
||||
EffectCache []Effect //这里是命中前执行的容器,也就是命中前执行的所有逻辑相关,理论上一个effect被激活,就应该同时将其他的effect取消激活
|
||||
EffectLost []Effect
|
||||
Effects []Effect //effects 实际上全局就是effect无限回合 //effects容器 技能的
|
||||
EffectCache []Effect //这里是命中前执行的容器,也就是命中前执行的所有逻辑相关,理论上一个effect被激活,就应该同时将其他的effect取消激活
|
||||
EffectLost []Effect
|
||||
effectsByBase map[int64][]Effect
|
||||
indexedEffects int
|
||||
// 删掉伤害记录,可以在回调中记录,而不是每次调用记录
|
||||
*model.AttackValue
|
||||
FightC common.FightI
|
||||
@@ -57,6 +66,7 @@ func NewInput(c common.FightI, p common.PlayerI) *Input {
|
||||
ret := &Input{FightC: c, Player: p}
|
||||
ret.Effects = make([]Effect, 0)
|
||||
ret.CurPet = make([]*info.BattlePetEntity, 0)
|
||||
ret.effectsByBase = make(map[int64][]Effect)
|
||||
|
||||
// t := Geteffect(EffectType.Damage, 0)
|
||||
// t.Effect.SetArgs(ret)
|
||||
@@ -115,6 +125,27 @@ func (our *Input) BenchPets() []*info.BattlePetEntity {
|
||||
return bench
|
||||
}
|
||||
|
||||
func (our *Input) HasLivingBench() bool {
|
||||
if our == nil {
|
||||
return false
|
||||
}
|
||||
current := our.CurrentPet()
|
||||
currentCatchTime := uint32(0)
|
||||
if current != nil {
|
||||
currentCatchTime = current.Info.CatchTime
|
||||
}
|
||||
for _, pet := range our.AllPet {
|
||||
if pet == nil || pet.Info.Hp == 0 {
|
||||
continue
|
||||
}
|
||||
if current != nil && pet.Info.CatchTime == currentCatchTime {
|
||||
continue
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (our *Input) OpponentSlots() []*Input {
|
||||
if our == nil {
|
||||
return nil
|
||||
@@ -299,20 +330,12 @@ func (our *Input) GetPet(id uint32) (ii *info.BattlePetEntity, Reason info.Chang
|
||||
// GetStatusBonus 获取最高的状态倍率
|
||||
// 遍历状态数组,返回存在的状态中最高的倍率(无状态则返回1.0)
|
||||
func (our *Input) GetStatusBonus() float64 {
|
||||
// 异常状态倍率映射表(状态索引 -> 倍率)
|
||||
var statusBonuses = map[info.EnumPetStatus]float64{
|
||||
info.PetStatus.Paralysis: 1.5,
|
||||
info.PetStatus.Poisoned: 1.5,
|
||||
info.PetStatus.Sleep: 2.0,
|
||||
// /info.BattleStatus.Frozen: 2.0,
|
||||
}
|
||||
maxBonus := 1.0 // 默认无状态倍率
|
||||
|
||||
for statusIdx := 0; statusIdx < 20; statusIdx++ {
|
||||
t := our.InitEffect(EffectType.Status, statusIdx)
|
||||
t := our.GetEffect(EffectType.Status, statusIdx)
|
||||
|
||||
// 检查状态是否存在(数组中值为1表示存在该状态)
|
||||
if t != nil && t.Stack() > 0 {
|
||||
if t != nil && t.Alive() {
|
||||
if bonus, exists := statusBonuses[info.EnumPetStatus(statusIdx)]; exists && bonus > maxBonus {
|
||||
maxBonus = bonus
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ type EffectNode struct {
|
||||
canStack bool // 最大叠加层数 ,正常都是不允许叠加的,除了衰弱特殊效果 ,异常和能力的叠层
|
||||
isFirst bool
|
||||
SideEffectArgs []int // 附加效果参数
|
||||
cachedArgs []alpacadecimal.Decimal
|
||||
// owner bool //是否作用自身
|
||||
Success bool // 是否执行成功 成功XXX,失败XXX
|
||||
arget bool // 传出作用对象,默认0是自身,1是作用于对面
|
||||
@@ -240,18 +241,22 @@ func (e *EffectNode) SetArgs(t *input.Input, a ...int) {
|
||||
e.Input = t
|
||||
if len(a) > 0 {
|
||||
e.SideEffectArgs = a
|
||||
e.cachedArgs = e.cachedArgs[:0]
|
||||
for _, v := range a {
|
||||
e.cachedArgs = append(e.cachedArgs, alpacadecimal.NewFromInt(int64(v)))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
func (e *EffectNode) Args() []alpacadecimal.Decimal {
|
||||
var ret []alpacadecimal.Decimal
|
||||
|
||||
for _, v := range e.SideEffectArgs {
|
||||
ret = append(ret, alpacadecimal.NewFromInt(int64(v)))
|
||||
|
||||
if len(e.cachedArgs) == len(e.SideEffectArgs) {
|
||||
return e.cachedArgs
|
||||
}
|
||||
|
||||
return ret
|
||||
e.cachedArgs = e.cachedArgs[:0]
|
||||
for _, v := range e.SideEffectArgs {
|
||||
e.cachedArgs = append(e.cachedArgs, alpacadecimal.NewFromInt(int64(v)))
|
||||
}
|
||||
return e.cachedArgs
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,11 @@
|
||||
package player
|
||||
|
||||
import (
|
||||
"blazing/logic/service/fight/info"
|
||||
"blazing/logic/service/task"
|
||||
"blazing/modules/player/model"
|
||||
|
||||
"github.com/pointernil/bitset32"
|
||||
)
|
||||
|
||||
// 辅助函数:获取任务奖励,封装逻辑便于复用和统一检查
|
||||
// 返回nil表示无奖励
|
||||
func (p *Player) getTaskGift(taskID int, ot int) *task.TaskResult {
|
||||
// 防御性检查:taskID非法时直接返回nil
|
||||
if taskID <= 0 {
|
||||
return nil
|
||||
}
|
||||
return task.GetTaskInfo(taskID, ot)
|
||||
}
|
||||
|
||||
// SptCompletedTask 完成任务(单分支)
|
||||
// 优化点:仅当奖励存在时,才完成任务并发放奖励
|
||||
func (p *Player) SptCompletedTask(taskID int, ot int) {
|
||||
@@ -29,15 +17,17 @@ func (p *Player) SptCompletedTask(taskID int, ot int) {
|
||||
return
|
||||
}
|
||||
|
||||
// 2. 核心逻辑:先检查奖励是否存在,无奖励则直接返回(不完成任务)
|
||||
gift := p.getTaskGift(taskID, ot)
|
||||
if gift == nil {
|
||||
if !p.canCompleteTaskReward(taskID, ot) {
|
||||
return
|
||||
}
|
||||
|
||||
granted, err := p.ApplyTaskCompletion(uint32(taskID), ot, nil)
|
||||
if err != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// 3. 奖励存在时,才标记任务完成 + 发放奖励
|
||||
p.Info.SetTask(taskID, model.Completed)
|
||||
p.bossgive(taskID, ot)
|
||||
p.SendTaskCompletionBonus(uint32(taskID), granted)
|
||||
}
|
||||
|
||||
// TawerCompletedTask 完成塔类任务(多分支)
|
||||
@@ -48,10 +38,12 @@ func (p *Player) TawerCompletedTask(taskID int, ot int) {
|
||||
}
|
||||
// 处理默认分支(ot=-1):仅奖励存在时才完成主任务
|
||||
if p.Info.GetTask(taskID) != model.Completed {
|
||||
defaultGift := p.getTaskGift(taskID, -1)
|
||||
if defaultGift != nil { // 奖励存在才标记主任务完成
|
||||
p.Info.SetTask(taskID, model.Completed)
|
||||
p.bossgive(taskID, -1)
|
||||
if p.canCompleteTaskReward(taskID, -1) {
|
||||
granted, err := p.ApplyTaskCompletion(uint32(taskID), -1, nil)
|
||||
if err == 0 {
|
||||
p.Info.SetTask(taskID, model.Completed)
|
||||
p.SendTaskCompletionBonus(uint32(taskID), granted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,53 +53,19 @@ func (p *Player) TawerCompletedTask(taskID int, ot int) {
|
||||
return
|
||||
}
|
||||
|
||||
// 核心检查:指定分支的奖励是否存在
|
||||
branchGift := p.getTaskGift(taskID, ot)
|
||||
if branchGift == nil {
|
||||
if !p.canCompleteTaskReward(taskID, ot) {
|
||||
return
|
||||
}
|
||||
|
||||
r := bitset32.From(taskData.Data)
|
||||
if !r.Test(uint(ot)) {
|
||||
r.Set(uint(ot))
|
||||
p.bossgive(taskID, ot)
|
||||
granted, rewardErr := p.ApplyTaskCompletion(uint32(taskID), ot, nil)
|
||||
if rewardErr != 0 {
|
||||
return
|
||||
}
|
||||
p.SendTaskCompletionBonus(uint32(taskID), granted)
|
||||
taskData.Data = r.Bytes()
|
||||
_ = p.Service.Task.SetTask(taskData)
|
||||
}
|
||||
}
|
||||
|
||||
// bossgive 发放任务奖励(逻辑保持不变,仅补充注释)
|
||||
func (p *Player) bossgive(taskID int, ot int) {
|
||||
gift := p.getTaskGift(taskID, ot)
|
||||
if gift == nil {
|
||||
return
|
||||
}
|
||||
|
||||
res := &info.S2C_GET_BOSS_MONSTER{
|
||||
BonusID: uint32(taskID),
|
||||
}
|
||||
|
||||
// 发放宠物奖励
|
||||
if gift.Pet != nil {
|
||||
p.Service.Pet.PetAdd(gift.Pet, 0)
|
||||
res.PetID = gift.Pet.ID
|
||||
res.CaptureTm = gift.Pet.CatchTime
|
||||
}
|
||||
|
||||
// 发放道具奖励(仅成功添加的道具才返回给前端)
|
||||
for _, item := range gift.ItemList {
|
||||
if success := p.ItemAdd(item.ItemId, item.ItemCnt); success {
|
||||
res.AddItemInfo(item)
|
||||
}
|
||||
}
|
||||
|
||||
// 发放称号奖励
|
||||
if gift.Title != 0 {
|
||||
p.GiveTitle(gift.Title)
|
||||
}
|
||||
|
||||
// 发送奖励通知给前端
|
||||
if res.HasReward() {
|
||||
p.SendPackCmd(8004, res)
|
||||
}
|
||||
}
|
||||
|
||||
193
logic/service/player/task_completion.go
Normal file
193
logic/service/player/task_completion.go
Normal file
@@ -0,0 +1,193 @@
|
||||
package player
|
||||
|
||||
import (
|
||||
"blazing/common/data"
|
||||
"blazing/common/socket/errorcode"
|
||||
fightinfo "blazing/logic/service/fight/info"
|
||||
tasklogic "blazing/logic/service/task"
|
||||
configmodel "blazing/modules/config/model"
|
||||
configservice "blazing/modules/config/service"
|
||||
playermodel "blazing/modules/player/model"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type TaskCompletionContext struct {
|
||||
TaskID uint32
|
||||
OutState int
|
||||
Config *configmodel.TaskConfig
|
||||
Reward *tasklogic.TaskResult
|
||||
Result *tasklogic.CompleteTaskOutboundInfo
|
||||
|
||||
SkipDefaultReward bool
|
||||
}
|
||||
|
||||
type TaskCompletionHandler func(*Player, *TaskCompletionContext) errorcode.ErrorCode
|
||||
|
||||
var taskCompletionRegistry = struct {
|
||||
sync.RWMutex
|
||||
handlers map[uint32]TaskCompletionHandler
|
||||
}{
|
||||
handlers: make(map[uint32]TaskCompletionHandler),
|
||||
}
|
||||
|
||||
type taskRewardGrantResult struct {
|
||||
Pet *playermodel.PetInfo
|
||||
Items []data.ItemInfo
|
||||
}
|
||||
|
||||
func RegisterTaskCompletionHandler(taskID uint32, handler TaskCompletionHandler) {
|
||||
if taskID == 0 || handler == nil {
|
||||
return
|
||||
}
|
||||
|
||||
taskCompletionRegistry.Lock()
|
||||
taskCompletionRegistry.handlers[taskID] = handler
|
||||
taskCompletionRegistry.Unlock()
|
||||
}
|
||||
|
||||
func RegisterTaskTalkLimitHandler(taskID, talkID, needCount uint32) {
|
||||
RegisterTaskCompletionHandler(taskID, func(p *Player, _ *TaskCompletionContext) errorcode.ErrorCode {
|
||||
if p == nil || p.Service == nil || p.Service.Talk == nil {
|
||||
return errorcode.ErrorCodes.ErrSystemError
|
||||
}
|
||||
|
||||
currentCount, ok := p.Service.Talk.Progress(int(talkID))
|
||||
if !ok || currentCount < needCount {
|
||||
return errorcode.ErrorCodes.ErrNeedCompleteTaskForPrize
|
||||
}
|
||||
|
||||
return 0
|
||||
})
|
||||
}
|
||||
|
||||
func (p *Player) getTaskGift(taskID int, outState int) *tasklogic.TaskResult {
|
||||
if taskID <= 0 {
|
||||
return nil
|
||||
}
|
||||
return tasklogic.GetTaskInfo(taskID, outState)
|
||||
}
|
||||
|
||||
func hasTaskCompletionHandler(taskID uint32) bool {
|
||||
taskCompletionRegistry.RLock()
|
||||
_, ok := taskCompletionRegistry.handlers[taskID]
|
||||
taskCompletionRegistry.RUnlock()
|
||||
return ok
|
||||
}
|
||||
|
||||
func getTaskCompletionHandler(taskID uint32) TaskCompletionHandler {
|
||||
taskCompletionRegistry.RLock()
|
||||
handler := taskCompletionRegistry.handlers[taskID]
|
||||
taskCompletionRegistry.RUnlock()
|
||||
return handler
|
||||
}
|
||||
|
||||
func (p *Player) canCompleteTaskReward(taskID, outState int) bool {
|
||||
if taskID <= 0 {
|
||||
return false
|
||||
}
|
||||
return p.getTaskGift(taskID, outState) != nil || hasTaskCompletionHandler(uint32(taskID))
|
||||
}
|
||||
|
||||
func (p *Player) ApplyTaskCompletion(taskID uint32, outState int, result *tasklogic.CompleteTaskOutboundInfo) (*taskRewardGrantResult, errorcode.ErrorCode) {
|
||||
if p == nil {
|
||||
return nil, errorcode.ErrorCodes.ErrSystemError
|
||||
}
|
||||
|
||||
ctx := &TaskCompletionContext{
|
||||
TaskID: taskID,
|
||||
OutState: outState,
|
||||
Config: configservice.NewTaskService().Get(int(taskID), outState),
|
||||
Reward: tasklogic.GetTaskInfo(int(taskID), outState),
|
||||
Result: result,
|
||||
}
|
||||
|
||||
if ctx.Reward == nil && !hasTaskCompletionHandler(taskID) {
|
||||
return nil, errorcode.ErrorCodes.ErrNeedCompleteTaskForPrize
|
||||
}
|
||||
|
||||
if handler := getTaskCompletionHandler(taskID); handler != nil {
|
||||
if err := handler(p, ctx); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.SkipDefaultReward {
|
||||
if result != nil {
|
||||
result.ItemLen = uint32(len(result.ItemList))
|
||||
}
|
||||
return &taskRewardGrantResult{Items: make([]data.ItemInfo, 0)}, 0
|
||||
}
|
||||
|
||||
if ctx.Reward == nil {
|
||||
return nil, errorcode.ErrorCodes.ErrNeedCompleteTaskForPrize
|
||||
}
|
||||
|
||||
return p.grantTaskReward(ctx.Reward, result), 0
|
||||
}
|
||||
|
||||
func (p *Player) grantTaskReward(reward *tasklogic.TaskResult, result *tasklogic.CompleteTaskOutboundInfo) *taskRewardGrantResult {
|
||||
granted := &taskRewardGrantResult{
|
||||
Items: make([]data.ItemInfo, 0),
|
||||
}
|
||||
|
||||
if reward == nil {
|
||||
if result != nil {
|
||||
result.ItemLen = uint32(len(result.ItemList))
|
||||
}
|
||||
return granted
|
||||
}
|
||||
|
||||
if reward.Pet != nil {
|
||||
p.Service.Pet.PetAdd(reward.Pet, 0)
|
||||
granted.Pet = reward.Pet
|
||||
if result != nil {
|
||||
result.CaptureTime = reward.Pet.CatchTime
|
||||
result.PetTypeId = reward.Pet.ID
|
||||
}
|
||||
}
|
||||
|
||||
for _, item := range reward.ItemList {
|
||||
if !p.ItemAdd(item.ItemId, item.ItemCnt) {
|
||||
continue
|
||||
}
|
||||
granted.Items = append(granted.Items, item)
|
||||
if result != nil {
|
||||
result.ItemList = append(result.ItemList, item)
|
||||
}
|
||||
}
|
||||
|
||||
if reward.Title != 0 {
|
||||
p.GiveTitle(reward.Title)
|
||||
}
|
||||
if reward.RewardPetID != 0 {
|
||||
p.GrantTaskPetRewards(reward.RewardPetID, reward.TrainSkillIDs, reward.SkinIDs)
|
||||
}
|
||||
|
||||
if result != nil {
|
||||
result.ItemLen = uint32(len(result.ItemList))
|
||||
}
|
||||
return granted
|
||||
}
|
||||
|
||||
func (p *Player) SendTaskCompletionBonus(bonusID uint32, granted *taskRewardGrantResult) {
|
||||
if p == nil {
|
||||
return
|
||||
}
|
||||
|
||||
res := &fightinfo.S2C_GET_BOSS_MONSTER{
|
||||
BonusID: bonusID,
|
||||
}
|
||||
if granted != nil && granted.Pet != nil {
|
||||
res.PetID = granted.Pet.ID
|
||||
res.CaptureTm = granted.Pet.CatchTime
|
||||
}
|
||||
if granted != nil {
|
||||
for _, item := range granted.Items {
|
||||
res.AddItemInfo(item)
|
||||
}
|
||||
}
|
||||
|
||||
if res.HasReward() {
|
||||
p.SendPackCmd(8004, res)
|
||||
}
|
||||
}
|
||||
115
logic/service/player/task_reward.go
Normal file
115
logic/service/player/task_reward.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package player
|
||||
|
||||
import "blazing/modules/player/model"
|
||||
|
||||
func applyTaskRewardToPetInfo(pet *model.PetInfo, trainSkillIDs, skinIDs []uint32) bool {
|
||||
if pet == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
changed := false
|
||||
|
||||
mergedSkills := mergeTaskRewardIDs(pet.ExtSKill, trainSkillIDs)
|
||||
if len(mergedSkills) != len(pet.ExtSKill) {
|
||||
pet.ExtSKill = mergedSkills
|
||||
changed = true
|
||||
}
|
||||
|
||||
mergedSkins := mergeTaskRewardIDs(pet.ExtSkin, skinIDs)
|
||||
if len(mergedSkins) != len(pet.ExtSkin) {
|
||||
pet.ExtSkin = mergedSkins
|
||||
changed = true
|
||||
}
|
||||
|
||||
if pet.SkinID == 0 {
|
||||
for _, skinID := range mergedSkins {
|
||||
if skinID == 0 {
|
||||
continue
|
||||
}
|
||||
pet.SkinID = skinID
|
||||
changed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return changed
|
||||
}
|
||||
|
||||
func mergeTaskRewardIDs(dst []uint32, src []uint32) []uint32 {
|
||||
if len(src) == 0 {
|
||||
return dst
|
||||
}
|
||||
|
||||
seen := make(map[uint32]struct{}, len(dst)+len(src))
|
||||
result := make([]uint32, 0, len(dst)+len(src))
|
||||
|
||||
for _, id := range dst {
|
||||
if id == 0 {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[id]; ok {
|
||||
continue
|
||||
}
|
||||
seen[id] = struct{}{}
|
||||
result = append(result, id)
|
||||
}
|
||||
|
||||
for _, id := range src {
|
||||
if id == 0 {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[id]; ok {
|
||||
continue
|
||||
}
|
||||
seen[id] = struct{}{}
|
||||
result = append(result, id)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (p *Player) GrantTaskPetRewards(targetPetID uint32, trainSkillIDs, skinIDs []uint32) bool {
|
||||
if p == nil || targetPetID == 0 || (len(trainSkillIDs) == 0 && len(skinIDs) == 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
changed := false
|
||||
|
||||
for i := range p.Info.PetList {
|
||||
if p.Info.PetList[i].ID != targetPetID {
|
||||
continue
|
||||
}
|
||||
if applyTaskRewardToPetInfo(&p.Info.PetList[i], trainSkillIDs, skinIDs) {
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
|
||||
for i := range p.Info.BackupPetList {
|
||||
if p.Info.BackupPetList[i].ID != targetPetID {
|
||||
continue
|
||||
}
|
||||
if applyTaskRewardToPetInfo(&p.Info.BackupPetList[i], trainSkillIDs, skinIDs) {
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
|
||||
if p.Service == nil || p.Service.Pet == nil {
|
||||
return changed
|
||||
}
|
||||
|
||||
allPets := p.Service.Pet.PetInfo(0)
|
||||
for i := range allPets {
|
||||
if allPets[i].Data.ID != targetPetID {
|
||||
continue
|
||||
}
|
||||
if !applyTaskRewardToPetInfo(&allPets[i].Data, trainSkillIDs, skinIDs) {
|
||||
continue
|
||||
}
|
||||
allPets[i].Data.CatchTime = allPets[i].CatchTime
|
||||
if p.Service.Pet.Update(allPets[i].Data) {
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
|
||||
return changed
|
||||
}
|
||||
@@ -10,8 +10,11 @@ import (
|
||||
type TaskResult struct {
|
||||
Pet *model.PetInfo `json:"petTypeId" description:"发放的精灵ID"` // 发放的精灵ID,
|
||||
|
||||
ItemList []data.ItemInfo `json:"itemList" description:"发放物品的数组"` // 发放物品的数组,
|
||||
Title uint32 `json:"title" description:"称号奖励"`
|
||||
ItemList []data.ItemInfo `json:"itemList" description:"发放物品的数组"` // 发放物品的数组,
|
||||
Title uint32 `json:"title" description:"称号奖励"`
|
||||
RewardPetID uint32 `json:"rewardPetId" description:"宠物相关奖励目标精灵ID"`
|
||||
TrainSkillIDs []uint32 `json:"trainSkillIds" description:"特训技能奖励"`
|
||||
SkinIDs []uint32 `json:"skinIds" description:"皮肤奖励"`
|
||||
}
|
||||
|
||||
func GetTaskInfo(id, ot int) *TaskResult {
|
||||
@@ -26,6 +29,12 @@ func GetTaskInfo(id, ot int) *TaskResult {
|
||||
if pet != nil {
|
||||
ret.Pet = model.GenPetInfo(int(pet.MonID), int(pet.DV), int(pet.Nature), int(pet.Effect), int(pet.Lv), nil, 0)
|
||||
}
|
||||
ret.RewardPetID = r.RewardPetID
|
||||
ret.TrainSkillIDs = append(ret.TrainSkillIDs, r.TrainSkillIDs...)
|
||||
ret.SkinIDs = append(ret.SkinIDs, r.SkinIDs...)
|
||||
if ret.Pet != nil {
|
||||
applyTaskRewardPetExtras(ret.Pet, ret.TrainSkillIDs, ret.SkinIDs)
|
||||
}
|
||||
|
||||
for _, itemID := range r.ItemRewardIds {
|
||||
iteminfo := service.NewItemService().GetItemCount(itemID)
|
||||
@@ -39,3 +48,59 @@ func GetTaskInfo(id, ot int) *TaskResult {
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func applyTaskRewardPetExtras(pet *model.PetInfo, trainSkillIDs, skinIDs []uint32) {
|
||||
if pet == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if merged := mergeTaskRewardIDs(pet.ExtSKill, trainSkillIDs); len(merged) != len(pet.ExtSKill) {
|
||||
pet.ExtSKill = merged
|
||||
}
|
||||
|
||||
mergedSkins := mergeTaskRewardIDs(pet.ExtSkin, skinIDs)
|
||||
if len(mergedSkins) != len(pet.ExtSkin) {
|
||||
pet.ExtSkin = mergedSkins
|
||||
}
|
||||
if pet.SkinID == 0 {
|
||||
for _, skinID := range mergedSkins {
|
||||
if skinID != 0 {
|
||||
pet.SkinID = skinID
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mergeTaskRewardIDs(dst []uint32, src []uint32) []uint32 {
|
||||
if len(src) == 0 {
|
||||
return dst
|
||||
}
|
||||
|
||||
seen := make(map[uint32]struct{}, len(dst)+len(src))
|
||||
result := make([]uint32, 0, len(dst)+len(src))
|
||||
|
||||
for _, id := range dst {
|
||||
if id == 0 {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[id]; ok {
|
||||
continue
|
||||
}
|
||||
seen[id] = struct{}{}
|
||||
result = append(result, id)
|
||||
}
|
||||
|
||||
for _, id := range src {
|
||||
if id == 0 {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[id]; ok {
|
||||
continue
|
||||
}
|
||||
seen[id] = struct{}{}
|
||||
result = append(result, id)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -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