ecs/servers/game/logic/player_battle.go
2025-06-20 15:34:32 +08:00

397 lines
11 KiB
Go

package logic
import (
"ecs/proto"
"ecs/proto/pb"
"ecs/servers/game/data"
"github.com/oylshe1314/framework/util"
"sort"
)
func (this *Player) EnterBattle(sceneTable *data.Scene) {
this.Temp.Fighting = true
this.Temp.RandSeed = util.DefaultRandom.Uint64()
this.enterScene(uint32(sceneTable.Id))
this.copyBattle(sceneTable)
}
func (this *Player) EndBattle() {
this.Temp.Fighting = false
this.Temp.RandSeed = 0
this.enterScene(0)
}
func (this *Player) copyBattle(sceneTable *data.Scene) {
var ack, err = this.virtualBattle(sceneTable)
if err != nil {
_ = this.TipNotice(err)
return
}
if ack.Succeed {
this.PassedCopy(sceneTable, ack.Score)
}
_ = this.Send(pb.ModId_ModuleBattle, pb.MsgId_ModBattleEnter, ack)
}
type _BattleBuff struct {
id uint32
targetType uint32
targetArgs []uint32
rangeType uint32
rangeNum uint32
priorityType []uint32
priorityArgs []uint32
buffType uint32
buffArgs []int64
durationType uint32
duration uint32
canMerge bool
canCover bool
canStack bool
canClean bool
}
type _BattleSkill struct {
id uint32
tipe uint32
rage uint32
buffs []*_BattleBuff
}
type _BattleUnit struct {
id uint64
position uint32
gender uint32
country uint32
hp uint64
rage uint32
speed uint32
baseSpeed uint32
posSpeed uint32
amuletSpeed uint32
harnessSpeed uint32
attrs Attrs
role *_BattleRole
buffs []*_BattleBuff
deBuffs []*_BattleBuff
attackSkills []*_BattleSkill
passiveSkills []*_BattleSkill
}
type _BattleRole struct {
attacker bool
addSpeed uint32
capacity uint64
unitList []*_BattleUnit
//sellList []*_BattleUnit
}
func (this *Player) virtualBattle(sceneTable *data.Scene) (ack *pb.BattleEnterAck, tip proto.TipError) {
var lineup = util.MapFindValue(this.Lineup, func(lineup *PlayerLineup) bool {
return lineup.Active
})
if lineup == nil {
return nil, proto.TipLineupNotFound
}
var me = &_BattleRole{attacker: true}
me.capacity, me.unitList, tip = this.loadHeroes(me, lineup)
if tip != nil {
_ = this.TipNotice(tip)
return
}
//sort.Slice(me.unitList, func(i, j int) bool {
// return me.unitList[i].pos < me.unitList[j].pos
//})
var he = &_BattleRole{attacker: false}
if pb.CopyType(sceneTable.CopyType) == pb.CopyType_CopyArena {
} else {
he.capacity, he.unitList, tip = this.loadMonsters(he, []int{sceneTable.Monster1, sceneTable.Monster2, sceneTable.Monster3, sceneTable.Monster4, sceneTable.Monster5, sceneTable.Monster6})
if tip != nil {
_ = this.TipNotice(tip)
return
}
}
//sort.Slice(he.unitList, func(i, j int) bool {
// return he.unitList[i].pos < he.unitList[j].pos
//})
ack = &pb.BattleEnterAck{
SceneId: uint32(sceneTable.Id),
}
ack.Heroes = make([]*pb.BattleUnit, 6)
for i := range me.unitList {
if me.unitList[i] != nil {
ack.Heroes[i] = &pb.BattleUnit{
UnitId: me.unitList[i].id,
}
}
}
ack.Enemies = make([]*pb.BattleUnit, 6)
for i := range he.unitList {
if he.unitList[i] != nil {
ack.Enemies[i] = &pb.BattleUnit{
UnitId: he.unitList[i].id,
}
}
}
if len(me.unitList) == 0 {
ack.Succeed = false
ack.Score = 0
} else if len(he.unitList) == 0 {
ack.Succeed = true
ack.Score = 3
} else {
var calculator = &_BattleCalculator{
rd: util.NewRand(),
me: me,
he: he,
}
ack.Succeed, ack.RoundList = calculator.calcBattle(sceneTable.BattleRound, me, he)
ack.BattleRounds = uint32(len(ack.RoundList))
if ack.Succeed {
//TODO calc stars
ack.Score = 2
if me.unitList[0].hp > 0 {
ack.Score = 3
}
this.addExp(this.RoleLevel*uint32(sceneTable.ExpMultiple), LogTypeItemObtainByCopy)
this.addMoney(pb.MoneyType_Coin, this.RoleLevel*uint32(sceneTable.CoinMultiple), LogTypeItemObtainByCopy)
//TODO calc reward
var rewardItems = map[uint32]uint32{}
if this.GetCopyPassed(pb.CopyType(sceneTable.CopyType), uint32(sceneTable.CopyId)) == 0 {
var dropResult = this.manager.tables.Drop.Drop(sceneTable.FirstDrop, 1)
for _, items := range dropResult {
rewardItems[uint32(items[0])] += uint32(items[1])
ack.RewardList = append(ack.RewardList, &pb.Item{
ItemId: uint32(items[0]),
ItemNum: uint32(items[1]),
})
}
}
var dropResult = this.manager.tables.Drop.Drop(sceneTable.PassDrop, 1)
for _, items := range dropResult {
rewardItems[uint32(items[0])] += uint32(items[1])
ack.RewardList = append(ack.RewardList, &pb.Item{
ItemId: uint32(items[0]),
ItemNum: uint32(items[1]),
})
}
this.AddItems(rewardItems, LogTypeItemObtainByCopy)
}
}
return ack, nil
}
func (this *Player) calcAttrsCapacity(attrs Attrs) uint64 {
return uint64((float64(attrs[pb.AttrType_Attack]) * 2) +
(float64(attrs[pb.AttrType_Hp]) * 0.2) +
(float64(attrs[pb.AttrType_PhysicalDefense]) * 6) +
(float64(attrs[pb.AttrType_MagicDefense]) * 6) +
(float64(attrs[pb.AttrType_DamageRatio]) * 12) +
(float64(attrs[pb.AttrType_DamageRelief]) * 12) +
(float64(attrs[pb.AttrType_CriticalRate]) * 12) +
(float64(attrs[pb.AttrType_CriticalResistance]) * 12) +
(float64(attrs[pb.AttrType_CriticalDamage]) * 12) +
(float64(attrs[pb.AttrType_CriticalDamageRelief]) * 12) +
(float64(attrs[pb.AttrType_HitRate]) * 12) +
(float64(attrs[pb.AttrType_DodgeRate]) * 12) +
(float64(attrs[pb.AttrType_TreatRatio]) * 12) +
(float64(attrs[pb.AttrType_ByTreatedRate]) * 12) +
(float64(attrs[pb.AttrType_FinalDamageRatio]) * 12))
}
func (this *Player) loadHeroes(role *_BattleRole, lineup *PlayerLineup) (capacity uint64, unitList []*_BattleUnit, tip proto.TipError) {
unitList = make([]*_BattleUnit, 6)
var heroIndex = 0
for i := range 6 {
if lineup.Heroes[i] != nil {
if hero := this.Hero[lineup.Heroes[i].HeroUid]; hero != nil {
capacity += lineup.Heroes[i].Capacity
var unit = &_BattleUnit{
id: lineup.Heroes[i].HeroUid,
position: lineup.Heroes[i].Position,
attrs: hero.Attrs(),
role: role,
}
var heroTable = this.manager.tables.Hero.Find1(int(hero.Id))
if heroTable == nil {
return 0, nil, proto.TipDataTablesError
}
unit.gender = uint32(heroTable.Sex)
unit.country = uint32(heroTable.Country)
unit.attackSkills, tip = this.loadSkills(heroTable.Skill)
if tip != nil {
return
}
sort.Slice(unit.attackSkills, func(i, j int) bool {
return unit.attackSkills[i].tipe > unit.attackSkills[j].tipe
})
unit.hp = unit.attrs[pb.AttrType_Hp]
unit.rage = 4
unit.baseSpeed = 100
unit.posSpeed = uint32(20 - 4*heroIndex)
unit.amuletSpeed = 0 //TODO calc speed
unit.harnessSpeed = 0 //TODO calc speed
//TODO load hero passive skills, from equip, break, soul
unitList[lineup.Heroes[i].Position-1] = unit
}
}
}
return
}
func (this *Player) loadMonsters(role *_BattleRole, monsterIds []int) (capacity uint64, unitList []*_BattleUnit, tip proto.TipError) {
unitList = make([]*_BattleUnit, 6)
var monsterIndex uint64 = 0
for i, monsterId := range monsterIds {
if monsterId == 0 {
continue
}
var monsterTable = this.manager.tables.Monster.Find(int(monsterId))
if monsterTable == nil {
return 0, nil, proto.TipDataTablesError
}
var unit = &_BattleUnit{
id: uint64(monsterTable.Id),
position: uint32(i + 1),
gender: uint32(monsterTable.Gender),
country: uint32(monsterTable.Country),
role: role,
}
unit.attackSkills, tip = this.loadSkills(monsterTable.AttackSkills)
if tip != nil {
return
}
sort.Slice(unit.attackSkills, func(i, j int) bool {
return unit.attackSkills[i].tipe > unit.attackSkills[j].tipe
})
unit.passiveSkills, tip = this.loadSkills(monsterTable.PassiveSkills)
if tip != nil {
return
}
unit.attrs[pb.AttrType_Attack] = uint64(monsterTable.AttrValue1)
unit.attrs[pb.AttrType_Hp] = uint64(monsterTable.AttrValue2)
unit.attrs[pb.AttrType_PhysicalDefense] = uint64(monsterTable.AttrValue3)
unit.attrs[pb.AttrType_MagicDefense] = uint64(monsterTable.AttrValue4)
unit.attrs[pb.AttrType_AttackRatio] = uint64(monsterTable.AttrValue5)
unit.attrs[pb.AttrType_HpRatio] = uint64(monsterTable.AttrValue6)
unit.attrs[pb.AttrType_PhysicalDefenseRatio] = uint64(monsterTable.AttrValue7)
unit.attrs[pb.AttrType_MagicDefenseRatio] = uint64(monsterTable.AttrValue8)
unit.attrs[pb.AttrType_DamageRatio] = uint64(monsterTable.AttrValue9)
unit.attrs[pb.AttrType_DamageRelief] = uint64(monsterTable.AttrValue10)
unit.attrs[pb.AttrType_CriticalRate] = uint64(monsterTable.AttrValue11)
unit.attrs[pb.AttrType_CriticalResistance] = uint64(monsterTable.AttrValue12)
unit.attrs[pb.AttrType_CriticalDamage] = uint64(monsterTable.AttrValue13)
unit.attrs[pb.AttrType_CriticalDamageRelief] = uint64(monsterTable.AttrValue14)
unit.attrs[pb.AttrType_HitRate] = uint64(monsterTable.AttrValue15)
unit.attrs[pb.AttrType_DodgeRate] = uint64(monsterTable.AttrValue16)
unit.attrs[pb.AttrType_TreatRatio] = uint64(monsterTable.AttrValue17)
unit.attrs[pb.AttrType_ByTreatedRate] = uint64(monsterTable.AttrValue18)
unit.attrs[pb.AttrType_FinalDamageRatio] = uint64(monsterTable.AttrValue19)
unit.attrs[pb.AttrType_FinalDamageRelief] = uint64(monsterTable.AttrValue20)
monsterIndex += 1
unit.hp = unit.attrs[pb.AttrType_Hp]
unit.rage = 4
unit.baseSpeed = 0
unit.posSpeed = uint32(20 - 4*monsterIndex)
unit.amuletSpeed = 0 //TODO calc speed
unit.harnessSpeed = 0 //TODO calc speed
capacity += this.calcAttrsCapacity(unit.attrs)
unitList[i] = unit
}
return
}
func (this *Player) loadSkills(skillIds []int) (skillList []*_BattleSkill, tip proto.TipError) {
skillList = make([]*_BattleSkill, 0, len(skillIds))
for _, skillId := range skillIds {
var skillTable = this.manager.tables.Skill.Find(skillId)
if skillTable == nil {
return nil, proto.TipDataTablesError
}
var skill = &_BattleSkill{
id: uint32(skillId),
tipe: uint32(skillTable.SkillType),
rage: uint32(skillTable.RageConsume),
}
skill.buffs, tip = this.loadSkillsBuff(skillTable.SkillBuff)
if tip != nil {
return
}
skillList = append(skillList, skill)
}
return
}
func (this *Player) loadSkillsBuff(buffIds []int) (buffList []*_BattleBuff, tip proto.TipError) {
buffList = make([]*_BattleBuff, 0, len(buffIds))
for _, buffId := range buffIds {
var buffTable = this.manager.tables.SkillBuff.Find(buffId)
if buffTable == nil {
return nil, proto.TipDataTablesError
}
var buff = &_BattleBuff{
id: uint32(buffId),
targetType: uint32(buffTable.TargetType),
targetArgs: util.NumbersConvert2(buffTable.TargetArgs, uint32(0)),
rangeType: uint32(buffTable.RangeType),
rangeNum: uint32(buffTable.RangeNum),
priorityType: util.NumbersConvert2(buffTable.PriorityType, uint32(0)),
priorityArgs: util.NumbersConvert2(buffTable.PriorityArgs, uint32(0)),
buffType: uint32(buffTable.BuffType),
buffArgs: util.NumbersConvert2(buffTable.BuffArgs, int64(0)),
durationType: uint32(buffTable.DurationType),
duration: uint32(buffTable.Duration),
canMerge: buffTable.CanMerge,
canCover: buffTable.CanCover,
canStack: buffTable.CanStack,
canClean: buffTable.CanClean,
}
buffList = append(buffList, buff)
}
return buffList, nil
}