431 lines
12 KiB
Go
431 lines
12 KiB
Go
package logic
|
|
|
|
import (
|
|
"ecs/proto"
|
|
"ecs/proto/pb"
|
|
"ecs/servers/game/data"
|
|
"github.com/oylshe1314/framework/util"
|
|
"sort"
|
|
)
|
|
|
|
func (this *Player) EnterBattle(opponent *Player, sceneTable *data.Scene) {
|
|
this.Temp.Fighting = true
|
|
this.Temp.RandSeed = util.DefaultRandom.Uint64()
|
|
|
|
this.enterScene(uint32(sceneTable.Id))
|
|
this.copyBattle(opponent, sceneTable)
|
|
}
|
|
|
|
func (this *Player) EndBattle() {
|
|
this.Temp.Fighting = false
|
|
this.Temp.RandSeed = 0
|
|
this.enterScene(0)
|
|
}
|
|
|
|
func (this *Player) copyBattle(opponent *Player, sceneTable *data.Scene) {
|
|
var ack, err = this.virtualBattle(opponent, 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
|
|
group int32
|
|
targetType uint32
|
|
targetArgs []int32
|
|
conditionType []uint32
|
|
conditionArgs []int32
|
|
rangeType uint32
|
|
rangeNum uint32
|
|
priorityType []uint32
|
|
priorityArgs []int32
|
|
buffType uint32
|
|
buffArgs []int64
|
|
duration uint32
|
|
canMerge bool
|
|
canCover bool
|
|
canStack bool
|
|
canClean bool
|
|
}
|
|
|
|
type _BattleSkill struct {
|
|
id uint32
|
|
skillType uint32
|
|
cooldown uint32
|
|
consumeRage uint32
|
|
releaseRound 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
|
|
}
|
|
|
|
func (this *Player) virtualBattle(opponent *Player, sceneTable *data.Scene) (ack *pb.BattleEnterAck, tip proto.TipError) {
|
|
|
|
var lineup = this.CurrentLineup()
|
|
if lineup == nil {
|
|
return nil, proto.TipLineupNotFound
|
|
}
|
|
|
|
var me = &_BattleRole{attacker: true}
|
|
me.capacity, me.unitList, tip = this.loadHeroes(me, lineup)
|
|
if tip != nil {
|
|
return nil, tip
|
|
}
|
|
|
|
var he = &_BattleRole{attacker: false}
|
|
if pb.CopyType(sceneTable.CopyType) == pb.CopyType_CopyArena {
|
|
if opponent == nil {
|
|
return nil, proto.TipOpponentNotFound
|
|
}
|
|
|
|
var heLineup = opponent.CurrentLineup()
|
|
if heLineup == nil {
|
|
return nil, proto.TipLineupNotFound
|
|
}
|
|
|
|
he.capacity, he.unitList, tip = this.loadHeroes(he, heLineup)
|
|
if tip != nil {
|
|
return nil, tip
|
|
}
|
|
} 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 {
|
|
return nil, tip
|
|
}
|
|
}
|
|
|
|
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)
|
|
ack.BattleRounds = uint32(len(ack.RoundList))
|
|
|
|
var rewardItems = map[uint32]uint32{}
|
|
if ack.Succeed {
|
|
ack.Score = 2
|
|
if me.unitList[0].hp > 0 {
|
|
ack.Score = 3
|
|
}
|
|
|
|
if sceneTable.PassExpMultiple > 0 {
|
|
this.addExp(this.RoleLevel*uint32(sceneTable.PassExpMultiple), LogTypeItemObtainByCopy)
|
|
}
|
|
|
|
if sceneTable.PassCoinMultiple > 0 {
|
|
this.addMoney(pb.MoneyType_Coin, this.RoleLevel*uint32(sceneTable.PassCoinMultiple), LogTypeItemObtainByCopy)
|
|
}
|
|
|
|
if sceneTable.FirstPassDrop > 0 {
|
|
if this.GetCopyPassed(pb.CopyType(sceneTable.CopyType), uint32(sceneTable.CopyId)) == 0 {
|
|
var dropResult = this.manager.tables.Drop.Drop(sceneTable.FirstPassDrop, 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]),
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
if sceneTable.PassDrop > 0 {
|
|
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]),
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
if sceneTable.MustDrop > 0 {
|
|
var dropResult = this.manager.tables.Drop.Drop(sceneTable.MustDrop, 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 {
|
|
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].skillType > unit.attackSkills[j].skillType
|
|
})
|
|
|
|
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
|
|
|
|
capacity += this.calcAttrsCapacity(unit.attrs)
|
|
|
|
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].skillType > unit.attackSkills[j].skillType
|
|
})
|
|
|
|
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),
|
|
skillType: uint32(skillTable.SkillType),
|
|
consumeRage: uint32(skillTable.ConsumeRage),
|
|
}
|
|
|
|
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, int32(0)),
|
|
rangeType: uint32(buffTable.RangeType),
|
|
rangeNum: uint32(buffTable.RangeNum),
|
|
priorityType: util.NumbersConvert2(buffTable.PriorityType, uint32(0)),
|
|
priorityArgs: util.NumbersConvert2(buffTable.PriorityArgs, int32(0)),
|
|
buffType: uint32(buffTable.BuffType),
|
|
buffArgs: util.NumbersConvert2(buffTable.BuffArgs, int64(0)),
|
|
duration: uint32(buffTable.Duration),
|
|
canMerge: buffTable.CanMerge,
|
|
canCover: buffTable.CanCover,
|
|
canStack: buffTable.CanStack,
|
|
canClean: buffTable.CanClean,
|
|
}
|
|
|
|
buffList = append(buffList, buff)
|
|
}
|
|
sort.Slice(buffList, func(i, j int) bool {
|
|
if buffList[i].group == buffList[j].group {
|
|
return buffList[i].id < buffList[j].id
|
|
} else {
|
|
if buffList[i].group == 0 {
|
|
return false
|
|
}
|
|
if buffList[j].group == 0 {
|
|
return true
|
|
}
|
|
return buffList[i].group < buffList[j].group
|
|
}
|
|
})
|
|
return buffList, nil
|
|
}
|