feat(xmlres): 更新 BOSS 配置结构并优化字段注释

新增多个 BOSS 相关配置字段,包括任务关联、奖励机制与挑战限制等,
增强 BOSS 精灵的可配置性与业务表达能力。同时完善字段注释以对齐 XML
实际使用情况,并保留原有部分字段用于兼容历史配置。

fix(fight): 调整战斗胜利回调执行顺序以确保数据一致性

将战斗结束回调移至广播之前执行,保证在发送战斗结果前已完成所有状态
更新,尤其是针对胜利宠物的信息同步
This commit is contained in:
2025-11-22 22:57:32 +08:00
parent 7f443736bc
commit 1dbd4169e9
35 changed files with 518 additions and 360 deletions

View File

@@ -146,7 +146,7 @@ func init() {
}
if event.IsWrite() {
glog.Debug(ctx, "写入文件 : ", event.Path)
initfile() //先初始化一次
//initfile() //先初始化一次
}
if event.IsRemove() {
glog.Debug(ctx, "删除文件 : ", event.Path)

View File

@@ -70,19 +70,27 @@ type TriggerPt struct {
// BOSS配置对应 <Boss>
type BossConfig struct {
Id *int `xml:"Id,attr"` // BOSSID可选用指针处理空值
BossCatchable int `xml:"BossCatchable,attr"` // 是否可捕捉0/1默认0
AppearTime string `xml:"AppearTime,attr"` // 出现时间(如"0 23"
BossVisible int `xml:"BossVisible,attr"` // 是否可见0/1默认0
Name string `xml:"Name,attr"` // BOSS名称选)
DailyKey *string `xml:"DailyKey,attr"` // 每日挑战次数Key可选
MaxTimes *int `xml:"MaxTimes,attr"` // 非VIP每日挑战上限可选
VipMaxTimes *int `xml:"VipMaxTimes,attr"` // VIP每日挑战上限可选
WinBonusId *string `xml:"WinBonusId,attr"` // 胜利奖励ID可选
WinOutId *int `xml:"WinOutId,attr"` // 胜利输出ID可选
FailBonusId *string `xml:"FailBonusId,attr"` // 失败奖励ID可选
FailOutId *int `xml:"FailOutId,attr"` // 失败输出ID可选
BossMon []BossMon `xml:"BossMon"` // BOSS对应的精灵多个
Id *int `xml:"Id,attr"` // BOSSID可选XML中有Id="0"/"1"
TaskID *int `xml:"TaskID,attr"` // 关联任务ID可选如311/353/541
BossCatchable int `xml:"BossCatchable,attr"` // 是否可捕捉0/1默认0XML中有BossCatchable="0"
AppearTime string `xml:"AppearTime,attr"` // 出现时间(如"0 23",必选
BossVisible int `xml:"BossVisible,attr"` // 是否可见0/1默认0选)
Name string `xml:"Name,attr"` // BOSS名称可选如"SPT哈莫雷特"
SptLevel *int `xml:"SptLevel,attr"` // SPT等级可选如1/2
BonusProbability *int `xml:"BonusProbability,attr"` // 奖励概率可选如20
BonusTotalProbability *int `xml:"BonusTotalProbability,attr"` // 奖励总概率可选如1000
BonusID *string `xml:"BonusID,attr"` // 基础奖励ID可选如5017
ItemBonusOutID *int `xml:"ItemBonusOutID,attr"` // 物品奖励输出ID可选如2
BossFinOnce *int `xml:"BossFinOnce,attr"` // 是否仅可完成一次可选0/1如1
BossFinTaskWay *int `xml:"BossFinTaskWay,attr"` // 任务完成方式可选如1
DailyKey *string `xml:"DailyKey,attr"` // 每日挑战次数Key可选XML中未出现保留
MaxTimes *int `xml:"MaxTimes,attr"` // 非VIP每日挑战上限可选XML中未出现保留
VipMaxTimes *int `xml:"VipMaxTimes,attr"` // VIP每日挑战上限可选XML中未出现保留
WinBonusId *string `xml:"WinBonusId,attr"` // 胜利奖励ID可选XML中未出现保留
WinOutId *int `xml:"WinOutId,attr"` // 胜利输出ID可选XML中未出现保留
FailBonusId *string `xml:"FailBonusId,attr"` // 失败奖励ID可选XML中未出现保留
FailOutId *int `xml:"FailOutId,attr"` // 失败输出ID可选XML中未出现保留
BossMon []BossMon `xml:"BossMon"` // BOSS对应的精灵列表必选多个
}
// BOSS精灵配置对应 <BossMon>

View File

@@ -3,7 +3,6 @@ package controller
import (
"blazing/common/data/xmlres"
"blazing/common/socket/errorcode"
"fmt"
"math/rand"
"strings"
@@ -14,6 +13,7 @@ import (
"blazing/modules/blazing/model"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/grand"
)
func processMonID(bm string) string {
@@ -50,19 +50,9 @@ func (h Controller) PlayerFightBoss(data *fight.ChallengeBossInboundInfo, c *pla
var mo *model.PetInfo
moinfo := &model.PlayerInfo{}
// 新手任务2选择不同精灵
// <Map ID="8" Name="机械舱" InitX="456" InitY="143">
// <Bosses>
// <Boss TaskID="4" AppearTime="0 23" BossVisible="0" >
// <BossMon MonID="1 4 7" Hp="10" Lv="2" />
// </Boss>
// <Boss AppearTime="0 23" BossVisible="0" >
// <!--boss for task 526 -->
// <BossMon MonID="506" Hp="55" Lv="18" NewSeIdxs="80 157 158" />
// </Boss>
// </Bosses>
// </Map>
var taskid int
var cancpet int
mdata, ok := xmlres.MonsterMap[int(c.Info.MapID)]
if !ok {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
@@ -76,8 +66,14 @@ func (h Controller) PlayerFightBoss(data *fight.ChallengeBossInboundInfo, c *pla
bc.Id = gconv.PtrInt(0)
}
if (bc.Id == nil && data.BossId == 0) || uint32(*bc.Id) == data.BossId { //打默认第一个boss
if (bc.Id == nil && data.BossId == 0) || uint32(*bc.Id) == data.BossId { //打默认第一个boss
if bc.TaskID != nil {
taskid = *bc.TaskID
}
if bc.BossCatchable == 1 {
cancpet = xmlres.PetMAP[int(mo.ID)].CatchRate
}
for _, bm := range bc.BossMon {
mo = c.GenPetInfo(
@@ -102,19 +98,32 @@ func (h Controller) PlayerFightBoss(data *fight.ChallengeBossInboundInfo, c *pla
c.Fightinfo.Mode = info.BattleMode.MULTI_MODE
ai := player.NewAI_player(moinfo)
//给予打过一次的奖励
event := c.Done.SPT(c.Info.MapID, data.BossId, 1, func() bool {
fmt.Println("触发事件", "第一次奖励")
return true
})
event1 := c.Done.SPT(c.Info.MapID, data.BossId, 2, func() bool {
fmt.Println("触发事件", "第二次奖励")
return true
})
ai.CanCapture = cancpet
fight.NewFight(c, ai, func(foi *info.FightOverInfo) {
c.Done.Exec(model.MilestoneMode.BOSS, []uint32{c.Info.MapID, data.BossId})
event.Cancel() //取消事件
event1.Cancel()
c.Done.Exec(model.MilestoneMode.BOSS, []uint32{c.Info.MapID, data.BossId, uint32(foi.Reason)}, func(results *model.MilestoneEX) uint32 {
if foi.Reason == 0 && foi.WinnerId == c.Info.UserID {
if results.CheakNoNumber(1) && taskid != 0 { //触发3次奖励
c.Info.TaskList[taskid-1] = 3
moinfo.PetList[0].Downgrade(1)
PetID := moinfo.PetList[0].ID
newm1 := model.GenPetInfo(int(PetID), -1, -1, 0, 0, 1)
c.Service.Pet.PetAdd(*newm1)
c.SendPackCmd(8004, &info.S2C_GET_BOSS_MONSTER{
BonusID: uint32(taskid),
PetID: PetID,
CaptureTm: newm1.CatchTime,
})
return 1
}
}
return 0
})
})
@@ -146,7 +155,32 @@ func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundIn
c.Fightinfo.Mode = info.BattleMode.MULTI_MODE //多人模式
fight.NewFight(c, ai, func(foi *info.FightOverInfo) {
c.Done.Exec(model.MilestoneMode.Moster, []uint32{c.Info.MapID, moinfo.PetList[0].ID, uint32(foi.Reason)}, func(results *model.MilestoneEX) uint32 {
if foi.Reason == 0 && foi.WinnerId == c.Info.UserID {
if refpet.Item != 0 {
c.SendPackCmd(8004, &info.S2C_GET_BOSS_MONSTER{
ItemList: c.ItemAdd(model.ItemInfo{
ItemId: refpet.Item,
ItemCnt: uint32(grand.Intn(2) + 1),
}),
})
}
foi.Winpet.ADD_EV(gconv.Uint32s(strings.Split(xmlres.PetMAP[int(mo.ID)].YieldingEV, " ")))
exp := uint32(xmlres.PetMAP[int(mo.ID)].YieldingExp) * mo.Level / 7
c.Info.ExpPool += exp * 4
c.AddPetExp(foi.Winpet, uint32(exp)*2)
c.SendPackCmd(2509, &info.PET_WAR_EXP_NOTICE{
EXP: exp * 2,
})
}
return 0
})
})
return nil, -1

View File

@@ -46,7 +46,7 @@ func (h Controller) BuyItem(data *item.BuyInboundInfo, c *player.Player) (result
tt, ok := xmlres.ItemsMAP[int(data.ItemId)]
if ok && tt.Price != 0 && c.UseCoins(data.Count*uint32(tt.Price)) {
r := c.ItemAdd(model.SingleItemInfo{ItemId: data.ItemId, ItemCnt: data.Count})
r := c.ItemAdd(model.ItemInfo{ItemId: data.ItemId, ItemCnt: data.Count})
if len(r) != 0 {
return &item.BuyOutboundInfo{
ItemId: data.ItemId,
@@ -55,7 +55,8 @@ func (h Controller) BuyItem(data *item.BuyInboundInfo, c *player.Player) (result
Coins: c.Info.Coins,
}, 0
}
//购买失败,返还豆子
c.Info.Coins += data.Count * uint32(tt.Price)
}
return &item.BuyOutboundInfo{
@@ -129,7 +130,7 @@ func (h Controller) TalkCate(data *item.TalkCateInboundInfo, c *player.Player) (
t[data.ID] += 1
if t[data.ID] < uint32(te.CollectCnt) {
result.OutList = append(result.OutList, item.CateInfo{ID: uint32(talkcacche[te.Name]), Count: uint32(randomNum)})
c.ItemAdd(model.SingleItemInfo{ItemId: uint32(talkcacche[te.Name]), ItemCnt: uint32(randomNum)})
c.ItemAdd(model.ItemInfo{ItemId: uint32(talkcacche[te.Name]), ItemCnt: uint32(randomNum)})
}
return true
@@ -143,12 +144,12 @@ func (h Controller) TalkCate(data *item.TalkCateInboundInfo, c *player.Player) (
return result, 0
}
func (h Controller) BuyMItem(data *item.BuyMultiInboundInfo, c *player.Player) (result *item.BuyMultiOutboundInfo, err errorcode.ErrorCode) {
var rrr []model.SingleItemInfo
var rrr []model.ItemInfo
for _, v := range data.ItemIds {
_, ok := xmlres.ItemsMAP[int(v)]
if ok {
rrr = append(rrr, model.SingleItemInfo{ItemId: uint32(v), ItemCnt: 1})
rrr = append(rrr, model.ItemInfo{ItemId: uint32(v), ItemCnt: 1})
}
}

View File

@@ -23,6 +23,25 @@ func (h *Controller) MapEnter(data *maps.InInfo, c *player.Player) (result *info
copier.Copy(result, c.Info)
defer c.GetSpace().EnterMap(c)
// go func() {
// for {
// <-time.After(time.Second * 5)
// var t info.MapBossSInfo
// t.INFO = make([]info.MapBossInfo, 0)
// t.INFO = append(t.INFO, info.MapBossInfo{
// Id: 47,
// Hp: 1,
// Pos: 1,
// })
// c.SendPackCmd(2021, &t)
// }
// }()
return result, 0
}
func (h Controller) MapHot(data *maphot.InInfo, c *player.Player) (result *maphot.OutInfo, err errorcode.ErrorCode) {

View File

@@ -63,7 +63,7 @@ func (h Controller) Complete_Task(data *task.CompleteTaskInboundInfo, c *player.
c.Info.TaskList[data.TaskId-1] = 3
result = &task.CompleteTaskOutboundInfo{
TaskId: data.TaskId,
ItemList: make([]task.ItemInfo, 0),
ItemList: make([]model.ItemInfo, 0),
}
//提交任务
@@ -82,11 +82,8 @@ func (h Controller) Complete_Task(data *task.CompleteTaskInboundInfo, c *player.
c.Service.Pet.PetAdd(*r)
}
var ttt []model.SingleItemInfo
ret := c.ItemAdd(result.ItemList...) //获取成功的条目
copier.CopyWithOption(&ttt, &result.ItemList, copier.Option{IgnoreEmpty: true, DeepCopy: true})
ret := c.ItemAdd(ttt...) //获取成功的条目
result.ItemList = make([]task.ItemInfo, 0) //清空
copier.CopyWithOption(&result.ItemList, &ret, copier.Option{IgnoreEmpty: true, DeepCopy: true})
return result, 0 //通过PUB/SUB回包

View File

@@ -18,6 +18,8 @@ require (
golang.org/x/sync v0.11.0
)
require github.com/valyala/fastrand v1.1.0 // indirect
require (
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/antlabs/stl v0.0.2 // indirect
@@ -32,7 +34,7 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/magiconair/properties v1.8.7 // indirect

View File

@@ -40,11 +40,12 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
github.com/gogf/gf/contrib/nosql/redis/v2 v2.8.0/go.mod h1:8Jp8s33CX4yPajGv5NVUlYHPi5Pru81HUKQv+ccS4/o=
github.com/gogf/gf/v2 v2.8.0/go.mod h1:6iYuZZ+A0ZcH8+4MDS/P0SvTPCvKzRvyAsY1kbkJYJc=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
@@ -99,6 +100,8 @@ github.com/tnnmigga/enum v1.0.2 h1:Yvchx0Esc01X5HiphW78sKzH/RXKttdFsfPO1ARiOa4=
github.com/tnnmigga/enum v1.0.2/go.mod h1:QaBFBwGJi/2GAM34b2pz6UL2NRtl2TRZ8lXp4vGwqhA=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8=
github.com/valyala/fastrand v1.1.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=

View File

@@ -43,6 +43,10 @@ func (h *TomeeHeader) Pack(data any) []byte {
fmt.Println(err)
}
if len(data1.Bytes()) == 0 {
fmt.Println("数据为空")
}
//datar = data1.Bytes()
// 4. 手动打包包头+数据体
return h.packHeaderWithData(data1.Bytes())

View File

@@ -53,10 +53,6 @@ func (e *Effect21) Skill_Use_ex() bool {
if e.Ctx().SkillEntity == nil {
return true
}
//0血不触发
if e.Input.CurrentPet.Info.Hp <= 0 {
return true
}
e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{

View File

@@ -24,10 +24,10 @@ func (e *Effect38) OnSkill() bool {
ee.EffectNode.Duration(-1) //给对方挂3回合子buff
//ee.ID(e.ID() + int(input.EffectType.Sub)) //子效果ID
_, _, pr := input.EffectIDCombiner{}.Split(ee.ID())
ids, _ := input.NewEffectCombined(input.EffectType.Sub, 0, pr)
tt := e.EffectIDCombiner
tt.EffectType(input.EffectType.Sub)
ee.ID(ids.GetEffectID())
ee.ID(tt)
ee.SetArgs(e.Ctx().Our, e.SideEffectArgs...)
e.Ctx().Opp.AddEffect(e.Ctx().Our, ee)
return true

View File

@@ -100,10 +100,10 @@ func (e *Effect62) OnSkill() bool {
}
ee.duy = e.EffectNode.SideEffectArgs[0]
ee.EffectNode.Duration(math.MaxInt) //给对方挂3回合子buff
_, _, pr := input.EffectIDCombiner{}.Split(ee.ID())
ids, _ := input.NewEffectCombined(input.EffectType.Sub, 0, pr)
tt := e.ID()
tt.EffectType(input.EffectType.Sub)
ee.ID(ids.GetEffectID())
ee.ID(tt)
//e.e.EffectNode.Duration(e.EffectNode.SideEffectArgs[0])
//给对方添加我方施加的buff
ee.SetArgs(e.Ctx().Our, e.SideEffectArgs...)

View File

@@ -31,10 +31,10 @@ func (e *Effect69) OnSkill() bool {
t := &Effect69_sub{
EffectNode: node.EffectNode{},
}
_, _, pr := input.EffectIDCombiner{}.Split(t.ID())
ids, _ := input.NewEffectCombined(input.EffectType.Sub, 0, pr)
tt := e.EffectIDCombiner
tt.EffectType(input.EffectType.Sub)
t.ID(ids.GetEffectID())
t.ID(tt)
t.SetArgs(e.Input, e.SideEffectArgs...)
t.Duration(e.SideEffectArgs[0])
e.Ctx().Opp.AddEffect(e.Ctx().Our, t)

View File

@@ -53,10 +53,10 @@ func (e *Effect71) Switch(in *input.Input, at info.AttackValue, oldpet *info.Bat
}
t := &Effect71_sub{}
t.Duration(1)
_, _, pr := input.EffectIDCombiner{}.Split(t.ID())
ids, _ := input.NewEffectCombined(input.EffectType.Sub, 0, pr)
tt := e.EffectIDCombiner
tt.EffectType(input.EffectType.Sub)
t.ID(ids.GetEffectID())
t.ID(tt)
e.Ctx().Our.AddEffect(e.Ctx().Our, t)
e.Alive(false)

View File

@@ -59,11 +59,9 @@ func (e *EffectConditionalAddDamage) OnSkill() bool {
if !e.Hit() {
return true
}
_, _, pr := input.EffectIDCombiner{}.Split(e.ID())
ids, _ := input.NewEffectCombined(input.EffectType.Sub, 0, pr)
// 2. 获取当前效果ID对应的条件函数
cond, ok := conditionMap[int(ids.GetSuffix())]
cond, ok := conditionMap[int(e.EffectIDCombiner.Suffix())]
if !ok {
return true // 无对应条件函数,不触发
}

View File

@@ -245,15 +245,17 @@ func (f *FightC) enterturn(fattack, sattack *action.SelectSkillAction) {
}
}
//0血不触发
if defender.CurrentPet.Info.Hp > 0 {
//技能使用后
defender.Exec(func(t input.Effect) bool {
t.Ctx().SkillEntity = currentskill
//技能使用后
defender.Exec(func(t input.Effect) bool {
t.Ctx().SkillEntity = currentskill
t.Skill_Use_ex()
t.Skill_Use_ex()
return true
})
return true
})
}
//技能使用后
attacker.Exec(func(t input.Effect) bool { //技能使用后的我方效果

View File

@@ -271,7 +271,7 @@ type FightOverInfo struct {
// 3=isDraw 双方平手
// 4=isSysError 系统错误
// 5=isNpcEscape 精灵主动逃跑
Winpet *model.PetInfo `struc:"skip"`
//7 切磋结束
Reason EnumBattleOverReason // 固定值0
WinnerId uint32 // 胜者的米米号 野怪为0

View File

@@ -0,0 +1,18 @@
package info
import "blazing/modules/blazing/model"
type S2C_GET_BOSS_MONSTER struct {
BonusID uint32 // 奖金ID未知作用填写0即可
PetID uint32 // 发放精灵的ID
CaptureTm uint32 // 发放精灵的捕获时间
ItemListLen uint32 `struc:"sizeof=ItemList"`
ItemList []model.ItemInfo // 发放物品的数组:
// 特殊说明:
// 1. 仅发放精灵不发放物品时ItemList 无需填充元素,但序列化时需先写入 uint 类型的长度值为0
// 2. 发放多个物品时:序列化时先写入 uint 类型的数组长度再依次写入每个ItemInfo元素
// 3. 该List结构参考PetInfo的特性List长度为Uint型非int
}
type PET_WAR_EXP_NOTICE struct {
EXP uint32 // 奖金ID未知作用填写0即可
}

View File

@@ -27,32 +27,27 @@ var EffectType = enum.New[struct {
var NodeM = make(map[int64]Effect, 0)
func InitEffect(etype EnumEffectType, id int, t Effect) {
ids, err := NewEffectCombined(etype, 0, gconv.Uint16(id))
if err != nil {
panic(err)
pr := EffectIDCombiner{}
pr.Combine(etype, 0, gconv.Uint16(id))
}
t.ID(ids.effectID) //设置ID
t.ID(pr) //设置ID
NodeM[ids.effectID] = t
NodeM[pr.EffectID()] = t
}
// 这里的catchtime为0,取出来之后如果是魂印,要重新赋值
func Geteffect[T int | byte](etype EnumEffectType, id T) Effect {
ids, err := NewEffectCombined(etype, 0, gconv.Uint16(id))
if err != nil {
panic(err)
pr := EffectIDCombiner{}
pr.Combine(etype, 0, gconv.Uint16(id))
}
//todo 获取前GetEffect
ret, ok := NodeM[ids.effectID]
ret, ok := NodeM[pr.EffectID()]
if ok {
//todo 获取前GetEffect
eff := deep.MustCopy(ret)
combiner := EffectIDCombiner{}
prefix, _, _ := combiner.Split(eff.ID())
if prefix == EffectType.Status {
if etype == EffectType.Status {
eff.CanStack(true) //状态类不能被覆盖,只能无限叠加
}
@@ -91,14 +86,11 @@ func (our *Input) GetProp(id int, istue bool) int {
func (our *Input) GetEffect(etype EnumEffectType, id int) Effect {
var ret []Effect
ids, err := NewEffectCombined(etype, 0, gconv.Uint16(id))
if err != nil {
panic(err)
pr := EffectIDCombiner{}
pr.Combine(etype, 0, gconv.Uint16(id))
}
eid := ids.effectID
for _, v := range our.Effects {
if v.ID() == eid && v.Alive() {
if v.ID().Base == pr.Base && v.Alive() {
ret = append(ret, v)
}
@@ -118,9 +110,10 @@ func (our *Input) StatEffect_Exist(id info.EnumPetStatus) bool {
}
func (our *Input) StatEffect_Exist_all() bool {
for _, v := range our.Effects {
combiner := EffectIDCombiner{}
prefix, _, _ := combiner.Split(v.ID())
if prefix == EffectType.Status && v.Alive() {
t := v.ID()
if t.EffectType() == EffectType.Status && v.Alive() {
return true
}
@@ -131,8 +124,8 @@ func (our *Input) StatEffect_Exist_all() bool {
// 判断是否是状态技能
func (our *Input) IS_Stat(v Effect) bool {
em, _, _ := EffectIDCombiner{}.Split(v.ID())
if em == EffectType.Status && v.Alive() {
t := v.ID()
if t.EffectType() == EffectType.Status && v.Alive() {
return true
}
@@ -188,7 +181,7 @@ func (our *Input) AddEffect(in *Input, e Effect) Effect {
//如果效果相同,id相同,参数相同,就是同一个,确认是否可以叠加,正常来说本身就可以共存
//衰弱本身参数也是相同的,区别只是传入的回合数不一样和层数不一样
if v.ID() == e.ID() && //找到相同的效果id
if v.ID().Base == e.ID().Base && //找到相同的效果id
v.Alive() && //如果之前的效果还存活
equalInts(v.Args(), e.Args()) { //如果层数可以叠加或者是无限层数

View File

@@ -21,7 +21,9 @@ const (
// -------------------------- 64位拼接工具无状态工具类 --------------------------
// EffectIDCombiner 64位效果ID拼接器[效果类型(uint16)+CatchTime(uint32)+扩展标识(uint16)] → int64
// 无状态设计,可全局复用
type EffectIDCombiner struct{}
type EffectIDCombiner struct {
Base int64
}
// Combine 拼接三个字段为64位效果ID
// 参数:
@@ -29,112 +31,90 @@ type EffectIDCombiner struct{}
// catchTime: 中32位核心字段32位CatchTime
// suffix: 低16位扩展标识/子ID
// 返回拼接后的int64参数超出范围返回错误
func (c EffectIDCombiner) Combine(prefix uint16, catchTime uint32, suffix uint16) (int64, error) {
// 范围校验(避免溢出)
if prefix > maxPrefix {
return 0, fmt.Errorf("效果类型值%d超出uint16范围最大%d", prefix, maxPrefix)
}
if catchTime > maxCatch {
return 0, fmt.Errorf("CatchTime值%d超出uint32范围最大%d", catchTime, maxCatch)
}
if suffix > maxSuffix {
return 0, fmt.Errorf("扩展标识值%d超出uint16范围最大%d", suffix, maxSuffix)
}
func (c *EffectIDCombiner) Combine(prefix EnumEffectType, catchTime uint32, suffix uint16) {
// // 范围校验(避免溢出)
// if prefix > maxPrefix {
// return 0, fmt.Errorf("效果类型值%d超出uint16范围最大%d", prefix, maxPrefix)
// }
// if catchTime > maxCatch {
// return 0, fmt.Errorf("CatchTime值%d超出uint32范围最大%d", catchTime, maxCatch)
// }
// if suffix > maxSuffix {
// return 0, fmt.Errorf("扩展标识值%d超出uint16范围最大%d", suffix, maxSuffix)
// }
// 位运算拼接(无重叠,按位或)
return (int64(prefix) << prefixOffset) |
c.Base = (int64(prefix) << prefixOffset) |
(int64(catchTime) << catchOffset) |
int64(suffix), nil
int64(suffix)
}
// Split 从64位效果ID拆分出三个字段
// 返回:效果类型(prefix)、CatchTime、扩展标识(suffix)
func (c EffectIDCombiner) Split(val int64) (prefix EnumEffectType, catchTime uint32, suffix uint16) {
suffix = uint16(val & suffixMask)
catchTime = uint32((val >> catchOffset) & catchMask)
prefix = EnumEffectType((val >> prefixOffset) & prefixMask)
return
// EffectID 获取完整的64位效果ID
func (e *EffectIDCombiner) EffectID() int64 {
return e.Base
}
// -------------------------- 组合结构体封装64位ID支持自由取值 --------------------------
// EffectCombined 效果组合结构体封装64位ID提供语义化取值方法
type EffectCombined struct {
effectID int64 // 拼接后的64位效果ID
combiner EffectIDCombiner // 内置拼接器,避免重复创建
}
// NewEffectCombined 构造函数:创建效果组合实例
// 参数:
// effectType: 效果类型如EffectType.Skill
// catchTime: 32位CatchTime中32位核心值
// suffix: 低16位扩展标识
// 返回:组合实例,失败返回错误
func NewEffectCombined(effectType EnumEffectType, catchTime uint32, suffix uint16) (*EffectCombined, error) {
combiner := EffectIDCombiner{}
// 校验效果类型是否在uint16范围内
prefix := uint16(effectType)
if uint64(effectType) > uint64(maxPrefix) {
return nil, fmt.Errorf("效果类型(值%d超出uint16范围", effectType)
// EffectType 读取/替换效果类型(读写一体)
// 参数t可选传入则替换当前效果类型不传则仅读取
// 返回当前的效果类型EnumEffectType
func (e *EffectIDCombiner) EffectType(t ...EnumEffectType) EnumEffectType {
if len(t) > 0 {
// 替换逻辑先清空高16位再设置新值
e.Base = (e.Base & ^prefixMask) | (int64(t[0]) << prefixOffset)
}
// 读取并返回当前效果类型
return EnumEffectType((e.Base >> prefixOffset) & 0xFFFF)
}
// 拼接64位ID
effectID, err := combiner.Combine(prefix, catchTime, suffix)
if err != nil {
return nil, fmt.Errorf("拼接效果ID失败%w", err)
// CatchTime 读取/替换CatchTime读写一体完全保留你的写法
// 参数t可选传入则替换当前CatchTime不传则仅读取
// 返回当前的CatchTime值
func (e *EffectIDCombiner) CatchTime(t ...uint32) uint32 {
if len(t) > 0 {
e.Base = (e.Base & ^catchMask) | (int64(t[0]) << catchOffset)
}
return uint32((e.Base >> catchOffset) & catchMask)
}
return &EffectCombined{
effectID: effectID,
combiner: combiner,
}, nil
// Suffix 读取/替换扩展标识读写一体和CatchTime写法一致
// 参数t可选传入则替换当前扩展标识不传则仅读取
// 返回:当前的扩展标识值
func (e *EffectIDCombiner) Suffix(t ...uint16) uint16 {
if len(t) > 0 {
// 替换逻辑先清空低16位再设置新值
e.Base = (e.Base & ^suffixMask) | int64(t[0])
}
// 读取并返回当前扩展标识
return uint16(e.Base & suffixMask)
}
// -------------------------- 自由取值方法(核心需求:按需取不同类型) --------------------------
// GetEffectID 获取完整的64位效果ID
func (e *EffectCombined) GetEffectID() int64 {
return e.effectID
}
// GetEffectType 获取效果类型转为EnumEffectType类型安全
func (e *EffectCombined) GetEffectType() EnumEffectType {
prefix, _, _ := e.combiner.Split(e.effectID)
return EnumEffectType(prefix)
}
// GetCatchTime 获取32位CatchTime核心字段直接从64位ID中拆分
func (e *EffectCombined) GetCatchTime() uint32 {
_, catchTime, _ := e.combiner.Split(e.effectID)
return catchTime
}
// GetSuffix 获取低16位扩展标识
func (e *EffectCombined) GetSuffix() uint16 {
_, _, suffix := e.combiner.Split(e.effectID)
return suffix
}
func Test() {
combiner := &EffectIDCombiner{}
// 2. 创建组合实例
combined, err := NewEffectCombined(EffectType.Skill, 584464, 8980)
if err != nil {
fmt.Printf("创建失败:%v\n", err)
return
}
// 3. 自由获取不同类型的值(核心需求)
fmt.Println("完整64位效果ID", combined.GetEffectID())
fmt.Println("效果类型(枚举值):", combined.GetEffectType())
// fmt.Println("效果类型(描述):", combined.GetEffectTypeDesc())
fmt.Println("32位CatchTime", combined.GetCatchTime()) // 直接取中32位的CatchTime
fmt.Println("低16位扩展标识", combined.GetSuffix())
// 1. 初始化拼接ID
combiner.Combine(EffectType.Skill, 123456, 789)
// 4. 手动拆分验证(可选)
combiner := EffectIDCombiner{}
prefix, ct, sf := combiner.Split(combined.GetEffectID())
fmt.Printf("\n手动拆分结果\n")
fmt.Printf("效果类型uint16%d\n", prefix)
fmt.Printf("CatchTimeuint32%d\n", ct)
fmt.Printf("扩展标识uint16%d\n", sf)
fmt.Println("=== 初始值 ===")
fmt.Printf("完整ID%d\n", combiner.EffectID())
fmt.Printf("效果类型:%d\n", combiner.EffectType()) // 仅读取
fmt.Printf("CatchTime%d\n", combiner.CatchTime()) // 仅读取
fmt.Printf("扩展标识:%d\n", combiner.Suffix()) // 仅读取
// 2. 替换字段(传参即替换)
combiner.EffectType(EffectType.NewSel) // 替换效果类型为Buff
combiner.CatchTime(987654) // 替换CatchTime
combiner.Suffix(666) // 替换扩展标识
fmt.Println("\n=== 替换后 ===")
fmt.Printf("完整ID%d\n", combiner.EffectID())
fmt.Printf("效果类型:%d\n", combiner.EffectType())
fmt.Printf("CatchTime%d\n", combiner.CatchTime())
fmt.Printf("扩展标识:%d\n", combiner.Suffix())
// 3. 链式替换+读取(一行完成替换并获取新值)
newCatchTime := combiner.CatchTime(111222) // 替换并返回新值
fmt.Printf("\n替换CatchTime并读取%d\n", newCatchTime)
}

View File

@@ -65,6 +65,6 @@ type Effect interface {
//Owner(...bool) bool // 技能属主,比如寄生和镇魂歌,属主是对方)
GetInput() *Input
ID(...int64) int64
ID(...EffectIDCombiner) EffectIDCombiner
//GetSkill() *BattleSkillEntity //获得技能ctx
}

View File

@@ -39,10 +39,7 @@ func (f *FightC) battleLoop() {
f.resolveRound(actions[ourID], actions[oppID])
}
if f.callback != nil {
f.callback(&f.FightOverInfo) //先执行回调,再执行返回信息,在回调内修改战斗判断
}
f.Broadcast(func(ff *input.Input) {
//todo 将血量和技能pp传回enterturn
@@ -56,6 +53,13 @@ func (f *FightC) battleLoop() {
for j := 0; j < len(ff.Player.GetInfo().PetList); j++ {
if ff.Player.GetInfo().PetList[j].CatchTime == ff.AllPet[i].Info.CatchTime {
if ff.UserID == f.WinnerId {
if ff.CurrentPet.Info.CatchTime == ff.Player.GetInfo().PetList[j].CatchTime {
f.Winpet = &ff.Player.GetInfo().PetList[j]
}
}
ff.Player.GetInfo().PetList[j].Hp = ff.AllPet[i].Info.Hp
ff.Player.GetInfo().PetList[j].SkillList = ff.AllPet[i].Info.SkillList
}
@@ -68,7 +72,11 @@ func (f *FightC) battleLoop() {
//大乱斗,给个延迟
<-time.After(500)
}
if f.callback != nil {
f.callback(&f.FightOverInfo) //先执行回调,再执行返回信息,在回调内修改战斗判断
}
ff.Player.SendPackCmd(2506, &f.FightOverInfo)
ff.Player.QuitFight()

View File

@@ -13,7 +13,7 @@ type EffectNode struct {
Input *input.Input
stacks int // 当前层数
id int64
id input.EffectIDCombiner
canStack bool // 最大叠加层数 ,正常都是不允许叠加的,除了衰弱特殊效果 ,异常和能力的叠层
SideEffectArgs []int // 附加效果参数
// owner bool //是否作用自身
@@ -24,6 +24,7 @@ type EffectNode struct {
hit bool
trunl sync.Once
ctx input.Ctx
input.EffectIDCombiner
//增加owner target如果owner target都为自身就回合效果结束后再使用回合效果
}
@@ -53,9 +54,10 @@ func (e *EffectNode) Stack(t ...int) int {
return e.stacks
}
func (e *EffectNode) ID(t ...int64) int64 {
func (e *EffectNode) ID(t ...input.EffectIDCombiner) input.EffectIDCombiner {
if len(t) > 0 {
e.id = t[0]
}
return e.id

View File

@@ -28,6 +28,18 @@ type WalkOutInfo struct {
Path string
}
type MapBossSInfo struct {
InfoLen uint32 `struc:"sizeof=INFO" json:"info_len"`
INFO []MapBossInfo
}
type MapBossInfo struct {
Id uint32 `json:"id" protobuf:"1,req,name=id"` // 需要刷新的BOSS精灵ID
Region uint32 `json:"region" protobuf:"2,req,name=region"` // 刷新区域蘑菇怪为0
Hp uint32 `json:"hp" protobuf:"3,req,name=hp"` // HP值蘑菇怪为A其他BOSS暂未明确用途可能无实际作用
Pos uint32 `json:"pos" protobuf:"4,req,name=pos"` // 刷新坐标类似野怪的位置ID蘑菇怪初始为2战斗退出后该值会变化
}
// 这里存储星球的map
//var planetmap utils.SyncMap[] //= space.NewSyncMap()

View File

@@ -1,21 +1,18 @@
package player
import (
"github.com/badu/bus"
"github.com/samber/lo"
"blazing/modules/blazing/model"
)
type Done struct {
*Player //对玩家进行操作
*bus.Topic[*model.MilestoneEX]
// *bus.Topic[*model.MilestoneEX]
}
func NewDone(P *Player) Done {
return Done{
Player: P,
Topic: bus.NewTopic[*model.MilestoneEX](),
/// Topic: bus.NewTopic[*model.MilestoneEX](),
}
}
@@ -25,37 +22,46 @@ func NewDone(P *Player) Done {
// BOSSID 地图BOSSID
// 注册胜利次数
// 监听器返回奖励是否发送完成,完成就done
func (d *Done) SPT(mapid, bossid, count uint32, fn func() bool) *bus.Listener[*model.MilestoneEX] {
return d.Topic.Sub(func(v *model.MilestoneEX) {
//然后每次触发使用前缀匹配,只要前缀满足就触发
if v.DoneType == model.MilestoneMode.BOSS && IsPrefixBasicSlice(v.Args, []uint32{mapid, bossid}) && v.Count == count {
// func (d *Done) SPT(mapid, bossid, count uint32, fn func() bool) *bus.Listener[*model.MilestoneEX] {
// return d.Topic.Sub(func(v *model.MilestoneEX) {
// //然后每次触发使用前缀匹配,只要前缀满足就触发
// if v.DoneType == model.MilestoneMode.BOSS && IsPrefixBasicSlice(v.Args, []uint32{mapid, bossid}) && v.Count == count {
_, ok := lo.Find(v.Args, func(v1 uint32) bool { //寻找是否触发过
//大于触发值就触发然后1的返回false因为没有奖励这样就可以一直触发
return v1 >= count //大于等于就触发
})
if !ok { //说明没有触发过
// _, ok := lo.Find(v.Args, func(v1 uint32) bool { //寻找是否触发过
// //大于触发值就触发然后1的返回false因为没有奖励这样就可以一直触发
// return v1 >= count //大于等于就触发
// })
// if !ok { //说明没有触发过
if fn() {
v.Results = append(v.Results, count) //把本次的记录添加
}
// if fn() {
// v.Results = append(v.Results, count) //把本次的记录添加
// }
}
// }
}
// }
})
// })
}
// }
// 分发事件 ,指定事件+1 并触发是否完成
func (d *Done) Exec(Donetype model.EnumMilestone, id []uint32) {
func (d *Player) Exec(Donetype model.EnumMilestone, id []uint32, fn func(*model.MilestoneEX) uint32) {
d.Service.Done.Exec(Donetype, id, func(t *model.MilestoneEX) bool {
d.Topic.Pub(t) //异步发送,然后给事件+1
//这里给予即时奖励,并将用户计数+1
t.Count++
//然后有需要自动发送奖励地方,发送完奖励给置真
if fn != nil {
t1 := fn(t)
if t1 != 0 {
t.Results = append(t.Results, t1) //把本次的记录添加
}
}
// d.Topic.Pub(t) //异步发送,然后给事件+1
// d.Topic.PubAsyncCallBack(s, func() { //如果没执行完,说明奖励没发完,直接掉线
// d.Service.Done.Exec(s) //给计数器加1
// }) //提交触发里程碑奖励

View File

@@ -53,7 +53,7 @@ func (h *ClientData) Recv(data common.TomeeHeader) {
cmdlister, ok := cool.CmdCache.Load(data.CMD)
if !ok {
glog.Debug(context.Background(), data.CMD, "cmd未注册")
glog.Debug(context.Background(), data.UserID, data.CMD, "cmd未注册")
return //TODO 待实现cmd未注册
}

View File

@@ -43,6 +43,7 @@ type OgrePetInfo struct {
Id uint32
Shiny uint32
Lv uint32 `struc:"skip"` //等级
Item uint32 `struc:"skip"` //奖励,如果有的话
}
type Player struct {
@@ -185,16 +186,24 @@ func (p *Player) genMonster(mapid uint32) {
mapss, ok := xmlres.MonsterMap[gconv.Int(mapid)]
if ok && mapss.Monsters != nil {
ok, _, _ := p.PlayerCaptureContext.Roll(mapss.Monsters.WildBonusProb, mapss.Monsters.WildBonusTotalProb)
for i, m := range mapss.Monsters.Monsters { //这里是9个
id := strings.Split(m.ID, " ")
lv := strings.Split(m.Lv, " ")
ttt := OgrePetInfo{
Id: gconv.Uint32(RandomStringFromSlice(id)),
}
if ok {
ttt.Item = uint32(mapss.Monsters.ItemBonusID)
}
if ttt.Id != 0 {
ttt.Shiny = 0 //待确认是否刷新异色
ttt.Lv = gconv.Uint32(RandomStringFromSlice(lv))
}
t1.Data[i] = ttt
}
@@ -261,8 +270,8 @@ func replaceOneNumber(original [3]int) ([3]int, int, int) {
}
// 添加物品 返回成功添加的物品
func (p *Player) ItemAdd(t ...model.SingleItemInfo) (result []model.SingleItemInfo) {
var ttt []model.SingleItemInfo
func (p *Player) ItemAdd(t ...model.ItemInfo) (result []model.ItemInfo) {
var ttt []model.ItemInfo
for _, v := range t {
switch v.ItemId {

View File

@@ -1,6 +1,9 @@
package task
import "blazing/logic/service/common"
import (
"blazing/logic/service/common"
"blazing/modules/blazing/model"
)
type CompleteTaskInboundInfo struct {
Head common.TomeeHeader `cmd:"2202|2233" struc:"[0]pad"`
@@ -8,16 +11,9 @@ type CompleteTaskInboundInfo struct {
OutState uint32 `json:"outState" ` // 当前状态1表示完成任务
}
type CompleteTaskOutboundInfo struct {
TaskId uint32 `json:"taskId" description:"任务ID"` // 任务ID
PetTypeId uint32 `json:"petTypeId" description:"发放的精灵ID"` // 发放的精灵ID
CaptureTime uint32 `json:"captureTime" description:"发放的精灵捕获时间"` // 发放的精灵捕获时间,
ItemLen uint32 `struc:"sizeof=ItemList"`
ItemList []ItemInfo `json:"itemList" description:"发放物品的数组"` // 发放物品的数组,
}
// ItemInfo
// 用于表示发放物品的信息
type ItemInfo struct {
ItemId uint32 `json:"itemId" description:"发放物品ID"` // 发放物品ID
ItemCnt uint32 `json:"itemCount" description:"发放物品的数量"` // 发放物品的数量,
TaskId uint32 `json:"taskId" description:"任务ID"` // 任务ID
PetTypeId uint32 `json:"petTypeId" description:"发放的精灵ID"` // 发放的精灵ID
CaptureTime uint32 `json:"captureTime" description:"发放的精灵捕获时间"` // 发放的精灵捕获时间,
ItemLen uint32 `struc:"sizeof=ItemList"`
ItemList []model.ItemInfo `json:"itemList" description:"发放物品的数组"` // 发放物品的数组,
}

View File

@@ -1,12 +1,13 @@
package task
import (
"blazing/modules/blazing/model"
"sync"
)
// RegisterTask 注册任务奖励
// 参数任务ID、分支(OutState)、物品列表、精灵类型(0=无)
func RegisterTask(taskID uint32, outState uint32, items []ItemInfo, petType uint32) {
func RegisterTask(taskID uint32, outState uint32, items []model.ItemInfo, petType uint32) {
if _, ok := TaskResultMap[taskID]; !ok {
TaskResultMap[taskID] = make(map[uint32]TaskResult)
}
@@ -18,24 +19,24 @@ func RegisterTask(taskID uint32, outState uint32, items []ItemInfo, petType uint
func init() {
// -------------------------- 新手任务 --------------------------
RegisterTask(85, 1, []ItemInfo{ // 新手任务1默认分支1
RegisterTask(85, 1, []model.ItemInfo{ // 新手任务1默认分支1
{100027, 1}, // 新手帽
{100028, 1}, // 新手腰带
{500001, 1}, // 精灵仓库
{500502, 1}, // 精灵恢复仓
}, 0)
RegisterTask(86, 1, []ItemInfo{}, 1) // 新手任务2分支1布布种子
RegisterTask(86, 2, []ItemInfo{}, 7) // 新手任务2分支2小火猴
RegisterTask(86, 3, []ItemInfo{}, 4) // 新手任务2分支3伊优
RegisterTask(86, 0, []ItemInfo{}, 1) // 新手任务2默认分支布布种子
RegisterTask(86, 1, []model.ItemInfo{}, 1) // 新手任务2分支1布布种子
RegisterTask(86, 2, []model.ItemInfo{}, 7) // 新手任务2分支2小火猴
RegisterTask(86, 3, []model.ItemInfo{}, 4) // 新手任务2分支3伊优
RegisterTask(86, 0, []model.ItemInfo{}, 1) // 新手任务2默认分支布布种子
RegisterTask(87, 0, []ItemInfo{ // 新手任务3默认分支
RegisterTask(87, 0, []model.ItemInfo{ // 新手任务3默认分支
{300001, 5}, // 普通胶囊x5
{300011, 3}, // 初级体力药剂x3
}, 0)
RegisterTask(88, 1, []ItemInfo{ // 新手任务4默认分支
RegisterTask(88, 1, []model.ItemInfo{ // 新手任务4默认分支
{1, 50000}, // 赛尔豆x50000
{3, 50000}, // 累积经验x50000
{5, 20}, // 金豆x20
@@ -44,19 +45,19 @@ func init() {
}, 0)
// -------------------------- 普通任务(无精灵奖励) --------------------------
RegisterTask(90, 0, []ItemInfo{ // 克洛斯星的皮皮
RegisterTask(90, 0, []model.ItemInfo{ // 克洛斯星的皮皮
{1, 1000}, // 赛尔豆x1000
{3, 1000}, // 经验x1000
}, 0)
RegisterTask(8, 0, []ItemInfo{{500510, 1}}, 0) // 西塔的珍贵回忆记忆晶体x1
RegisterTask(9, 0, []ItemInfo{{100059, 1}}, 0) // 进入神秘通道电能锯子x1
RegisterTask(10, 0, []ItemInfo{}, 0) // 神秘通道拼图(无奖励)
RegisterTask(12, 0, []ItemInfo{}, 0) // 精灵广场拿石头(无奖励)
RegisterTask(19, 0, []ItemInfo{{3, 3000}}, 0) // 先锋队招募积累经验x3000
RegisterTask(25, 0, []ItemInfo{{400501, 10}}, 0) // 新船员的考验神奇扭蛋牌x10
RegisterTask(8, 0, []model.ItemInfo{{500510, 1}}, 0) // 西塔的珍贵回忆记忆晶体x1
RegisterTask(9, 0, []model.ItemInfo{{100059, 1}}, 0) // 进入神秘通道电能锯子x1
RegisterTask(10, 0, []model.ItemInfo{}, 0) // 神秘通道拼图(无奖励)
RegisterTask(12, 0, []model.ItemInfo{}, 0) // 精灵广场拿石头(无奖励)
RegisterTask(19, 0, []model.ItemInfo{{3, 3000}}, 0) // 先锋队招募积累经验x3000
RegisterTask(25, 0, []model.ItemInfo{{400501, 10}}, 0) // 新船员的考验神奇扭蛋牌x10
RegisterTask(37, 0, []ItemInfo{ // 帕诺星系星球测绘
RegisterTask(37, 0, []model.ItemInfo{ // 帕诺星系星球测绘
{1, 3000}, // 赛尔豆x3000
{700452, 1}, // 中型智慧芯片x1
{100178, 1}, // 勘察头盔x1
@@ -65,182 +66,182 @@ func init() {
{100181, 1}, // 勘察军靴x1
}, 0)
RegisterTask(47, 0, []ItemInfo{ // 突围磁风暴
RegisterTask(47, 0, []model.ItemInfo{ // 突围磁风暴
{3, 5000}, // 累积经验x5000
{1, 5000}, // 赛尔豆x5000
{500585, 1}, // 磁力光束枪台x1
}, 0)
RegisterTask(48, 0, []ItemInfo{ // 神秘失踪的爱丽丝
RegisterTask(48, 0, []model.ItemInfo{ // 神秘失踪的爱丽丝
{3, 3000}, // 累积经验x3000
{1, 2000}, // 赛尔豆x2000
{700452, 2}, // 中型智慧芯片x2
}, 0)
RegisterTask(52, 0, []ItemInfo{ // 谁偷走了雪球能源?
RegisterTask(52, 0, []model.ItemInfo{ // 谁偷走了雪球能源?
{3, 3000}, // 累积经验x3000
{400021, 10}, // 雪球能源x10
{100254, 1}, // 斯诺纪念x1
}, 0)
RegisterTask(54, 0, []ItemInfo{ // 米鲁族的两个小不点
RegisterTask(54, 0, []model.ItemInfo{ // 米鲁族的两个小不点
{3, 5000}, // 累积经验x5000
{400021, 10}, // 雪球能源x10
}, 0)
RegisterTask(57, 0, []ItemInfo{ // 米鲁族食王选拔赛
RegisterTask(57, 0, []model.ItemInfo{ // 米鲁族食王选拔赛
{3, 3000}, // 累积经验x3000
{1, 3000}, // 赛尔豆x3000
}, 0)
RegisterTask(58, 0, []ItemInfo{ // 斯诺岩洞的不解之谜
RegisterTask(58, 0, []model.ItemInfo{ // 斯诺岩洞的不解之谜
{3, 3000}, // 累积经验x3000
{1, 3000}, // 赛尔豆x3000
{400021, 10}, // 雪球能源x10
}, 0)
RegisterTask(63, 0, []ItemInfo{ // 新型试作机SR-01同步调试
RegisterTask(63, 0, []model.ItemInfo{ // 新型试作机SR-01同步调试
{3, 3000}, // 累积经验x3000
{1, 3000}, // 赛尔豆x3000
}, 0)
RegisterTask(64, 0, []ItemInfo{ // 铸造斯诺冰冠
RegisterTask(64, 0, []model.ItemInfo{ // 铸造斯诺冰冠
{3, 3000}, // 累积经验x3000
{1, 3000}, // 赛尔豆x3000
{400021, 10}, // 雪球能源x10
}, 0)
RegisterTask(65, 0, []ItemInfo{ // 露希欧星勘察
RegisterTask(65, 0, []model.ItemInfo{ // 露希欧星勘察
{3, 3000}, // 累积经验x3000
{1, 3000}, // 赛尔豆x3000
}, 0)
RegisterTask(66, 0, []ItemInfo{ // 合金强化试验
RegisterTask(66, 0, []model.ItemInfo{ // 合金强化试验
{3, 3000}, // 累积经验x3000
{1, 3000}, // 赛尔豆x3000
}, 0)
RegisterTask(68, 0, []ItemInfo{ // 资料室的神秘事件
RegisterTask(68, 0, []model.ItemInfo{ // 资料室的神秘事件
{3, 3000}, // 累积经验x3000
{1, 3000}, // 赛尔豆x3000
}, 0)
RegisterTask(69, 0, []ItemInfo{ // 宇宙遭遇站
RegisterTask(69, 0, []model.ItemInfo{ // 宇宙遭遇站
{3, 3000}, // 累积经验x3000
{1, 3000}, // 赛尔豆x3000
}, 0)
RegisterTask(70, 0, []ItemInfo{ // 船体紧急修复
RegisterTask(70, 0, []model.ItemInfo{ // 船体紧急修复
{3, 3000}, // 累积经验x3000
{1, 3000}, // 赛尔豆x3000
}, 0)
RegisterTask(72, 0, []ItemInfo{ // 船长搜救任务
RegisterTask(72, 0, []model.ItemInfo{ // 船长搜救任务
{3, 2000}, // 累积经验x2000
{1, 1000}, // 赛尔豆x1000
}, 0)
RegisterTask(73, 0, []ItemInfo{ // 秘制改良机SR-02
RegisterTask(73, 0, []model.ItemInfo{ // 秘制改良机SR-02
{100303, 1}, // SR-02铠甲x1
{400055, 30}, // 变形能量块x30
{3, 3000}, // 累积经验x3000
}, 0)
RegisterTask(74, 0, []ItemInfo{{3, 3000}}, 0) // 露希欧星历险积累经验x3000
RegisterTask(74, 0, []model.ItemInfo{{3, 3000}}, 0) // 露希欧星历险积累经验x3000
RegisterTask(75, 0, []ItemInfo{ // 哈莫的童年片段一
RegisterTask(75, 0, []model.ItemInfo{ // 哈莫的童年片段一
{3, 3000}, // 累积经验x3000
{100324, 1}, // 龙之纪念x1
}, 0)
RegisterTask(79, 0, []ItemInfo{ // 寻找哈莫雷特的族人
RegisterTask(79, 0, []model.ItemInfo{ // 寻找哈莫雷特的族人
{3, 3000}, // 累积经验x3000
{1, 2000}, // 赛尔豆x2000
}, 0)
RegisterTask(80, 0, []ItemInfo{ // 重铸贾斯丁站长
RegisterTask(80, 0, []model.ItemInfo{ // 重铸贾斯丁站长
{3, 2000}, // 累积经验x2000
{1, 3000}, // 赛尔豆x3000
}, 0)
RegisterTask(81, 0, []ItemInfo{ // 守候宿命的追随者
RegisterTask(81, 0, []model.ItemInfo{ // 守候宿命的追随者
{3, 1000}, // 累积经验x1000
{1, 1000}, // 赛尔豆x1000
}, 0)
RegisterTask(83, 0, []ItemInfo{ // 光暗之迷
RegisterTask(83, 0, []model.ItemInfo{ // 光暗之迷
{3, 1000}, // 累积经验x1000
{1, 1000}, // 赛尔豆x1000
}, 0)
RegisterTask(84, 0, []ItemInfo{ // 星球改造计划
RegisterTask(84, 0, []model.ItemInfo{ // 星球改造计划
{3, 2000}, // 累积经验x2000
{1, 2000}, // 赛尔豆x2000
}, 0)
RegisterTask(89, 0, []ItemInfo{ // 试炼之塔的磨练
RegisterTask(89, 0, []model.ItemInfo{ // 试炼之塔的磨练
{3, 500}, // 累积经验x500
{1, 1000}, // 赛尔豆x1000
}, 0)
RegisterTask(91, 0, []ItemInfo{ // 月光下的约定
RegisterTask(91, 0, []model.ItemInfo{ // 月光下的约定
{3, 2000}, // 累积经验x2000
{1, 2000}, // 赛尔豆x2000
}, 0)
RegisterTask(93, 0, []ItemInfo{ // 云霄星的新来客
RegisterTask(93, 0, []model.ItemInfo{ // 云霄星的新来客
{3, 1000}, // 累积经验x1000
{1, 500}, // 赛尔豆x500
}, 0)
RegisterTask(94, 0, []ItemInfo{ // 初识星球能源
RegisterTask(94, 0, []model.ItemInfo{ // 初识星球能源
{3, 500}, // 累积经验x500
{1, 1000}, // 赛尔豆x1000
}, 0)
RegisterTask(96, 0, []ItemInfo{ // 旅途中的伙伴
RegisterTask(96, 0, []model.ItemInfo{ // 旅途中的伙伴
{3, 500}, // 累积经验x500
{1, 1000}, // 赛尔豆x1000
}, 0)
RegisterTask(97, 0, []ItemInfo{ // 我是音乐小麦霸
RegisterTask(97, 0, []model.ItemInfo{ // 我是音乐小麦霸
{3, 1000}, // 累积经验x1000
{1, 1000}, // 赛尔豆x1000
}, 0)
RegisterTask(98, 0, []ItemInfo{ // 尼布守卫战
RegisterTask(98, 0, []model.ItemInfo{ // 尼布守卫战
{3, 2000}, // 累积经验x2000
{1, 1000}, // 赛尔豆x1000
}, 0)
RegisterTask(201, 0, []ItemInfo{{100062, 1}}, 0) // 教官考核教官指挥棒x1
RegisterTask(300, 0, []ItemInfo{{400150, 1}}, 0) // 领取谱尼真身谱尼的精元x1
RegisterTask(201, 0, []model.ItemInfo{{100062, 1}}, 0) // 教官考核教官指挥棒x1
RegisterTask(300, 0, []model.ItemInfo{{400150, 1}}, 0) // 领取谱尼真身谱尼的精元x1
// -------------------------- 带精灵奖励的任务 --------------------------
RegisterTask(28, 0, []ItemInfo{}, 102) // 遗迹中的精灵信号奇塔类型102
RegisterTask(40, 0, []ItemInfo{}, 139) // 时空之门迪卢卡类型139
RegisterTask(28, 0, []model.ItemInfo{}, 102) // 遗迹中的精灵信号奇塔类型102
RegisterTask(40, 0, []model.ItemInfo{}, 139) // 时空之门迪卢卡类型139
RegisterTask(49, 0, []ItemInfo{ // 密林中的托尼(托尼+物品)
RegisterTask(49, 0, []model.ItemInfo{ // 密林中的托尼(托尼+物品)
{700452, 2}, // 中型智慧芯片x2
}, 158) // 托尼类型158
RegisterTask(71, 0, []ItemInfo{ // 赛尔号大整修TOE+物品)
RegisterTask(71, 0, []model.ItemInfo{ // 赛尔号大整修TOE+物品)
{3, 1000}, // 累积经验x1000
{1, 1000}, // 赛尔豆x1000
}, 213) // TOE类型213
RegisterTask(92, 0, []ItemInfo{ // 站长归来(尼布+物品)
RegisterTask(92, 0, []model.ItemInfo{ // 站长归来(尼布+物品)
{3, 2000}, // 累积经验x2000
{1, 2000}, // 赛尔豆x2000
}, 95) // 尼布类型95
RegisterTask(133, 0, []ItemInfo{ // 寻找迷失的心(史空+物品)
RegisterTask(133, 0, []model.ItemInfo{ // 寻找迷失的心(史空+物品)
{3, 2000}, // 累积经验x2000
{1, 2000}, // 赛尔豆x2000
}, 381) // 史空类型381
// -------------------------- 多分支任务 --------------------------
RegisterTask(95, 1, []ItemInfo{ // 宇宙中的黑色旋涡分支1刺蜂套装
RegisterTask(95, 1, []model.ItemInfo{ // 宇宙中的黑色旋涡分支1刺蜂套装
{3, 4000}, // 累积经验x4000
{1, 2000}, // 赛尔豆x2000
{100346, 1}, // 刺蜂重盔x1
@@ -249,7 +250,7 @@ func init() {
{100349, 1}, // 刺蜂滚轮x1
}, 0)
RegisterTask(95, 2, []ItemInfo{ // 宇宙中的黑色旋涡分支2锡蝶套装
RegisterTask(95, 2, []model.ItemInfo{ // 宇宙中的黑色旋涡分支2锡蝶套装
{3, 4000}, // 累积经验x4000
{1, 2000}, // 赛尔豆x2000
{100350, 1}, // 锡蝶重盔x1

View File

@@ -1,9 +1,11 @@
package task
import "blazing/modules/blazing/model"
type TaskResult struct {
PetTypeId uint32 `json:"petTypeId" description:"发放的精灵ID"` // 发放的精灵ID
ItemList []ItemInfo `json:"itemList" description:"发放物品的数组"` // 发放物品的数组,
ItemList []model.ItemInfo `json:"itemList" description:"发放物品的数组"` // 发放物品的数组,
}
var TaskResultMap = make(map[uint32]map[uint32]TaskResult)
@@ -25,9 +27,9 @@ func Get_Task_Info(v CompleteTaskInboundInfo) *TaskResult {
}
func init() {
// 定义通用奖励经验奖励ItemId:3数量20000
expReward := []ItemInfo{{ItemId: 3, ItemCnt: 20000}}
expReward := []model.ItemInfo{{ItemId: 3, ItemCnt: 20000}}
// 定义扭蛋牌奖励ItemId:400501数量5
eggReward := []ItemInfo{{ItemId: 400501, ItemCnt: 5}}
eggReward := []model.ItemInfo{{ItemId: 400501, ItemCnt: 5}}
// 批量初始化任务ID 401-407奖励均为经验
for taskID := 401; taskID <= 407; taskID++ {

View File

@@ -3,15 +3,17 @@ package model
import (
"blazing/cool"
"github.com/samber/lo"
"github.com/tnnmigga/enum"
)
type EnumMilestone int
var MilestoneMode = enum.New[struct {
BOSS EnumMilestone //boss类 地图ID->BOSSID ,胜利次数 mapid bossid petid防止换boss后数据不可用
ITEM EnumMilestone //物品类 物品ID 使用精灵
Fight EnumMilestone //挑战类 对战模式->对战类型->1是赢,0是总局数
BOSS EnumMilestone //boss类 地图ID->BOSSID ,胜利次数 mapid bossid petid防止换boss后数据不可用
ITEM EnumMilestone //物品类 物品ID 使用精灵
Fight EnumMilestone //挑战类 对战模式->对战类型->1是赢,0是总局数
Moster EnumMilestone //野怪统计 地图ID->怪物ID
}]()
// 里程碑数据结构与DoneEvent对应记录单条里程碑的详细信息
@@ -43,6 +45,25 @@ type MilestoneEX struct {
Results []uint32 `json:"results"` // 解析后的里程碑详细数据
}
// 检查是否触发过,成功返回触发的次数,失败返回0
func (m *MilestoneEX) CheakNoNumber(count uint32) bool {
// if v.DoneType == model.MilestoneMode.BOSS && IsPrefixBasicSlice(v.Args, []uint32{mapid, bossid}) && v.Count == count {
_, ok := lo.Find(m.Results, func(v1 uint32) bool { //寻找是否触发过
//大于触发值就触发然后1的返回false因为没有奖励这样就可以一直触发
return v1 == count //大于等于就触发
})
//没找到且次数满足才能返回真
if !ok && m.Count >= count {
return true
}
//已经触发过
return false
// }
}
// TableName 返回表名
func (*Milestone) TableName() string {
return TableNameMilestone

View File

@@ -6,6 +6,13 @@ import (
const TableNamePlayerBagItem = "player_bag_item"
// ItemInfo
// 用于表示发放物品的信息
type ItemInfo struct {
ItemId uint32 `json:"itemId" description:"发放物品ID"` // 发放物品ID
ItemCnt uint32 `json:"itemCount" description:"发放物品的数量"` // 发放物品的数量,
}
// PlayerBagItem mapped from table <player_bag_item>
type Item struct {
*cool.Model

View File

@@ -2,6 +2,7 @@ package model
import (
"blazing/common/data/xmlres"
"blazing/common/utils"
"blazing/cool"
"math"
"math/rand"
@@ -95,6 +96,21 @@ type PetInfo struct {
// AbilityType uint32 `struc:"skip"` //特性
}
func (pet *PetInfo) ADD_EV(evadd []uint32) {
var sum uint32
for i := range pet.Ev {
sum += pet.Ev[i]
}
cansum := 510 - sum
for i := 0; i < 6; i++ {
pet.Ev[i] += evadd[i]
pet.Ev[i] = utils.Min(pet.Ev[i], 255)
pet.Ev[i] = utils.Min(pet.Ev[i], cansum)
}
}
func (pet *PetInfo) Cure() {
pet.Hp = pet.MaxHp
for i := 0; i < len(pet.SkillList); i++ {
@@ -107,44 +123,62 @@ func (pet *PetInfo) Cure() {
}
}
func (pet *PetInfo) Downgrade(level uint32) {
for pet.Level > uint32(level) {
basic, ok := xmlres.PetMAP[int(pet.ID)]
if ok {
if basic.EvolvesFrom != 0 {
pet.ID = uint32(basic.EvolvesFrom)
}
}
pet.Level--
//进行降级操作
}
}
// 传入bool则不升级
// Update 改造为循环进化:直到宠物无法再进化为止,再更新经验
// t ...bool原参数逻辑len(t)==0时触发进化检查否则仅更新经验
func (petinfo *PetInfo) Update(t ...bool) {
// 仅在无额外参数时触发循环进化逻辑
if len(t) == 0 {
// 最大进化次数限制(防止配置表闭环导致死循环)
maxEvolveTimes := 10
evolveCount := 0
func (petinfo *PetInfo) Update() {
// 循环进化:直到不满足进化条件 或 达到最大进化次数
for {
// 防止死循环,超出次数直接退出
if evolveCount >= maxEvolveTimes {
break
}
// 最大进化次数限制(防止配置表闭环导致死循环)
maxEvolveTimes := 10
evolveCount := 0
// 获取当前宠物形态的配置
basic, ok := xmlres.PetMAP[int(petinfo.ID)]
// 配置不存在,直接退出循环
if !ok {
break
}
// 检查是否满足进化条件
canEvolve := basic.EvolvesTo != 0 && // 有明确的进化目标
int(petinfo.Level) >= basic.EvolvingLv && // 等级达到进化要求
basic.IsLarge == 0 // 非最终形态
// 不满足进化条件,退出循环
if !canEvolve {
break
}
// 执行进化更新宠物ID为进化后形态
petinfo.ID = uint32(basic.EvolvesTo)
evolveCount++ // 进化次数+1
// 循环进化:直到不满足进化条件 或 达到最大进化次数
for {
// 防止死循环,超出次数直接退出
if evolveCount >= maxEvolveTimes {
break
}
// 获取当前宠物形态的配置
basic, ok := xmlres.PetMAP[int(petinfo.ID)]
// 配置不存在,直接退出循环
if !ok {
break
}
// 检查是否满足进化条件
canEvolve := basic.EvolvesTo != 0 && // 有明确的进化目标
int(petinfo.Level) >= basic.EvolvingLv && // 等级达到进化要求
basic.IsLarge == 0 // 非最终形态
// 不满足进化条件,退出循环
if !canEvolve {
break
}
// 执行进化更新宠物ID为进化后形态
petinfo.ID = uint32(basic.EvolvesTo)
evolveCount++ // 进化次数+1
}
// 进化完成后,统一更新经验(原逻辑保留)
@@ -310,7 +344,7 @@ func GenPetInfo(
// ---- 属性计算 ----
p.CalculatePetPane()
p.Update(true)
p.Update()
return p
}

View File

@@ -22,7 +22,7 @@ func (s *DoneService) Exec(data model.EnumMilestone, id []uint32, fn func(*model
Milestone: model.Milestone{
DoneType: data,
Args: strings.Join(gconv.Strings(id), "-"),
Count: 1,
//Count: 1,
},
}
}

View File

@@ -464,7 +464,7 @@ eg:
</Map>
<Map ID="10" Name="克洛斯星一" InitX="725" InitY="172" StarExplorationID="1" PrimaryScene="1">
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5239" ItemBonusID="1" >
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5239" ItemBonusID="400004" des="空气结晶" >
<Monster ID="164 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0" Lv="1 2"/>
<Monster ID="10" Lv="1 2"/>
<Monster ID="10" Lv="1 2"/>
@@ -530,7 +530,7 @@ eg:
</Map>
<Map ID="11" Name="克洛斯星二" InitX="735" InitY="240" StarExplorationID="1">
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5240" ItemBonusID="1" >
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5240" ItemBonusID="400005" des="光合能量" >
<Monster ID="27 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16" Lv="3 4"/>
<Monster ID="16" Lv="4 5"/>
<Monster ID="16" Lv="4 5"/>
@@ -624,7 +624,7 @@ eg:
</Map-->
<Map ID="15" Name="火山星一" InitX="170" InitY="270" StarExplorationID="4" PrimaryScene="1">
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5241" ItemBonusID="1" >
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5241" ItemBonusID="400007" des="火焰元素" >
<Monster ID="38" Lv="16 17"/>
<Monster ID="38" Lv="16 17"/>
<Monster ID="38" Lv="16 17"/>
@@ -646,7 +646,7 @@ eg:
</Map>
<Map ID="16" Name="火山星山洞" InitX="472" InitY="135" StarExplorationID="4">
<Monsters WildBonusProb="700" WildBonusTotalProb="1000" BonusID="5242" ItemBonusID="1" >
<Monsters WildBonusProb="700" WildBonusTotalProb="1000" BonusID="5242" ItemBonusID="400030" des="熔岩晶体" >
<Monster ID="35" Lv="17 18"/>
<Monster ID="35" Lv="17 18"/>
<Monster ID="35" Lv="17 18"/>
@@ -866,7 +866,7 @@ eg:
</Map>
<Map ID="20" Name="海洋星一" InitX="718" InitY="201" StarExplorationID="2" PrimaryScene="1">
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5236" ItemBonusID="1" >
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5236" ItemBonusID="400006" des="水之精华">
<Monster ID="30" Lv="7 8" Name="贝尔"/>
<Monster ID="30" Lv="7 8"/>
<Monster ID="30" Lv="7 8"/>
@@ -927,7 +927,7 @@ eg:
</Map>
<Map ID="21" Name="海洋星二" InitX="663" InitY="217" StarExplorationID="2">
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5237" ItemBonusID="1" >
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5237" ItemBonusID="400029" des="海洋能量">
<Monster ID="33" Lv="9 10" Name="利牙鱼"/>
<Monster ID="33" Lv="9 10"/>
<Monster ID="33" Lv="9 10"/>
@@ -990,7 +990,7 @@ eg:
</Map>
<Map ID="25" Name="云霄星一" InitX="80" InitY="250" StarExplorationID="5" PrimaryScene="1">
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5254" ItemBonusID="1" >
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5254" ItemBonusID="400004" des="空气结晶" >
<Monster ID="23" Lv="21 22" Name="卡洛"/>
<Monster ID="10" Lv="9 10"/>
<Monster ID="23" Lv="21 22"/>
@@ -1006,7 +1006,7 @@ eg:
</Map>
<Map ID="26" Name="云霄星二" InitX="192" InitY="247" StarExplorationID="5">
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5255" ItemBonusID="1" >
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5255" ItemBonusID="400028" des="纯净能量" >
<Monster ID="26" Lv="23 24"/>
<Monster ID="26" Lv="23 24"/>
<Monster ID="26" Lv="23 24"/>
@@ -1043,7 +1043,7 @@ eg:
<!--GbtlBoss MonId="69" Hp="500" Lv="45" NewSeIdxs="54 55"/-->
<GbtlBoss MonId="69" Hp="350" Lv="45" NewSeIdxs="54"/>
</GbtlBosses>
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5005" ItemBonusID="1" >
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5005" ItemBonusID="400028" des="纯净能量" >
<Monster ID="250" Lv="25 26"/>
<Monster ID="250" Lv="25 26"/>
<Monster ID="250" Lv="25 26"/>
@@ -1116,7 +1116,7 @@ eg:
</Map>
<Map ID="30" Name="赫尔卡星一" InitX="659" InitY="420" StarExplorationID="3" PrimaryScene="1">
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5234" ItemBonusID="1" >
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5234" ItemBonusID="400008" des="电容球" >
<Monster ID="13" Lv="11 12"/>
<Monster ID="13" Lv="11 12"/>
<Monster ID="13" Lv="11 12"/>
@@ -1379,7 +1379,7 @@ eg:
</Map>
<Map ID="43" Name="赫尔卡飞船" InitX="230" InitY="130" StarExplorationID="7">
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5263" ItemBonusID="1" >
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5263" ItemBonusID="400003" des="玄冰">
<Monster ID="51" Lv="25 26" Name="玄冰兽"/>
<Monster ID="51" Lv="25 26"/>
<Monster ID="51" Lv="25 26"/>
@@ -1529,7 +1529,7 @@ eg:
</Map>
<Map ID="47" Name="双子贝塔星" InitX="780" InitY="409" StarExplorationID="8" PrimaryScene="1">
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5260" ItemBonusID="1">
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5260" ItemBonusID="400032" des="贝壳精华">
<Monster ID="120" Lv="33 34"/>
<Monster ID="119" Lv="15 16"/>
<Monster ID="120" Lv="33 34"/>
@@ -1596,7 +1596,7 @@ eg:
<GbtlBoss MonId="113" Hp="1100" Lv="75" NewSeIdxs="76"/>
</GbtlBosses>
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5259" ItemBonusID="1">
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5259" ItemBonusID="400031" des="大地之核">
<Monster ID="106" Lv="35 36"/>
<Monster ID="106" Lv="35 36"/>
<Monster ID="106" Lv="35 36"/>
@@ -1717,16 +1717,21 @@ eg:
<Monster ID="205" Lv="16 17"/>
<Monster ID="205" Lv="16 17"/>
</Monsters-->
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5274" ItemBonusID="1" >
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5274" ItemBonusID="400033" des="晶化气泡" >
<Monster ID="699" Lv="16 17"/>
<Monster ID="699" Lv="16 17"/>
<Monster ID="699" Lv="16 17"/>
<Monster ID="700" Lv="39 40"/>
<!-- <Monster ID="700" Lv="39 40"/>
<Monster ID="700" Lv="39 40"/>
<Monster ID="700" Lv="39 40"/>
<Monster ID="700" Lv="39 40"/>
<Monster ID="700" Lv="39 40"/>
<Monster ID="700" Lv="39 40"/>
<Monster ID="700" Lv="39 40"/> -->
<Monster ID="207" Lv="39 40"/>
<Monster ID="207" Lv="39 40"/>
<Monster ID="205" Lv="16 17"/>
<Monster ID="205" Lv="16 17"/>
<Monster ID="205" Lv="16 17"/>
</Monsters>
<Bosses>
<Boss AppearTime="19 21" Name="20110106小魔王" >
@@ -1760,7 +1765,7 @@ eg:
</Map>
<Map ID="55" Name="露希欧泥潭" InitX="635" InitY="480" >
<!--Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5005" ItemBonusID="6">
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5005" ItemBonusID="400027" des="露希之核">
<Monster ID="208" Lv="16 17"/>
<Monster ID="210" Lv="41 42"/>
<Monster ID="210" Lv="41 42"/>
@@ -1770,7 +1775,7 @@ eg:
<Monster ID="210" Lv="41 42"/>
<Monster ID="210" Lv="41 42"/>
<Monster ID="203 208 208 208 208 208 208 208 208 208 208 208 208 208 208 208 208 208 208 208 208 208 208 208 208 208 208 208 208 208" Lv="16 17"/>
</Monsters-->
</Monsters>
</Map>
<Map ID="56" Name="露希欧之洋" InitX="540" InitY="480" NonVipCost="100000">
@@ -1778,7 +1783,7 @@ eg:
<GameTriggerGrp GameID="17" >
<TriggerPt ID="1" />
</GameTriggerGrp>
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5005" ItemBonusID="7">
<Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5005" ItemBonusID="400034" des="水生海草" >
<Monster ID="211" Lv="18 19"/>
<Monster ID="211" Lv="18 19"/>
<Monster ID="211" Lv="18 19"/>
@@ -3181,7 +3186,7 @@ eg:
<!--<BossMon MonID="188" LvHpMatchUser="1" Hp="0" Lv="0"/>-->
<!--</Boss>-->
</Bosses>
<Monsters WildBonusProb="500" WildBonusTotalProb="1000" BonusID="5256" ItemBonusID="1">
<Monsters WildBonusProb="500" WildBonusTotalProb="1000" BonusID="5256" ItemBonusID="400030" des="熔岩晶体">
<!--Monsters WildBonusProb="300" WildBonusTotalProb="1000" BonusID="5005" ItemBonusID="3"-->
<Monster ID="89" Lv="16 17"/>
<Monster ID="90" Lv="27 28"/>
@@ -3553,7 +3558,7 @@ eg:
<!--BonusProbability="20" BonusTotalProbability="1000" BonusID="5016" ItemBonusOutID="9">-->
<!--<BossMon MonID="264" Hp="8000" Lv="60" NewSeIdxs="2 1 58 96 97 55 80 110"/>-->
<!--</Boss>-->
<Boss TaskID="312" AppearTime="0 23" BossVisible="0" Name="SPT奈尼芬多"
<Boss TaskID="312" AppearTime="0 23" BossVisible="0" Name="SPT奈尼芬多"
BonusProbability="20" BonusTotalProbability="1000" BonusID="5016" ItemBonusOutID="9" SptLevel="1">
<BossMon MonID="264" Hp="2500" Lv="60" NewSeIdxs="2 1 58 96 97 80 110"/>
</Boss>