代码拉取完成,页面将自动刷新
package logic
import (
"fmt"
"math"
"math/rand"
"sort"
"strconv"
"strings"
"gitee.com/liuxuezhan/mylib/GameServer/CSV"
"gitee.com/liuxuezhan/mylib/GameServer/cache"
"gitee.com/liuxuezhan/mylib/GameServer/observer"
"gitee.com/liuxuezhan/mylib/GameServer/oss"
proto "gitee.com/liuxuezhan/mylib/Protocol"
"gitee.com/liuxuezhan/mylib/Utils/wlog"
"gitee.com/liuxuezhan/mylib/Utils/wsort"
"gitee.com/liuxuezhan/mylib/common"
"gitee.com/liuxuezhan/mylib/wtime"
)
//行为的目标类型,每次修改需要和客户端同步
const (
targetUnUse uint32 = 0
targetMainCity uint32 = 1 //主城
targetMine uint32 = 3 //矿
targetMonster uint32 = 4 //单人boss怪
targetMutiMonster uint32 = 5 //多人怪
targetCity uint32 = 6 //现在没用
targetBestationed uint32 = 7 //营地
targetRayolCity uint32 = 8 //大小奇迹
targetUndergroundPalace uint32 = 9 //星际之门
targetMineGem uint32 = 10 /// 钻石矿,埋点时有特殊需求
targetWarCity uint32 = 11 //城市争霸
targetAirShip uint32 = 12 //推图(飞艇)
targetBlockUnlock uint32 = 13 //地块解锁
targetMonsterEx uint32 = 14 //单人小怪
targetSummonMutiMonster uint32 = 15 //多人召唤野怪
targetLeagueCenter uint32 = 16 //联盟堡垒
targetCashhouse uint32 = 17 //联盟仓库
targetMultiCash uint32 = 18 //联盟超级矿
)
const (
actionBase_None uint32 = 0
actionBase_Monster uint32 = 1 //怪物(都是防守方)
actionBase_Atk uint32 = 2 //攻击方
actionBase_Def uint32 = 3 //防守方
)
const (
fightRlt_None uint32 = 0 //目标不存在
fightRlt_Hit uint32 = 1 //命中
fightRlt_Miss uint32 = 2 //闪避
)
const (
battleRlt_Error uint32 = 0 //逻辑错误
battleRlt_AtkEmpty uint32 = 1 //进攻方兵力耗尽
battleRlt_DefEmpty uint32 = 2 //防守方兵力耗尽
battleRlt_AllEmpty uint32 = 3 //双方兵力耗尽
battleRlt_Continue uint32 = 4 //战斗继续
battleRlt_Over uint32 = 5 //战斗结束
)
//英雄战斗信息
type stHeroBattleInfo struct {
heroID uint32
mainType uint32 //主属性类型 HeroBranchType
level uint32
star uint32
rank uint32
skillList []*proto.ST_HeroSkill_PB //存放技能ID
branceValue []uint32 //进入战斗时刻的3属性,顺序存放,不包括带兵量
fightBuff map[uint32]*stFightBuff //战斗buff
skillCDList map[uint32]uint32 //技能CD
specialBuff []*stFightBuff //特殊被动buff
}
//军团
type stCorps struct {
unitType proto.UnitBattleType
curUnits []*proto.ST_Unit_PB //当前战斗单位
startUnits []*proto.ST_Unit_PB //战斗开始时的战斗单位
summonUnits []*proto.ST_Unit_PB //找召唤的影子部队
fightBuff map[uint32]*stFightBuff //战斗buff
specialBuff []*stFightBuff //特殊被动buff
attributeMap map[uint32]uint64 //军团攻防属性等
unitHp map[uint32]uint64 //每个等级的战斗单位的衰减总生命
unitPower map[uint32]uint64 //每个战斗单位的战斗力
curAllUnitNum uint32 //当前战斗单位数量
}
//军团阵型
type stFormation struct {
id uint32 //阵型ID
unitData map[proto.CorpsPos][]*stCorps //最大4个,前中后天上顺序存放,每个5种等级
trapsData map[proto.UnitBattleType][]*stCorps //4种陷阱,每个5种等级
}
//城墙
type stWall struct {
wallLevel uint32 //城墙等级
startWallHp uint64 //城墙战斗开始时的血量
curWallHp uint64 //城墙当前血量
wallDef uint32 //城墙防御
fightBuff map[uint32]*stFightBuff //战斗buff
}
//战斗行为基本数据
type stBattleActionBaseData struct {
actionBaseType uint32 //0 怪物 1攻击方 2防守方
userData *cache.Info //玩家信息 (与怪物组ID互斥)
monsterGroupID int64 //怪物组ID (与玩家信息互斥)worldMonsterConfig
heroList []*stHeroBattleInfo //英雄信息
formation *stFormation //军团阵型信息,记录了总的详细兵力
globalAttribute map[uint64]uint64 //全局加成拷贝信息(例如:被动技能,英雄对士兵加成)
wall *stWall //城墙信息,攻打玩家主城时防守方才有
roundBaseInfo *proto.ST_RoundBaseInfo_PB //记录回合内的战斗信息
monsterAtk bool //怪物攻城
}
//以兵种类型为单位记录军团信息
type stCorpsMap struct {
unitList map[proto.UnitBattleType][]*stCorps //4种兵种
trapList map[proto.UnitBattleType][]*stCorps //4种陷阱
}
//战斗单位克制效果
type stRestrainParm struct {
damageParm map[uint32]uint32 //k:克制兵种 v:克制效果(CSV表配置)
}
//战斗通用参数
type stCommonBattleParm struct {
maxbattleRound uint32 //战斗最大回合
unitRestrainParm map[int64]*stRestrainParm //战斗单位克制效果 百分比
corpAtkOrder map[int64]int64 //战斗单位指定攻击目标,目前只有陷阱生效
hitParm []uint32 //命中公式参数 :A,B,C,命中下限 万分比
baoJiParm []uint32 //暴击公式参数 :A,B,C,暴击上限 万分比
battleDamageParm []uint32 //战斗伤害参数 :K,M,P,Q,Y 万分比
critDamageParm uint32 //暴击额外伤害,百分比
attriDamageLimit []uint32 //伤害加减范围 :下限,上限 万分比
skillSpecialParm []uint32 //特殊行为系数里的参数: P,Q
atkParm []uint32 //军团攻击公式参数 M幂
defParm []uint32 //军团防御公式参数 M幂
trapLossParm uint32 //陷阱自毁系数
hpParm []uint32 //军团及其陷阱的血量衰减系数,t|r
}
var CommonBattleParm *stCommonBattleParm
//战斗buff效果
type stFightBuff struct {
csvIndex int32
effectType uint32 //效果类型 1:增益 2:负面 3:伤害 4:持续伤害 5:特殊效果
effectValue uint64 //具体数值,在释放的一瞬间就计算好了的,除了dot、hot类效果,其余存的都是万分比的
effectRound uint32 //持续回合
triggerTime uint32 //触发时机 1立即
heroID uint32 //buff释放的英雄ID
orgiSkillID int64 //效果所属技能
params []uint32 // 效果参数
}
//兵力占比
type stUserUnitInfo struct {
isBigBrother bool //带队玩家
charUID uint64 //玩家UID
unitMap map[proto.UnitBattleType][]*stUnitInfo //按战斗等级记录的兵力数据
totalPower int64 //总战力
corpRatioMap map[proto.UnitBattleType]float32 //记录玩家各军团占【集结总兵团】的战力比
unitRatioMap map[uint32]float32 //记录玩家各等级兵种在同等级下的战力比(每个兵种占【集结总兵团】的百分比,区分等级)
}
type stUnitInfo struct {
unit *proto.ST_Unit_PB
power int64
powerRatio float32 //在同类型军团中的战力比(因为击杀数量是按军团算的,单个兵种的击杀数量根据它与军团的战力比来计算)
}
func getBigMiracleUnitCount(cityData *cache.WorldDataEntry) uint64 {
if nil == cityData {
return 0
}
return uint64(len(cityData.GetGActionList()))
}
/**
@brief v4转化成道具的数据结构
*/
func createItemByVector4(str string) []*proto.ST_ItemEntry_PB {
ret := make([]*proto.ST_ItemEntry_PB, 0)
if str == "" {
return ret
}
for _, v := range common.ParseStringToVector4(str) {
if v.GetX() == int32(proto.VectorType_VT_ITEM) {
itemenry := &proto.ST_ItemEntry_PB{
ItemId: proto.SetUint32(uint32(v.GetY())),
ItemNum: proto.SetUint32(uint32(v.GetW())),
}
ret = append(ret, itemenry)
} else if v.GetX() == int32(proto.VectorType_VT_DROP) {
for i := int32(0); i < v.GetW(); i++ {
ret = append(ret, CSV.GetDropItem(v.GetY())...)
}
}
}
return ret
}
/**
@brief 把数据组合成Appenddata数据 key|value
*/
func encodeActionAppendData(str, key string, value string) string {
var retstr string
var find bool = false
tmpstr := make([]string, 0)
tmpstrList := strings.Split(str, "|")
for _, v := range tmpstrList {
substrList := strings.Split(v, "=")
if len(substrList) < 2 {
continue
}
if substrList[0] == key {
find = true
substrList[1] = value
}
tmpstr = append(tmpstr, strings.Join(substrList, "="))
}
if find {
retstr = strings.Join(tmpstr, "|")
} else {
tmp := make([]string, 0)
tmp = append(tmp, key)
tmp = append(tmp, value)
tmpstr = append(tmpstr, strings.Join(tmp, "="))
retstr = strings.Join(tmpstr, "|")
}
return retstr
}
func splitKV(str, sep string) (string, string) {
strList := strings.Split(str, sep)
if len(strList) < 2 {
return "", ""
}
return strList[0], strings.Join(strList[1:], "=")
}
/**
@brief 根据指定字段解析Appenddata数据
*/
func decodeActionAppendData(str, key string) string {
tmpstrList := strings.Split(str, "|")
var retstr string
for _, v := range tmpstrList {
k, v1 := splitKV(v, "=")
switch k {
case key:
retstr = v1
}
}
return retstr
}
func DecodeActionAppendDataEx(str, key string) string {
return decodeActionAppendData(str, key)
}
/**
@brief 解析Appenddata里的单位或者资源信息
*/
func decodeAttackAppendData(str string) (*proto.ST_UnitAsset_PB, *proto.ST_CashAsset_PB) {
retUnit := &proto.ST_UnitAsset_PB{}
retResource := &proto.ST_CashAsset_PB{}
tmpstrList := strings.Split(str, "|")
for _, v := range tmpstrList {
k, v1 := splitKV(v, "=")
switch k {
case "units":
proto.Unmarshal([]byte(v1), retUnit)
case "resource":
proto.Unmarshal([]byte(v1), retResource)
default:
continue
}
}
return retUnit, retResource
}
/**
@brief 指定字段,然后删除Appenddata里对应的数据
*/
func deleteActionAppendData(str, key string) string {
var retStr = ""
tmpstrList := strings.Split(str, "|")
for _, v := range tmpstrList {
k, v1 := splitKV(v, "=")
if k == key {
continue
}
retStr = encodeActionAppendData(retStr, k, v1)
}
return retStr
}
/**
@brief 扣除战斗单位(ST_UnitAsset_PB)
*/
func reduceUnitsAsset(units *proto.ST_UnitAsset_PB, dieNum uint64) *proto.ST_UnitAsset_PB {
var (
dieUnit = make(map[uint32]uint64)
)
loop:
for i := int64(1); i <= 4; i++ {
for _, v := range units.GetUnits() {
unitConfig := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.GetUnitid()))
if unitConfig == nil {
continue
}
if unitConfig.UnitPosType != i {
continue
}
if dieNum > v.GetUnitnum() {
dieUnit[v.GetUnitid()] = v.GetUnitnum()
dieNum -= v.GetUnitnum()
} else {
dieUnit[v.GetUnitid()] = dieNum
dieNum = 0
}
if dieNum == 0 {
break loop
}
}
}
for _, v := range units.GetUnits() {
if v1, ok := dieUnit[v.GetUnitid()]; ok {
v.Unitnum = proto.SetUint64(v.GetUnitnum() - v1)
}
}
return createUnitAssetByMap(dieUnit)
}
/**
@brief 扣除战斗单位(stCorps)
*/
func reduceCorpsUnits(outTargetCorps, inSrcCorps *stCorps) {
if nil == outTargetCorps || nil == inSrcCorps {
return
}
if outTargetCorps.unitType != inSrcCorps.unitType {
return
}
for _, src := range inSrcCorps.curUnits {
for _, target := range outTargetCorps.curUnits {
if src.GetUnitid() == target.GetUnitid() {
if src.GetUnitnum() > target.GetUnitnum() {
target.Unitnum = proto.SetUint64(0)
} else {
target.Unitnum = proto.SetUint64(target.GetUnitnum() - src.GetUnitnum())
}
break
}
}
}
}
/**
@brief 根据数量直接扣除战斗单位(stCorps)
*/
func reduceCorpUnitsByNum(outCorps *stCorps, lostValue uint64) []*proto.ST_Unit_PB {
//扣除顺序从低级兵种到高级兵种
//理论上curUnits是从低到高排序
lostUnitList := make([]*proto.ST_Unit_PB, 0)
if nil == outCorps || uint64(0) == lostValue {
return lostUnitList
}
unitsLen := len(outCorps.curUnits)
if 0 == unitsLen {
return lostUnitList
}
for tmpLen := 0; tmpLen < unitsLen; tmpLen++ {
v := outCorps.curUnits[tmpLen]
if uint64(0) == v.GetUnitnum() {
continue
}
curUnitValue := v.GetUnitnum()
if curUnitValue > lostValue {
curUnitValue -= lostValue
lostValue = 0
} else {
lostValue -= curUnitValue
curUnitValue = 0
}
//当前单位剩余数量
oldNum := v.GetUnitnum()
v.Unitnum = proto.SetUint64(curUnitValue)
//记录损失的数量
tmp := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v.GetUnitid()),
Unitnum: proto.SetUint64(oldNum - curUnitValue),
}
lostUnitList = append(lostUnitList, tmp)
outCorps.curAllUnitNum -= uint32(tmp.GetUnitnum())
if lostValue <= uint64(0) {
return lostUnitList
}
}
return lostUnitList
}
/**
@brief 处理部队护盾
*/
func processShield(buffList map[uint32]*stFightBuff, lostHp float64) float64 {
for _, v := range buffList {
if v.csvIndex == int32(proto.FightBuffAttibute_DamageShield) && v.effectValue > 0 {
if float64(v.effectValue) >= lostHp {
v.effectValue -= uint64(lostHp)
lostHp = 0
} else {
lostHp -= float64(v.effectValue)
v.effectValue = 0
}
if lostHp <= 0 {
break
}
}
}
return lostHp
}
/**
@brief 根据衰减总血量来扣除军团的战斗单位
*/
func reduceCorpUnitsByHp(outCorps *stCorps, lostHp float64) ([]*proto.ST_Unit_PB, float64) {
//此函数主于陷阱及其军团攻击时调用
/*
理论上curUnits是从低到高排序
扣除顺序从低级兵种到高级兵种
【最终伤害】是否≥Tn衰减总生命
是:扣除Tn兵团总人数,计算【扣除Tn后伤害】= 【最终伤害】-Tn衰减总生命
否:扣除Tn兵团人数=【最终伤害】÷ Tn平均生命 ; 结束扣除人数流程
*/
lostUnitList := make([]*proto.ST_Unit_PB, 0)
realLossHp := float64(0) //实际已扣除的血量
if nil == outCorps {
return lostUnitList, realLossHp
}
unitsLen := len(outCorps.curUnits)
if 0 == unitsLen {
return lostUnitList, realLossHp
}
// 处理护盾buff逻辑
lostHp = processShield(outCorps.fightBuff, lostHp)
for tmpLen := 0; tmpLen < unitsLen; tmpLen++ {
unitInfo := outCorps.curUnits[tmpLen]
corpTotalNum := unitInfo.GetUnitnum() //当前等级的兵力
if uint64(0) == corpTotalNum {
continue
}
//计算损失
unitTotalHp := float64(outCorps.unitHp[unitInfo.GetUnitid()]) //当前等级的衰竭总生命
unitAvgHp := unitTotalHp / float64(corpTotalNum) //当前等级的平局衰竭生命
lostNum := uint64(0)
if unitTotalHp > lostHp {
lostNum = uint64(math.Ceil(lostHp / unitAvgHp))
if lostNum > corpTotalNum {
lostNum = corpTotalNum
}
realLossHp += lostHp
lostHp = float64(0)
} else {
realLossHp += unitTotalHp
lostHp -= unitTotalHp
lostNum = corpTotalNum
}
unitInfo.Unitnum = proto.SetUint64(corpTotalNum - lostNum)
//记录损失的数量
tmp := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(unitInfo.GetUnitid()),
Unitnum: proto.SetUint64(lostNum),
}
lostUnitList = append(lostUnitList, tmp)
outCorps.curAllUnitNum -= uint32(tmp.GetUnitnum())
if lostHp <= float64(0) {
return lostUnitList, realLossHp
}
}
return lostUnitList, realLossHp
}
/**
@brief 根据数量直接添加战斗单位(stCorps)
*/
func addCorpsUnits(outTargetCorps, inSrcCorps *stCorps) {
if nil == outTargetCorps || nil == inSrcCorps {
return
}
//先加数量
for _, src := range inSrcCorps.curUnits {
for _, target := range outTargetCorps.curUnits {
if src.GetUnitid() == target.GetUnitid() {
target.Unitnum = proto.SetUint64(src.GetUnitnum() + target.GetUnitnum())
break
}
}
}
//当前数量不允许超过战斗开始时的数量
for _, cur := range inSrcCorps.curUnits {
for _, start := range outTargetCorps.startUnits {
if cur.GetUnitid() == start.GetUnitid() {
if cur.GetUnitnum() > start.GetUnitnum() {
cur.Unitnum = proto.SetUint64(start.GetUnitnum())
}
break
}
}
}
}
func addUnits(target, scr []*proto.ST_Unit_PB) []*proto.ST_Unit_PB {
if nil == target || nil == scr {
return target
}
for _, scrv := range scr {
isFind := false
for _, tarv := range target {
if tarv.GetUnitid() == scrv.GetUnitid() {
tarv.Unitnum = proto.SetUint64(tarv.GetUnitnum() + scrv.GetUnitnum())
isFind = true
break
}
}
if false == isFind {
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(scrv.GetUnitid()),
Unitnum: proto.SetUint64(scrv.GetUnitnum()),
}
target = append(target, unit)
}
}
return target
}
/**
@brief 增加军团的战斗单位数量
*/
func addCorpUnitsByNum(outCorps *stCorps, AddValue uint64) ([]*proto.ST_Unit_PB, uint64) {
//恢复顺序从高级兵种到低级兵种
//理论上curUnits是从低到高排序
addUnitList := make([]*proto.ST_Unit_PB, 0)
totalAddUnitNum := uint64(0)
tmpLen := len(outCorps.curUnits)
if nil == outCorps || uint64(0) == AddValue || 0 == tmpLen {
return addUnitList, totalAddUnitNum
}
tmpLen -= 1
for ; tmpLen >= 0; tmpLen-- {
v := outCorps.curUnits[tmpLen]
curNum := v.GetUnitnum()
maxNum := outCorps.startUnits[tmpLen].GetUnitnum()
if uint64(0) == curNum {
continue
}
lostNum := maxNum - curNum //已损失的当前等级的兵种数量
realAddNum := uint64(0)
if AddValue > lostNum {
realAddNum = lostNum
} else {
realAddNum = AddValue
}
AddValue -= realAddNum
oldNum := v.GetUnitnum()
v.Unitnum = proto.SetUint64(v.GetUnitnum() + realAddNum)
if v.GetUnitnum() > maxNum {
v.Unitnum = proto.SetUint64(maxNum)
}
//记录增加的的数量
tmp := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v.GetUnitid()),
Unitnum: proto.SetUint64(v.GetUnitnum() - oldNum),
}
addUnitList = append(addUnitList, tmp)
totalAddUnitNum += tmp.GetUnitnum()
outCorps.curAllUnitNum += uint32(v.GetUnitnum() - oldNum)
if AddValue <= uint64(0) {
return addUnitList, totalAddUnitNum
}
}
return addUnitList, totalAddUnitNum
}
/**
@brief 根据血量来增加军团的战斗单位(暂时没用2019_3_1)
*/
func addCorpUnitsByHp(outCorps *stCorps, AddHpValue float64) ([]*proto.ST_Unit_PB, uint64) {
//恢复顺序从高级兵种到低级兵种
//理论上curUnits是从低到高排序
addUnitList := make([]*proto.ST_Unit_PB, 0)
totalAddUnitNum := uint64(0)
if nil == outCorps || float64(0) == AddHpValue {
return addUnitList, totalAddUnitNum
}
tmpLen := len(outCorps.curUnits)
if 0 == tmpLen {
return addUnitList, totalAddUnitNum
}
tmpLen -= 1
for ; tmpLen >= 0; tmpLen-- {
v := outCorps.curUnits[tmpLen]
curNum := v.GetUnitnum()
maxNum := outCorps.startUnits[tmpLen].GetUnitnum()
if uint64(0) == curNum {
continue
}
if k, ok := outCorps.unitHp[v.GetUnitid()]; ok {
unitAvgHp := float64(k) / float64(curNum)
if unitAvgHp == 0 {
continue
}
lostHp := float64(maxNum-curNum) * unitAvgHp //已损失的总血量
realAddHp := float64(0)
if AddHpValue > lostHp {
realAddHp = lostHp
} else {
realAddHp = AddHpValue
}
AddHpValue -= realAddHp
oldNum := v.GetUnitnum()
v.Unitnum = proto.SetUint64(v.GetUnitnum() + uint64(realAddHp/unitAvgHp))
if v.GetUnitnum() > maxNum {
v.Unitnum = proto.SetUint64(maxNum)
}
//记录增加的的数量
tmp := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v.GetUnitid()),
Unitnum: proto.SetUint64(v.GetUnitnum() - oldNum),
}
addUnitList = append(addUnitList, tmp)
totalAddUnitNum += tmp.GetUnitnum()
outCorps.curAllUnitNum += uint32(v.GetUnitnum() - oldNum)
}
if AddHpValue <= float64(0) {
return addUnitList, totalAddUnitNum
}
}
return addUnitList, totalAddUnitNum
}
/**
@brief 以军团为单位,统计其中的战斗单位数量
*/
func countUnitsNumByCorps(corps *stCorps) {
total := uint64(0)
if nil == corps {
return
}
for _, v := range corps.curUnits {
total += v.GetUnitnum()
}
corps.curAllUnitNum = uint32(total)
}
func countUnitsNumFromList(unitList []*proto.ST_Unit_PB) uint64 {
total := uint64(0)
if nil == unitList || 0 == len(unitList) {
return total
}
for _, v := range unitList {
total += v.GetUnitnum()
}
return total
}
func countUnitsNum(unitAsset *proto.ST_UnitAsset_PB) uint32 {
total := uint64(0)
if nil == unitAsset {
return uint32(total)
}
for _, v := range unitAsset.Units {
total += v.GetUnitnum()
}
return uint32(total)
}
/**
@brief 从map转成PB结构
*/
func createUnitAssetByMap(in map[uint32]uint64) *proto.ST_UnitAsset_PB {
ret := &proto.ST_UnitAsset_PB{}
for k, v := range in {
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(k),
Unitnum: proto.SetUint64(v),
}
ret.Units = append(ret.Units, unit)
}
return ret
}
/**
@brief 从PB结构转成Map
*/
func genUnitInfoByAsset(in *proto.ST_UnitAsset_PB) map[uint32]uint64 {
ret := make(map[uint32]uint64)
for _, v := range in.GetUnits() {
if v1, ok := ret[v.GetUnitid()]; ok {
ret[v.GetUnitid()] = v1 + v.GetUnitnum()
} else {
ret[v.GetUnitid()] = v.GetUnitnum()
}
}
return ret
}
/**
@brief 从PB结构转成Map
*/
func recordBattleAllAttri(baseData *stBattleActionBaseData) *proto.ST_AttributeList_PB {
allBattleAttri := &proto.ST_AttributeList_PB{
List: make([]*proto.ST_Attribute_PB, 0),
}
if nil == baseData || nil == baseData.userData {
return allBattleAttri
}
for _, v := range proto.AtttibuteType_value {
tmpattr := &proto.ST_Attribute_PB{
Type: proto.SetUint32(uint32(v)),
Value: proto.SetUint32(baseData.userData.GetAttributeByType(proto.AtttibuteType(v))),
}
allBattleAttri.List = append(allBattleAttri.List, tmpattr)
}
return allBattleAttri
}
/**
@brief 获取在大奇迹里的第一个玩家
*/
func getBigMiracleGarrisonUser(cityData *cache.WorldDataEntry) *cache.Info {
if nil == cityData {
return nil
}
if len(cityData.GetWorldData().GetSimpleEntry().GetGActionList()) <= 0 {
return nil
}
actionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(cityData.GetWorldData().GetSimpleEntry().GetGActionList()[0])
if actionData == nil || actionData.Actiondata == nil {
return nil
}
return cache.GetCharinfo(actionData.Actiondata.GetUid())
}
/**
@brief 援助大奇迹, 城市
*/
func garrisonToBigMiracle(actionData *cache.GlobalActionEntry, cityData *cache.WorldDataEntry) bool {
if nil == cityData {
return false
}
if ownerIncludeMe(cityData, actionData.Actiondata.GetUid()) {
return false
}
if !checkCanGarrisonBigMiracle(actionData.Actiondata.GetUnits(), cityData) {
return false
}
userData := cache.GetCharinfo(actionData.Actiondata.GetUid())
if nil == userData {
return false
}
tmpUser := getBigMiracleGarrisonUser(cityData)
if nil != tmpUser {
if tmpUser.GetLeagueID() != userData.GetLeagueID() {
return false
}
}
actionIds := cityData.CopyGActionList()
if len(actionIds) <= 0 {
details := make([]uint64, 0)
fuction := userData.GetBuildingFuctionByConfigType(int64(proto.BuildingType_BT_COMMAND))
capability := common.StringToUint64(fuction["capability"])
capability = countAdditional(capability, userData, proto.AtttibuteType_MaxAggregation) // 1003;//联盟集结上限(百分比)
var totalCount = countUnitNum(actionData.Actiondata.GetUnits())
details = append(details, capability)
details = append(details, totalCount)
actionData.Actiondata.Details = details
} else {
tmpActionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionIds[0])
if len(tmpActionData.Actiondata.Details) >= 2 {
if tmpActionData.Actiondata.Details[0] < tmpActionData.Actiondata.Details[1]+countUnitNum(actionData.Actiondata.GetUnits()) {
return false
}
tmpActionData.Actiondata.Details[1] += countUnitNum(actionData.Actiondata.GetUnits())
tmpActionData.Dirty()
} else {
return false
}
}
if getWorldDataTargetType(cityData) == targetRayolCity {
observer.ObserverSingleton.AsyncNotify(observer.AddMiracleWarRecordEvent, []interface{}{int32(2), userData, tmpUser})
}
actionData.UpdateStage(wtime.GetNow(), 5, uint32(proto.MapStageType_MST_WORKING)) //集结每支部队都处理,空城也需要
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MASS) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_JOINMASS) {
// cache.Instance_GlobalAssetGlobalAction.DeleteGlobalAction(actionData.Actiondata.GetActionid())
// userData.RemoveGlobalActionID(actionData.Actiondata.GetActionid())
// newActionId := cache.Instance_GlobalAssetGlobalAction.AllocGlobalActionId()
// actionData.Actiondata.Actionid = proto.SetUint64(newActionId) //先赋值
actionData.SetActionType(uint32(proto.ActionType_AT_WORLDMAP_GARRISON))
deleteRadar(actionData.Actiondata)
// cache.Instance_GlobalAssetGlobalAction.AddCopyGlobalAction(newActionId, actionData)
// userData.AddGlobalActionID(newActionId)
}
cityData.BindGlobalActionId(actionData.Actiondata.GetActionid())
wlog.Error("garrisonToBigMiracle bind act:", actionData.Actiondata.GetActionid(), actionData.Actiondata.GetTotaltime())
remainTime := countMarchTime(actionData.Actiondata.GetUid(), actionData.Actiondata.GetStartTileID(),
actionData.Actiondata.GetEndTileID(), actionData.Actiondata.GetWorldDataID(), actionData.Actiondata.GetActiontype(),
actionData.Actiondata.GetHeroIDList(), actionData.Actiondata.GetUnits(), actionData.Actiondata.GetCrossSpecialTile())
actionData.Actiondata.Totaltime = proto.SetUint64(remainTime)
actionData.Dirty()
cityData.Dirty()
return true
}
func GarrisonToLeagueCenter(actionData *cache.GlobalActionEntry, cityData *cache.WorldDataEntry) bool {
if nil == cityData {
return false
}
userData := cache.GetCharinfo(actionData.Actiondata.GetUid())
if nil == userData {
return false
}
actionIds := cityData.CopyGActionList()
if len(actionIds) <= 0 {
details := make([]uint64, 0)
wdataAsset := cache.Instance_GlobalAssetWorldData.GetWorldDataByTileId(actionData.Actiondata.GetEndTileID())
var totalCount = countUnitNum(actionData.Actiondata.GetUnits())
details = append(details, wdataAsset.GetWorldData().DetailEntry.Detail_City.GetGarrisonCapalibity())
details = append(details, totalCount)
actionData.Actiondata.Details = details
} else {
tmpActionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionIds[0])
if len(tmpActionData.Actiondata.Details) >= 2 {
if tmpActionData.Actiondata.Details[0] < tmpActionData.Actiondata.Details[1]+countUnitNum(actionData.Actiondata.GetUnits()) {
return false
}
tmpActionData.Actiondata.Details[1] += countUnitNum(actionData.Actiondata.GetUnits())
tmpActionData.Dirty()
} else {
return false
}
}
actionData.UpdateStage(wtime.GetNow(), 5, uint32(proto.MapStageType_MST_WORKING)) //集结每支部队都处理,空城也需要
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MASS) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_GARRISON) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_JOINMASS) {
actionData.SetActionType(uint32(proto.ActionType_AT_WORLDMAP_GARRISON))
deleteRadar(actionData.Actiondata)
}
cityData.BindGlobalActionId(actionData.Actiondata.GetActionid())
wlog.Error("garrisonToBigMiracle bind act:", actionData.Actiondata.GetActionid(), actionData.Actiondata.GetTotaltime())
remainTime := countMarchTime(actionData.Actiondata.GetUid(), actionData.Actiondata.GetStartTileID(),
actionData.Actiondata.GetEndTileID(), actionData.Actiondata.GetWorldDataID(), actionData.Actiondata.GetActiontype(),
actionData.Actiondata.GetHeroIDList(), actionData.Actiondata.GetUnits(), actionData.Actiondata.GetCrossSpecialTile())
actionData.Actiondata.Totaltime = proto.SetUint64(remainTime)
actionData.Dirty()
cityData.Dirty()
if cityData.GetWorldData().SimpleEntry.GetLid() != userData.GetLeagueID() {
x, y, _ := common.ConvertIdToCoordinate(cityData.GetWorldDataTileID())
conf := cityData.GetWorldEntryConfig()
if conf != nil {
sendLanguageIDMailToMembers(userData.GetLeagueID(), uint32(proto.MailType_MT_SYSTEM),
common.CreateTips(76300),
common.CreateTips(76032, userData.GetUserName(),
cache.Instance_GlobalAssetLeague.GetLeagueName(cityData.GetWorldData().SimpleEntry.GetLid()), common.Int64ToString(conf.EntryLevel),
common.Int32ToString(cityData.GetWorldDataTileID()), common.Int32ToString(x), common.Int32ToString(y)))
sendLanguageIDMailToMembers(cityData.GetWorldData().SimpleEntry.GetLid(), uint32(proto.MailType_MT_SYSTEM),
common.CreateTips(76297),
common.CreateTips(76033, cache.Instance_GlobalAssetLeague.GetLeagueName(userData.GetLeagueID()), common.Int64ToString(conf.EntryLevel),
common.Int32ToString(cityData.GetWorldDataTileID()), common.Int32ToString(x), common.Int32ToString(y)))
}
}
return true
}
/**
@brief 把行为转成援助
*/
func convertActionToGarrison(actionData *cache.GlobalActionEntry, cityData *cache.WorldDataEntry) {
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) {
if !garrisonToBigMiracle(actionData, cityData) {
actionData.UpdateStage(wtime.GetNow(), actionData.Actiondata.GetTotaltime(), uint32(proto.MapStageType_MST_BACK))
}
} else if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MASS) {
ret := garrisonToBigMiracle(actionData, cityData)
for _, v := range actionData.Actiondata.GetChildrenID() {
actionEntry := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(v)
if nil != actionEntry {
actionEntry.Actiondata.EndTileID = proto.SetInt32(actionData.Actiondata.GetEndTileID())
actionEntry.Actiondata.WorldDataID = proto.SetUint64(actionData.Actiondata.GetWorldDataID())
actionEntry.Actiondata.EndScope = actionData.Actiondata.GetEndScope()
if !garrisonToBigMiracle(actionEntry, cityData) {
actionData.UpdateStage(wtime.GetNow(), actionData.Actiondata.GetTotaltime(), uint32(proto.MapStageType_MST_BACK))
}
}
}
actionData.Actiondata.ChildrenID = make([]uint64, 0)
actionData.Dirty()
if !ret {
actionData.UpdateStage(wtime.GetNow(), actionData.Actiondata.GetTotaltime(), uint32(proto.MapStageType_MST_BACK))
}
}
}
/**
@brief 设置阵型
*/
func setFormation(formationID uint32, corpsMap *stCorpsMap) (bool, *stFormation) {
if nil == corpsMap {
return false, nil
}
formation := &stFormation{
id: formationID,
unitData: make(map[proto.CorpsPos][]*stCorps),
}
//默认步兵坦克火炮飞机
if 0 == formationID {
if v, ok := corpsMap.unitList[proto.UnitBattleType_UBT_NOMAL_BUBING]; ok {
formation.unitData[proto.CorpsPos_CP_FRONT] = v
}
if v, ok := corpsMap.unitList[proto.UnitBattleType_UBT_NOMAL_TANK]; ok {
formation.unitData[proto.CorpsPos_CP_MIDDLE] = v
}
if v, ok := corpsMap.unitList[proto.UnitBattleType_UBT_NOMAL_HUOPAO]; ok {
formation.unitData[proto.CorpsPos_CP_Behind] = v
}
if v, ok := corpsMap.unitList[proto.UnitBattleType_UBT_NOMAL_FEIJI]; ok {
formation.unitData[proto.CorpsPos_CP_SKY] = v
}
}
//陷阱
formation.trapsData = corpsMap.trapList
return true, formation
}
/**
@brief ST_UnitAsset_PB转化成map
*/
func unitAssetToMap(in *proto.ST_UnitAsset_PB) map[uint32]uint64 {
ret := make(map[uint32]uint64)
for _, v := range in.GetUnits() {
if v1, ok := ret[v.GetUnitid()]; ok {
ret[v.GetUnitid()] = v1 + v.GetUnitnum()
} else {
ret[v.GetUnitid()] = v.GetUnitnum()
}
}
return ret
}
/**
@brief 按等级从低到高排序
*/
func sortUnitLevel(orgiInfoList []*stUnitInfo) []*stUnitInfo {
//unitInfoList := make([]*stUnitInfo, 0)
if nil == orgiInfoList || 0 == len(orgiInfoList) {
return orgiInfoList
}
tmpMap := make(map[int64]*stUnitInfo)
levelList := make([]int64, 0)
for _, v := range orgiInfoList {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.unit.GetUnitid()))
if nil == unitCSV {
continue
}
tmpMap[unitCSV.UnitLevel] = v
levelList = append(levelList, unitCSV.UnitLevel)
}
sort.Sort(wsort.Int64Slice(levelList))
for k, v := range levelList {
/*unitInfo := &stUnitInfo{
unit: tmpMap[v].unit,
powerRatio: tmpMap[v].powerRatio,
}*/
orgiInfoList[k] = tmpMap[v]
}
return orgiInfoList
}
/**
@brief 按等级从低到高排序
*/
func sortUnitLevelEx(corp *stCorps) *stCorps {
if nil == corp || 0 == len(corp.startUnits) {
return corp
}
tmpMap := make(map[int64]*proto.ST_Unit_PB)
levelList := make([]int64, 0)
for _, unit := range corp.startUnits {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unit.GetUnitid()))
if nil == unitCSV {
continue
}
tmpMap[unitCSV.UnitLevel] = unit
levelList = append(levelList, unitCSV.UnitLevel)
}
sort.Sort(wsort.Int64Slice(levelList))
corp.startUnits = make([]*proto.ST_Unit_PB, 0)
for _, v := range levelList {
corp.startUnits = append(corp.startUnits, tmpMap[v])
}
corp.curUnits = make([]*proto.ST_Unit_PB, 0)
for _, v := range corp.startUnits {
tmp := proto.Clone(v).(*proto.ST_Unit_PB)
corp.curUnits = append(corp.curUnits, tmp)
}
return corp
}
//计算士兵战斗力占比
func analysisUnitAssetToUserUnitInfo(units *proto.ST_UnitAsset_PB) *stUserUnitInfo {
userUnitInfo := &stUserUnitInfo{}
if nil == units {
return userUnitInfo
}
totalUnitPower := int64(0)
//var unitInfoList []*stUnitInfo
unitMap := make(map[proto.UnitBattleType][]*stUnitInfo)
for _, v := range units.Units {
unitInfo := &stUnitInfo{
unit: &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v.GetUnitid()),
Unitnum: proto.SetUint64(v.GetUnitnum()),
},
}
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.GetUnitid()))
if nil != unitCSV {
unitMap[proto.UnitBattleType(unitCSV.UnitPosType)] = append(unitMap[proto.UnitBattleType(unitCSV.UnitPosType)], unitInfo)
}
}
/*
for k, v := range unitMap {
unitInfoList = sortUnitLevel(v)
unitMap[k] = unitInfoList
}
*/
userUnitInfo.unitMap = unitMap
//不同等级兵种在同类型兵种中的战力比(eg:T1,T2,T3,T4在步兵中的战力占比)
for _, unitInfoList := range userUnitInfo.unitMap {
corpPower := int64(0)
for _, unitInfo := range unitInfoList {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unitInfo.unit.GetUnitid()))
unitInfo.power = int64(unitInfo.unit.GetUnitnum()) * unitCSV.Power
corpPower += unitInfo.power
}
for _, unitInfo := range unitInfoList {
if 0 == corpPower {
unitInfo.powerRatio = 0
} else {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unitInfo.unit.GetUnitid()))
unitInfo.powerRatio = float32(int64(unitInfo.unit.GetUnitnum())*unitCSV.Power) / float32(corpPower)
}
}
totalUnitPower += corpPower
}
userUnitInfo.totalPower = totalUnitPower
return userUnitInfo
}
func analysisUnitAssetToCorpsMap(corpsMap *stCorpsMap, unitAsset *proto.ST_UnitAsset_PB) bool {
if nil == corpsMap || nil == unitAsset {
return false
}
if nil == corpsMap.unitList {
corpsMap.unitList = make(map[proto.UnitBattleType][]*stCorps)
}
if nil == corpsMap.trapList {
corpsMap.trapList = make(map[proto.UnitBattleType][]*stCorps)
}
//unitsMap := unitAssetToMap(unitAsset)
for _, k := range unitAsset.GetUnits() {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(k.GetUnitid()))
if nil == unitCSV {
continue
}
//兵种
tmpUnitType := proto.UnitBattleType(unitCSV.UnitPosType)
if (proto.UnitBattleType_UBT_NOMAL_TANK <= tmpUnitType) &&
(proto.UnitBattleType_UBT_NOMAL_FEIJI >= tmpUnitType) {
var tmpActionUnit *stCorps
_, ok := corpsMap.unitList[tmpUnitType]
if !ok {
corpsMap.unitList[tmpUnitType] = make([]*stCorps, 5)
}
if corpsMap.unitList[tmpUnitType][unitCSV.UnitLevel-1] == nil {
tmpActionUnit = &stCorps{
unitType: tmpUnitType,
curUnits: make([]*proto.ST_Unit_PB, 0),
startUnits: make([]*proto.ST_Unit_PB, 0),
fightBuff: make(map[uint32]*stFightBuff),
unitHp: make(map[uint32]uint64),
}
tmpActionUnit.startUnits = append(tmpActionUnit.startUnits, k)
tmp := proto.Clone(k).(*proto.ST_Unit_PB)
tmpActionUnit.curUnits = append(tmpActionUnit.curUnits, tmp)
corpsMap.unitList[tmpUnitType][unitCSV.UnitLevel-1] = tmpActionUnit
}
//tmpActionUnit.curUnits = common.CombineUnit(tmpActionUnit.curUnits, k)
//tmpActionUnit.startUnits = common.CombineUnit(tmpActionUnit.startUnits, k)
} else if (proto.UnitBattleType_UBT_NOMAL_TRAP1 <= tmpUnitType) &&
(proto.UnitBattleType_UBT_NOMAL_TRAP4 >= tmpUnitType) { //陷阱
var tmpActionUnit *stCorps
_, ok := corpsMap.trapList[tmpUnitType]
if !ok {
corpsMap.trapList[tmpUnitType] = make([]*stCorps, 5)
}
if corpsMap.trapList[tmpUnitType][unitCSV.UnitLevel-1] == nil {
tmpActionUnit = &stCorps{
unitType: tmpUnitType,
curUnits: make([]*proto.ST_Unit_PB, 0),
startUnits: make([]*proto.ST_Unit_PB, 0),
fightBuff: make(map[uint32]*stFightBuff),
unitHp: make(map[uint32]uint64),
}
tmpActionUnit.startUnits = append(tmpActionUnit.startUnits, k)
tmp := proto.Clone(k).(*proto.ST_Unit_PB)
tmpActionUnit.curUnits = append(tmpActionUnit.curUnits, tmp)
corpsMap.trapList[tmpUnitType][unitCSV.UnitLevel-1] = tmpActionUnit
}
//tmp := proto.Clone(v).(*proto.ST_Unit_PB)
//corp.curUnits = append(corp.curUnits, tmp)
//tmpActionUnit.curUnits = common.CombineUnit(tmpActionUnit.curUnits, k)
//tmpActionUnit.startUnits = common.CombineUnit(tmpActionUnit.startUnits, k)
}
}
//for k, v := range corpsMap.unitList {
// corpsMap.unitList[k] = sortUnitLevelEx(v)
//}
//for k, v := range corpsMap.trapList {
// corpsMap.trapList[k] = sortUnitLevelEx(v)
//}
if nil == unitAsset {
wlog.Error("sort unitAsset Level error")
return false
}
//统计下各个军团的总数量
for _, lst := range corpsMap.unitList {
for _, v := range lst {
countUnitsNumByCorps(v)
}
}
for _, lst := range corpsMap.trapList {
for _, v := range lst {
countUnitsNumByCorps(v)
}
}
return true
}
/*
@brief 战斗关键信息
通用数据必须有
如果是大地图行为,则大地图行为数据必须有
反之,必须有本地行为数据
*/
type stBattleKey struct {
//通用数据,必须有
UID uint64 //攻击发起人UID
heroIDList []uint32 //攻击方英雄列表
units *proto.ST_UnitAsset_PB //攻击发起人战斗单位
formation uint32 //攻击方阵型
//大地图行为数据
actionID uint64 //攻击方行为ID
childrenID []uint64
endTileID int32 //目的地
//本地行为数据 targetTuiTu
targetType uint32 //目标类型
monsterGroupID int64 //怪物组ID
airShipConfId int64 //飞艇配置
}
func prepareBattleKey(dataAsset *cache.GlobalActionEntry) (bool, *stBattleKey) {
if nil == dataAsset || nil == dataAsset.Actiondata {
return false, nil
}
battleKey := &stBattleKey{
childrenID: make([]uint64, 0),
heroIDList: make([]uint32, 0),
}
//通用数据,必须有
battleKey.UID = dataAsset.Actiondata.GetUid()
battleKey.heroIDList = dataAsset.Actiondata.GetHeroIDList()
battleKey.units = dataAsset.Actiondata.GetUnits()
battleKey.formation = dataAsset.Actiondata.GetFormation()
//大地图行为数据
battleKey.actionID = dataAsset.Actiondata.GetActionid()
battleKey.childrenID = dataAsset.Actiondata.GetChildrenID()
battleKey.endTileID = dataAsset.Actiondata.GetEndTileID()
return true, battleKey
}
/**
@brief 不同战斗场景的逻辑入口
*/
func worldBattle(dataAsset *cache.GlobalActionEntry) {
//TODO
//战斗开始,不同的目标,需要根据自身规则处理相关前期逻辑
rlt, battleKey := prepareBattleKey(dataAsset)
if false == rlt {
return
}
//正式开始战斗
RobotWorldBattleManager.CreateInstance(battleKey.UID)
battleRlt, _, targetType, battleInfo, battleReport, monsterBattleReport := worldRealBattle(battleKey)
RobotWorldBattleManager.EndRobotBattle(battleKey.UID, battleRlt)
//TODO
//战斗结束,根据不同的目标根据结果处理相关逻辑
if targetMonster != targetType {
if dataAsset.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MACATTCK) {
processMacWorldBattleResult(battleRlt, targetType, dataAsset, battleReport, battleInfo)
} else {
processWorldBattleResult(battleRlt, targetType, dataAsset, battleReport, battleInfo)
}
} else {
processWildMonsterResult(dataAsset, monsterBattleReport, battleInfo)
}
}
func airShipBattle(bk *stBattleKey) (proto.RetActionType, bool, *proto.ST_BattleInfo_PB, *proto.ST_Vector4IntList_PB, uint32, *proto.ST_Vector4IntList_PB) {
//正式开始战斗
battleRlt, _, targetType, battleInfo, battleReport, _ := worldRealBattle(bk)
isWin, _ := checkFinalRlt(targetType, battleRlt, battleReport)
ret, items, star, firstPassItems := processAirShipBattleResult(isWin, targetType, bk, battleReport, battleInfo)
for _, v := range battleReport.GetAtkInfo() {
if nil == v.GetCommanderReport() {
continue
}
atkData := cache.GetCharinfo(v.CommanderReport.GetUid())
if atkData == nil {
continue
}
break
}
return ret, isWin, battleInfo, items, star, firstPassItems
}
/**
@brief 机器人战斗
*/
func RobotBattle(battleKey *stBattleKey) {
RobotWorldBattleManager.CreateInstance(battleKey.UID)
battleRlt, _, _, _, _, _ := worldRealBattle(battleKey)
RobotWorldBattleManager.EndRobotBattle(battleKey.UID, battleRlt)
}
func maincityBattle(userData *cache.Info, bk *stBattleKey) (bool, *proto.ST_BattleInfo_PB) {
//主城地块解锁正式开始战斗
battleRlt, _, targetType, battleInfo, battleReport, _ := worldRealBattle(bk)
isWin, _ := checkFinalRlt(targetType, battleRlt, battleReport)
if nil != userData {
//处理战后兵力信息
//AtkInfo只有自己
injuredUnitList := make(map[uint32]uint32)
for _, v := range battleReport.GetAtkInfo() {
units := &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
}
for _, v1 := range v.GetUnitListReport() {
newUnit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v1.GetUnitID()),
Unitnum: proto.SetUint64(uint64(v1.GetSurvival())),
}
injuredUnitList[v1.GetUnitID()] = v1.GetInjured()
units.Units = common.CombineUnit(units.Units, newUnit)
}
userData.AddUnitAssets(units)
break
}
hurtUnit, _ := processBattleHospital(userData, injuredUnitList)
userData.AddHospitalUnitAsset(hurtUnit)
}
return isWin, battleInfo
}
/**
@brief 根据战斗对象和战损比来获取最终结果
*/
func checkFinalRlt(targetType uint32, battleRlt uint32, battleReport *proto.ST_BattleReport_PB) (bool, bool) {
threshold := CSV.GetGameConfigValueUint32("BATTLE_LOSS_RATIO") //攻方失败后,能否查看战报的阈值
isAtkWin := true
hasMailReport := true
atkPowerReport := battleReport.GetAtkPowerReport()
defPowerReport := battleReport.GetDefPowerReport()
defInfoLen := len(battleReport.GetDefInfo())
lastRoundDefInfo := battleReport.GetDefInfo()[defInfoLen-1] //防守方最后一回合信息
//单人野怪永远胜利
if targetType != targetMonster {
//战力比
if atkPowerReport.GetAllPower() == 0 {
isAtkWin = false
hasMailReport = false
goto end
}
allPowerRatio := uint32(defPowerReport.GetAllPower() / atkPowerReport.GetAllPower())
//进攻玩家主城时,城墙未破,则防守方胜利
if nil != lastRoundDefInfo.GetWallReport() && uint32(0) != lastRoundDefInfo.GetWallReport().GetAfterHp() {
isAtkWin = false
if allPowerRatio > threshold {
hasMailReport = false
}
goto end
}
//兵力耗尽或者回合结束,通过战损比判定胜负
if battleRlt_AllEmpty == battleRlt || battleRlt_Over == battleRlt {
wlog.Info(atkPowerReport.GetLossValue(), defPowerReport.GetLossValue())
if atkPowerReport.GetLossValue() >= defPowerReport.GetLossValue() {
isAtkWin = false
if allPowerRatio > threshold {
hasMailReport = false
}
}
goto end
}
//进攻方兵力耗尽
if battleRlt_AtkEmpty == battleRlt {
isAtkWin = false
if allPowerRatio > threshold {
hasMailReport = false
}
goto end
}
}
end:
return isAtkWin, hasMailReport
}
func processWildMonsterResult(actionDataAsset *cache.GlobalActionEntry, monsterBattleReport *proto.ST_MonsterKill_PB, battleInfo *proto.ST_BattleInfo_PB) {
actionDataEntry := actionDataAsset.Actiondata
if actionDataEntry == nil {
return
}
worldAssetData := cache.Instance_GlobalAssetWorldData.GetWorldDataByTileId(actionDataEntry.GetEndTileID())
if worldAssetData == nil || monsterBattleReport == nil {
return
}
if getWorldDataTargetType(worldAssetData) != targetMonster {
return
}
//actionDataEntry.Units = &proto.ST_UnitAsset_PB{}
csvWorldConfig := worldAssetData.GetWorldEntryConfig()
if csvWorldConfig == nil {
return
}
attUser := actionDataAsset.GetActionOwner()
if attUser == nil {
return
}
tmps := strings.Split(csvWorldConfig.ContinuityHurt, ";")
if len(tmps) < 2 {
wlog.Error("processWorldBattleResult targetMonster err: ", csvWorldConfig.ID)
return
}
//计算伤害
hot := uint32(0)
attUser.WithKillWildMonsterAsset(false, func(assert *cache.Asset_KillWildMonster) bool {
if assert.Dataid == worldAssetData.GetWorldDataID() {
if assert.Number > 0 {
hurtMaxNum := CSV.GetGameConfigValueUint32("Continuity_Hurt_Number")
hurtMaxNum = uint32(countAdditional(uint64(hurtMaxNum), attUser, proto.AtttibuteType_AttMonsCount))
if assert.Number <= hurtMaxNum {
hurtMaxNum = assert.Number
}
hot += common.StringToUint32(tmps[0])
if uint32(wtime.GetNow()-assert.Time) <= CSV.GetGameConfigValueUint32("Continuity_Hurt_Time")*60 {
hot += (hurtMaxNum - 1) * common.StringToUint32(tmps[1])
}
}
assert.Number += 1
} else {
assert.Dataid = worldAssetData.GetWorldDataID()
assert.Number = 1
}
assert.Time = wtime.GetNow()
monsterBattleReport.MonsterInf.Count = proto.SetUint32(assert.Number)
return true
})
hitCount := actionDataEntry.GetHit()
monsterBattleReport.MonsterInf.Times = proto.SetUint32(hitCount)
hp := uint64((10000+hot)*monsterBattleReport.GetMonsterInf().GetDropHP()/10000) * uint64(hitCount)
if worldAssetData.GetWorldData().SimpleEntry.GetHp() < hp {
hp = worldAssetData.GetWorldData().SimpleEntry.GetHp()
}
worldAssetData.GetWorldData().SimpleEntry.Hp = proto.SetUint64(worldAssetData.GetWorldData().SimpleEntry.GetHp() - hp)
monsterBattleReport.MonsterInf.CurrentHP = proto.SetUint32(uint32(worldAssetData.GetWorldData().SimpleEntry.GetHp()))
monsterBattleReport.MonsterInf.DropHP = proto.SetUint32(uint32(hp))
monsterBattleReport.Uid = proto.SetUint64(attUser.GetUid())
monsterBattleReport.Monsterid = proto.SetInt64(csvWorldConfig.ID)
monsterBattleReport.MonsterInf.AddDamage = proto.SetUint32(hot)
actionDataAsset.SetAppedData(encodeActionAppendData(actionDataEntry.GetAppenddata(), "DelHp", common.Uint64ToString(hp)))
worldAssetData.AddStatus(proto.WorldDataStatus_WDS_DelHp)
//加英雄经验
entryConfig := common.ParseParameterStringToMap(csvWorldConfig.EntryConfig)
heroExpStr, ok := entryConfig["HeroExp"]
if ok {
heroExp := common.ParseStringToUint64List(heroExpStr)
if len(heroExp) == 2 {
var heroLevelUp []uint32
expRise := getPassiveAfterFightSkillEffect(attUser, actionDataEntry.GetHeroIDList(), "ExpRise")
for _, id := range actionDataEntry.GetHeroIDList() {
isLevelUp := false
attUser.WithHeroAsset(true, id, func(heroAsset *proto.ST_HeroEntry_PB) bool {
conf := CSV.Mgr.CSV_HeroLevel.GetEntryPtr(int64(heroAsset.GetLevel()))
exp := (heroExp[0]*uint64(conf.ExpCoefficient) + heroExp[1]) * uint64(hitCount)
exp = uint64(10000+expRise) * exp / 10000
flag, fixExp := attUser.CanAddHeroExp(id, exp)
if flag {
_, isLevelUp = attUser.AddHeroExp(id, fixExp)
}
if isLevelUp {
heroLevelUp = append(heroLevelUp, heroAsset.GetId())
}
heroReport := &proto.ST_HeroBattleReport_PB{
Id: proto.SetUint32(heroAsset.GetId()),
Level: proto.SetUint32(heroAsset.GetLevel()),
Star: proto.SetUint32(heroAsset.GetStar()),
Exp: proto.SetUint64(heroAsset.GetExp()),
AddExp: proto.SetUint64(fixExp),
IsLevelUp: proto.SetBool(isLevelUp),
//Rank: proto.SetUint32(heroAsset.GetRank()),
}
heroReport.SkillList = make([]*proto.ST_HeroSkill_PB, 0)
for _, v := range heroAsset.GetSkillList() {
skill := &proto.ST_HeroSkill_PB{
SkillLogicType: proto.SetUint32(v.GetSkillLogicType()),
SkillID: proto.SetUint32(v.GetSkillID()),
}
heroReport.SkillList = append(heroReport.SkillList, skill)
}
heroReport.BranchValue = make([]uint32, 0)
for _, v := range heroAsset.GetBranchValue() {
heroReport.BranchValue = append(heroReport.BranchValue, v)
}
monsterBattleReport.HeroListReport = append(monsterBattleReport.HeroListReport, heroReport)
return true
})
}
attUser.AddLevelUpHeroList(heroLevelUp)
}
}
commanderExpStr, ok := entryConfig["CommanderExp"]
addexp := uint64(0)
if ok {
commanderExp := common.ParseStringToUint64List(commanderExpStr)
if len(commanderExp) == 2 {
conf := CSV.Mgr.CSV_CommanderLevelUp.GetEntryPtr(int64(attUser.GetLevel()))
commanderExp := (commanderExp[0]*uint64(conf.ExpCoefficient) + commanderExp[1]) * uint64(actionDataEntry.GetHit())
addexp = attUser.AddExp(commanderExp)
monsterBattleReport.CommanderExp = proto.SetUint32(uint32(addexp))
}
}
//多次猎杀奖励
for i := actionDataEntry.GetHit(); i > 0; i-- {
itemList := createItemByVector4(entryConfig["Rward"])
for _, item := range itemList {
AddItem(attUser, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcTypeKillMonster)
}
monsterBattleReport.Reward = append(monsterBattleReport.Reward, itemList...)
activityItemList := processDropActivity(attUser, int32(proto.DropActivityType_DAT_AttackMonster), 0, 1)
for _, item := range activityItemList {
AddItem(attUser, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcDropActivity)
}
monsterBattleReport.Reward = append(monsterBattleReport.Reward, activityItemList...)
}
monsterBattleReport.Reward = common.CombineItemList(monsterBattleReport.Reward)
isWin := 2
if worldAssetData.GetWorldData().SimpleEntry.GetHp() == 0 {
isWin = 1
cache.Instance_GlobalAssetWorldData.WithWildMonsterListAsset(false, func(asset *cache.ST_WildMonsterList) bool {
asset.List[worldAssetData.GetWorldDataID()] = 0
return true
})
//RecallCityArmy(worldAssetData)
actionDataAsset.SetAppedData(encodeActionAppendData(actionDataEntry.GetAppenddata(), "needDeleteID", common.Uint64ToString(worldAssetData.GetWorldDataID())))
worldAssetData.AddStatus(proto.WorldDataStatus_WDS_Delete)
//击杀奖励
AddLeagueGift(attUser.GetLeagueID(), uint32(csvWorldConfig.HitReward), "", 0)
attUser.SyncAchievementIfGraterSet(cache.LSMWDJEvent, uint64(csvWorldConfig.EntryLevel))
attUser.SyncAchievementAdd(cache.LJLSMWCSEvent, uint64(1))
//7日挑战积分
observer.ObserverSingleton.AsyncNotify(observer.ChallengeKillMonsterEvent, []interface{}{attUser, csvWorldConfig.EntryLevel, uint32(1)})
observer.ObserverSingleton.AsyncNotify(observer.ActivityTaskKillMonsterEvent, []interface{}{attUser, uint32(1), uint32(1)})
observer.ObserverSingleton.AsyncNotify(observer.KillMonsterEvent, []interface{}{attUser, uint32(1), uint32(1), uint32(csvWorldConfig.EntryLevel), targetMonster})
}
attUser.SyncAchievementAdd(cache.AtkMonEvent, uint64(actionDataEntry.GetHit()))
observer.ObserverSingleton.AsyncNotify(observer.AttackMonsterEvent, []interface{}{attUser, actionDataEntry.GetHit(), uint32(worldAssetData.GetWorldDataEntry().GetZ())})
SFUID := common.GetSFUID()
strSFUID := strconv.FormatInt(SFUID, 10)
// 暂时添加为测试英雄技能
//strInfo := string(proto.Marshal(battleInfo))
//cache.Instance_BattleInfoListCache.AddBattleInfo(SFUID, &strInfo)
mailtype := uint32(proto.MailType_MT_MONSTER)
titleTips := common.CreateTips(90000093, uint32(csvWorldConfig.Name))
contentTips := common.CreateTips(72065, uint32(csvWorldConfig.Name), common.ConvertToString(csvWorldConfig.EntryLevel))
_, mailid := attUser.AddLanguageIDMailAsset(mailtype, 0, worldAssetData.GetWorldDataTileID(), int32(proto.MailSourceType_MST_Default), titleTips, contentTips,
string(proto.Marshal(monsterBattleReport)), strSFUID)
//右下角战斗通知
atkBattleNotice := &proto.ST_BattleNotice_PB{IsHaveBattleInfo: proto.SetBool(false)} //进攻方的战斗结果通知
atkBattleNotice.LanguageID = proto.SetUint32(75551) //您攻击了lv.$0$@0@
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
atkBattleNotice.ParaString = append(atkBattleNotice.ParaString, common.ConvertToString(csvWorldConfig.EntryLevel))
atkBattleNotice.BattleRlt = proto.SetBool(true)
// 暂时添加为测试英雄技能
//atkBattleNotice.IsHaveBattleInfo = proto.SetBool(true)
atkBattleNotice.MailID = proto.SetUint64(mailid)
attUser.CreateBattleNotice(SFUID, atkBattleNotice)
newOssBattleRecord(attUser, oss.OBT_Monster, isWin == 1, 0, 1, targetMonster,
int32(monsterBattleReport.GetMonsterInf().GetTileID()), monsterBattleReport.GetHeroListReport(), monsterBattleReport.GetUints())
newOssMonsterBattle(attUser, 1, actionDataEntry.GetHit(), worldAssetData, hp, addexp, isWin, monsterBattleReport.GetHeroListReport(),
monsterBattleReport.GetUints(), monsterBattleReport.GetReward(), 0, []uint64{})
}
/**
@brief 根据不同的目标根据结果处理相关逻辑
*/
func processWorldBattleResult(battleRlt uint32, targetType uint32, actionDataAsset *cache.GlobalActionEntry, battleReport *proto.ST_BattleReport_PB, battleInfo *proto.ST_BattleInfo_PB) {
if battleReport == nil || actionDataAsset == nil {
wlog.Error("processWorldBattleResult:", targetType)
return
}
if len(battleReport.GetAtkInfo()) <= 0 || len(battleReport.GetDefInfo()) <= 0 {
wlog.Error("processWorldBattleResult < 0 ")
return
}
worldAssetData := cache.Instance_GlobalAssetWorldData.GetWorldDataByTileId(actionDataAsset.Actiondata.GetEndTileID())
if worldAssetData == nil {
return
}
csvWorldConfig := worldAssetData.GetWorldEntryConfig()
if csvWorldConfig == nil {
return
}
heroList := make([]uint32, 0)
monsterLevel := uint32(csvWorldConfig.EntryLevel)
actionDataEntry := actionDataAsset.Actiondata
function := common.ParseParameterStringToMap(csvWorldConfig.EntryConfig)
award := function["AttackRward"]
unitChannel := oss.UnitChangeTypePVP
initiatorRward := function["InitiatorRward"]
var attInfo = getBigBrother(battleReport.AtkInfo) //攻击方首回合信息
var defInfo = getBigBrother(battleReport.DefInfo) //防守方首回合信息
if attInfo == nil || defInfo == nil {
return
}
isMultiuserAtk := false //集结攻击
isMultiuserDef := false //援助
if actionDataAsset.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MASS) {
isMultiuserAtk = true
}
if 1 < len(battleReport.GetDefInfo()) {
isMultiuserDef = true
}
defInfoLen := len(battleReport.GetDefInfo())
lastRoundDefInfo := battleReport.GetDefInfo()[defInfoLen-1] //防守方最后一回合信息
attUser := cache.GetCharinfo(attInfo.GetCommanderReport().GetUid())
if attUser == nil {
return
}
for _, v := range attInfo.GetHeroListReport() {
heroList = append(heroList, v.GetId())
}
// defUser 可能为nil
var defUser *cache.Info
if defInfo.CommanderReport != nil {
defUser = cache.GetCharinfo(defInfo.GetCommanderReport().GetUid())
}
isWin, hasMailReport := checkFinalRlt(targetType, battleRlt, battleReport)
battleInfo.IsAtkWin = proto.SetBool(isWin)
attActionUnitMap, defActionUnitMap, attRemainUnit := getActionUnitMapByBattleReport(battleReport)
//处理战斗后兵种资产
processGlobalActionAfterBattle(defActionUnitMap, worldAssetData, targetType, defUser, actionDataEntry.GetActiontype(), nil, isWin, false)
processGlobalActionAfterBattle(attActionUnitMap, worldAssetData, targetType, attUser, actionDataEntry.GetActiontype(), battleReport.GetReturnUnitsList(), isWin, true)
checkAtkDefAllDieout(attActionUnitMap, defActionUnitMap, targetType, worldAssetData)
//处理玩家统计信息
cid := GetcityID(worldAssetData)
pvp := true
if cid != 0 && defUser == nil {
pvp = false
}
kill, _ := processStatisticsAsset(isWin, targetType, attUser, defUser, true, battleReport.GetAtkInfo(), true, pvp)
defkill, _ := processStatisticsAsset(isWin, targetType, defUser, attUser, true, battleReport.GetDefInfo(), false, true)
atkBattleNotice := &proto.ST_BattleNotice_PB{IsHaveBattleInfo: proto.SetBool(true)} //进攻方的战斗结果通知
targetBattleNotice := &proto.ST_BattleNotice_PB{IsHaveBattleInfo: proto.SetBool(true)} //被进攻方的战斗结果通知
targetSubBattleNotice := &proto.ST_BattleNotice_PB{IsHaveBattleInfo: proto.SetBool(true)} //援助方的战斗结果通知
atkTitleTips := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())}
defTitleTips := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())} //防守方主要对象收到的信息
defSubTitleTips := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())} //防守方支援对象收到的信息
atkMutiMonsterContent := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())}
if isWin {
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, 90000093)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 90000092)
defSubTitleTips.ParaUint32 = append(defSubTitleTips.ParaUint32, 90000092)
atkBattleNotice.BattleRlt = proto.SetBool(true)
targetBattleNotice.BattleRlt = proto.SetBool(false)
targetSubBattleNotice.BattleRlt = proto.SetBool(false)
} else {
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, 90000094)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 90000091)
defSubTitleTips.ParaUint32 = append(defSubTitleTips.ParaUint32, 90000091)
atkBattleNotice.BattleRlt = proto.SetBool(false)
targetBattleNotice.BattleRlt = proto.SetBool(true)
targetSubBattleNotice.BattleRlt = proto.SetBool(true)
}
atkUsers := make([]uint64, 0)
switch targetType {
case targetMainCity:
battleReport.DefFailInfo = &proto.ST_DefFailInfo_PB{}
if nil != lastRoundDefInfo.GetWallReport() {
Speed := countAdditional(uint64(CSV.GetGameConfigValueUint32("WALL_BURN_SPEED")), attUser, proto.AtttibuteType_SiegeAttack)
battleReport.DefFailInfo.BurningTime = proto.SetUint32(ProcessMainCityDefenseLogic(worldAssetData.GetWorldDataOwner(), isWin, lastRoundDefInfo.WallReport.GetAfterHp(), Speed))
}
atkTitleTips.LanguageID = proto.SetUint32(90000012)
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, 20000125)
atkTitleTips.ParaString = append(atkTitleTips.ParaString, defUser.GetUserName())
defTitleTips.LanguageID = proto.SetUint32(90000011)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 20000125)
defTitleTips.ParaString = append(defTitleTips.ParaString, attUser.GetUserName())
defSubTitleTips.LanguageID = proto.SetUint32(90000011)
defSubTitleTips.ParaUint32 = append(defSubTitleTips.ParaUint32, 71026)
defSubTitleTips.ParaString = append(defSubTitleTips.ParaString, attUser.GetUserName())
//右下角战斗提示
atkBattleNotice.LanguageID = proto.SetUint32(75549) //您攻击了$0$
if isMultiuserAtk {
atkBattleNotice.LanguageID = proto.SetUint32(75555) //您集结攻击了$0$
}
atkBattleNotice.ParaString = append(atkBattleNotice.ParaString, defUser.GetUserName())
if isMultiuserAtk {
targetBattleNotice.LanguageID = proto.SetUint32(75558) //$0$集结攻击了您
} else {
targetBattleNotice.LanguageID = proto.SetUint32(75550) //$0$攻击了您
}
targetBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
if isMultiuserDef {
targetSubBattleNotice.LanguageID = proto.SetUint32(75559) //$0$攻击了您援助的$1$
if isMultiuserAtk {
targetSubBattleNotice.LanguageID = proto.SetUint32(75599) //$0$集结攻击了您援助的$1$
}
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
if defUser != nil {
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, defUser.GetUserName())
}
}
if isWin {
// 资源掠夺
totalResource, actionResource := genGrabResource(attUser, defUser, attRemainUnit, attActionUnitMap, isWin, targetMainCity, heroList, worldAssetData.GetWorldDataID())
//>>>完成攻击成就[6501001]
attUser.SyncAchievementAdd(cache.LJGJWJHSEvent, uint64(1))
processPrisonAfterBattle(battleReport.GetAtkInfo(), attUser, defUser)
_, CaptureMap := captureCommander(attUser, defUser, true, targetType)
for k := range CaptureMap {
battleReport.DefFailInfo.PrisonID = proto.SetUint64(k)
break
}
//资源掠夺总奖励 key|Value
battleReport.TotalReward = proto.SetString(encodeActionAppendData("", "usrCash", string(proto.Marshal(totalResource))))
//参与玩家各自的奖励
for _, v := range battleReport.AtkInfo {
userInfo := cache.GetCharinfo(v.GetCommanderReport().GetUid())
if nil == userInfo {
continue
}
if rewardResource, ok := actionResource[v.GetActionID()]; ok {
v.Reward = proto.SetString(encodeActionAppendData("", "usrCash", string(proto.Marshal(rewardResource))))
}
itemList := processDropActivity(userInfo, int32(proto.DropActivityType_DAT_AttackMainCity), 0, 1)
for _, item := range itemList {
AddItem(userInfo, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcDropActivity)
v.MutirMonReward = append(v.MutirMonReward, item)
}
}
}
case targetMonsterEx:
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
atkMutiMonsterContent.ParaUint32 = append(atkMutiMonsterContent.ParaUint32, uint32(csvWorldConfig.Name))
atkMutiMonsterContent.ParaString = append(atkMutiMonsterContent.ParaString, common.ConvertToString(csvWorldConfig.EntryLevel))
if isWin {
atkTitleTips.LanguageID = proto.SetUint32(90000093) //进攻胜利
atkMutiMonsterContent.LanguageID = proto.SetUint32(72065) //您成功摧毁了Lv.$0$ @0@
attUser.SyncAchievementAdd2(cache.NewTask1, int64(proto.WorldEntryType_WET_WILDMONSTEREX), int64(csvWorldConfig.EntryLevel), 1)
} else {
atkTitleTips.LanguageID = proto.SetUint32(90000094) //进攻失败
atkMutiMonsterContent.LanguageID = proto.SetUint32(72066) //进攻Lv.$0$ @0@失败
}
//右下角战斗通知
atkBattleNotice.LanguageID = proto.SetUint32(75551) //您攻击了lv.$0$@0@
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
atkBattleNotice.ParaString = append(atkBattleNotice.ParaString, common.ConvertToString(csvWorldConfig.EntryLevel))
atkBattleNotice.BattleRlt = proto.SetBool(isWin)
atkBattleNotice.IsHaveBattleInfo = proto.SetBool(false)
// 暂时添加为测试英雄技能
//atkBattleNotice.IsHaveBattleInfo = proto.SetBool(true)
//加英雄经验
//成功击杀
if isWin {
entryConfig := common.ParseParameterStringToMap(csvWorldConfig.EntryConfig)
heroExpStr, ok := entryConfig["HeroExp"]
if ok {
heroExp := common.ParseStringToUint64List(heroExpStr)
if len(heroExp) == 2 {
expRise := getPassiveAfterFightSkillEffect(attUser, heroList, "ExpRise")
var heroLevelUp []uint32
for _, v := range attInfo.HeroListReport {
isLevelUp := false
attUser.WithHeroAsset(true, v.GetId(), func(heroAsset *proto.ST_HeroEntry_PB) bool {
conf := CSV.Mgr.CSV_HeroLevel.GetEntryPtr(int64(heroAsset.GetLevel()))
exp := heroExp[0]*uint64(conf.ExpCoefficient) + heroExp[1]
exp = (uint64(expRise) + 10000) * exp / 10000
flag, fixExp := attUser.CanAddHeroExp(v.GetId(), exp)
if flag {
_, isLevelUp = attUser.AddHeroExp(v.GetId(), fixExp)
}
if isLevelUp {
heroLevelUp = append(heroLevelUp, heroAsset.GetId())
v.Level = proto.SetUint32(heroAsset.GetLevel())
}
v.AddExp = proto.SetUint64(exp)
v.IsLevelUp = proto.SetBool(isLevelUp)
return true
})
}
attUser.AddLevelUpHeroList(heroLevelUp)
}
}
//指挥官经验
commanderExpStr, ok := entryConfig["CommanderExp"]
addexp := uint64(0)
if ok {
commanderExp := common.ParseStringToUint64List(commanderExpStr)
if len(commanderExp) == 2 {
conf := CSV.Mgr.CSV_CommanderLevelUp.GetEntryPtr(int64(attUser.GetLevel()))
exp := commanderExp[0]*uint64(conf.ExpCoefficient) + commanderExp[1]
addexp = attUser.AddExp(exp)
attInfo.CommanderReport.AddExp = proto.SetUint64(addexp)
}
}
//RecallCityArmy(worldAssetData)
actionDataAsset.SetAppedData(encodeActionAppendData(actionDataEntry.GetAppenddata(), "needDeleteID", common.Uint64ToString(worldAssetData.GetWorldDataID())))
worldAssetData.AddStatus(proto.WorldDataStatus_WDS_Delete)
//给予首杀奖励
if uint32(csvWorldConfig.EntryLevel) > attUser.GetKilledMonsterLevel() {
firstReward, ok := entryConfig["FirstKillAward"]
if ok {
finilReward := &proto.ST_Vector4IntList_PB{}
itemList := createItemByVector4(firstReward)
for _, item := range itemList {
AddItem(attUser, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcKillMonsterEx)
tmp := &proto.ST_Vector4Int_PB{
Y: proto.SetInt32(int32(item.GetItemId())),
W: proto.SetInt32(int32(item.GetItemNum())),
}
finilReward.Reward = append(finilReward.Reward, tmp)
}
attInfo.Reward = proto.SetString(encodeActionAppendData("", "firstKill", string(proto.Marshal(finilReward))))
}
attUser.SetKilledMonsterLevel(uint32(csvWorldConfig.EntryLevel))
}
//给予击杀奖励
reward, ok := entryConfig["Rward"]
if ok {
//v := battleReport.AtkInfo[0]
itemList := createItemByVector4(reward)
for _, item := range itemList {
AddItem(attUser, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcKillMonsterEx)
attInfo.MutirMonReward = append(attInfo.MutirMonReward, item)
}
activityItemList := processDropActivity(attUser, int32(proto.DropActivityType_DAT_KillMonster), 0, 1)
for _, item := range activityItemList {
AddItem(attUser, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcDropActivity)
}
attInfo.MutirMonReward = append(attInfo.MutirMonReward, activityItemList...)
}
observer.ObserverSingleton.AsyncNotify(observer.KillMonsterExEvent, []interface{}{attUser, csvWorldConfig.EntryLevel})
observer.ObserverSingleton.AsyncNotify(observer.ActivityTaskKillMonsterEvent, []interface{}{attUser, uint32(3)})
}
case targetSummonMutiMonster:
atkTitleTips.LanguageID = proto.SetUint32(90000089)
atkBattleNotice.LanguageID = proto.SetUint32(75556) //您集结攻击了lv.$0$@0@
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
atkBattleNotice.ParaString = append(atkBattleNotice.ParaString, common.ConvertToString(csvWorldConfig.EntryLevel))
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
atkBattleNotice.IsHaveBattleInfo = proto.SetBool(false)
// 暂时添加为测试英雄技能
//atkBattleNotice.IsHaveBattleInfo = proto.SetBool(true)
if isWin {
actionDataAsset.SetAppedData(encodeActionAppendData(actionDataEntry.GetAppenddata(), "needDeleteID", common.Uint64ToString(worldAssetData.GetWorldDataID())))
worldAssetData.AddStatus(proto.WorldDataStatus_WDS_Delete)
//公会奖励
AddLeagueGift(attUser.GetLeagueID(), uint32(csvWorldConfig.HitReward), "", 0)
lid := worldAssetData.GetWorldData().SimpleEntry.GetMstLid()
//参与者奖励
for _, v := range battleReport.AtkInfo {
tmpUserData := cache.GetCharinfo(v.GetCommanderReport().GetUid())
if nil == tmpUserData {
continue
}
atkUsers = append(atkUsers, v.GetCommanderReport().GetUid())
//怪物攻城集结怪只有参与报名的成员才有奖励
if lid != 0 && attUser.GetLeagueID() != GetMacMgrInstance().GetOrgLid(tmpUserData) {
continue
}
award := function["Rward"]
itemList := createItemByVector4(award)
for _, item := range itemList {
AddItem(tmpUserData, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcKillSummonMonster)
v.MutirMonReward = append(v.MutirMonReward, item)
}
}
if lid != 0 {
GetMacMgrInstance().rallMonsterKilled(lid)
}
}
case targetMutiMonster:
atkTitleTips.LanguageID = proto.SetUint32(90000089)
atkBattleNotice.LanguageID = proto.SetUint32(75557) //您集结攻击了lv.$0$@0@
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
atkBattleNotice.ParaString = append(atkBattleNotice.ParaString, common.ConvertToString(csvWorldConfig.EntryLevel))
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
if isWin {
actionDataAsset.SetAppedData(encodeActionAppendData(actionDataEntry.GetAppenddata(), "needDeleteID", common.Uint64ToString(worldAssetData.GetWorldDataID())))
worldAssetData.AddStatus(proto.WorldDataStatus_WDS_Delete)
AddLeagueGift(attUser.GetLeagueID(), uint32(csvWorldConfig.HitReward), "", 0)
for _, v := range battleReport.AtkInfo {
tmpUserData := cache.GetCharinfo(v.GetCommanderReport().GetUid())
if nil == tmpUserData {
continue
}
atkUsers = append(atkUsers, v.GetCommanderReport().GetUid())
observer.ObserverSingleton.AsyncNotify(observer.ActivityTaskKillMonsterEvent, []interface{}{tmpUserData, uint32(2)})
observer.ObserverSingleton.AsyncNotify(observer.KillMachineCenterEvent, []interface{}{tmpUserData, uint32(monsterLevel)})
tmpUserData.SyncAchievementAdd(cache.LJLSMWCSEvent, uint64(1))
// 活动积分
observer.ObserverSingleton.AsyncNotify(observer.KillMonsterEvent, []interface{}{tmpUserData, uint32(1), uint32(1), monsterLevel, targetMutiMonster})
//>>猎杀LV.1魔物[6503801]
tmpUserData.SyncAchievementIfGraterSet(cache.LSMWDJEvent, uint64(monsterLevel))
tmpUserData.SyncAchievementAdd(cache.Src2009, &cache.UInt64Tuple{uint64(monsterLevel), uint64(1)})
//if GetMutiMonsterRewardTimes(tmpUserData) > 0 {
itemList := createItemByVector4(award)
for _, item := range itemList {
AddItem(tmpUserData, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcKillMutliMonster)
v.MutirMonReward = append(v.MutirMonReward, item)
}
itemList = createItemByVector4(initiatorRward)
for _, item := range itemList {
AddItem(tmpUserData, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcKillMutliMonster)
v.MutirMonReward = append(v.MutirMonReward, item)
}
itemList = processDropActivity(tmpUserData, int32(proto.DropActivityType_DAT_KillMuliMonster), 0, 1)
for _, item := range itemList {
AddItem(tmpUserData, item.GetItemId(), item.GetItemNum(), oss.AddCashSrcDropActivity)
v.MutirMonReward = append(v.MutirMonReward, item)
}
//ReduceMutiMonsterRewardTimes(tmpUserData)
//SetLastMutiMonsterRewardTime(tmpUserData, wtime.GetNow())
}
observer.ObserverSingleton.AsyncNotify(observer.MASSMutiMonsterEvent, []interface{}{monsterLevel, targetMutiMonster, attUser.GetLeagueID()})
}
//}
case targetRayolCity:
atkTitleTips.LanguageID = proto.SetUint32(90000089)
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
defTitleTips.LanguageID = proto.SetUint32(90000090)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
defTitleTips.ParaString = append(defTitleTips.ParaString, attUser.GetUserName())
atkBattleNotice.LanguageID = proto.SetUint32(75552) //您攻击了@0@
if isMultiuserAtk {
atkBattleNotice.LanguageID = proto.SetUint32(75556) //您集结攻击了@0@
}
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
if isMultiuserAtk {
targetBattleNotice.LanguageID = proto.SetUint32(75622) //$0$集结攻击了您的@0@
} else {
targetBattleNotice.LanguageID = proto.SetUint32(75554) //$0$攻击了您的@0@
}
targetBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
targetBattleNotice.ParaUint32 = append(targetBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
if isMultiuserDef {
targetSubBattleNotice.LanguageID = proto.SetUint32(75559) //$0$攻击了您援助的$1$
if isMultiuserAtk {
targetSubBattleNotice.LanguageID = proto.SetUint32(75599) //$0$集结攻击了您援助的$1$
}
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
if defUser != nil {
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, defUser.GetUserName())
}
}
if isWin {
processMiracleWarEvent(attUser, GetcityID(worldAssetData))
if defUser != nil {
tips := common.CreateTips(75644, attUser.GetLeagueName(), uint32(csvWorldConfig.Name))
cache.Instance_GlobalAssetChat.AddLanguageIdGlobalMessage(tips)
go func() {
content := fmt.Sprintf("[%d][%s][%s][%s][%d]", 75573, attUser.GetUserName(), attUser.GetLeagueName(), defUser.GetLeagueName(), csvWorldConfig.Name)
//cache.Instance_GlobalAssetChat.AddSystemChat(int32(proto.ChatChannelType_CT_ALLIANCE), attUser.GetLeagueID(), content)
sendLeagueSystemMsg(attUser.GetLeagueID(), content)
content = fmt.Sprintf("[%d][%s][%s][%s][%d]", 75574, attUser.GetUserName(), defUser.GetLeagueName(), attUser.GetLeagueName(), csvWorldConfig.Name)
//cache.Instance_GlobalAssetChat.AddSystemChat(int32(proto.ChatChannelType_CT_ALLIANCE), defUser.GetLeagueID(), content)
sendLeagueSystemMsg(defUser.GetLeagueID(), content)
}()
}
}
for _, v := range battleReport.GetAtkInfo() {
if nil == v.GetCommanderReport() {
continue
}
tmpUser := cache.GetCharinfo(v.GetCommanderReport().GetUid())
if nil == tmpUser {
continue
}
observer.ObserverSingleton.AsyncNotify(observer.AddMiracleWarRecordEvent, []interface{}{int32(1), tmpUser, defUser})
}
// 重新计算大奇迹, 城市容量
calcBigMiracleGarrsonCapAfterBattle(worldAssetData)
case targetLeagueCenter:
atkTitleTips.LanguageID = proto.SetUint32(90000089)
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
defTitleTips.LanguageID = proto.SetUint32(90000090)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
defTitleTips.ParaString = append(defTitleTips.ParaString, attUser.GetUserName())
atkBattleNotice.LanguageID = proto.SetUint32(75552) //您攻击了@0@
if isMultiuserAtk {
atkBattleNotice.LanguageID = proto.SetUint32(75556) //您集结攻击了@0@
}
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
if isMultiuserAtk {
targetBattleNotice.LanguageID = proto.SetUint32(75622) //$0$集结攻击了您的@0@
} else {
targetBattleNotice.LanguageID = proto.SetUint32(75554) //$0$攻击了您的@0@
}
targetBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
targetBattleNotice.ParaUint32 = append(targetBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
if isMultiuserDef {
targetSubBattleNotice.LanguageID = proto.SetUint32(75559) //$0$攻击了您援助的$1$
if isMultiuserAtk {
targetSubBattleNotice.LanguageID = proto.SetUint32(75599) //$0$集结攻击了您援助的$1$
}
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
if defUser != nil {
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, defUser.GetUserName())
}
}
case targetWarCity, targetCity:
atkTitleTips.LanguageID = proto.SetUint32(90000089)
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
defTitleTips.LanguageID = proto.SetUint32(90000090)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, uint32(csvWorldConfig.Name))
defTitleTips.ParaString = append(defTitleTips.ParaString, attUser.GetUserName())
atkBattleNotice.LanguageID = proto.SetUint32(75552) //您攻击了@0@
if isMultiuserAtk {
atkBattleNotice.LanguageID = proto.SetUint32(75556) //您集结攻击了@0@
}
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
if isMultiuserAtk {
targetBattleNotice.LanguageID = proto.SetUint32(75622) //$0$集结攻击了您的@0@
} else {
targetBattleNotice.LanguageID = proto.SetUint32(75554) //$0$攻击了您的@0@
}
targetBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
targetBattleNotice.ParaUint32 = append(targetBattleNotice.ParaUint32, uint32(csvWorldConfig.Name))
if isMultiuserDef {
targetSubBattleNotice.LanguageID = proto.SetUint32(75559) //$0$攻击了您援助的$1$
if isMultiuserAtk {
targetSubBattleNotice.LanguageID = proto.SetUint32(75599) //$0$集结攻击了您援助的$1$
}
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
if defUser != nil {
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, defUser.GetUserName())
}
}
if isWin {
DelWarCityData(actionDataAsset.Actiondata.GetEndTileID(), defInfo.GetActionID())
if AddWarCityData(actionDataAsset) != 0 {
unitChannel = oss.UnitChangeTypeCityWar
}
}
AddWarCityKill(actionDataAsset.Actiondata.GetEndTileID(), actionDataAsset.Actiondata.GetActionid(), kill)
AddWarCityKill(actionDataAsset.Actiondata.GetEndTileID(), defInfo.GetActionID(), defkill)
CountWarCityData(cid)
case targetBestationed:
atkTitleTips.LanguageID = proto.SetUint32(90000012)
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, 20000212)
atkTitleTips.ParaString = append(atkTitleTips.ParaString, defUser.GetUserName())
defTitleTips.LanguageID = proto.SetUint32(90000011)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 20000212)
defTitleTips.ParaString = append(defTitleTips.ParaString, attUser.GetUserName())
atkBattleNotice.LanguageID = proto.SetUint32(75553) //您攻击了$0$的@0@
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, 20000212)
if defUser != nil {
atkBattleNotice.ParaString = append(atkBattleNotice.ParaString, defUser.GetUserName())
}
targetBattleNotice.LanguageID = proto.SetUint32(75554) //$0$攻击了您的@0@
targetBattleNotice.ParaUint32 = append(targetBattleNotice.ParaUint32, 20000212)
targetBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
if isWin {
DelWarCityData(actionDataAsset.Actiondata.GetEndTileID(), defInfo.GetActionID())
if AddWarCityData(actionDataAsset) != 0 {
unitChannel = oss.UnitChangeTypeCityWar
}
}
AddWarCityKill(actionDataAsset.Actiondata.GetEndTileID(), actionDataAsset.Actiondata.GetActionid(), kill)
AddWarCityKill(actionDataAsset.Actiondata.GetEndTileID(), defInfo.GetActionID(), defkill)
CountWarCityData(cid)
case targetMine, targetMineGem:
atkTitleTips.LanguageID = proto.SetUint32(90000012)
atkTitleTips.ParaUint32 = append(atkTitleTips.ParaUint32, 20000211)
if defUser == nil {
atkTitleTips.ParaString = append(atkTitleTips.ParaString, "")
} else {
atkTitleTips.ParaString = append(atkTitleTips.ParaString, defUser.GetUserName())
}
defTitleTips.LanguageID = proto.SetUint32(90000011)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 20000211)
defTitleTips.ParaString = append(defTitleTips.ParaString, attUser.GetUserName())
atkBattleNotice.LanguageID = proto.SetUint32(75553) //您攻击了$0$的@0@
atkBattleNotice.ParaUint32 = append(atkBattleNotice.ParaUint32, 20000211)
if nil != defUser {
atkBattleNotice.ParaString = append(atkBattleNotice.ParaString, defUser.GetUserName())
}
targetBattleNotice.LanguageID = proto.SetUint32(75554) //$0$攻击了您的@0@
targetBattleNotice.ParaUint32 = append(targetBattleNotice.ParaUint32, 20000211)
targetBattleNotice.ParaString = append(targetBattleNotice.ParaString, attUser.GetUserName())
if isWin {
//worldAssetData.DeleteStatus(proto.WorldDataStatus_WDS_Work)
processCollectionBattleAtkWin(targetType, attUser, attActionUnitMap, defActionUnitMap, worldAssetData, isWin)
} else {
// 重新计算采矿时间
processBattleResultOnMine(actionDataAsset, worldAssetData, isWin)
}
}
ossBattleType := oss.OBT_Monster
ossFiledType := uint32(1)
if len(battleReport.AtkInfo) > 1 || len(battleReport.DefInfo) > 1 {
ossFiledType = 2
}
mailType := uint32(proto.MailType_MT_BATTLE)
if targetMonsterEx == targetType {
mailType = uint32(proto.MailType_MT_MONSTER_EX)
}
//发送防守方的邮件
defBattleReport := proto.Clone(battleReport).(*proto.ST_BattleReport_PB)
defBattleReport.IsWin = proto.SetBool(!isWin)
strInfo := string(proto.Marshal(battleInfo))
SFUID := common.GetSFUID()
strSFUID := strconv.FormatInt(SFUID, 10)
for _, v := range battleReport.DefInfo {
tmpUserInfo := cache.GetCharinfo(v.CommanderReport.GetUid())
if tmpUserInfo == nil {
continue
}
ossBattleType = oss.OBT_PVP
//攻打玩家城市,对发送给主城玩家和支援玩家的邮件标题做区分
//带头大哥和小弟的战斗提示框不同
if true == v.GetIsBigBrother() || targetType != targetMainCity {
cache.Instance_BattleInfoListCache.AddBattleInfo(SFUID, &strInfo)
_, mailid := tmpUserInfo.AddLanguageIDMailAsset(mailType, 0, worldAssetData.GetWorldDataTileID(), int32(proto.MailSourceType_MST_Default), defTitleTips, defTitleTips,
string(proto.Marshal(defBattleReport)), strSFUID)
if v.GetIsBigBrother() {
targetBattleNotice.MailID = proto.SetUint64(mailid)
if true == tmpUserInfo.IsRealOnline() {
tmpUserInfo.CreateBattleNotice(SFUID, targetBattleNotice)
}
} else {
targetSubBattleNotice.MailID = proto.SetUint64(mailid)
if true == tmpUserInfo.IsRealOnline() {
tmpUserInfo.CreateBattleNotice(SFUID, targetSubBattleNotice)
}
}
} else {
cache.Instance_BattleInfoListCache.AddBattleInfo(SFUID, &strInfo)
_, mailid := tmpUserInfo.AddLanguageIDMailAsset(mailType, 0, worldAssetData.GetWorldDataTileID(), int32(proto.MailSourceType_MST_Default), defSubTitleTips, defSubTitleTips,
string(proto.Marshal(defBattleReport)), strSFUID)
targetSubBattleNotice.MailID = proto.SetUint64(mailid)
if true == tmpUserInfo.IsRealOnline() {
tmpUserInfo.CreateBattleNotice(SFUID, targetSubBattleNotice)
}
}
newOssBattleRecord(tmpUserInfo, ossBattleType, !isWin, 0, ossFiledType, targetType,
actionDataAsset.Actiondata.GetEndTileID(), v.GetHeroListReport(), v.GetUnitListReport())
for _, u := range v.GetUnitListReport() {
newOssUnitChange(tmpUserInfo, uint32(unitChannel), u.GetUnitID(), int32(u.GetDeath()), int32(u.GetInjured()))
}
}
//送攻击方的邮件
atkBattleReport := proto.Clone(battleReport).(*proto.ST_BattleReport_PB)
atkBattleReport.IsWin = proto.SetBool(isWin)
//单人小怪、多人召唤怪不论输赢,永远有邮件,但是没战斗回放
if false == hasMailReport && targetType != targetMonsterEx && targetType != targetSummonMutiMonster {
atkBattleReport = &proto.ST_BattleReport_PB{
IsWin: proto.SetBool(isWin),
}
battleInfo = nil
atkBattleNotice.IsHaveBattleInfo = proto.SetBool(false)
// 暂时添加为测试英雄技能
//atkBattleNotice.IsHaveBattleInfo = proto.SetBool(true)
}
monRes := 1
if !isWin {
monRes = 0
}
if targetType == targetMainCity && battleInfo.GetIsAtkWin() {
attUser.UpdateFeedback(true, uint32(0), uint32(0))
}
for _, v := range battleReport.AtkInfo {
tmpUserInfo := cache.GetCharinfo(v.CommanderReport.GetUid())
if tmpUserInfo == nil {
continue
}
cache.Instance_BattleInfoListCache.AddBattleInfo(SFUID, &strInfo)
_, mailid := tmpUserInfo.AddLanguageIDMailAsset(mailType, 0, worldAssetData.GetWorldDataTileID(), int32(proto.MailSourceType_MST_Default), atkTitleTips, atkMutiMonsterContent,
string(proto.Marshal(atkBattleReport)), strSFUID)
atkBattleNotice.MailID = proto.SetUint64(mailid)
if true == tmpUserInfo.IsRealOnline() {
tmpUserInfo.CreateBattleNotice(SFUID, atkBattleNotice)
}
newOssBattleRecord(tmpUserInfo, ossBattleType, isWin, 0, ossFiledType, targetType,
actionDataAsset.Actiondata.GetEndTileID(), v.GetHeroListReport(), v.GetUnitListReport())
for _, u := range v.GetUnitListReport() {
newOssUnitChange(tmpUserInfo, uint32(unitChannel), u.GetUnitID(), int32(u.GetDeath()), int32(u.GetInjured()))
}
if targetType == targetMutiMonster || targetType == targetMonsterEx || targetType == targetSummonMutiMonster {
ossMultiMonsterBattle(tmpUserInfo, worldAssetData, monRes, v.GetHeroListReport(), v.GetUnitListReport(), award, attUser.GetUid(), atkUsers, targetType)
}
}
//清除体力返还(主要针对集结怪)
if battleRlt != battleRlt_Error && actionDataEntry.GetCostSta() > 0 {
actionDataEntry.CostSta = proto.SetUint64(0)
for _, v := range actionDataEntry.GetChildrenID() {
tmpactiondata := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(v)
if tmpactiondata != nil && tmpactiondata.Actiondata.GetCostSta() > 0 {
tmpactiondata.Actiondata.CostSta = proto.SetUint64(0)
}
}
}
// 增加战斗日志
if attUser != nil && defUser != nil {
if attUser.GetLeagueID() != 0 || defUser.GetLeagueID() != 0 {
logEntry := createLeagueBattleLog(attUser, defUser, isWin, isMultiuserAtk)
if attUser.GetLeagueID() != 0 {
if cache.InstanceGlobalAssetLeagueBattleLog.AddLeagueBattleLog(attUser.GetLeagueID(), logEntry) {
NotifyLeagueBattleLog(attUser.GetLeagueID())
}
}
if defUser.GetLeagueID() != 0 {
if cache.InstanceGlobalAssetLeagueBattleLog.AddLeagueBattleLog(defUser.GetLeagueID(), proto.Clone(logEntry).(*proto.ST_LeagueBattle_Log_Entry)) {
NotifyLeagueBattleLog(defUser.GetLeagueID())
}
}
}
}
}
func NotifyLeagueBattleLog(lid uint64) {
memberIds := cache.Instance_GlobalAssetLeague.GetLeagueMemberIds(lid)
for _, id := range memberIds {
if cache.Sessionkey.IsRealOnline(id) {
userData := cache.GetCharinfo(id)
if userData != nil {
userData.AddLeagueBattleLogCount()
}
}
}
}
func createLeagueBattleLog(atkUser, defUser *cache.Info, isWid, isMulti bool) *proto.ST_LeagueBattle_Log_Entry {
atkInfo := &proto.ST_LeagueBattle_User{
Lid: proto.SetUint64(atkUser.GetLeagueID()),
UserName: proto.SetString(atkUser.GetUserName()),
Avatar: proto.SetString(atkUser.GetAvatar()),
AvatarBoxID: proto.SetUint32(atkUser.GetAvatarBoxId()),
AvatarID: proto.SetString(atkUser.GetLordIcon()),
LeagueShortName: proto.SetString(atkUser.GetLeagueShortName()),
Uid: proto.SetUint64(atkUser.GetUid()),
}
defInfo := &proto.ST_LeagueBattle_User{
Lid: proto.SetUint64(defUser.GetLeagueID()),
UserName: proto.SetString(defUser.GetUserName()),
Avatar: proto.SetString(defUser.GetAvatar()),
AvatarBoxID: proto.SetUint32(defUser.GetAvatarBoxId()),
AvatarID: proto.SetString(defUser.GetLordIcon()),
LeagueShortName: proto.SetString(defUser.GetLeagueShortName()),
Uid: proto.SetUint64(defUser.GetUid()),
}
logEntry := &proto.ST_LeagueBattle_Log_Entry{
Attacker: atkInfo,
Defer: defInfo,
IsMulti: proto.SetBool(isMulti),
IsWin: proto.SetBool(isWid),
Times: proto.SetInt32(1),
Timestamp: proto.SetUint64(wtime.GetNow()),
}
return logEntry
}
func getBigBrother(battleReport []*proto.ST_BattleReportDetail_PB) *proto.ST_BattleReportDetail_PB {
for _, v := range battleReport {
if v.GetIsBigBrother() {
return v
}
}
return nil
}
/**
@brief 处理资源矿和主城战的资源掠夺逻辑
*/
func genGrabResource(attUserData, defUserData *cache.Info, units *proto.ST_UnitAsset_PB,
actionUnitMap map[uint64]*proto.ST_UnitAsset_PB, win bool, targetType uint32, heroid []uint32, wdataid uint64) (*proto.ST_CashAsset_PB, map[uint64]*proto.ST_CashAsset_PB) {
mapresource := make(map[uint64]*proto.ST_CashAsset_PB)
resource := common.NewCashAsset()
if !win {
return resource, mapresource
}
if defUserData == nil {
return resource, mapresource
}
var c1, c2, c3, c4, c5, c100 uint64
switch targetType {
case targetMainCity:
c1, c2, c3, c4, c5 = getCanLostResource(defUserData)
case targetMine, targetMineGem:
c1, c2, c3, c4, c5, c100 = getCanGrabResourceOnMine(wdataid)
default:
return resource, mapresource
}
weight := getWeightByUnitAsset(attUserData, heroid, units)
if weight == 0 {
return resource, mapresource
}
tmpcashAsset := &proto.ST_CashAsset_PB{
Cash1: proto.SetUint64(c1),
Cash2: proto.SetUint64(c2),
Cash3: proto.SetUint64(c3),
Cash4: proto.SetUint64(c4),
Cash5: proto.SetUint64(c5),
Cash100: proto.SetUint64(c100),
}
totalcanlost := countCashWeightByNum(tmpcashAsset)
if totalcanlost <= 0 {
totalcanlost = 1
}
var robCash1, robCash2, robCash3, robCash4, robCash5, robCash100 uint64 = 0, 0, 0, 0, 0, 0
if weight < totalcanlost {
robCash1 = c1 * weight / totalcanlost
robCash2 = c2 * weight / totalcanlost
robCash3 = c3 * weight / totalcanlost
robCash4 = c4 * weight / totalcanlost
robCash5 = c5 * weight / totalcanlost
robCash100 = c100 * weight / totalcanlost
} else {
robCash1 = c1
robCash2 = c2
robCash3 = c3
robCash4 = c4
robCash5 = c5
robCash100 = c100
}
resource.Cash1 = proto.SetUint64(robCash1)
resource.Cash2 = proto.SetUint64(robCash2)
resource.Cash3 = proto.SetUint64(robCash3)
resource.Cash4 = proto.SetUint64(robCash4)
resource.Cash5 = proto.SetUint64(robCash5)
resource.Cash100 = proto.SetUint64(robCash100)
if targetType == targetMainCity {
defUserData.ReduceCashAsset(resource, oss.ReduceCashScrTypePVPGrab)
}
for k, v := range actionUnitMap {
actionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(k)
if actionData == nil {
continue
}
tmpUserData := cache.GetCharinfo(actionData.Actiondata.GetUid())
if tmpUserData == nil {
continue
}
tmpWeight := getWeightByUnitAsset(tmpUserData, actionData.Actiondata.GetHeroIDList(), v)
tmpresource := &proto.ST_CashAsset_PB{
Cash100: proto.SetUint64(robCash100 * tmpWeight / weight),
Cash1: proto.SetUint64(robCash1 * tmpWeight / weight),
Cash2: proto.SetUint64(robCash2 * tmpWeight / weight),
Cash3: proto.SetUint64(robCash3 * tmpWeight / weight),
Cash4: proto.SetUint64(robCash4 * tmpWeight / weight),
Cash5: proto.SetUint64(robCash5 * tmpWeight / weight),
}
mapresource[k] = tmpresource
actionData.SetAppedData(encodeActionAppendData(actionData.Actiondata.GetAppenddata(), "resource", string(proto.Marshal(tmpresource))))
}
return resource, mapresource
}
/**
@brief 处理玩家统计信息
*/
func processStatisticsAsset(isWin bool, targetType uint32, atkUser, defUser *cache.Info, isCapCommander bool, battleReport []*proto.ST_BattleReportDetail_PB, isAtk bool, pvp bool) (
uint64, map[uint64]*proto.ST_UnitAsset_PB) {
if targetType == targetMonster ||
targetType == targetMutiMonster ||
targetType == targetSummonMutiMonster ||
targetType == targetMonsterEx {
return 0, nil
}
if isAtk && atkUser == nil {
return 0, nil
}
commanderExpParm := common.ParseStringToUint32List(
CSV.GetGameConfigValueString("COMMANDER_EXP_PARM"))
heroExpParm := common.ParseStringToUint32List(
CSV.GetGameConfigValueString("HERO_EXP_PARM"))
killsInfo := make(map[uint64]*proto.ST_UnitAsset_PB, 2)
WarCityKill := uint64(0)
for k, v := range battleReport {
if v.GetCommanderReport() == nil {
continue
}
tmpUser := cache.GetCharinfo(v.GetCommanderReport().GetUid())
if nil == tmpUser {
continue
}
attUserStatisticsAsset := tmpUser.GetStatisticsInnerAsset()
if k == 0 {
if targetType == targetMainCity ||
targetType == targetRayolCity ||
targetType == targetLeagueCenter ||
targetType == targetWarCity {
if isWin {
if isAtk {
attUserStatisticsAsset.UpdateAttackWin(1)
} else {
attUserStatisticsAsset.UpdateDefenceFail(1)
/*if isCapCommander {
attUserStatisticsAsset.UpdateCaptiveTimes()
attUserStatisticsAsset.UpdateArrestHeroNumber(1)
}*/
}
} else {
if isAtk {
attUserStatisticsAsset.UpdateAttackFail(1)
} else {
attUserStatisticsAsset.UpdateDefenceWin(1)
//attUserStatisticsAsset.UpdateEscapeTimes()
}
}
}
}
lostPower, totalKillUnits, heroKillUnits, corpsKillUnits, lostUnits, herokillunitsCnt :=
processUnitListReport(v.GetUnitListReport(), v.GetHeroListReport())
attUserStatisticsAsset.UpdateUnitLoss(lostPower)
if pvp {
attUserStatisticsAsset.UpdateKillUnit(totalKillUnits)
}
attUserStatisticsAsset.UpdateLossUnit(lostUnits)
killsInfo[v.GetActionID()] = totalKillUnits
// 处理跨服决战死兵
processTransferBattleDeathUnit(tmpUser, defUser, v.GetUnitListReport())
//攻击成就
killNum := uint64(0)
unitNumByLv := make(map[uint32]uint32, 0)
unitNumByLv2 := make(map[uint32]uint32, 0)
unitNumByLv3 := make(map[uint32]uint32, 0)
for _, v := range totalKillUnits.GetUnits() {
unitEntry := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.GetUnitid()))
if unitEntry != nil {
unitType := unitEntry.Type
if int64(proto.UnitType_UT_NORMAL_BEGIN) < unitType && int64(proto.UnitType_UT_NORMAL_END) > unitType {
//击杀士兵成就[6501701]
tmpUser.SyncAchievementAdd(cache.LJJSSBEvent, &cache.UInt64Tuple{uint64(unitEntry.UnitLevel), v.GetUnitnum()})
}
unitNumByLv[uint32(unitEntry.UnitLevel)] = unitNumByLv[uint32(unitEntry.UnitLevel)] + uint32(v.GetUnitnum())
}
killNum += v.GetUnitnum()
if pvp {
observer.ObserverSingleton.AsyncNotify(observer.PVPKillEvevt, []interface{}{tmpUser, uint32(unitEntry.UnitLevel), uint32(v.GetUnitnum()), isWin, defUser})
}
}
for _, v := range lostUnits.Units {
unitEntry := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.GetUnitid()))
if unitEntry != nil {
if pvp {
observer.ObserverSingleton.AsyncNotify(observer.PVPBeKilledEvent, []interface{}{tmpUser, uint32(unitEntry.UnitLevel), uint32(v.GetUnitnum()), defUser})
}
}
}
for _, v := range heroKillUnits.GetUnits() {
unitEntry := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.GetUnitid()))
if unitEntry != nil {
unitNumByLv2[uint32(unitEntry.UnitLevel)] = unitNumByLv2[uint32(unitEntry.UnitLevel)] + uint32(v.GetUnitnum())
}
}
for _, v := range corpsKillUnits.GetUnits() {
unitEntry := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.GetUnitid()))
if unitEntry != nil {
unitNumByLv3[uint32(unitEntry.UnitLevel)] = unitNumByLv3[uint32(unitEntry.UnitLevel)] + uint32(v.GetUnitnum())
}
}
commanderExp := uint64(0)
heroExp := uint64(0)
//通过英雄击杀来计算英雄经验
for k, v := range unitNumByLv2 {
num := float64(v)
heroExp += uint64(float64(heroExpParm[k-1]) / 10000 * num)
}
//通过军团击杀来计算指挥官经验
for k, v := range unitNumByLv3 {
num := float64(v)
commanderExp += uint64(float64(commanderExpParm[k-1]) / 10000 * num)
}
v.CommanderReport.AddExp = proto.SetUint64(commanderExp)
atkUser.AddExp(commanderExp)
var heroLevelUp []uint32
for _, heroReport := range v.GetHeroListReport() {
atkUser.WithHeroAsset(true, heroReport.GetId(), func(heroAsset *proto.ST_HeroEntry_PB) bool {
oldLevel := heroReport.GetLevel()
heroID := heroReport.GetId()
flag := false
fixExp := uint64(0)
flag, fixExp = atkUser.CanAddHeroExp(heroID, heroExp)
if flag {
atkUser.AddHeroExp(heroID, fixExp)
heroReport.AddExp = proto.SetUint64(fixExp)
}
if oldLevel != heroAsset.GetLevel() {
heroLevelUp = append(heroLevelUp, heroAsset.GetId())
heroReport.Level = proto.SetUint32(heroAsset.GetLevel())
heroReport.IsLevelUp = proto.SetBool(true)
}
//heroReport.Exp = proto.SetUint64(heroReport.GetExp())
return false
})
}
atkUser.AddLevelUpHeroList(heroLevelUp)
if (isAtk && !isWin) || (!isAtk && isWin) {
defeatRecoup(tmpUser, lostUnits)
}
//通知指挥官杀敌数量更新
if pvp {
observer.ObserverSingleton.AsyncNotify(observer.CommanderKilledUpgradeEvent, []interface{}{tmpUser, killNum})
observer.ObserverSingleton.AsyncNotify(observer.HeroKilledUpgradeEvent, []interface{}{tmpUser, herokillunitsCnt})
}
WarCityKill += killNum
}
return WarCityKill, killsInfo
}
func processTransferBattleDeathUnit(atkUser *cache.Info, defUser *cache.Info, unitReport []*proto.ST_UnitBattleReport_PB) {
if nil == atkUser || defUser == nil {
return
}
atkUser.WithTransferBattleAsset(false, func(asset *proto.ST_Asset_TransferBattle_PB) bool {
if asset.GetStage() == uint32(proto.ActivityStage_AS_ProcessingStage) {
if tbGroupInfo != nil {
if (tbGroupInfo.GetSid1() == defUser.GetSid() && tbGroupInfo.GetSid2() == atkUser.GetSid()) ||
(tbGroupInfo.GetSid1() == atkUser.GetSid() && tbGroupInfo.GetSid2() == defUser.GetSid()) {
deathUnits := &proto.ST_UnitAsset_PB{}
for _, unit := range unitReport {
if unit.GetDeath() > 0 {
deathUnits.Units = append(deathUnits.Units, &proto.ST_Unit_PB{
Unitnum: proto.SetUint64(uint64(unit.GetDeath())),
Unitid: unit.UnitID,
})
}
}
if asset.DeathUnits == nil {
asset.DeathUnits = &proto.ST_UnitAsset_PB{}
}
common.CombineUnitAsset(asset.DeathUnits, deathUnits)
return true
}
}
}
return false
})
}
func processUnitListReport(unitInfs []*proto.ST_UnitBattleReport_PB, heroBattleList []*proto.ST_HeroBattleReport_PB) (
uint64, *proto.ST_UnitAsset_PB, *proto.ST_UnitAsset_PB, *proto.ST_UnitAsset_PB, *proto.ST_UnitAsset_PB, map[uint32]uint64) {
power := uint64(0)
totalKillUnits := &proto.ST_UnitAsset_PB{} //总击杀
heroKillUnits := &proto.ST_UnitAsset_PB{} //英雄击杀
corpsKillUnits := &proto.ST_UnitAsset_PB{} //军团击杀
lostUnits := &proto.ST_UnitAsset_PB{}
heroKillUnitsCnt := make(map[uint32]uint64, 5) //每个英雄击杀士兵数量
//英雄
for _, heroBattle := range heroBattleList {
killUnitAsset := &proto.ST_UnitAsset_PB{}
for _, killUnit := range heroBattle.KillList {
killUnitAsset.Units = append(killUnitAsset.Units, killUnit)
num, ok := heroKillUnitsCnt[heroBattle.GetId()]
if !ok {
heroKillUnitsCnt[heroBattle.GetId()] = uint64(killUnit.GetUnitnum())
} else {
heroKillUnitsCnt[heroBattle.GetId()] = uint64(killUnit.GetUnitnum()) + num
}
}
common.CombineUnitAsset(totalKillUnits, killUnitAsset)
common.CombineUnitAsset(heroKillUnits, killUnitAsset)
}
//战斗单位
for _, v := range unitInfs {
conf := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(v.GetUnitID()))
if conf != nil {
power += uint64(conf.Power * int64(v.GetDeath()+v.GetInjured()))
}
tmpUnit := &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
}
tmpUnit.Units = append(tmpUnit.Units, &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v.GetUnitID()),
Unitnum: proto.SetUint64(uint64(v.GetDeath() + v.GetInjured())),
})
common.CombineUnitAsset(lostUnits, tmpUnit)
common.CombineUnitAsset(totalKillUnits, v.GetKillList())
common.CombineUnitAsset(corpsKillUnits, v.GetKillList())
}
return power, totalKillUnits, heroKillUnits, corpsKillUnits, lostUnits, heroKillUnitsCnt
}
/**
@brief 战败补充
*/
func defeatRecoup(userData *cache.Info, lostUnits *proto.ST_UnitAsset_PB) {
trueLost := uint64(0)
rewList := &proto.ST_CashAsset_PB{}
for _, v := range CSV.Mgr.CSV_DefeatRecoup.GetIDList() {
csvRecoup := CSV.Mgr.CSV_DefeatRecoup.GetEntryPtr(v)
if csvRecoup == nil {
continue
}
lostNum := uint64(0)
cashCost := &proto.ST_CashAsset_PB{}
recoupNeed := common.ParseStringToInt64List(csvRecoup.RewLimit)
for _, unit := range lostUnits.GetUnits() {
csvUnit := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unit.GetUnitid()))
if csvUnit == nil {
continue
}
if csvUnit.Quality != recoupNeed[0] {
continue
}
lostNum += unit.GetUnitnum()
cost := common.ParseVector4ToCashAsset(common.ParseStringToVector4(csvUnit.AssetsRequire))
common.MultiResourceAsset(cost, float64(lostNum))
common.CombineResourceAsset(cashCost, cost)
}
if lostNum < uint64(recoupNeed[1]) {
continue
}
trueLost += lostNum
common.MultiResourceAsset(cashCost, float64(csvRecoup.Recoup)/100.0)
common.CombineResourceAsset(rewList, cashCost)
}
if trueLost <= 0 {
return
}
titleTips := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())}
contentTips := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())}
titleTips.LanguageID = proto.SetUint32(CSV.GetGameConfigValueUint32("DefeatRecoupText"))
contentTips.LanguageID = proto.SetUint32(CSV.GetGameConfigParamUint32("DefeatRecoupText"))
userData.AddDefeatRecoupMailAsset(uint32(proto.MailType_MT_SYSTEM), titleTips, contentTips, rewList)
}
/**
@brief 从战报中获取战斗双方的GlobalActionMap
*/
func getActionUnitMapByBattleReport(battleReport *proto.ST_BattleReport_PB) (map[uint64]*proto.ST_UnitAsset_PB, map[uint64]*proto.ST_UnitAsset_PB, *proto.ST_UnitAsset_PB) {
attUnitMap := make(map[uint64]*proto.ST_UnitAsset_PB)
defUnitMap := make(map[uint64]*proto.ST_UnitAsset_PB)
attRemainUnit := &proto.ST_UnitAsset_PB{}
if battleReport == nil {
wlog.Info("getActionUnitMapByBattleReport battleReport nil")
return attUnitMap, defUnitMap, attRemainUnit
}
for _, v := range battleReport.GetAtkInfo() {
units := &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
}
for _, v1 := range v.GetUnitListReport() {
newUnit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v1.GetUnitID()),
Unitnum: proto.SetUint64(uint64(v1.GetSurvival())),
}
units.Units = common.CombineUnit(units.Units, newUnit)
}
attUnitMap[uint64(v.GetActionID())] = units
common.CombineUnitAsset(attRemainUnit, units)
}
for _, v := range battleReport.GetDefInfo() {
units := &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
}
for _, v1 := range v.GetUnitListReport() {
newUnit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(v1.GetUnitID()),
Unitnum: proto.SetUint64(uint64(v1.GetSurvival())),
}
units.Units = common.CombineUnit(units.Units, newUnit)
if v.GetActionID() == 0 && v.GetCommanderReport() != nil {
tmpUser := cache.GetCharinfo(v.GetCommanderReport().GetUid())
if tmpUser != nil {
tmpUser.DeleteUnitAsset(v1.GetUnitID(), uint64(v1.GetJoin()))
}
}
}
defUnitMap[uint64(v.GetActionID())] = units
}
return attUnitMap, defUnitMap, attRemainUnit
}
/**
@brief 处理战斗后的GlobalAction
*/
func processGlobalActionAfterBattle(actionUintMap map[uint64]*proto.ST_UnitAsset_PB, wdata *cache.WorldDataEntry,
targetType uint32, userData *cache.Info, actionType uint32, returnUnitsList []*proto.ST_ReturnUnits_PB, win bool, isAtt bool) {
x, y, _ := common.ConvertIdToCoordinate(wdata.GetWorldData().SimpleEntry.GetTileId())
cid, _ := GetWarCityFromPos(x, y)
if !isAtt && win && wdata != nil {
// 防守失败
if targetType == targetRayolCity || cid != 0 {
actionIds := wdata.CopyGActionList()
if len(actionIds) > 0 {
actionAsset := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionIds[0])
if actionAsset != nil {
recvActionIds := actionAsset.Actiondata.GetRecvActionIDList()
//获取出针对次地块的攻击、侦察、集结、援助行为
//然后从撤军的玩家的预警雷达中删除
for _, recvActionId := range recvActionIds {
otherActionAsset := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(recvActionId)
if nil == otherActionAsset {
continue
}
actionType = otherActionAsset.Actiondata.GetActiontype()
if actionType == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) ||
actionType == uint32(proto.ActionType_AT_WORLDMAP_SPYINTO) ||
actionType == uint32(proto.ActionType_AT_WORLDMAP_MASS) ||
actionType == uint32(proto.ActionType_AT_WORLDMAP_GARRISON) {
deleteRadar(otherActionAsset.Actiondata)
}
}
}
}
}
}
for k, v := range actionUintMap {
if k == 0 {
if targetType == targetMainCity && !isAtt {
userData.AddUnitAssets(v)
userData.CalcPower()
}
continue
}
actionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(k)
if actionData == nil {
continue
}
userData := cache.GetCharinfo(actionData.Actiondata.GetUid())
if userData == nil {
continue
}
//进攻方返还多人战斗中死亡的兵力
if (targetType == targetMutiMonster || targetType == targetMonsterEx || targetType == targetSummonMutiMonster) && isAtt && nil != returnUnitsList {
for _, returnUnitInfo := range returnUnitsList {
if k != returnUnitInfo.GetActionID() {
continue
}
common.CombineUnitAsset(v, returnUnitInfo.ReturnUnitInfo)
returnUnitInfo.ReturnUnitInfo = &proto.ST_UnitAsset_PB{}
}
}
//deleteRadar(actionData.Actiondata)
if countUnitNum(v) <= 0 {
for _, herid := range actionData.Actiondata.GetHeroIDList() {
setHeroStatus(userData, herid, proto.HeroStatus_HS_NORMAL)
}
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_GARRISON) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_COLLECT) {
RadarCheckOtherGAction(actionData, true)
cache.Instance_GlobalAssetGlobalAction.DeleteGlobalAction(k)
wdata.UnBindGlobalActionId(actionData.Actiondata.GetActionid())
userData.RemoveGlobalActionID(actionData.Actiondata.GetActionid())
} else if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_BESTATIONED) {
RadarCheckOtherGAction(actionData, true)
cache.Instance_GlobalAssetGlobalAction.DeleteGlobalAction(k)
userData.RemoveGlobalActionID(actionData.Actiondata.GetActionid())
} else {
actionData.UpdateUnitAsset(v)
}
} else {
actionData.UpdateUnitAsset(v)
switch targetType {
case targetWarCity:
if isAtt {
// 进攻方胜利
if win {
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MASS) {
convertActionToGarrison(actionData, wdata)
processCityWarAsset(actionData)
}
}
}
case targetLeagueCenter:
if isAtt {
// 进攻方胜利
if win {
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MASS) {
GarrisonToLeagueCenter(actionData, wdata)
wdata.UpdateOwner(userData.GetLeagueID(), userData.GetUid())
TimeLeagueCenter(wdata) //驻扎后开始计算时间
}
}
}
case targetRayolCity:
if isAtt {
// 进攻方胜利
if win {
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) ||
actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MASS) {
convertActionToGarrison(actionData, wdata)
cityAsset := wdata.GetWorldData().DetailEntry.GetDetail_City()
if cityAsset != nil {
cityAsset.NpcUnits = &proto.ST_UnitAsset_PB{}
wdata.Dirty()
}
}
}
}
case targetBestationed:
if isAtt {
// 进攻方胜利
if win {
if actionData.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_ATTCK) {
garrisonToCityWarBestationed(actionData) //攻击水泥地后驻扎
}
}
}
case targetMine, targetMineGem:
if !isAtt {
// 采集防守失败
if win {
actionData.UpdateStage(wtime.GetNow(), actionData.Actiondata.GetTotaltime(), uint32(proto.MapStageType_MST_BACK))
wdata.UnBindGlobalActionId(k)
}
}
default:
}
}
userData.CalcPower()
}
if !isAtt && win && wdata != nil {
// 防守失败
defenderFailed(targetType, cid, wdata)
}
}
//进攻方和防守方都死完了,判定为防守防胜,由于防守方没有兵了,要自动撤军
func checkAtkDefAllDieout(atk, def map[uint64]*proto.ST_UnitAsset_PB, targetType uint32, wdata *cache.WorldDataEntry) {
for _, v := range atk {
for _, unit := range v.Units {
if unit.GetUnitnum() > 0 {
return
}
}
}
for _, v := range def {
for _, unit := range v.Units {
if unit.GetUnitnum() > 0 {
return
}
}
}
if wdata != nil {
x, y, _ := common.ConvertIdToCoordinate(wdata.GetWorldData().SimpleEntry.GetTileId())
cid, _ := GetWarCityFromPos(x, y)
defenderFailed(targetType, cid, wdata)
}
}
func defenderFailed(targetType, cid uint32, wdata *cache.WorldDataEntry) {
if targetType == targetRayolCity || targetType == targetLeagueCenter || targetType == targetBestationed || cid != 0 {
//CountLeagueCenter(wdata) //返回前计算
actionIds := wdata.CopyGActionList()
if len(actionIds) > 0 {
for _, v := range actionIds {
recallArmy(v, false)
}
}
}
if targetType == targetMine && len(wdata.GetGActionList()) == 0 {
wdata.UpdateOwner(0, 0)
}
if targetType == targetBestationed {
cache.Instance_GlobalAssetWorldData.DeleteDataEntry(wdata.GetWorldDataID(), false)
}
}
/**
@brief 生成英雄报告
*/
func createHeroReport(userInfo *cache.Info, heroID uint32, battleInfo *proto.ST_BattleInfo_PB, isAtk bool) (bool, *proto.ST_HeroBattleReport_PB) {
report := &proto.ST_HeroBattleReport_PB{}
if nil == userInfo || uint32(0) == heroID || nil == battleInfo {
return false, report
}
userInfo.WithHeroAsset(true, heroID, func(heroAsset *proto.ST_HeroEntry_PB) bool {
report.Id = proto.SetUint32(heroAsset.GetId())
report.Level = proto.SetUint32(heroAsset.GetLevel())
report.Star = proto.SetUint32(heroAsset.GetStar())
report.Power = proto.SetUint64(heroAsset.GetPower())
report.IsLevelUp = proto.SetBool(false)
report.SkillList = make([]*proto.ST_HeroSkill_PB, 0)
for _, v := range heroAsset.GetSkillList() {
skill := &proto.ST_HeroSkill_PB{
SkillLogicType: proto.SetUint32(v.GetSkillLogicType()),
SkillID: proto.SetUint32(v.GetSkillID()),
}
report.SkillList = append(report.SkillList, skill)
}
report.BranchValue = make([]uint32, 0)
for _, v := range heroAsset.GetBranchValue() {
report.BranchValue = append(report.BranchValue, v)
}
for _, v := range battleInfo.RoundInfo {
var roundInfo *proto.ST_RoundBaseInfo_PB
if isAtk {
roundInfo = v.AtkRoundInfo
} else {
roundInfo = v.DefRoundInfo
}
for _, heroBattleInfo := range roundInfo.HeroList {
if heroBattleInfo.GetHeroID() != heroID {
continue
}
//计算技能释放次数
if heroBattleInfo.GetUseOrder() != 0 {
report.UseSkillTimes = proto.SetUint32(report.GetUseSkillTimes() + 1)
}
//击杀单位数量
report.DestoryUnitCount = proto.SetUint64(report.GetDestoryUnitCount() + countUnitsNumFromList(heroBattleInfo.KillList))
//治疗单位数量
report.RecoveryUnitCount = proto.SetUint64(report.GetRecoveryUnitCount() + countUnitsNumFromList(heroBattleInfo.RecoveryList))
for _, killUnit := range heroBattleInfo.KillList {
tmpUnit := proto.Clone(killUnit).(*proto.ST_Unit_PB)
report.KillList = append(report.KillList, tmpUnit)
}
}
}
return false
})
return true, report
}
/**
@brief 生成战斗报告详细数据
*/
func createReportDetail(targetType uint32, worldAssetData *cache.WorldDataEntry, battleInfo *proto.ST_BattleInfo_PB,
orgiUnitAssetMap map[uint64]*stUserUnitInfo, unitBattleInfoMap map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB, isAtk bool) ([]*proto.ST_BattleReportDetail_PB, *proto.ST_PowerReport_PB) {
if nil == battleInfo || nil == orgiUnitAssetMap {
return nil, nil
}
totalLossPower := int64(0)
totalStartPower := int64(0)
reportDetailList := make([]*proto.ST_BattleReportDetail_PB, 0)
powerReport := &proto.ST_PowerReport_PB{}
for actionID, userUnitInfo := range orgiUnitAssetMap {
var actionAsset *cache.GlobalActionEntry
if 0 == actionID {
//玩家主城的拥有者
} else {
actionAsset = cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionID)
}
var userInfo *cache.Info
if actionAsset != nil && actionAsset.Actiondata != nil {
userInfo = cache.GetCharinfo(actionAsset.Actiondata.GetUid())
} else if nil != worldAssetData {
userInfo = cache.GetCharinfo(worldAssetData.GetWorldDataOwner())
}
if actionAsset != nil && actionAsset.Actiondata.GetMacMonsterId() > 0 && userInfo == nil {
userInfo = cache.GetCharinfo(worldAssetData.GetWorldDataOwner())
}
battleReportDetail := &proto.ST_BattleReportDetail_PB{
IsBigBrother: proto.SetBool(userUnitInfo.isBigBrother),
ActionID: proto.SetUint64(actionID),
}
battleReportDetail.CommanderReport = &proto.ST_BattleCommanderSimpleInfo_PB{}
if nil != userInfo {
if userInfo.GetCommanderStatus() == uint32(proto.HeroStatus_HS_IMPRISONED) {
battleReportDetail.IsArrest = proto.SetBool(true)
}
//指挥官信息
battleReportDetail.CommanderReport.Uid = proto.SetUint64(userInfo.GetUid())
battleReportDetail.CommanderReport.Name = proto.SetString(userInfo.GetUserName())
battleReportDetail.CommanderReport.LeagueName = proto.SetString(userInfo.GetLeagueName())
//英雄
if actionAsset != nil && actionAsset.Actiondata != nil {
for _, heroID := range actionAsset.Actiondata.HeroIDList {
if ok, heroBattleReport := createHeroReport(userInfo, heroID, battleInfo, isAtk); ok {
battleReportDetail.HeroListReport = append(battleReportDetail.HeroListReport, heroBattleReport)
}
}
} else {
//守城英雄ID
userInfo.ForeachHero(true, func(heroAsset *proto.ST_HeroEntry_PB) bool {
if heroAsset == nil {
return false
}
if heroAsset.GetHeroStatus() == uint32(proto.HeroStatus_HS_DEFENSE) {
if ok, heroBattleReport := createHeroReport(userInfo, heroAsset.GetId(), battleInfo, isAtk); ok {
battleReportDetail.HeroListReport = append(battleReportDetail.HeroListReport, heroBattleReport)
}
}
return true
})
}
//天赋
battleReportDetail.NaturalGift = make([]uint32, 0)
userInfo.ForeachTalentAsset(true, func(rid uint32) bool {
if conf := CSV.Mgr.CSV_Talent.GetEntryPtr(int64(rid)); conf != nil {
if conf.TalentType == 1 {
battleReportDetail.NaturalGift = append(battleReportDetail.NaturalGift, rid)
}
}
return true
})
//科技等级
battleReportDetail.TechnologyLevel = make([]uint32, 0)
techAsset := userInfo.GetResearchAsset()
if techAsset != nil {
for _, v := range techAsset.GetEntryList() {
battleReportDetail.TechnologyLevel = append(battleReportDetail.TechnologyLevel, v.GetRID())
}
}
//雕像
battleReportDetail.Statue = make([]*proto.ST_Simple_Statue, 0)
statueAsset := userInfo.GetStatueAsset()
if statueAsset != nil {
for _, v := range statueAsset.AssetData.StatueList {
tmpMap := common.StatueFuncArrayToMap(v.GetFuncKeyArr(), v.GetFuncValueArr())
for k2, v2 := range tmpMap {
tmpData := &proto.ST_Simple_Statue{}
tmpData.EffectType = proto.SetString(k2)
tmpData.EffectValue = proto.SetUint32(v2)
battleReportDetail.Statue = append(battleReportDetail.Statue, tmpData)
}
}
}
//装备
battleReportDetail.EquipList = make([]uint32, 0)
userInfo.WithCommanderEquipAsset(true, func(asset *cache.Asset_CommanderEquip) {
for _, v := range asset.AssetData_WearEquip {
battleReportDetail.EquipList = append(battleReportDetail.EquipList, v.GetCsvid())
}
})
if actionAsset != nil && actionAsset.Actiondata != nil {
battleReportDetail.CommanderReport.TileID = proto.SetUint32(uint32(actionAsset.Actiondata.GetStartTileID()))
} else {
battleReportDetail.CommanderReport.TileID = proto.SetUint32(uint32(worldAssetData.GetWorldDataTileID()))
}
} else if false == isAtk &&
(targetType == uint32(targetMutiMonster) || targetType == uint32(targetCity) || targetType == uint32(targetRayolCity) || targetType == uint32(targetLeagueCenter) || targetType == uint32(targetWarCity)) {
//把多人野怪的坐标记录到指挥官信息里
battleReportDetail.CommanderReport = &proto.ST_BattleCommanderSimpleInfo_PB{}
battleReportDetail.CommanderReport.TileID = proto.SetUint32(uint32(worldAssetData.GetWorldDataTileID()))
}
if isAtk && actionAsset != nil && actionAsset.Actiondata.GetMacMonsterId() > 0 {
battleReportDetail.CommanderReport.TileID = proto.SetUint32(uint32(actionAsset.Actiondata.GetStartTileID()))
}
//战斗力
battleReportDetail.TotalPower = proto.SetInt64(userUnitInfo.totalPower)
totalStartPower += userUnitInfo.totalPower
//战斗单位
powerlost := int64(0)
if unitBattleInfoMap, ok := unitBattleInfoMap[actionID]; ok {
for _, unitList := range userUnitInfo.unitMap {
for _, unit := range unitList {
report := &proto.ST_UnitBattleReport_PB{}
report.UnitID = proto.SetUint32(unit.unit.GetUnitid())
report.Join = proto.SetUint32(uint32(unit.unit.GetUnitnum()))
report.Survival = proto.SetUint32(report.GetJoin())
if v, ok := unitBattleInfoMap[report.GetUnitID()]; ok {
report.Survival = proto.SetUint32(v.GetSurvival())
report.Injured = proto.SetUint32(v.GetInjured())
report.Death = proto.SetUint32(v.GetDeath())
report.Kill = proto.SetUint32(v.GetKill())
report.KillList = &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, len(v.KillList.Units)),
}
copy(report.KillList.Units, v.KillList.GetUnits())
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(report.GetUnitID()))
if nil != unitCSV {
powerlost += unitCSV.Power * int64(report.GetJoin()-report.GetSurvival())
}
}
battleReportDetail.UnitListReport = append(battleReportDetail.UnitListReport, report)
}
}
}
totalLossPower += powerlost
//城墙
battleReportDetail.WallReport = &proto.ST_WallReport_PB{
BeforeHp: proto.SetUint32(0),
AfterHp: proto.SetUint32(0),
Level: proto.SetUint32(0),
}
battleReportDetail.MutirMonReward = make([]*proto.ST_ItemEntry_PB, 0)
roundNum := len(battleInfo.RoundInfo)
if 0 != roundNum {
defRoundBaseInfo := battleInfo.RoundInfo[roundNum-1].DefRoundInfo
if nil != defRoundBaseInfo.WallHp {
battleReportDetail.WallReport.BeforeHp = proto.SetUint32(defRoundBaseInfo.WallHp.GetBeforeHp())
battleReportDetail.WallReport.AfterHp = proto.SetUint32(defRoundBaseInfo.WallHp.GetAfterHp())
battleReportDetail.WallReport.Level = proto.SetUint32(battleInfo.DefSimpleStartInfo.GetWallLevel())
}
}
reportDetailList = append(reportDetailList, battleReportDetail)
lossCount := uint32(0)
for _, v := range battleReportDetail.UnitListReport {
tmpCount := v.GetJoin() - v.GetSurvival()
lossCount += tmpCount
}
CheckAllGiftSaleCondition(userInfo, proto.GiftConditionType_GCT_LOSS_COUNT, int64(lossCount))
CheckAllGiftSaleCondition(userInfo, proto.GiftConditionType_GCT_POWER_LOSE, int64(powerlost))
}
powerReport.LossValue = proto.SetInt64(totalLossPower)
powerReport.LossRatio = proto.SetFloat32(float32(totalLossPower) / float32(totalStartPower))
powerReport.AllPower = proto.SetInt64(totalStartPower)
return reportDetailList, powerReport
}
/**
@brief 生成集结怪/单人小怪/集结召唤怪的战斗报告详细数据
*/
func createMutiMonsterReportDetail(monsterBaseData *stBattleActionBaseData, worldAssetData *cache.WorldDataEntry, battleInfo *proto.ST_BattleInfo_PB,
orgiUnitAssetMap map[uint64]*stUserUnitInfo, unitBattleInfoMap map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB) ([]*proto.ST_BattleReportDetail_PB, *proto.ST_PowerReport_PB) {
if nil == monsterBaseData || nil == battleInfo || nil == orgiUnitAssetMap {
return nil, nil
}
totalLossPower := int64(0)
totalStartPower := int64(0)
reportDetailList := make([]*proto.ST_BattleReportDetail_PB, 0)
powerReport := &proto.ST_PowerReport_PB{}
for actionID, userUnitInfo := range orgiUnitAssetMap {
battleReportDetail := &proto.ST_BattleReportDetail_PB{
IsBigBrother: proto.SetBool(true),
ActionID: proto.SetUint64(0),
}
battleReportDetail.CommanderReport = &proto.ST_BattleCommanderSimpleInfo_PB{}
if 0 == len(monsterBaseData.heroList) {
report := &proto.ST_HeroBattleReport_PB{
SkillList: make([]*proto.ST_HeroSkill_PB, 0),
BranchValue: make([]uint32, 0),
KillList: make([]*proto.ST_Unit_PB, 0),
}
battleReportDetail.HeroListReport = append(battleReportDetail.HeroListReport, report)
} else {
for _, k := range monsterBaseData.heroList {
heroID := k.heroID
report := &proto.ST_HeroBattleReport_PB{}
report.Id = proto.SetUint32(heroID)
report.Level = proto.SetUint32(k.level)
for _, v := range battleInfo.RoundInfo {
var roundInfo *proto.ST_RoundBaseInfo_PB
roundInfo = v.DefRoundInfo
for _, heroBattleInfo := range roundInfo.HeroList {
if heroBattleInfo.GetHeroID() != heroID {
continue
}
//计算技能释放次数
if heroBattleInfo.GetUseOrder() != 0 {
report.UseSkillTimes = proto.SetUint32(report.GetUseSkillTimes() + 1)
}
//击杀单位数量
report.DestoryUnitCount = proto.SetUint64(report.GetDestoryUnitCount() + countUnitsNumFromList(heroBattleInfo.KillList))
//治疗单位数量
report.RecoveryUnitCount = proto.SetUint64(report.GetRecoveryUnitCount() + countUnitsNumFromList(heroBattleInfo.RecoveryList))
for _, killUnit := range heroBattleInfo.KillList {
tmpUnit := proto.Clone(killUnit).(*proto.ST_Unit_PB)
report.KillList = append(report.KillList, tmpUnit)
}
}
}
battleReportDetail.HeroListReport = append(battleReportDetail.HeroListReport, report)
}
}
battleReportDetail.CommanderReport.TileID = proto.SetUint32(uint32(worldAssetData.GetWorldDataTileID()))
//战斗力
battleReportDetail.TotalPower = proto.SetInt64(userUnitInfo.totalPower)
totalStartPower += userUnitInfo.totalPower
//战斗单位
if unitBattleInfoMap, ok := unitBattleInfoMap[actionID]; ok {
for _, unitList := range userUnitInfo.unitMap {
for _, unit := range unitList {
report := &proto.ST_UnitBattleReport_PB{}
report.UnitID = proto.SetUint32(unit.unit.GetUnitid())
report.Join = proto.SetUint32(uint32(unit.unit.GetUnitnum()))
report.Survival = proto.SetUint32(report.GetJoin())
if v, ok := unitBattleInfoMap[report.GetUnitID()]; ok {
report.Survival = proto.SetUint32(v.GetSurvival())
report.Injured = proto.SetUint32(v.GetInjured())
report.Death = proto.SetUint32(v.GetDeath())
report.Kill = proto.SetUint32(v.GetKill())
report.KillList = &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, len(v.KillList.Units)),
}
copy(report.KillList.Units, v.KillList.GetUnits())
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(report.GetUnitID()))
if nil != unitCSV {
totalLossPower += unitCSV.Power * int64(report.GetJoin()-report.GetSurvival())
}
}
battleReportDetail.UnitListReport = append(battleReportDetail.UnitListReport, report)
}
}
}
//城墙
battleReportDetail.WallReport = &proto.ST_WallReport_PB{
BeforeHp: proto.SetUint32(0),
AfterHp: proto.SetUint32(0),
Level: proto.SetUint32(0),
}
battleReportDetail.MutirMonReward = make([]*proto.ST_ItemEntry_PB, 0)
roundNum := len(battleInfo.RoundInfo)
if 0 != roundNum {
defRoundBaseInfo := battleInfo.RoundInfo[roundNum-1].DefRoundInfo
if nil != defRoundBaseInfo.WallHp {
battleReportDetail.WallReport.BeforeHp = proto.SetUint32(defRoundBaseInfo.WallHp.GetBeforeHp())
battleReportDetail.WallReport.AfterHp = proto.SetUint32(defRoundBaseInfo.WallHp.GetAfterHp())
battleReportDetail.WallReport.Level = proto.SetUint32(1)
}
}
reportDetailList = append(reportDetailList, battleReportDetail)
lossCount := uint32(0)
for _, v := range battleReportDetail.UnitListReport {
tmpCount := v.GetJoin() - v.GetSurvival()
lossCount += tmpCount
}
}
powerReport.LossValue = proto.SetInt64(totalLossPower)
powerReport.LossRatio = proto.SetFloat32(float32(totalLossPower) / float32(totalStartPower))
powerReport.AllPower = proto.SetInt64(totalStartPower)
//wlog.Error("LossValue...AllPower...LossRatio", totalLossPower, totalStartPower, powerReport.GetLossRatio())
return reportDetailList, powerReport
}
/**
@brief 生成单人野怪战斗报告详细数据
*/
func createMonsterReportDetail(worldAssetData *cache.WorldDataEntry, orgiAtkUnitAssetMap, orgidefUnitAssetMap map[uint64]*stUserUnitInfo,
unitDefBattleInfoMap map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB, reportDetail *proto.ST_MonsterKill_PB) {
if nil == worldAssetData || orgiAtkUnitAssetMap == nil || unitDefBattleInfoMap == nil || orgidefUnitAssetMap == nil {
return
}
conf := worldAssetData.GetWorldEntryConfig()
if conf == nil {
return
}
if len(orgiAtkUnitAssetMap) != 1 || len(orgidefUnitAssetMap) != 1 || len(unitDefBattleInfoMap) != 1 {
return
}
for actionID, userUnitInfo := range orgiAtkUnitAssetMap {
actionAsset := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionID)
if actionAsset == nil || actionAsset.Actiondata == nil {
return
}
reportDetail.Uints = &proto.ST_UnitAsset_PB{Units: make([]*proto.ST_Unit_PB, 0)}
for _, v1 := range userUnitInfo.unitMap {
for _, v2 := range v1 {
reportDetail.Uints.Units = common.CombineUnit(reportDetail.Uints.Units, v2.unit)
}
}
}
reportDetail.MonsterInf = &proto.ST_MonsterInfo_PB{}
reportDetail.MonsterInf.TileID = proto.SetUint64(uint64(worldAssetData.GetWorldDataTileID()))
//totalPower := int64(0)
totalLossPower := int64(0)
for _, userUnitInfo := range orgidefUnitAssetMap {
//totalPower = userUnitInfo.totalPower
if unitBattleInfoMap, ok := unitDefBattleInfoMap[0]; ok {
for _, unitList := range userUnitInfo.unitMap {
for _, unit := range unitList {
if v, ok := unitBattleInfoMap[unit.unit.GetUnitid()]; ok {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unit.unit.GetUnitid()))
if nil != unitCSV {
totalLossPower += unitCSV.Power * int64(unit.unit.GetUnitnum()-uint64(v.GetSurvival()))
}
}
}
}
}
}
//战斗单位
if conf.MonsterFighting == 0 {
reportDetail.MonsterInf.DropHP = proto.SetUint32(0)
} else {
reportDetail.MonsterInf.DropHP = proto.SetUint32(uint32(totalLossPower * 10000 / conf.MonsterFighting))
if reportDetail.MonsterInf.GetDropHP() > 10000 {
reportDetail.MonsterInf.DropHP = proto.SetUint32(10000)
}
}
}
/*
@brief 获取兵力返还比例
*/
func getReturnUnitPara(targetType uint32, isAtk, mstAtk bool) uint32 {
if mstAtk {
return CSV.GetGameConfigValueUint32("Pirate_RETURN")
}
parm := uint32(0)
if false == isAtk {
return parm
}
switch targetType {
case targetMutiMonster: //集结怪
parm = CSV.GetGameConfigValueUint32("MUTI_MONSTER_RETURN_UNITS")
case targetMonsterEx: //单人怪
parm = CSV.GetGameConfigValueUint32("MONSTEREX_RETURN")
case targetSummonMutiMonster: //多人召唤怪
parm = CSV.GetGameConfigValueUint32("SUMMON_MUTI_MONSTER_RETURN")
default:
parm = 0
}
return parm
}
/*
@brief 获取伤兵比例
*/
func getLostUnitPara(userdata *cache.Info, targetType uint32, isAtk, mstAtk bool) float32 {
var list []uint64
var param uint64
switch targetType {
case targetMainCity: //玩家主城
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("PLAYER_BASE_LOST"))
case targetWarCity, targetLeagueCenter: //城市争霸,攻打联盟城市(小奇迹)
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("CITY_LOST"))
case targetRayolCity: //大奇迹
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("WONDER_LOST"))
case targetBestationed, targetMine, targetMineGem: //营地,矿点
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("RESOURCE_LOST"))
case targetMutiMonster: //集结怪
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("MUTI_MONSTER_LOST"))
case targetMonsterEx: //单人怪targetSummonMutiMonster
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("MONSTEREX_LOST"))
case targetSummonMutiMonster: //多人召唤怪
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("SUMMON_MUTI_MONSTER_LOST"))
case targetBlockUnlock: //目前用于地块解锁
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("BLOCK_UNLOCK_LOST"))
default:
param = 10000
}
if mstAtk {
list = common.ParseStringToUint64List(CSV.GetGameConfigValueString("Pirate_LOST"))
}
if len(list) < 2 {
return float32(1)
}
if isAtk {
param = list[0]
} else {
param = list[1]
}
if nil != userdata {
addValue, _, _ := userdata.GetAttriValue(nil, proto.AtttibuteType_ToWounded)
param += uint64(addValue)
if param > 10000 {
param = 10000
}
}
return float32(param) / 10000
}
/*
@brief 处理医院存放受伤战斗单位逻辑
*/
func processBattleHospital(userdata *cache.Info, injuredUnitList map[uint32]uint32) (*proto.ST_UnitAsset_PB, *proto.ST_UnitAsset_PB) {
hurtUnits := &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
}
//维修站放不下的的伤兵
DeathUnits := &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
}
capacity := uint32(getHospitalCapacity(userdata))
if capacity <= 0 {
for k, v := range injuredUnitList {
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(k),
Unitnum: proto.SetUint64(uint64(v)),
}
DeathUnits.Units = append(hurtUnits.Units, unit)
}
return hurtUnits, DeathUnits
}
unitLevel := make(map[int64]int64)
levelNum := make(map[int64]uint32)
for k, v := range injuredUnitList {
if unitIsPitfall(k) || v == 0 {
continue
}
if res := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(k)); res != nil {
unitlevel := res.UnitLevel
unitLevel[unitlevel] = unitlevel
if v1, ok := levelNum[unitlevel]; ok {
levelNum[unitlevel] = v1 + v
} else {
levelNum[unitlevel] = v
}
}
}
tmpLevelList := make([]int64, 0)
for _, v := range unitLevel {
tmpLevelList = append(tmpLevelList, v)
}
sort.Sort(sort.Reverse(wsort.Int64Slice(tmpLevelList)))
needBreak := false
for _, level := range tmpLevelList {
if injuredNum, ok := levelNum[int64(level)]; ok {
if injuredNum == 0 {
continue
}
if injuredNum > capacity {
injuredNum = capacity
needBreak = true
}
for k1, v1 := range injuredUnitList {
if unitIsPitfall(k1) {
continue
}
if v1 == 0 {
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(k1),
Unitnum: proto.SetUint64(0),
}
hurtUnits.Units = append(hurtUnits.Units, unit)
DeathUnits.Units = append(DeathUnits.Units, unit)
continue
}
if CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(k1)).UnitLevel == int64(level) {
selfNum := v1
if selfNum > capacity {
tmp := selfNum - capacity
selfNum = capacity
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(k1),
Unitnum: proto.SetUint64(uint64(tmp)),
}
DeathUnits.Units = append(DeathUnits.Units, unit)
}
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(k1),
Unitnum: proto.SetUint64(uint64(selfNum)),
}
hurtUnits.Units = append(hurtUnits.Units, unit)
capacity -= selfNum
}
}
if needBreak {
break
}
}
}
return hurtUnits, DeathUnits
}
/**
@brief 统计军团击杀及其损失
*/
func genCorpsKillAndLoss(battleInfo *proto.ST_BattleInfo_PB, baseData *stBattleActionBaseData, isAtk bool) (map[proto.UnitBattleType][]*proto.ST_Unit_PB, map[uint32]*proto.ST_Unit_PB, map[uint32]*proto.ST_Unit_PB) {
unitKillMap := make(map[proto.UnitBattleType][]*proto.ST_Unit_PB) //key:造成击杀的军团类型 value:被击杀的战斗单位list
unitLossMap := make(map[uint32]*proto.ST_Unit_PB, 0) //单位损失
trapLossMap := make(map[uint32]*proto.ST_Unit_PB, 0) //陷阱损失
var roundBaseInfo *proto.ST_RoundBaseInfo_PB
for _, roundInfo := range battleInfo.RoundInfo {
roundBaseInfo = roundInfo.AtkRoundInfo
if false == isAtk {
roundBaseInfo = roundInfo.DefRoundInfo
}
for _, corp := range roundBaseInfo.CorpList {
killUnitList := make([]*proto.ST_Unit_PB, 0)
if nil == corp {
continue
}
for _, unit := range corp.UnitKill {
unit := proto.Clone(unit).(*proto.ST_Unit_PB)
killUnitList = append(killUnitList, unit)
}
//军团击杀
if _, ok := unitKillMap[proto.UnitBattleType(corp.GetUnitType())]; ok {
unitKillMap[proto.UnitBattleType(corp.GetUnitType())] = addUnits(unitKillMap[proto.UnitBattleType(corp.GetUnitType())], killUnitList)
} else {
unitKillMap[proto.UnitBattleType(corp.GetUnitType())] = killUnitList
}
}
}
//军团损失
for _, v := range baseData.formation.unitData {
for _, corps := range v {
if corps == nil {
continue
}
num := len(corps.startUnits)
if 0 == num {
continue
}
for index := 0; index < num; index++ {
lostUnit := &proto.ST_Unit_PB{}
startNum := corps.startUnits[index].GetUnitnum()
CurNum := corps.curUnits[index].GetUnitnum()
if CurNum > startNum {
CurNum = startNum
}
lossNum := startNum - CurNum
lossID := corps.startUnits[index].GetUnitid()
lostUnit.Unitid = proto.SetUint32(lossID)
lostUnit.Unitnum = proto.SetUint64(lossNum)
unitLossMap[lossID] = lostUnit
}
}
}
//陷阱损失
for _, v := range baseData.formation.trapsData {
for _, corps := range v {
if corps == nil {
continue
}
num := len(corps.startUnits)
if 0 == num {
continue
}
for index := 0; index < num; index++ {
lostUnit := &proto.ST_Unit_PB{}
lossNum := corps.startUnits[index].GetUnitnum() - corps.curUnits[index].GetUnitnum()
lossID := corps.startUnits[index].GetUnitid()
lostUnit.Unitid = proto.SetUint32(lossID)
lostUnit.Unitnum = proto.SetUint64(lossNum)
trapLossMap[lossID] = lostUnit
}
}
}
return unitKillMap, unitLossMap, trapLossMap
}
/**
@brief 统计军团以及英雄击杀
*/
func genBattleAllKill(battleInfo *proto.ST_BattleInfo_PB, isAtk bool) (map[uint32]*proto.ST_Unit_PB, map[proto.UnitBattleType][]*proto.ST_Unit_PB, map[uint32]*proto.ST_Unit_PB) {
unitKillMap := make(map[proto.UnitBattleType][]*proto.ST_Unit_PB) //key:造成击杀的军团类型 value:被击杀的战斗单位list
heroKillMap := make(map[uint32]*proto.ST_Unit_PB, 0) //英雄总击杀
trapLossMap := make(map[uint32]*proto.ST_Unit_PB, 0) //陷阱损失
var roundBaseInfo *proto.ST_RoundBaseInfo_PB
for _, roundInfo := range battleInfo.RoundInfo {
roundBaseInfo = roundInfo.AtkRoundInfo
if false == isAtk {
roundBaseInfo = roundInfo.DefRoundInfo
}
//军团击杀
for _, corp := range roundBaseInfo.CorpList {
killUnitList := make([]*proto.ST_Unit_PB, 0)
if nil == corp {
continue
}
for _, unit := range corp.UnitKill {
unit := proto.Clone(unit).(*proto.ST_Unit_PB)
killUnitList = append(killUnitList, unit)
}
if _, ok := unitKillMap[proto.UnitBattleType(corp.GetUnitType())]; ok {
unitKillMap[proto.UnitBattleType(corp.GetUnitType())] = addUnits(unitKillMap[proto.UnitBattleType(corp.GetUnitType())], killUnitList)
} else {
unitKillMap[proto.UnitBattleType(corp.GetUnitType())] = killUnitList
}
//陷阱自损
if corp.GetUnitType() >= uint32(proto.UnitBattleType_UBT_NOMAL_TRAP1) &&
corp.GetUnitType() <= uint32(proto.UnitBattleType_UBT_NOMAL_TRAP4) {
for _, unit := range corp.UnitLost {
unit := proto.Clone(unit).(*proto.ST_Unit_PB)
if k, ok := trapLossMap[unit.GetUnitid()]; ok {
k.Unitnum = proto.SetUint64(k.GetUnitnum() + unit.GetUnitnum())
} else {
trapLossMap[unit.GetUnitid()] = unit
}
}
}
}
//英雄击杀
for _, hero := range roundBaseInfo.HeroList {
for _, unit := range hero.KillList {
unit := proto.Clone(unit).(*proto.ST_Unit_PB)
if k, ok := heroKillMap[unit.GetUnitid()]; ok {
k.Unitnum = proto.SetUint64(k.GetUnitnum() + unit.GetUnitnum())
} else {
heroKillMap[unit.GetUnitid()] = unit
}
}
}
}
return heroKillMap, unitKillMap, trapLossMap
}
func getPassiveAfterFightSkillEffect(userData *cache.Info, heroList []uint32, effectName string) uint32 {
if userData == nil || len(heroList) == 0 {
return 0
}
value := uint32(0)
for _, id := range heroList {
userData.WithHeroAsset(true, id, func(heroAsset *proto.ST_HeroEntry_PB) bool {
for _, skill := range heroAsset.GetSkillList() {
skillCSV := CSV.Mgr.CSV_HeroNewSkills.GetEntryPtr(int64(skill.GetSkillID()))
if skillCSV != nil && skillCSV.SkillType == int64(proto.SkillMainType_ST_PASSIVE) {
effectMap := common.ParseParameterStringToMap(skillCSV.SkillEffect)
effectMap1 := common.ParseParameterStringToMap(skillCSV.SkillSubType)
subType, ok := effectMap1[effectName]
if !ok || common.StringToUint32(subType) != uint32(proto.SkillSubType_ST_PASSIVE_AFTERFIGHT) {
continue
}
if effect, ok := effectMap[effectName]; ok {
value += common.StringToUint32(effect)
}
}
}
return true
})
}
return value
}
/**
@brief 根据玩家初始兵力及其战后兵力来计算击杀,存活,伤兵,死亡信息
*/
func genUserBattleUnitInfo(targetType uint32, orgiUnitAssetMap map[uint64]*stUserUnitInfo, unitKillMap map[proto.UnitBattleType][]*proto.ST_Unit_PB,
unitLossMap, trapLossMap map[uint32]*proto.ST_Unit_PB, isAtk bool, atkBaseData, defBaseData *stBattleActionBaseData) (map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB, uint64, map[uint64]*proto.ST_UnitAsset_PB) {
atkUnitBattleInfoMap := make(map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB) //key1:action key2:unitid
returnUnitMap := make(map[uint64]*proto.ST_UnitAsset_PB, 0) //返回兵力详细信息key:actionID
//兵力死亡返还系数,百分比
returnUnitsParm := getReturnUnitPara(targetType, isAtk, atkBaseData.monsterAtk)
returnUnitsTotal := uint64(0) //返还兵力的总量
// 被动技能降低地方伤兵转化率
defHeroList := make([]uint32, 0)
for _, v := range defBaseData.heroList {
defHeroList = append(defHeroList, v.heroID)
}
decLostRatio := getPassiveAfterFightSkillEffect(defBaseData.userData, defHeroList, "KillWounded")
if decLostRatio > 10000 {
decLostRatio = 10000
}
resWourd := uint32(0)
if targetType == targetMine || targetType == targetMineGem {
atkHeroList := make([]uint32, 0)
for _, v := range atkBaseData.heroList {
atkHeroList = append(atkHeroList, v.heroID)
}
resWourd = getPassiveAfterFightSkillEffect(atkBaseData.userData, atkHeroList, "ResWounded")
if resWourd > 10000 {
resWourd = 10000
}
}
for actionID, userUnitInfo := range orgiUnitAssetMap {
UnitBattleInfoMap := make(map[uint32]*proto.ST_UnitBattleReport_PB)
//根据己方击杀统计击杀(填充ST_UnitBattleReport_PB中的Join、kill信息)
tmpUnitBattleReportMap := make(map[uint32]*proto.ST_UnitBattleReport_PB)
for k, startUnitList := range userUnitInfo.unitMap {
for _, startUnit := range startUnitList {
var unitBattleReport *proto.ST_UnitBattleReport_PB
if tmp, ok := tmpUnitBattleReportMap[startUnit.unit.GetUnitid()]; ok {
unitBattleReport = tmp
} else {
unitBattleReport = &proto.ST_UnitBattleReport_PB{
UnitID: proto.SetUint32(startUnit.unit.GetUnitid()),
Join: proto.SetUint32(uint32(startUnit.unit.GetUnitnum())),
Survival: proto.SetUint32(uint32(startUnit.unit.GetUnitnum())),
KillList: &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
},
}
}
if killList, ok := unitKillMap[k]; ok {
for _, killUnit := range killList {
var killNum uint64
//做个四舍五入
killNum = uint64(math.Floor(float64(float32(killUnit.GetUnitnum())*userUnitInfo.corpRatioMap[k]*startUnit.powerRatio + 0.5)))
unitBattleReport.Kill = proto.SetUint32(unitBattleReport.GetKill() + uint32(killNum))
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(killUnit.GetUnitid()),
Unitnum: proto.SetUint64(killNum),
}
unitBattleReport.KillList.Units = append(unitBattleReport.KillList.Units, unit)
}
}
tmpUnitBattleReportMap[unitBattleReport.GetUnitID()] = unitBattleReport
}
}
//军团死亡、受伤(填充ST_UnitBattleReport_PB中的Survival、Injured信息)
tmpUserData := cache.GetCharinfo(userUnitInfo.charUID)
injuredUnitList := make(map[uint32]uint32) //key:id value:数量
lostRatio := float64(getLostUnitPara(tmpUserData, targetType, isAtk, atkBaseData.monsterAtk))
lostRatio = lostRatio * float64(10000-decLostRatio) / float64(10000)
for _, lossUnit := range unitLossMap {
tmpReport := tmpUnitBattleReportMap[lossUnit.GetUnitid()]
isFind := false
for _, startUnitList := range userUnitInfo.unitMap {
for _, startUnit := range startUnitList {
if startUnit.unit.GetUnitid() == lossUnit.GetUnitid() {
var tmpLost float64
//向上取整
tmpLost = math.Ceil(float64(float32(lossUnit.GetUnitnum()) * userUnitInfo.unitRatioMap[lossUnit.GetUnitid()]))
tmpSurvival := tmpReport.GetSurvival()
if tmpSurvival < uint32(tmpLost) {
tmpLost = float64(tmpSurvival)
}
//战损*系数=受伤娄;战损-受伤=死亡数
tmpReport.Survival = proto.SetUint32(tmpReport.GetSurvival() - uint32(tmpLost))
tmpReport.Injured = proto.SetUint32(tmpReport.GetInjured() + uint32(tmpLost*lostRatio))
tmpReport.Death = proto.SetUint32(tmpReport.GetDeath() + uint32(tmpLost) - uint32(tmpLost*lostRatio))
if targetType == targetMine || targetType == targetMineGem {
injured := tmpReport.GetInjured() * resWourd / 10000
tmpReport.Survival = proto.SetUint32(tmpReport.GetSurvival() + injured)
tmpReport.Injured = proto.SetUint32(tmpReport.GetInjured() - injured)
}
tmpUnitBattleReportMap[lossUnit.GetUnitid()] = tmpReport
injuredUnitList[tmpReport.GetUnitID()] = tmpReport.GetInjured()
isFind = true
break
}
}
if isFind {
break
}
}
}
//陷阱自损
for _, trapLossUnit := range trapLossMap {
tmpReport := tmpUnitBattleReportMap[trapLossUnit.GetUnitid()]
isFind := false
for _, startUnitList := range userUnitInfo.unitMap {
for _, startUnit := range startUnitList {
if startUnit.unit.GetUnitid() == trapLossUnit.GetUnitid() {
var tmpLost float64
//向上取整
tmpLost = math.Ceil(float64(float32(trapLossUnit.GetUnitnum()) * userUnitInfo.unitRatioMap[trapLossUnit.GetUnitid()]))
tmpSurvival := tmpReport.GetSurvival()
if tmpSurvival < uint32(tmpLost) {
tmpLost = float64(tmpSurvival)
}
tmpReport.Survival = proto.SetUint32(tmpReport.GetSurvival() - uint32(tmpLost))
tmpReport.Death = proto.SetUint32(tmpReport.GetDeath() + uint32(tmpLost))
tmpUnitBattleReportMap[trapLossUnit.GetUnitid()] = tmpReport
isFind = true
break
}
}
if isFind {
break
}
}
}
for k, v := range tmpUnitBattleReportMap {
UnitBattleInfoMap[k] = v
}
atkUnitBattleInfoMap[actionID] = UnitBattleInfoMap
if tmpUserData != nil {
hurtUnit, deathUnit := processBattleHospital(tmpUserData, injuredUnitList)
if targetType != targetMonster {
tmpUserData.AddHospitalUnitAsset(hurtUnit)
}
returnUnits := &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
}
//集结怪、单人小怪、多人召唤怪有返回兵力
//根据死亡兵力+未放入维修战的兵力,得出进攻方的返还兵力
if (targetType == targetMutiMonster || targetType == targetMonsterEx || targetType == targetSummonMutiMonster) && isAtk {
actionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionID)
if actionData == nil {
continue
}
for unitID, report := range tmpUnitBattleReportMap {
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(unitID),
Unitnum: proto.SetUint64(uint64(report.GetDeath() * returnUnitsParm / 100)),
}
returnUnits.Units = append(returnUnits.Units, unit)
}
for _, unit := range deathUnit.Units {
unit.Unitnum = proto.SetUint64(uint64(uint32(unit.GetUnitnum()) * returnUnitsParm / 100))
}
common.CombineUnitAsset(returnUnits, deathUnit)
actionData.UpdateUnitAsset(returnUnits)
returnUnitMap[actionID] = returnUnits
returnUnitsTotal += countUnitNum(returnUnits)
} else if atkBaseData.monsterAtk && !isAtk {
for unitID, report := range tmpUnitBattleReportMap {
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(unitID),
Unitnum: proto.SetUint64(uint64(report.GetDeath() * returnUnitsParm / 100)),
}
//report.Death = proto.SetUint32(report.GetDeath() - uint32(unit.GetUnitnum()))
returnUnits.Units = append(returnUnits.Units, unit)
}
tmpUserData.AddUnitAssets(returnUnits)
tmpUserData.CalcPower()
}
}
}
return atkUnitBattleInfoMap, returnUnitsTotal, returnUnitMap
}
/**
@brief 根据玩家出兵战力比分计算击杀,存活,伤兵,死亡信息
*/
func genBattleUserUnitInfo(targetType uint32, orgiUnitAssetMap map[uint64]*stUserUnitInfo, selfUnitKill, enemyUnitKill map[proto.UnitBattleType][]*proto.ST_Unit_PB,
enemyHeroKill map[uint32]*proto.ST_Unit_PB, trapLossTrap map[uint32]*proto.ST_Unit_PB, isAtk bool) map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB {
atkUnitBattleInfoMap := make(map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB) //key1:action key2:unitid
for actionID, userUnitInfo := range orgiUnitAssetMap {
UnitBattleInfoMap := make(map[uint32]*proto.ST_UnitBattleReport_PB)
//根据己方击杀统计击杀
tmpUnitBattleReportMap := make(map[uint32]*proto.ST_UnitBattleReport_PB)
for k, startUnitList := range userUnitInfo.unitMap {
for _, startUnit := range startUnitList {
var unitBattleReport *proto.ST_UnitBattleReport_PB
if tmp, ok := tmpUnitBattleReportMap[startUnit.unit.GetUnitid()]; ok {
unitBattleReport = tmp
} else {
unitBattleReport = &proto.ST_UnitBattleReport_PB{
UnitID: proto.SetUint32(startUnit.unit.GetUnitid()),
Join: proto.SetUint32(uint32(startUnit.unit.GetUnitnum())),
Survival: proto.SetUint32(uint32(startUnit.unit.GetUnitnum())),
KillList: &proto.ST_UnitAsset_PB{
Units: make([]*proto.ST_Unit_PB, 0),
},
}
}
if killList, ok := selfUnitKill[k]; ok {
for _, killUnit := range killList {
var killNum uint64
//做个四舍五入
killNum = uint64(math.Floor(float64(float32(killUnit.GetUnitnum())*userUnitInfo.corpRatioMap[k]*startUnit.powerRatio + 0.5)))
unitBattleReport.Kill = proto.SetUint32(unitBattleReport.GetKill() + uint32(killNum))
unit := &proto.ST_Unit_PB{
Unitid: proto.SetUint32(killUnit.GetUnitid()),
Unitnum: proto.SetUint64(killNum),
}
unitBattleReport.KillList.Units = append(unitBattleReport.KillList.Units, unit)
}
}
tmpUnitBattleReportMap[unitBattleReport.GetUnitID()] = unitBattleReport
}
}
//根据敌方击杀来统计己方损失
tmpUserData := cache.GetCharinfo(userUnitInfo.charUID)
injuredUnitList := make(map[uint32]uint32) //key:id value:数量
lostRatio := float64(getLostUnitPara(tmpUserData, targetType, isAtk, false))
//敌方军团击杀
for _, lossUnitList := range enemyUnitKill {
for _, lossUnit := range lossUnitList {
tmpReport := tmpUnitBattleReportMap[lossUnit.GetUnitid()]
isFind := false
for _, startUnitList := range userUnitInfo.unitMap {
for _, startUnit := range startUnitList {
if startUnit.unit.GetUnitid() == lossUnit.GetUnitid() {
var tmpLost float64
//向上取整
tmpLost = math.Ceil(float64(float32(lossUnit.GetUnitnum()) * userUnitInfo.unitRatioMap[lossUnit.GetUnitid()]))
tmpSurvival := tmpReport.GetSurvival()
if tmpSurvival < uint32(tmpLost) {
tmpLost = float64(tmpSurvival)
}
tmpReport.Survival = proto.SetUint32(tmpReport.GetSurvival() - uint32(tmpLost))
tmpReport.Injured = proto.SetUint32(tmpReport.GetInjured() + uint32(tmpLost*lostRatio))
tmpReport.Death = proto.SetUint32(tmpReport.GetDeath() + uint32(tmpLost) - uint32(tmpLost*lostRatio))
tmpUnitBattleReportMap[lossUnit.GetUnitid()] = tmpReport
injuredUnitList[tmpReport.GetUnitID()] = tmpReport.GetInjured()
isFind = true
break
}
}
if isFind {
break
}
}
}
}
//敌方英雄击杀
for _, lossUnit := range enemyHeroKill {
tmpReport := tmpUnitBattleReportMap[lossUnit.GetUnitid()]
isFind := false
for _, startUnitList := range userUnitInfo.unitMap {
for _, startUnit := range startUnitList {
if startUnit.unit.GetUnitid() == lossUnit.GetUnitid() {
var tmpLost float64
//向上取整
tmpLost = math.Ceil(float64(float32(lossUnit.GetUnitnum()) * userUnitInfo.unitRatioMap[lossUnit.GetUnitid()]))
tmpSurvival := tmpReport.GetSurvival()
if tmpSurvival < uint32(tmpLost) {
tmpLost = float64(tmpSurvival)
}
tmpReport.Survival = proto.SetUint32(tmpReport.GetSurvival() - uint32(tmpLost))
tmpReport.Injured = proto.SetUint32(tmpReport.GetInjured() + uint32(tmpLost*lostRatio))
tmpReport.Death = proto.SetUint32(tmpReport.GetDeath() + uint32(tmpLost) - uint32(tmpLost*lostRatio))
tmpUnitBattleReportMap[lossUnit.GetUnitid()] = tmpReport
injuredUnitList[tmpReport.GetUnitID()] = tmpReport.GetInjured()
isFind = true
break
}
}
if isFind {
break
}
}
}
//陷阱自损
for _, trapLossUnit := range trapLossTrap {
tmpReport := tmpUnitBattleReportMap[trapLossUnit.GetUnitid()]
isFind := false
for _, startUnitList := range userUnitInfo.unitMap {
for _, startUnit := range startUnitList {
if startUnit.unit.GetUnitid() == trapLossUnit.GetUnitid() {
var tmpLost float64
//向上取整
tmpLost = math.Ceil(float64(float32(trapLossUnit.GetUnitnum()) * userUnitInfo.unitRatioMap[trapLossUnit.GetUnitid()]))
tmpSurvival := tmpReport.GetSurvival()
if tmpSurvival < uint32(tmpLost) {
tmpLost = float64(tmpSurvival)
}
tmpReport.Survival = proto.SetUint32(tmpReport.GetSurvival() - uint32(tmpLost))
tmpReport.Death = proto.SetUint32(tmpReport.GetDeath() + uint32(tmpLost))
tmpUnitBattleReportMap[trapLossUnit.GetUnitid()] = tmpReport
isFind = true
break
}
}
if isFind {
break
}
}
}
for k, v := range tmpUnitBattleReportMap {
UnitBattleInfoMap[k] = v
}
atkUnitBattleInfoMap[actionID] = UnitBattleInfoMap
//医院逻辑
/*
if 0 != actionID{
gActionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionID)
if gActionData != nil {
tmpUserData := cache.GetCharinfo(gActionData.Actiondata.GetUid())
if tmpUserData != nil {
hurtUnit := processBattleHospital(tmpUserData, injuredUnitList)
tmpUserData.AddHospitalUnitAsset(hurtUnit)
}
}
}*/
if tmpUserData != nil {
/*
hurtUnit := processBattleHospital(tmpUserData, injuredUnitList)
tmpUserData.AddHospitalUnitAsset(hurtUnit)
*/
}
}
return atkUnitBattleInfoMap
}
/**
@brief 处理战斗后玩家兵力信息
*/
func processUnitBattleInfo(targetType uint32, battleInfo *proto.ST_BattleInfo_PB,
atkBaseData, defBaseData *stBattleActionBaseData, atkOrgiUnitAssetMap, defOrgiUnitAssetMap map[uint64]*stUserUnitInfo) (
map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB, map[uint64]map[uint32]*proto.ST_UnitBattleReport_PB, uint64, map[uint64]*proto.ST_UnitAsset_PB) {
if nil == battleInfo || nil == atkBaseData || nil == defBaseData {
return nil, nil, 0, nil
}
atkUnitKillMap, atkUnitLoss, _ := genCorpsKillAndLoss(battleInfo, atkBaseData, true)
defUnitKillMap, defUnitLoss, defTrapLoss := genCorpsKillAndLoss(battleInfo, defBaseData, false)
atkUnitBattleInfoMap, atkReturnUnitsTotal, returnUnitMap := genUserBattleUnitInfo(targetType, atkOrgiUnitAssetMap, atkUnitKillMap, atkUnitLoss, nil, true, atkBaseData, defBaseData)
defUnitBattleInfoMap, _, _ := genUserBattleUnitInfo(targetType, defOrgiUnitAssetMap, defUnitKillMap, defUnitLoss, defTrapLoss, false, defBaseData, atkBaseData)
return atkUnitBattleInfoMap, defUnitBattleInfoMap, atkReturnUnitsTotal, returnUnitMap
}
/**@brief 大地图上的战斗
@return 行为发起方是否获胜,是否经过战斗,目标类型
*/
func worldRealBattle(battleKey *stBattleKey) (uint32, bool, uint32, *proto.ST_BattleInfo_PB, *proto.ST_BattleReport_PB, *proto.ST_MonsterKill_PB) {
if nil == battleKey {
return battleRlt_Error, false, targetUnUse, nil, nil, nil
}
//战斗数据准备,先把在战斗中不会改变的属性计算好
ok, targetType, atkBaseData, defBaseData, commonBattleParm,
worldAssetData, atkOrgiUnitAssetMap, defOrgiUnitAssetMap := prepareBattlePara(battleKey)
if false == ok {
return battleRlt_Error, false, targetType, nil, nil, nil
}
//开始战斗
battleRlt, battleInfo := startBattle(targetType, atkBaseData, defBaseData, commonBattleParm)
if battleRlt_Error == battleRlt {
return battleRlt, true, targetType, nil, nil, nil
}
//wlog.Error("battleInfo:", battleInfo)
//处理战斗后的伤兵,伤兵,击杀等信息
tmpTargetType := targetType
if targetType == targetMonster && battleKey.targetType != 0 {
tmpTargetType = targetType
}
atkUnitBattleInfoMap, defUnitBattleInfoMap, atkReturnUnitsTotal, atkReturnUnitMap := processUnitBattleInfo(tmpTargetType, battleInfo, atkBaseData, defBaseData, atkOrgiUnitAssetMap, defOrgiUnitAssetMap)
//根据战斗信息生产战斗邮件
//并发送战报(战斗回放+战斗邮件)
var battleReport *proto.ST_BattleReport_PB
var monsterKillReport *proto.ST_MonsterKill_PB
if targetMonster != targetType {
//PVP战报
battleReport = &proto.ST_BattleReport_PB{}
var defReportDetailList []*proto.ST_BattleReportDetail_PB
var defPowerReport *proto.ST_PowerReport_PB
atkReportDetailList, atkPowerReport := createReportDetail(targetType, worldAssetData, battleInfo, atkOrgiUnitAssetMap, atkUnitBattleInfoMap, true)
//记录战斗全局加成
//battleReport.AtkAllBattleAttri = &proto.ST_AttributeList_PB{}
battleReport.AtkAllBattleAttri = recordBattleAllAttri(atkBaseData)
if targetMutiMonster == targetType || targetMonsterEx == targetType || targetSummonMutiMonster == targetType { //集结怪/单人小怪/集结召唤怪战报
defReportDetailList, defPowerReport = createMutiMonsterReportDetail(defBaseData, worldAssetData, battleInfo, defOrgiUnitAssetMap, defUnitBattleInfoMap)
battleReport.DefAllBattleAttri = &proto.ST_AttributeList_PB{
List: make([]*proto.ST_Attribute_PB, 0),
}
} else { //通用战报
defReportDetailList, defPowerReport = createReportDetail(targetType, worldAssetData, battleInfo, defOrgiUnitAssetMap, defUnitBattleInfoMap, false)
//记录战斗全局加成
//battleReport.defAllBattleAttri = &proto.ST_AttributeList_PB{}
battleReport.DefAllBattleAttri = recordBattleAllAttri(defBaseData)
}
battleReport.AtkInfo = atkReportDetailList
battleReport.DefInfo = defReportDetailList
battleReport.AtkPowerReport = atkPowerReport
battleReport.DefPowerReport = defPowerReport
battleReport.TargetType = proto.SetUint32(targetType)
battleReport.ReturnUnitsTotal = proto.SetInt64(int64(atkReturnUnitsTotal))
//记录下多人怪进攻方的返回兵力信息
battleReport.ReturnUnitsList = make([]*proto.ST_ReturnUnits_PB, 0)
for k, v := range atkReturnUnitMap {
returnUnit := &proto.ST_ReturnUnits_PB{
ActionID: proto.SetUint64(k),
}
returnUnit.ReturnUnitInfo = proto.Clone(v).(*proto.ST_UnitAsset_PB)
battleReport.ReturnUnitsList = append(battleReport.ReturnUnitsList, returnUnit)
}
if nil != worldAssetData && nil != worldAssetData.GetWorldEntryConfig() {
battleReport.WorldEntryConfigID = proto.SetInt64(worldAssetData.GetWorldEntryConfig().ID)
}
newOssPVPRecord(battleReport, worldAssetData)
} else {
//杀怪战报
monsterKillReport = &proto.ST_MonsterKill_PB{}
createMonsterReportDetail(worldAssetData, atkOrgiUnitAssetMap, defOrgiUnitAssetMap, defUnitBattleInfoMap, monsterKillReport)
}
return battleRlt, true, targetType, battleInfo, battleReport, monsterKillReport
}
/**
@brief 处理英雄战斗流程
*/
func processHeroFight(targetType uint32, atkBaseData, defBaseData *stBattleActionBaseData, commonBattleParm *stCommonBattleParm) uint32 {
if nil == atkBaseData || nil == defBaseData || nil == commonBattleParm {
return battleRlt_Error
}
type stInfo struct {
hero *stHeroBattleInfo
self *stBattleActionBaseData
Enemy *stBattleActionBaseData
}
useSkillOrder := uint32(1) //每个技能的释放顺序
//统计所有英雄的主属性,并记录所对应的攻击/防守玩家的数据
mainValueList := make([]uint32, 0)
heroMap := make(map[uint32]*stInfo)
for _, k := range atkBaseData.heroList {
info := &stInfo{}
info.hero = k
info.self = atkBaseData
info.Enemy = defBaseData
mainValue := uint32(float64(getHeroAtk(targetType, atkBaseData, commonBattleParm)) * float64(commonBattleParm.battleDamageParm[4]) / 10000)
//当出现英雄战斗力值相同的情况,其值自动+1,直到不重复
for {
if _, ok := heroMap[mainValue]; ok {
mainValue += 1
} else {
break
}
}
heroMap[mainValue] = info
mainValueList = append(mainValueList, mainValue)
}
for _, k := range defBaseData.heroList {
info := &stInfo{}
info.hero = k
info.self = defBaseData
info.Enemy = atkBaseData
mainValue := uint32(float64(getHeroAtk(targetType, defBaseData, commonBattleParm)) * float64(commonBattleParm.battleDamageParm[4]) / 10000)
//当出现英雄战斗力值相同的情况,其值自动+1,直到不重复
for {
if _, ok := heroMap[mainValue]; ok {
mainValue += 1
} else {
break
}
}
heroMap[mainValue] = info
mainValueList = append(mainValueList, mainValue)
}
//排序
sort.Sort(sort.Reverse(wsort.Uint32Slice(mainValueList)))
for _, k := range mainValueList {
if v, ok := heroMap[k]; ok {
hero := v.hero
self := v.self
enemy := v.Enemy
//眩晕
if _, ok := hero.fightBuff[uint32(proto.FightBuffAttibute_Dizzy)]; ok {
continue
}
//获取技能(根据技能的优先级和概率选择一个技能)
skill := heroUserSelectSkill(hero)
if nil == skill {
continue
}
//使用技能
if ok, unitType := heroSkillFightUnit(targetType, hero, skill, k, self, enemy, commonBattleParm); ok {
//-------------记录英雄战斗信息--------------
heroBattleInfo := &proto.ST_HeroBattleInfo_PB{
HeroID: proto.SetUint32(hero.heroID),
BuffList: make([]*proto.ST_BuffBattleInfo_PB, 0),
KillList: make([]*proto.ST_Unit_PB, 0),
RecoveryList: make([]*proto.ST_Unit_PB, 0),
}
for k, v := range hero.fightBuff {
buff := &proto.ST_BuffBattleInfo_PB{}
buff.BuffID = proto.SetUint32(k)
buff.BuffType = proto.SetUint32(v.effectType)
heroBattleInfo.BuffList = append(heroBattleInfo.BuffList, buff)
}
heroBattleInfo.UseSkill = &proto.ST_HeroSkillInfo_PB{
SkillID: proto.SetUint32(uint32(skill.ID)),
TargetType: proto.SetUint32(uint32(unitType)),
}
//不记录普通攻击顺序。
//目前所有普攻都是存放在第一位,skillList不可能为nil
heroBattleInfo.UseOrder = proto.SetUint32(useSkillOrder)
useSkillOrder += 1
self.roundBaseInfo.HeroList = append(self.roundBaseInfo.HeroList, heroBattleInfo)
//-------------记录英雄战斗信息--------------
//立即更新一次双方buff,触发立即生效的buff
processFightBuff(atkBaseData, defBaseData, 1)
processFightBuff(defBaseData, atkBaseData, 1)
rlt := checkBattleRlt(atkBaseData, defBaseData)
if battleRlt_Continue != rlt {
return rlt
}
}
}
}
return battleRlt_Continue
}
/**
@brief 处理战斗BUFF
*/
func processFightBuff(selfBaseData *stBattleActionBaseData, EnemyBaseData *stBattleActionBaseData, triggerTime uint32) {
if nil == selfBaseData || nil == EnemyBaseData {
return
}
//依次处理城墙-英雄-战斗单位的buff效果
if (selfBaseData.actionBaseType == actionBase_Def || selfBaseData.actionBaseType == actionBase_Monster) &&
nil != selfBaseData.wall && 0 != selfBaseData.wall.curWallHp {
for k, v := range selfBaseData.wall.fightBuff {
if uint32(0) >= v.effectRound {
delete(selfBaseData.wall.fightBuff, k)
continue
}
if v.csvIndex == int32(proto.FightBuffAttibute_DamageShield) && v.effectValue <= 0 {
delete(selfBaseData.wall.fightBuff, k)
continue
}
if triggerTime == v.triggerTime {
//触发效果
triggerWallFightBuff(selfBaseData, selfBaseData.wall, k, v)
v.triggerTime = 0
v.effectRound -= 1
}
}
}
for _, heroV := range selfBaseData.heroList {
for buffK, buffV := range heroV.fightBuff {
if triggerTime == buffV.triggerTime {
if uint32(0) >= buffV.effectRound {
delete(heroV.fightBuff, buffK)
continue
}
//触发效果
triggerHeroFightBuff(heroV, buffK, buffV)
buffV.triggerTime = 0
buffV.effectRound -= 1
}
}
}
for _, v := range selfBaseData.formation.unitData {
for _, unitV := range v {
if unitV == nil {
continue
}
for buffK, buffV := range unitV.fightBuff {
if triggerTime == buffV.triggerTime {
if uint32(0) >= buffV.effectRound {
if buffV.csvIndex == int32(proto.FightBuffAttibute_SummonTroops) {
unitV.summonUnits = make([]*proto.ST_Unit_PB, 0)
}
delete(unitV.fightBuff, buffK)
continue
}
if buffV.csvIndex == int32(proto.FightBuffAttibute_DamageShield) && buffV.effectValue <= 0 {
delete(unitV.fightBuff, buffK)
continue
}
//触发效果
triggerUnitFightBuff(selfBaseData, EnemyBaseData, unitV, buffK, buffV)
buffV.triggerTime = 0
buffV.effectRound -= 1
}
}
}
}
}
/**
@brief 获取英雄攻击力
*/
func getHeroAtk(targetType uint32, baseData *stBattleActionBaseData, commonBattleParm *stCommonBattleParm) uint64 {
if nil == baseData {
return 0
}
totalAtkValue := uint64(0)
for _, lst := range baseData.formation.unitData {
for _, corps := range lst {
if corps == nil {
continue
}
totalCorpValue := uint64(0)
tmpUnits := make([]*proto.ST_Unit_PB, 0)
tmpUnits = common.CombineUnitMap(tmpUnits, corps.curUnits)
tmpUnits = common.CombineUnitMap(tmpUnits, corps.summonUnits)
for _, unit := range tmpUnits {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unit.GetUnitid()))
if unitCSV == nil {
continue
}
if nil != commonBattleParm {
tmpValue := uint64(float64(unitCSV.Attack) * math.Pow(float64(unit.GetUnitnum()), float64(commonBattleParm.atkParm[0])/10000))
totalCorpValue += tmpValue
}
}
totalCorpValue = getAtkAdditional(totalCorpValue, targetType, corps.unitType, baseData.globalAttribute, corps.fightBuff, corps.specialBuff, baseData.actionBaseType == actionBase_Def)
totalAtkValue += totalCorpValue
}
}
return totalAtkValue
}
/**
@brief 检查是否存在技能释放对象
*/
func CheckSkillUnitTarget(skillCSV *CSV.CF_HeroNewSkills_DataEntry, defBaseData *stBattleActionBaseData) proto.UnitBattleType {
if nil == skillCSV || nil == defBaseData {
return proto.UnitBattleType_UBT_NOMAL_NONE
}
unitType := proto.UnitBattleType_UBT_NOMAL_NONE
//是否有指定兵种
DestineUnit := proto.UnitBattleType(skillCSV.DestineUnit)
if proto.UnitBattleType_UBT_NOMAL_NONE != DestineUnit {
if DestineUnit == proto.UnitBattleType_UBT_NOMAL_WALL { //城墙
if nil != defBaseData.wall && uint64(0) != defBaseData.wall.curWallHp {
unitType = proto.UnitBattleType_UBT_NOMAL_WALL
}
} else if DestineUnit == proto.UnitBattleType_UBT_SPECIAL_ALL_UNIT { //所有兵种
for _, lst := range defBaseData.formation.unitData {
bFind := false
for _, v := range lst {
if v != nil && v.curAllUnitNum != uint32(0) { //直接选取第一个数量不为0的军团
unitType = v.unitType
bFind = true
break
}
}
if bFind {
break
}
}
} else if DestineUnit == proto.UnitBattleType_UBT_NOMAL_HERO { //英雄
unitType = proto.UnitBattleType_UBT_NOMAL_HERO
} else if DestineUnit == proto.UnitBattleType_UBT_NOMAL_TRAP1 { //陷阱
for _, lst := range defBaseData.formation.trapsData {
bFind := false
for _, v := range lst { //步兵,坦克,火炮,飞机
if v != nil && v.unitType == DestineUnit && v.curAllUnitNum != uint32(0) { //直接选取第一个数量不为0的陷阱
unitType = v.unitType
bFind = true
break
}
}
if bFind {
break
}
}
} else {
for _, lst := range defBaseData.formation.unitData {
bFind := false
for _, v := range lst { //步兵,坦克,火炮,飞机
if v != nil && v.unitType == DestineUnit && v.curAllUnitNum != uint32(0) {
unitType = v.unitType
bFind = true
break
}
}
if !bFind {
break
}
}
}
}
if unitType != proto.UnitBattleType_UBT_NOMAL_NONE {
return unitType
}
//攻击位置上是否还存在战斗单位
if 0 != len(skillCSV.AttPos) {
posList := common.ParseStringToUint32List(skillCSV.AttPos)
for _, v := range posList {
bFind := false
lst := defBaseData.formation.unitData[proto.CorpsPos(v)]
for _, corp := range lst {
if corp != nil && uint32(0) != corp.curAllUnitNum {
unitType = corp.unitType
bFind = true
break
}
}
if bFind {
break
}
}
}
return unitType
}
/**
@brief 英雄使用技能
*/
func heroSkillFightUnit(targetType uint32, hero *stHeroBattleInfo, skillCSV *CSV.CF_HeroNewSkills_DataEntry, mainValue uint32, atkBaseData, defBaseData *stBattleActionBaseData, commonBattleParm *stCommonBattleParm) (bool, proto.UnitBattleType) {
if nil == skillCSV || nil == atkBaseData || nil == defBaseData || nil == commonBattleParm {
return false, proto.UnitBattleType_UBT_NOMAL_NONE
}
//判定是否存在释放目标
unitType := CheckSkillUnitTarget(skillCSV, defBaseData)
if unitType == proto.UnitBattleType_UBT_NOMAL_NONE {
return false, unitType
}
//攻击方英雄攻击力
atkHeroAtk := uint64(0)
skillEffectMap := strings.Split(skillCSV.SkillEffect, ";")
extraParamMap := common.ParseParameterStringToMap(skillCSV.ExtraParam)
for _, v := range skillEffectMap {
skillEffect := strings.Split(v, "=")
if len(skillEffect) < int(1) {
continue
}
index := proto.FightBuffAttibute_value[skillEffect[0]]
fightBuffInfo := CSV.Mgr.CSV_FightBuff.GetEntryPtr(int64(index))
if nil == fightBuffInfo {
continue
}
extraParamStr, ok := extraParamMap[skillEffect[0]]
extraParam := make([]uint32, 0)
if ok {
extraParam = common.ParseStringToUint32List(extraParamStr)
}
effectParm := common.ParseStringToUint32List(skillEffect[1]) // 作用对象|回合|固定值
tmpEffectValue := uint64(0)
specialRate := float64(1) //特殊行为系数
specialParm := commonBattleParm.skillSpecialParm //P|Q
var actionBase *stBattleActionBaseData
calcDamage := false
calcRecovery := false
switch proto.FightBuffAttibute(index) {
case proto.FightBuffAttibute_NomalDamage:
fallthrough
case proto.FightBuffAttibute_EnemyHDefDamage:
fallthrough
case proto.FightBuffAttibute_EnemyHHpDamage:
fallthrough
case proto.FightBuffAttibute_SelfLHpDamage:
actionBase = defBaseData
calcDamage = true
case proto.FightBuffAttibute_RecoveryCurHp:
tmpEffectValue = uint64(effectParm[2])
actionBase = atkBaseData
//calcRecovery = true
case proto.FightBuffAttibute_HotTreatment:
actionBase = atkBaseData
calcRecovery = true
case proto.FightBuffAttibute_ReduceHpRound:
actionBase = defBaseData
tmpEffectValue = uint64(effectParm[2])
//calcDamage = true
case proto.FightBuffAttibute_Dotdamage:
actionBase = defBaseData
//tmpEffectValue = uint64(effectParm[2])
calcDamage = true
case proto.FightBuffAttibute_ReduceDef:
fallthrough
case proto.FightBuffAttibute_ReduceAtt:
tmpEffectValue = uint64(effectParm[2])
actionBase = defBaseData
case proto.FightBuffAttibute_IncreaseFightAtt:
fallthrough
case proto.FightBuffAttibute_IncreaseFightDef:
tmpEffectValue = uint64(effectParm[2])
actionBase = atkBaseData
case proto.FightBuffAttibute_Dizzy:
fallthrough
case proto.FightBuffAttibute_Clearbuff:
actionBase = defBaseData
case proto.FightBuffAttibute_ClearDebuff:
actionBase = atkBaseData
case proto.FightBuffAttibute_IncreaseDamge:
actionBase = atkBaseData
tmpEffectValue = uint64(effectParm[2])
case proto.FightBuffAttibute_ReduceDamge:
actionBase = defBaseData
tmpEffectValue = uint64(effectParm[2])
case proto.FightBuffAttibute_SummonTroops:
actionBase = atkBaseData
case proto.FightBuffAttibute_NumDamage:
actionBase = atkBaseData
case proto.FightBuffAttibute_DamageShield:
actionBase = atkBaseData
tmpEffectValue = uint64(effectParm[2])
case proto.FightBuffAttibute_ExtraDamage:
actionBase = atkBaseData
case proto.FightBuffAttibute_NumCompare:
actionBase = atkBaseData
}
if calcDamage || calcRecovery {
atkHeroAtk = uint64(float64(getHeroAtk(targetType, atkBaseData, commonBattleParm)) * float64(commonBattleParm.battleDamageParm[4]) / 10000)
}
//英雄技能伤害系数=(基础系数+英雄主属性值/100×技能系数)×特殊行为系数/10000
//最终伤害=加成减免后伤害×英雄技能伤害系数
wall, heroList, corps, traps := getEffectTarget(unitType, effectParm[0], actionBase, hero)
//城墙
if nil != wall {
fightBuff := &stFightBuff{}
fightBuff.csvIndex = index
fightBuff.effectValue = tmpEffectValue
fightBuff.effectType = uint32(fightBuffInfo.BuffType)
fightBuff.effectRound = effectParm[1]
fightBuff.triggerTime = uint32(fightBuffInfo.Now)
fightBuff.heroID = hero.heroID
fightBuff.orgiSkillID = skillCSV.ID
fightBuff.params = extraParam
wall.fightBuff[uint32(index)] = fightBuff
if calcDamage {
//特殊行为系数
switch proto.FightBuffAttibute(index) {
case proto.FightBuffAttibute_EnemyHDefDamage:
//规划中...
case proto.FightBuffAttibute_EnemyHHpDamage:
//血量越高伤害越高,则 特殊行为系数= (血量百分比+P)/Q
specialRate = (float64(specialParm[0])/10000 + float64(wall.curWallHp)/float64(wall.startWallHp)) / float64(specialParm[1]) / 10000
case proto.FightBuffAttibute_SelfLHpDamage:
//血量越低伤害越高,则 特殊行为系数=Q/(P+血量百分比)
specialRate = (float64(specialParm[1]) / 10000) / (float64(specialParm[0])/10000 + float64(wall.curWallHp)/float64(wall.startWallHp))
}
skillDamageRate := (float64(effectParm[2])/10000 +
float64(mainValue)/100*float64(skillCSV.SkillRatio)/10000) * specialRate
damage := calcSkillDamageWithOutSpecialRate(atkHeroAtk, uint64(wall.wallDef), atkBaseData, defBaseData, hero.fightBuff, wall.fightBuff, hero.specialBuff, commonBattleParm, targetType)
fightBuff.effectValue = uint64(damage * (skillDamageRate * 10000))
}
if proto.FightBuffAttibute(index) == proto.FightBuffAttibute_HotTreatment {
if wall.curWallHp != 0 {
fightBuff.effectValue = atkHeroAtk * uint64(effectParm[2]) / (10000 * wall.curWallHp)
} else {
fightBuff.effectValue = 0
}
}
}
if nil != heroList && 1 == len(heroList) {
for _, v := range heroList {
fightBuff := &stFightBuff{}
fightBuff.csvIndex = index
fightBuff.effectValue = tmpEffectValue
fightBuff.effectType = uint32(fightBuffInfo.BuffType)
fightBuff.effectRound = effectParm[1]
fightBuff.triggerTime = uint32(fightBuffInfo.Now)
fightBuff.heroID = hero.heroID
fightBuff.orgiSkillID = skillCSV.ID
fightBuff.params = extraParam
v.fightBuff[uint32(index)] = fightBuff
}
}
//军团
if nil != corps && 0 != len(corps) {
for _, v := range corps {
if uint32(0) != v.curAllUnitNum {
fightBuff := &stFightBuff{}
fightBuff.csvIndex = index
fightBuff.effectValue = tmpEffectValue
fightBuff.effectType = uint32(fightBuffInfo.BuffType)
fightBuff.effectRound = effectParm[1]
fightBuff.triggerTime = uint32(fightBuffInfo.Now)
fightBuff.heroID = hero.heroID
fightBuff.orgiSkillID = skillCSV.ID
fightBuff.params = extraParam
v.fightBuff[uint32(index)] = fightBuff
if calcDamage {
//先重新统计下战斗单位属性
ProcessUnitAttribute(targetType, v, defBaseData.globalAttribute, commonBattleParm, defBaseData.actionBaseType == actionBase_Def, true)
curHp, MaxHp := getCorpCurTotalHp(v)
//特殊行为系数
if uint32(0) == uint32(specialRate) {
switch proto.FightBuffAttibute(index) {
case proto.FightBuffAttibute_EnemyHDefDamage:
//规划中...
case proto.FightBuffAttibute_EnemyHHpDamage:
//血量越高伤害越高,则 特殊行为系数= (血量百分比+P)/Q
specialRate = (float64(specialParm[0])/10000 + float64(curHp)/float64(MaxHp)) / float64(specialParm[1]) / 10000
case proto.FightBuffAttibute_SelfLHpDamage:
//血量越低伤害越高,则 特殊行为系数=Q/(P+血量百分比)
specialRate = (float64(specialParm[1]) / 10000) / (float64(specialParm[0])/10000 + float64(curHp)/float64(MaxHp))
}
}
skillDamageRate := (float64(effectParm[2])/10000 +
float64(mainValue)/100*float64(skillCSV.SkillRatio)/10000) * specialRate
damage := calcSkillDamageWithOutSpecialRate(atkHeroAtk, uint64(v.attributeMap[attribute_Def]), atkBaseData, defBaseData, hero.fightBuff, v.fightBuff, hero.specialBuff, commonBattleParm, targetType)
//技能伤害系数
//fightBuff.effectValue = uint64(math.Ceil(damage * skillDamageRate))
fightBuff.effectValue = uint64(damage * (skillDamageRate * 10000))
}
// 召唤 影子部队
if proto.FightBuffAttibute(index) == proto.FightBuffAttibute_SummonTroops {
v.summonUnits = make([]*proto.ST_Unit_PB, 0)
for _, unit := range v.curUnits {
v.summonUnits = append(v.summonUnits, &proto.ST_Unit_PB{
Unitid: proto.SetUint32(unit.GetUnitid()),
Unitnum: proto.SetUint64(unit.GetUnitnum() * uint64(effectParm[2]) / 10000),
})
}
} else if proto.FightBuffAttibute(index) == proto.FightBuffAttibute_HotTreatment {
fightBuff.effectValue = atkHeroAtk * uint64(effectParm[2]) * uint64(commonBattleParm.battleDamageParm[0]) / 10000
}
}
}
}
//陷阱
if nil != traps && 0 != len(traps) {
for _, v := range traps {
if uint32(0) != v.curAllUnitNum {
fightBuff := &stFightBuff{}
fightBuff.csvIndex = index
fightBuff.effectValue = tmpEffectValue
fightBuff.effectType = uint32(fightBuffInfo.BuffType)
fightBuff.effectRound = effectParm[1]
fightBuff.triggerTime = uint32(fightBuffInfo.Now)
fightBuff.heroID = hero.heroID
fightBuff.orgiSkillID = skillCSV.ID
fightBuff.params = extraParam
v.fightBuff[uint32(index)] = fightBuff
if calcDamage {
ProcessUnitAttribute(targetType, v, defBaseData.globalAttribute, commonBattleParm, defBaseData.actionBaseType == actionBase_Def, true)
curHp, MaxHp := getCorpCurTotalHp(v)
//特殊行为系数
if uint32(0) == uint32(specialRate) {
switch proto.FightBuffAttibute(index) {
case proto.FightBuffAttibute_EnemyHDefDamage:
//规划中...
case proto.FightBuffAttibute_EnemyHHpDamage:
//血量越高伤害越高,则 特殊行为系数= (血量百分比+P)/Q
specialRate = (float64(specialParm[0])/10000 + float64(curHp)/float64(MaxHp)) / float64(specialParm[1]) / 10000
case proto.FightBuffAttibute_SelfLHpDamage:
//血量越低伤害越高,则 特殊行为系数=Q/(P+血量百分比)
specialRate = (float64(specialParm[1]) / 10000) / (float64(specialParm[0])/10000 + float64(curHp)/float64(MaxHp))
}
}
//技能伤害系数
skillDamageRate := (float64(effectParm[2])/10000 +
float64(mainValue)/100*float64(skillCSV.SkillRatio)/10000) * specialRate
if proto.FightBuffAttibute_Dotdamage == proto.FightBuffAttibute(index) {
skillDamageRate = float64(effectParm[2]) / 10000
}
damage := calcSkillDamageWithOutSpecialRate(atkHeroAtk, uint64(uint64(v.attributeMap[attribute_Def])), atkBaseData, defBaseData, hero.fightBuff, v.fightBuff, hero.specialBuff, commonBattleParm, targetType)
fightBuff.effectValue = uint64(damage * (skillDamageRate * 10000))
}
if proto.FightBuffAttibute(index) == proto.FightBuffAttibute_HotTreatment {
fightBuff.effectValue = atkHeroAtk * uint64(effectParm[2]) * uint64(commonBattleParm.battleDamageParm[0]) / 10000
}
}
}
}
}
return true, unitType
}
/**
@brief 检查攻守军团剩余兵力
@return 0继续战斗 1攻击方无兵力 2防守方无兵力 3都没有
*/
func checkBattleRlt(atkBaseData, defBaseData *stBattleActionBaseData) uint32 {
if nil == atkBaseData {
return battleRlt_AtkEmpty
}
if nil == defBaseData {
return battleRlt_DefEmpty
}
atkOver := true
defOver := true
wallOver := true
for _, lst := range atkBaseData.formation.unitData {
for _, v := range lst {
if v == nil || v.curAllUnitNum == uint32(0) {
continue
}
atkOver = false
}
}
if nil != defBaseData.wall && defBaseData.wall.curWallHp != uint64(0) {
wallOver = false
}
for _, lst := range defBaseData.formation.unitData {
for _, v := range lst {
if v == nil || v.curAllUnitNum == uint32(0) {
continue
}
defOver = false
}
}
//双方全灭
if atkOver && defOver && wallOver {
return battleRlt_AllEmpty
}
//进攻方全灭,
if atkOver && (defOver != true || wallOver != true) {
return battleRlt_AtkEmpty
}
//防守放全灭
if atkOver != true && defOver && wallOver {
return battleRlt_DefEmpty
}
return battleRlt_Continue
}
/**
@brief 选择敌方被攻击对象
*/
func getEnemyCorps(unitBattleType proto.UnitBattleType, unitSpecialBuff []*stFightBuff, enemyFormation *stFormation) *stCorps {
//飞机有50%的几率随机攻击
if unitBattleType == proto.UnitBattleType_UBT_NOMAL_FEIJI {
if 0 == rand.Int31n(2) {
//先取出还有兵力的军团,再从中随机一个
tmpCorpList := []*stCorps{}
for _, lst := range enemyFormation.unitData {
for _, v := range lst {
if v != nil && v.curAllUnitNum != uint32(0) {
tmpCorpList = append(tmpCorpList, v)
}
}
}
tmpCount := int32(len(tmpCorpList))
if 0 != tmpCount {
return tmpCorpList[rand.Int31n(tmpCount)]
} else {
return nil
}
}
}
// 特殊被动技能会改变兵种的攻击顺序
fromBack := isRear(unitSpecialBuff)
if !fromBack {
for m := proto.CorpsPos_CP_FRONT; m <= proto.CorpsPos_CP_SKY; m++ {
lst := enemyFormation.unitData[m]
for _, tmp := range lst {
if nil != tmp && tmp.curAllUnitNum != uint32(0) {
return tmp
}
}
}
} else {
for m := proto.CorpsPos_CP_SKY; m >= proto.CorpsPos_CP_FRONT; m-- {
lst := enemyFormation.unitData[m]
for _, tmp := range lst {
if nil != tmp && tmp.curAllUnitNum != uint32(0) {
return tmp
}
}
}
}
return nil
}
/**
@brief 记录军团战斗流程
*/
func recordCropsBattleInfo(corp *stCorps, loss, kill []*proto.ST_Unit_PB) *proto.ST_CorpBattleInfo_PB {
corpBattleInfo := &proto.ST_CorpBattleInfo_PB{}
if nil == corp {
return corpBattleInfo
}
corpBattleInfo.UnitType = proto.SetUint32(uint32(corp.unitType))
corpBattleInfo.UnitNum = proto.SetUint32(corp.curAllUnitNum)
corpBattleInfo.UnitLost = make([]*proto.ST_Unit_PB, len(loss))
copy(corpBattleInfo.UnitLost, loss)
corpBattleInfo.UnitKill = make([]*proto.ST_Unit_PB, len(kill))
copy(corpBattleInfo.UnitKill, kill)
//buff信息
for k, v := range corp.fightBuff {
buff := &proto.ST_BuffBattleInfo_PB{}
buff.BuffID = proto.SetUint32(k)
buff.BuffType = proto.SetUint32(v.effectType)
corpBattleInfo.BuffList = append(corpBattleInfo.BuffList, buff)
}
//小军团详细信息
if len(corp.curUnits) > 0 {
corpBattleInfo.UnitId = proto.SetUint32(corp.curUnits[0].GetUnitid())
}
return corpBattleInfo
}
/**
@brief 处理军团战斗流程
*/
func processCorpsFight(targetType uint32, atkBaseData, defBaseData *stBattleActionBaseData, commonBattleParm *stCommonBattleParm) uint32 {
if nil == atkBaseData || nil == defBaseData || nil == commonBattleParm {
return 0
}
//有城墙时防守方的陷阱先攻击
if nil != defBaseData.wall && defBaseData.wall.curWallHp != 0 {
for _, v := range defBaseData.formation.trapsData {
for _, atkTrap := range v {
if nil == atkTrap || atkTrap.curAllUnitNum == uint32(0) {
continue
}
rlt := checkBattleRlt(atkBaseData, defBaseData)
if battleRlt_Continue != rlt {
return rlt
}
var beAtkCorps *stCorps
//获取被攻击的对象
//先选取被陷阱克制的单位
//如果没有,则顺序选取攻击对象
beAtkCorpType := proto.UnitBattleType(commonBattleParm.corpAtkOrder[int64(atkTrap.unitType)])
for _, v := range atkBaseData.formation.unitData {
for _, tmpCorp := range v {
if tmpCorp == nil || tmpCorp.unitType != beAtkCorpType {
continue
}
if tmpCorp.curAllUnitNum != uint32(0) {
beAtkCorps = tmpCorp
}
break
}
}
if nil == beAtkCorps {
for n := proto.CorpsPos_CP_FRONT; n <= proto.CorpsPos_CP_SKY; n++ {
lst := atkBaseData.formation.unitData[n]
for _, v := range lst {
beAtkCorps = v
if nil == beAtkCorps || beAtkCorps.curAllUnitNum == uint32(0) {
continue
}
break
}
}
}
if nil == beAtkCorps {
return battleRlt_AtkEmpty
}
isOnly := isOnlyCorp(atkBaseData, beAtkCorps)
//开始计算伤害及其损失
ProcessUnitAttribute(targetType, beAtkCorps, atkBaseData.globalAttribute, commonBattleParm, false, true)
ProcessUnitAttribute(targetType, atkTrap, defBaseData.globalAttribute, commonBattleParm, true, true)
_, trapDamage := unitFightUnitDamage(atkBaseData, defBaseData, atkTrap, beAtkCorps,
commonBattleParm, nil, true, targetType, atkTrap.specialBuff, isOnly, 0)
//根据伤害扣除战斗单位
atkLost, atkLossHp := reduceCorpUnitsByHp(beAtkCorps, trapDamage)
//陷阱自己的损失
trapLossDamage := math.Ceil(float64(atkLossHp) * float64(commonBattleParm.trapLossParm) / 10000)
trapLost, _ := reduceCorpUnitsByHp(atkTrap, trapLossDamage)
if nil != atkLost {
//进攻方损失
BeAtkCorpBattleInfo := recordCropsBattleInfo(beAtkCorps, atkLost, nil)
atkBaseData.roundBaseInfo.CorpList = append(atkBaseData.roundBaseInfo.CorpList, BeAtkCorpBattleInfo)
trapKillBattleInfo := recordCropsBattleInfo(atkTrap, nil, atkLost) //陷阱击杀
defBaseData.roundBaseInfo.CorpList = append(defBaseData.roundBaseInfo.CorpList, trapKillBattleInfo)
//陷阱损失
trapLossBattleInfo := recordCropsBattleInfo(atkTrap, trapLost, nil)
defBaseData.roundBaseInfo.CorpList = append(defBaseData.roundBaseInfo.CorpList, trapLossBattleInfo)
}
}
}
}
//拷贝一份进攻时的兵力信息
//存放单回合内未进攻的军团
cloneAtkUnitData := make(map[proto.CorpsPos][]*stCorps)
for k, v := range atkBaseData.formation.unitData {
cops := []*stCorps{}
for _, vv := range v {
cops = append(cops, vv)
}
cloneAtkUnitData[k] = cops
}
cloneDefUnitData := make(map[proto.CorpsPos][]*stCorps)
for k, v := range defBaseData.formation.unitData {
cops := []*stCorps{}
for _, vv := range v {
cops = append(cops, vv)
}
cloneDefUnitData[k] = cops
}
//接着双方兵团依次攻击
//在4种军团都存活的情况下,最多持续4*5小回合
for index := 1; index <= 4; index++ {
for tn := 0; tn < 5; tn++ {
rlt := checkBattleRlt(atkBaseData, defBaseData)
if battleRlt_Continue != rlt {
return rlt
}
var atkCorp *stCorps //攻击方战斗的军团
var defCorp *stCorps //防守方战斗的军团
var atkEnemyCorp *stCorps //攻击方攻击的敌方军团
var defEnemyCorp *stCorps //防守方攻击的敌方军团
//攻击方选择己方攻击军团及敌方被攻击军团
for atkIndex := proto.CorpsPos(index); atkIndex <= proto.CorpsPos_CP_SKY; atkIndex++ {
if lst, ok := cloneAtkUnitData[atkIndex]; ok {
bFind := false
for tnIdx := tn; tnIdx < 5; tnIdx++ {
if lst[tnIdx] != nil && lst[tnIdx].curAllUnitNum != uint32(0) {
atkCorp = lst[tnIdx]
atkEnemyCorp = getEnemyCorps(atkCorp.unitType, atkCorp.specialBuff, defBaseData.formation)
cloneAtkUnitData[atkIndex][tnIdx] = nil
bFind = true
break
}
}
if bFind {
break
}
}
}
//防守方选择己方攻击军团及敌方被攻击军团
for defIndex := proto.CorpsPos(index); defIndex <= proto.CorpsPos_CP_SKY; defIndex++ {
if lst, ok := cloneDefUnitData[defIndex]; ok {
bFind := false
for tnIdx := tn; tnIdx < 5; tnIdx++ {
if lst[tnIdx] != nil && lst[tnIdx].curAllUnitNum != uint32(0) {
defCorp = lst[tnIdx]
defEnemyCorp = getEnemyCorps(defCorp.unitType, defCorp.specialBuff, atkBaseData.formation)
cloneDefUnitData[defIndex][tnIdx] = nil
bFind = true
break
}
}
if bFind {
break
}
}
}
//进攻方进攻
var atkDamage float64 //进攻方造成的伤害
//更新参战军团的属性
ProcessUnitAttribute(targetType, atkCorp, atkBaseData.globalAttribute, commonBattleParm, false, true)
ProcessUnitAttribute(0, atkEnemyCorp, defBaseData.globalAttribute, commonBattleParm, true, true)
ProcessUnitAttribute(0, defCorp, defBaseData.globalAttribute, commonBattleParm, defBaseData.actionBaseType == actionBase_Def, true)
ProcessUnitAttribute(targetType, defEnemyCorp, atkBaseData.globalAttribute, commonBattleParm, atkBaseData.actionBaseType == actionBase_Def, true)
if (nil != atkEnemyCorp) && (nil == defCorp || defCorp.unitType != atkEnemyCorp.unitType) {
ProcessUnitAttribute(targetType, atkEnemyCorp, atkBaseData.globalAttribute, commonBattleParm, false, true)
}
isOnly := isOnlyCorp(defBaseData, atkEnemyCorp)
atkCorpPer := getAtkCorpPer(atkBaseData, atkCorp)
//如果城墙还有血,战斗单位必须打城墙
if nil != defBaseData.wall && defBaseData.wall.curWallHp != 0 && nil != atkCorp {
if _, ok := atkCorp.fightBuff[uint32(proto.FightBuffAttibute_Dizzy)]; !ok {
isRear := isRear(atkCorp.specialBuff)
if !isRear {
_, atkDamage = unitFightUnitDamage(atkBaseData, defBaseData, atkCorp, nil,
commonBattleParm, defBaseData.wall, false, targetType, atkCorp.specialBuff, false, atkCorpPer)
if defBaseData.wall.curWallHp <= uint64(atkDamage) {
defBaseData.wall.curWallHp = 0
} else {
defBaseData.wall.curWallHp -= uint64(atkDamage)
}
atkDamage = 0
} else {
//进攻军团产生的伤害
_, atkDamage = unitFightUnitDamage(atkBaseData, defBaseData, atkCorp, atkEnemyCorp,
commonBattleParm, nil, false, targetType, atkCorp.specialBuff, isOnly, atkCorpPer)
}
}
} else if nil != atkCorp {
//进攻军团产生的伤害
if _, ok := atkCorp.fightBuff[uint32(proto.FightBuffAttibute_Dizzy)]; !ok {
_, atkDamage = unitFightUnitDamage(atkBaseData, defBaseData, atkCorp, atkEnemyCorp,
commonBattleParm, nil, false, targetType, atkCorp.specialBuff, isOnly, atkCorpPer)
}
}
//防御方攻击
var defDamage float64 //防守方造成的伤害
if (nil != defEnemyCorp) && (nil == atkCorp || atkCorp.unitType != defEnemyCorp.unitType) {
ProcessUnitAttribute(0, defEnemyCorp, defBaseData.globalAttribute, commonBattleParm, defBaseData.actionBaseType == actionBase_Def, true)
}
isOnly = isOnlyCorp(atkBaseData, defEnemyCorp)
atkCorpPer = getAtkCorpPer(defBaseData, defCorp)
//如果城墙还有血,防御方只有飞机和坦火炮可以攻击
if nil != defBaseData.wall && defBaseData.wall.curWallHp != 0 {
if nil != defCorp &&
(defCorp.unitType == proto.UnitBattleType_UBT_NOMAL_HUOPAO || (defCorp.unitType == proto.UnitBattleType_UBT_NOMAL_FEIJI)) {
if _, ok := defCorp.fightBuff[uint32(proto.FightBuffAttibute_Dizzy)]; !ok {
//防守军团产生的伤害
_, defDamage = unitFightUnitDamage(defBaseData, atkBaseData, defCorp, defEnemyCorp,
commonBattleParm, nil, false, targetType, defCorp.specialBuff, isOnly, atkCorpPer)
}
}
} else {
if nil != defCorp {
if _, ok := defCorp.fightBuff[uint32(proto.FightBuffAttibute_Dizzy)]; !ok {
//防守军团产生的伤害
_, defDamage = unitFightUnitDamage(defBaseData, atkBaseData, defCorp, defEnemyCorp,
commonBattleParm, nil, false, targetType, defCorp.specialBuff, isOnly, atkCorpPer)
}
}
}
//根据伤害扣除战斗单位
atkLost, _ := reduceCorpUnitsByHp(defEnemyCorp, defDamage) //进攻方损失
defLost, _ := reduceCorpUnitsByHp(atkEnemyCorp, atkDamage) //防守方损失
//进攻方军团记录战斗信息
if nil != atkCorp && nil != defLost {
atkCorpBattleInfo := recordCropsBattleInfo(atkCorp, nil, defLost) //进攻方击杀
atkBaseData.roundBaseInfo.CorpList = append(atkBaseData.roundBaseInfo.CorpList, atkCorpBattleInfo)
}
if nil != defEnemyCorp && nil != atkLost {
atkCorpBattleInfo := recordCropsBattleInfo(defEnemyCorp, atkLost, nil) //进攻方损失
atkBaseData.roundBaseInfo.CorpList = append(atkBaseData.roundBaseInfo.CorpList, atkCorpBattleInfo)
}
//防守方军团记录战斗信息
if nil != defCorp && nil != atkLost {
defCorpBattleInfo := recordCropsBattleInfo(defCorp, nil, atkLost) //防守方击杀
defBaseData.roundBaseInfo.CorpList = append(defBaseData.roundBaseInfo.CorpList, defCorpBattleInfo)
}
if nil != atkEnemyCorp && nil != defLost {
defCorpBattleInfo := recordCropsBattleInfo(atkEnemyCorp, defLost, nil) //防守方损失
defBaseData.roundBaseInfo.CorpList = append(defBaseData.roundBaseInfo.CorpList, defCorpBattleInfo)
}
atkCorp = nil
atkEnemyCorp = nil
defCorp = nil
defEnemyCorp = nil
}
}
return battleRlt_Continue
}
// 判断特殊技能 是否改变攻击对象顺序
func isRear(specialBuff []*stFightBuff) bool {
isRear := false
for _, buff := range specialBuff {
if buff.csvIndex == int32(proto.FightBuffAttibute_AttRear) {
rand := common.GetRandomNum(10000)
if rand <= int32(buff.params[0]) {
isRear = true
}
}
}
return isRear
}
// 是否攻击对象是防御方里存活唯一的部队
func isOnlyCorp(defBaseData *stBattleActionBaseData, atkEnemyCorp *stCorps) bool {
tmp := make([]*stCorps, 0)
for _, v := range defBaseData.formation.unitData {
for _, tmpCorp := range v {
if tmpCorp != nil && tmpCorp.curAllUnitNum > 0 {
tmp = append(tmp, tmpCorp)
}
}
}
isOnly := false
if len(tmp) == 1 && atkEnemyCorp != nil && tmp[0].unitType == atkEnemyCorp.unitType {
isOnly = true
}
return isOnly
}
// 获取当前攻击部队在整个所有部队中的占比
func getAtkCorpPer(atkBaseData *stBattleActionBaseData, atkCorp *stCorps) uint32 {
if atkCorp == nil || atkBaseData == nil {
return 0
}
totalNum := uint32(0)
for _, v := range atkBaseData.formation.unitData {
for _, tmpCorp := range v {
if tmpCorp != nil {
totalNum += tmpCorp.curAllUnitNum
}
}
}
if totalNum > 0 {
return atkCorp.curAllUnitNum * 10000 / totalNum
}
return 0
}
/**
@brief 军团攻击是否命中
*/
func isHit(atkCorps *stCorps, defCorps *stCorps, commonBattleParm *stCommonBattleParm, atkGlobalAttribute map[uint64]uint64) bool {
/*公式
f(攻击方命中等级,受击方命中抵抗)= 攻击方命中等级÷(A×攻击方命中等级+B×受击方命中抵抗)×C;
攻击方兵团命中率 = max(Σ各途径命中率加值 + f(攻击方命中等级,受击方命中抵抗),命中率下限)
0 ≤ f(攻击方命中等级,受击方命中抵抗)≤ 100%
*/
if nil == atkCorps || nil == defCorps || nil == commonBattleParm {
return false
}
//陷阱百分百命中
if atkCorps.unitType >= proto.UnitBattleType_UBT_NOMAL_TRAP1 &&
atkCorps.unitType <= proto.UnitBattleType_UBT_NOMAL_TRAP2 {
return true
}
atkHitLevel := atkCorps.attributeMap[attribute_Hit]
defDodgeLevel := defCorps.attributeMap[attribute_Dodge]
parm := commonBattleParm.hitParm
baseHitRate := float64(atkHitLevel) /
(float64(parm[0])*float64(atkHitLevel)/10000 + float64(parm[1])*float64(defDodgeLevel)/10000) * float64(parm[3]) / 10000
addHitRate := float64(getHitRateAdditional(atkCorps.unitType, atkGlobalAttribute)) / 10000
finalHitRate := math.Max(baseHitRate+addHitRate, float64(parm[3])/10000)
randomRate := rand.Float64()
if finalHitRate < randomRate {
return false
}
return true
}
/**
@brief 军团攻击是否暴击
*/
func isBaoJi(atkCorps *stCorps, defCorps *stCorps, commonBattleParm *stCommonBattleParm, atkGlobalAttribute map[uint64]uint64) bool {
/*公式
f(攻击方暴击等级,受击方暴击抵抗)= 攻击方暴击等级÷(A×攻击方暴击等级+B×受击方暴击抵抗)×C
攻击方兵团暴击率 = min(Σ各途径暴击率加值 + f(攻击方暴击等级,受击方暴击抵抗),暴击率上限)
0 ≤ f(攻击方暴击等级,受击方暴击抵抗)≤ 100%
*/
if nil == atkCorps || nil == defCorps || nil == commonBattleParm {
return false
}
atkBaojiLevel := atkCorps.attributeMap[attribute_Crit]
defKangBaoLevel := defCorps.attributeMap[attribute_OpposeCrit]
parm := commonBattleParm.baoJiParm
baseCritRate := float64(atkBaojiLevel) /
(float64(parm[0])*float64(atkBaojiLevel)/10000 + float64(parm[1])*float64(defKangBaoLevel)/10000) * float64(parm[2]) / 10000
addCritRate := float64(getCritRateAdditional(atkCorps.unitType, atkGlobalAttribute)) / 10000
finalCritRate := math.Min(baseCritRate+addCritRate, float64(parm[3])/10000)
randomRate := rand.Float64()
if finalCritRate < randomRate {
return false
}
return true
}
/**
@brief 战斗单位之间的战斗流程
isOnly 防守方部队是否是唯一部队
atkCorpPer 进攻方部队人数,在所有部队中的占比
*/
func unitFightUnitDamage(atkBaseData, defBaseData *stBattleActionBaseData, atkCorps, defCorps *stCorps,
commonBattleParm *stCommonBattleParm, wall *stWall, calcBaseDamage bool, targetType uint32, specailBuff []*stFightBuff, isOnly bool, atkCorpPer uint32) (uint32, float64) {
//defCorps为nil ,则意味着打的是城墙
if nil == atkCorps || nil == commonBattleParm || nil == atkBaseData || nil == defBaseData {
return fightRlt_None, 0
}
if uint32(0) == atkCorps.curAllUnitNum {
return fightRlt_None, 0
}
//是否命中
if nil != defCorps && false == isHit(atkCorps, defCorps, commonBattleParm, atkBaseData.globalAttribute) {
return fightRlt_Miss, 0
}
parm := commonBattleParm.battleDamageParm
damageRateLimit := commonBattleParm.attriDamageLimit
atk := float64(atkCorps.attributeMap[attribute_Atk])
def := float64(0)
if nil != defCorps {
def = float64(defCorps.attributeMap[attribute_Def])
} else if nil != wall {
def = float64(wall.wallDef)
}
/*
基础伤害 = k*(攻击方攻击+m)^2/(攻击方攻击*P+防守方防御*Q)
*/
reduceDef := uint64(0)
addDamageParam := uint32(0)
for _, buff := range specailBuff {
if buff.csvIndex == int32(proto.FightBuffAttibute_IgnoreDef) {
reduceDef += uint64(buff.params[0])
} else if buff.csvIndex == int32(proto.FightBuffAttibute_EneNum) {
if isOnly {
addDamageParam += buff.params[0]
}
} else if buff.csvIndex == int32(proto.FightBuffAttibute_UnitnumDamage) && atkCorpPer > 0 {
if atkCorpPer >= buff.params[0] {
addDamageParam += buff.params[1]
}
}
}
if reduceDef > 10000 {
reduceDef = 10000
}
damage := float64(parm[0]) / 10000 * math.Pow(atk+float64(parm[1])/10000, 2) / ((atk*float64(parm[2]) + def*float64(parm[3])*float64(10000-reduceDef)/10000) / 10000)
if false == calcBaseDamage {
//是否暴击
if isBaoJi(atkCorps, defCorps, commonBattleParm, atkBaseData.globalAttribute) {
damage = damage * float64(commonBattleParm.critDamageParm) / 100
}
/*
伤害加减
加成减免后伤害=暴击后伤害×(1+伤害加成-伤害减免)
*/
add := getDamageAdd(defBaseData.actionBaseType, commonBattleParm, atkBaseData, defBaseData, atkCorps.fightBuff, targetType)
add += uint64(addDamageParam)
reduce := uint64(0)
if nil != defCorps {
reduce = getDamageReduce(atkBaseData.actionBaseType, commonBattleParm, defBaseData.globalAttribute, defCorps.fightBuff, targetType)
}
damageRate := float64(10000 + int64(add) - int64(reduce))
damageRate = math.Max(float64(damageRateLimit[0]), damageRate)
damageRate = math.Min(float64(damageRateLimit[1]), damageRate)
damage = damage * damageRate / 10000
/*
克制
【最终伤害】=【加成减免后伤害】× 克制系数
*/
if nil != defCorps {
if atkV, atkOk := commonBattleParm.unitRestrainParm[int64(atkCorps.unitType)]; atkOk {
if defV, defOk := atkV.damageParm[uint32(defCorps.unitType)]; defOk {
//向上取整,避免出现无法击杀最后一个单位的情况
damage = damage * float64(defV) / 100
}
}
}
}
return fightRlt_Hit, damage
}
/**
@brief 处理技能CD事件
*/
func processSkillCD(baseData *stBattleActionBaseData) {
if nil == baseData {
return
}
for _, hero := range baseData.heroList {
for k, v := range hero.skillCDList {
if v == uint32(0) {
delete(hero.skillCDList, k)
} else if v > 0 {
hero.skillCDList[k] -= 1
}
}
}
}
/**
@brief 获取当前类型最高等级的兵种ID
*/
func getMaxUnitInfo(corps []*stCorps) *proto.ST_ShowUnit_PB {
tmpShowUnit := &proto.ST_ShowUnit_PB{
ShowUnitType: proto.SetUint32(0),
ShowUnitID: proto.SetInt64(0),
}
for i := len(corps) - 1; i >= 0; i-- {
corp := corps[i]
if nil == corp {
continue
}
tmpShowUnit.ShowUnitType = proto.SetUint32(uint32(corp.unitType))
maxLevel := int64(1)
for _, unit := range corp.startUnits {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unit.GetUnitid()))
if nil == unitCSV {
continue
}
if maxLevel <= unitCSV.Quality {
maxLevel = unitCSV.Quality
tmpShowUnit.ShowUnitID = proto.SetInt64(unitCSV.ID)
}
if int64(4) == maxLevel {
return tmpShowUnit
}
}
}
return tmpShowUnit
}
/**
@brief 开始战斗
*/
func startBattle(targetType uint32, atkBaseData, defBaseData *stBattleActionBaseData,
commonBattleParm *stCommonBattleParm) (uint32, *proto.ST_BattleInfo_PB) {
var (
//返回值
battleRlt uint32 //进攻方是否获胜,0:逻辑错误 1:胜利 2:失败
battleInfo *proto.ST_BattleInfo_PB //战斗回放信息
)
battleRlt = battleRlt_Error
battleInfo = &proto.ST_BattleInfo_PB{}
if uint32(0) == targetType || nil == atkBaseData || nil == defBaseData ||
nil == commonBattleParm || nil == atkBaseData.formation || nil == defBaseData.formation {
return battleRlt, nil
}
battleInfo.TargetType = proto.SetUint32(targetType)
//阵型
battleInfo.AtkFormation = proto.SetUint32(atkBaseData.formation.id)
battleInfo.DefFormation = proto.SetUint32(defBaseData.formation.id)
//攻击方战斗起始的简单信息
atkSimpleStartInfo := &proto.ST_SimpleStartInfo_PB{
AllStartPower: proto.SetUint64(getAllPower(atkBaseData)),
StartHeroList: make([]uint32, 0),
StartUnitList: make([]*proto.ST_UnitCount_PB, 0),
ShowUnit: make([]*proto.ST_ShowUnit_PB, 0),
}
for _, hero := range atkBaseData.heroList {
atkSimpleStartInfo.StartHeroList = append(atkSimpleStartInfo.StartHeroList, hero.heroID)
if atkBaseData.userData != nil {
atkBaseData.userData.WithHeroAsset(true, hero.heroID, func(heroAsset *proto.ST_HeroEntry_PB) bool {
atkSimpleStartInfo.HeroPower = proto.SetUint64(atkSimpleStartInfo.GetHeroPower() + heroAsset.GetPower())
return false
})
}
}
for _, v := range atkBaseData.formation.unitData {
total := uint32(0)
var unitType proto.UnitBattleType
for _, corp := range v {
if nil != corp {
total += corp.curAllUnitNum
unitType = corp.unitType
}
}
if total > 0 {
unitCount := &proto.ST_UnitCount_PB{
UnitType: proto.SetUint32(uint32(unitType)),
UnitCount: proto.SetUint32(total),
}
atkSimpleStartInfo.StartUnitList = append(atkSimpleStartInfo.StartUnitList, unitCount)
}
tmpShowUnit := getMaxUnitInfo(v)
atkSimpleStartInfo.ShowUnit = append(atkSimpleStartInfo.ShowUnit, tmpShowUnit)
}
for _, v := range atkBaseData.formation.trapsData {
for _, trap := range v {
if nil != trap {
unitCount := &proto.ST_UnitCount_PB{
UnitType: proto.SetUint32(uint32(trap.unitType)),
UnitCount: proto.SetUint32(trap.curAllUnitNum),
}
atkSimpleStartInfo.StartUnitList = append(atkSimpleStartInfo.StartUnitList, unitCount)
}
}
}
battleInfo.AtkSimpleStartInfo = atkSimpleStartInfo
//防御方战斗起始的简单信息
defSimpleStartInfo := &proto.ST_SimpleStartInfo_PB{
AllStartPower: proto.SetUint64(getAllPower(defBaseData)),
StartHeroList: make([]uint32, 0),
StartUnitList: make([]*proto.ST_UnitCount_PB, 0),
ShowUnit: make([]*proto.ST_ShowUnit_PB, 0),
}
if defBaseData.wall != nil {
defSimpleStartInfo.WallLevel = proto.SetUint32(defBaseData.wall.wallLevel)
}
//城墙
if nil != defBaseData.wall {
defSimpleStartInfo.StartWallHp = proto.SetUint64(defBaseData.wall.startWallHp)
}
for _, hero := range defBaseData.heroList {
defSimpleStartInfo.StartHeroList = append(defSimpleStartInfo.StartHeroList, hero.heroID)
if defBaseData.userData != nil {
defBaseData.userData.WithHeroAsset(true, hero.heroID, func(heroAsset *proto.ST_HeroEntry_PB) bool {
defSimpleStartInfo.HeroPower = proto.SetUint64(defSimpleStartInfo.GetHeroPower() + heroAsset.GetPower())
return false
})
}
}
for _, v := range defBaseData.formation.unitData {
total := uint32(0)
var unitType proto.UnitBattleType
for _, corp := range v {
if nil != corp {
total += corp.curAllUnitNum
unitType = corp.unitType
}
}
if total > 0 {
unitCount := &proto.ST_UnitCount_PB{
UnitType: proto.SetUint32(uint32(unitType)),
UnitCount: proto.SetUint32(total),
}
defSimpleStartInfo.StartUnitList = append(defSimpleStartInfo.StartUnitList, unitCount)
}
tmpShowUnit := getMaxUnitInfo(v)
defSimpleStartInfo.ShowUnit = append(defSimpleStartInfo.ShowUnit, tmpShowUnit)
}
for _, v := range defBaseData.formation.trapsData {
total := uint32(0)
var unitType proto.UnitBattleType
for _, corp := range v {
if nil != corp {
total += corp.curAllUnitNum
unitType = corp.unitType
}
}
if total > 0 {
unitCount := &proto.ST_UnitCount_PB{
UnitType: proto.SetUint32(uint32(unitType)),
UnitCount: proto.SetUint32(total),
}
defSimpleStartInfo.StartUnitList = append(defSimpleStartInfo.StartUnitList, unitCount)
}
tmpShowUnit := getMaxUnitInfo(v)
defSimpleStartInfo.ShowUnit = append(defSimpleStartInfo.ShowUnit, tmpShowUnit)
}
battleInfo.DefSimpleStartInfo = defSimpleStartInfo
isEnd := false
for round := uint32(0); round < commonBattleParm.maxbattleRound; round++ {
atkBaseData.roundBaseInfo = &proto.ST_RoundBaseInfo_PB{
HeroList: make([]*proto.ST_HeroBattleInfo_PB, 0),
CorpList: make([]*proto.ST_CorpBattleInfo_PB, 0),
}
defBaseData.roundBaseInfo = &proto.ST_RoundBaseInfo_PB{
HeroList: make([]*proto.ST_HeroBattleInfo_PB, 0),
CorpList: make([]*proto.ST_CorpBattleInfo_PB, 0),
}
//---------记录回合开始前的信息-------
//战斗力
atkBaseData.roundBaseInfo.CurPower = proto.SetUint64(getAllPower(atkBaseData))
defBaseData.roundBaseInfo.CurPower = proto.SetUint64(getAllPower(defBaseData))
//城墙
if nil != defBaseData.wall {
defBaseData.roundBaseInfo.WallHp = &proto.ST_WallReport_PB{
BeforeHp: proto.SetUint32(uint32(defBaseData.wall.startWallHp)),
AfterHp: proto.SetUint32(uint32(defBaseData.wall.curWallHp)),
}
}
//---------记录回合开始前的信息-------
//处理技能CD
processSkillCD(atkBaseData)
processSkillCD(defBaseData)
//处理战斗buff
processFightBuff(atkBaseData, defBaseData, 0)
processFightBuff(defBaseData, atkBaseData, 0)
battleRlt = checkBattleRlt(atkBaseData, defBaseData)
if battleRlt_Continue != battleRlt {
isEnd = true
goto end
}
//处理英雄战斗
battleRlt = processHeroFight(targetType, atkBaseData, defBaseData, commonBattleParm)
if battleRlt_Continue != battleRlt {
isEnd = true
goto end
}
//处理军团战斗
battleRlt = processCorpsFight(targetType, atkBaseData, defBaseData, commonBattleParm)
if battleRlt_Continue != battleRlt {
isEnd = true
goto end
}
end:
//---------记录回合结束后的信息----------
//战斗力
atkBaseData.roundBaseInfo.CurPower = proto.SetUint64(getAllPower(atkBaseData))
defBaseData.roundBaseInfo.CurPower = proto.SetUint64(getAllPower(defBaseData))
//城墙血量
if nil != defBaseData.wall {
defBaseData.roundBaseInfo.WallHp.AfterHp = proto.SetUint32(uint32(defBaseData.wall.curWallHp))
}
battleRoundInfo := &proto.ST_BattleRoundInfo_PB{
Round: proto.SetUint32(round),
AtkRoundInfo: atkBaseData.roundBaseInfo,
DefRoundInfo: defBaseData.roundBaseInfo,
}
//---------记录回合结束后的信息----------
battleInfo.RoundInfo = append(battleInfo.RoundInfo, battleRoundInfo)
if isEnd {
break
}
}
if false == isEnd {
battleRlt = battleRlt_Over
}
return battleRlt, battleInfo
}
/**
@brief 准备英雄数据
*/
func prepareHeros(outBaseData *stBattleActionBaseData, uid uint64, heroIDList []uint32) bool {
if nil == outBaseData || 0 == uid {
return false
}
outBaseData.userData = cache.GetCharinfo(uid)
if nil == outBaseData.userData {
return false
}
//防守方城墙信息
if outBaseData.actionBaseType == actionBase_Def {
//需要从城墙资源获取
outBaseData.wall = &stWall{
startWallHp: uint64(GetCurDurable(outBaseData.userData)),
curWallHp: uint64(GetCurDurable(outBaseData.userData)),
wallDef: outBaseData.userData.GetWallDefValue(),
fightBuff: make(map[uint32]*stFightBuff),
}
level := outBaseData.userData.GetWallLevel()
outBaseData.wall.wallLevel = level
}
//拷贝全局属性,此属性会持续整个战斗过程
outBaseData.globalAttribute = outBaseData.userData.CopyAllAttribute()
//英雄信息
outBaseData.heroList = make([]*stHeroBattleInfo, 0)
if 0 == len(heroIDList) {
return true
}
for _, heroID := range heroIDList {
outBaseData.userData.WithHeroAsset(true, heroID, func(heroAsset *proto.ST_HeroEntry_PB) bool {
heroBattleInfo := &stHeroBattleInfo{}
heroBattleInfo.heroID = heroID
//heroBattleInfo.mainType = heroAsset.GetMaintype()
heroBattleInfo.level = heroAsset.GetLevel()
heroBattleInfo.star = heroAsset.GetStar()
//heroBattleInfo.rank = heroAsset.GetRank()
heroBattleInfo.fightBuff = make(map[uint32]*stFightBuff)
heroBattleInfo.skillCDList = make(map[uint32]uint32)
//英雄技能,只放(主动技能和被动特殊技能,后面处理完会删除被动特殊技能)
heroBattleInfo.skillList = make([]*proto.ST_HeroSkill_PB, 0)
for _, v := range heroAsset.GetSkillList() {
skillcsv := CSV.Mgr.CSV_HeroNewSkills.GetEntryPtr(int64(v.GetSkillID()))
if nil == skillcsv {
continue
}
// 初始化技能CD
heroBattleInfo.skillCDList[uint32(skillcsv.ID)] = uint32(skillcsv.CD)
heroBattleInfo.skillList = append(heroBattleInfo.skillList, proto.Clone(v).(*proto.ST_HeroSkill_PB))
}
heroBattleInfo.branceValue = make([]uint32, len(heroAsset.GetBranchValue()))
copy(heroBattleInfo.branceValue, heroAsset.GetBranchValue())
//把战斗被动技能加入全局属性中
MarchAtt := outBaseData.userData.CalcHeroSkillAttribute(heroAsset, proto.SkillSubType_ST_PASSIVE_FIGHT)
for k, v1 := range MarchAtt {
id := uint64(k)<<32 | uint64(proto.AttributeSource_Hero)
if v2, ok := outBaseData.globalAttribute[id]; ok {
outBaseData.globalAttribute[id] = v1 + v2
} else {
outBaseData.globalAttribute[id] = v1
}
}
// 把英雄4属性加入全局属性中
MarchAtt = outBaseData.userData.GetHeroBranchAttribute(heroAsset)
for k, v1 := range MarchAtt {
id := uint64(k)<<32 | uint64(proto.AttributeSource_Hero)
if v2, ok := outBaseData.globalAttribute[id]; ok {
outBaseData.globalAttribute[id] = v1 + v2
} else {
outBaseData.globalAttribute[id] = v1
}
}
outBaseData.heroList = append(outBaseData.heroList, heroBattleInfo)
return false
})
}
outBaseData.roundBaseInfo = &proto.ST_RoundBaseInfo_PB{}
return true
}
/**
@brief 准备军团数据
@parm:
actionid:主行为id 非大地图行为时,地块拥有者的行为ID都是0
childrenActionID:子行为id
units:当前行为军团信息
formationID:阵型
*/
func prepareUnits(mainActionID uint64, childrenActionID []uint64, units *proto.ST_UnitAsset_PB, formationID uint32) (bool,
*stFormation, map[uint64]*stUserUnitInfo) {
var (
//全部都为返回值
ok = true //结果
formation *stFormation //阵型兵力
orgiUnitAssetMap map[uint64]*stUserUnitInfo //记录多人攻击玩家的原始兵力资产 key:acitonid value:相关兵力资产
//以下不返回
formationRlt = false
analysisRlt = false
allUnits = &proto.ST_UnitAsset_PB{}
corpsMap = &stCorpsMap{}
tmpTotalPower = int64(0)
userUnitInfo *stUserUnitInfo //玩家兵力信息
tmpCorpPower = make(map[proto.UnitBattleType]int64) //各个军团合计的总战力(每个兵种一个军团)
tmpUnitPower = make(map[uint32]int64) //记录不同等级兵种各自的总战力
mainAsset *cache.GlobalActionEntry
tmpMainActionID uint64
)
if nil == units {
ok = false
goto endPrepareUnits
}
//把带头大哥和小弟的兵力加起来(allUnits),并分别记录(orgiUnitAssetMap)
common.CombineUnitAsset(allUnits, units)
orgiUnitAssetMap = make(map[uint64]*stUserUnitInfo)
userUnitInfo = analysisUnitAssetToUserUnitInfo(units)
userUnitInfo.isBigBrother = true
tmpTotalPower += userUnitInfo.totalPower
tmpMainActionID = mainActionID
//当为玩家主城防守方时,actionID为玩家ID
//其余时候为全局行为id
mainAsset = cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(mainActionID)
if mainAsset != nil {
userUnitInfo.charUID = mainAsset.Actiondata.GetUid()
} else {
userData := cache.GetCharinfo(mainActionID)
if nil != userData {
tmpMainActionID = 0
userUnitInfo.charUID = userData.GetUid()
}
}
orgiUnitAssetMap[tmpMainActionID] = userUnitInfo
if 0 != len(childrenActionID) {
for _, v := range childrenActionID {
if mainActionID == v {
continue
}
tmpAsset := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(v)
if tmpAsset == nil {
continue
}
common.CombineUnitAsset(allUnits, tmpAsset.Actiondata.GetUnits())
userUnitInfo = analysisUnitAssetToUserUnitInfo(tmpAsset.Actiondata.GetUnits())
userUnitInfo.isBigBrother = false
userUnitInfo.charUID = tmpAsset.Actiondata.GetUid()
tmpTotalPower += userUnitInfo.totalPower
orgiUnitAssetMap[v] = userUnitInfo
}
}
//开始计算玩家各个军团在整体军团中的战力比
for _, userUnitInfo := range orgiUnitAssetMap {
for corpType, corp := range userUnitInfo.unitMap {
if _, ok := tmpCorpPower[corpType]; !ok {
tmpCorpPower[corpType] = 0
}
for _, unitInfo := range corp {
tmpCorpPower[corpType] = tmpCorpPower[corpType] + unitInfo.power
if v, ok := tmpUnitPower[unitInfo.unit.GetUnitid()]; !ok {
tmpUnitPower[unitInfo.unit.GetUnitid()] = unitInfo.power
} else {
tmpUnitPower[unitInfo.unit.GetUnitid()] = v + unitInfo.power
}
}
}
}
for _, userUnitInfo := range orgiUnitAssetMap {
userUnitInfo.corpRatioMap = make(map[proto.UnitBattleType]float32, len(tmpCorpPower))
userUnitInfo.unitRatioMap = make(map[uint32]float32, len(tmpUnitPower))
for corpType, unitList := range userUnitInfo.unitMap {
selfCorpPower := int64(0) //一个军团的总战力
if corpTotalPower, ok := tmpCorpPower[corpType]; ok && int64(0) != corpTotalPower {
for _, unitInfo := range unitList {
selfCorpPower += unitInfo.power
}
userUnitInfo.corpRatioMap[corpType] = float32(selfCorpPower) / float32(corpTotalPower)
} else {
userUnitInfo.corpRatioMap[corpType] = 0
}
for _, unitInfo := range unitList {
if unitTotalPower, ok := tmpUnitPower[unitInfo.unit.GetUnitid()]; ok && int64(0) != unitTotalPower {
userUnitInfo.unitRatioMap[unitInfo.unit.GetUnitid()] = float32(unitInfo.power) / float32(unitTotalPower)
} else {
userUnitInfo.unitRatioMap[unitInfo.unit.GetUnitid()] = 0
}
}
}
}
//按类型解析兵力
analysisRlt = analysisUnitAssetToCorpsMap(corpsMap, allUnits)
if false == analysisRlt {
ok = false
goto endPrepareUnits
}
//再根据阵型设置军团位置
formationRlt, formation = setFormation(formationID, corpsMap)
if false == formationRlt {
ok = false
goto endPrepareUnits
}
//战斗单位单个战斗力
for _, v := range formation.unitData {
for _, corps := range v {
if corps == nil {
continue
}
corps.unitPower = make(map[uint32]uint64, len(corps.startUnits))
for _, unit := range corps.startUnits {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unit.GetUnitid()))
if nil == unitCSV {
continue
}
corps.unitPower[unit.GetUnitid()] = uint64(unitCSV.Power)
}
}
}
for _, v := range formation.trapsData {
for _, corps := range v {
if corps == nil {
continue
}
corps.unitPower = make(map[uint32]uint64, len(corps.startUnits))
for _, unit := range corps.startUnits {
unitCSV := CSV.Mgr.CSV_UnitConfig.GetEntryPtr(int64(unit.GetUnitid()))
if nil == unitCSV {
continue
}
corps.unitPower[unit.GetUnitid()] = uint64(unitCSV.Power)
}
}
}
endPrepareUnits:
return ok, formation, orgiUnitAssetMap
}
/**
@brief 准备战斗时的全局参数
*/
func perpareCommonBattleParm() *stCommonBattleParm {
if nil == CommonBattleParm {
commonBattleParm := &stCommonBattleParm{}
//最大战斗回合数
commonBattleParm.maxbattleRound = CSV.GetGameConfigValueUint32("MAX_BATTLE_ROUND")
//兵种克制
commonBattleParm.unitRestrainParm = make(map[int64]*stRestrainParm)
commonBattleParm.corpAtkOrder = make(map[int64]int64)
for _, k := range CSV.Mgr.CSV_UnitRestrain.GetIDList() {
csvRestrain := CSV.Mgr.CSV_UnitRestrain.GetEntryPtr(k)
if nil == csvRestrain {
continue
}
if _, ok := commonBattleParm.unitRestrainParm[csvRestrain.ID]; ok {
continue
}
restrainParm := &stRestrainParm{}
//先初始化一次,避免配置表少配
restrainParm.damageParm = map[uint32]uint32{1: 100, 2: 100, 3: 100, 4: 100, 5: 100, 6: 100, 7: 100, 8: 100, 9: 0, 10: 100}
commonBattleParm.unitRestrainParm[csvRestrain.ID] = restrainParm
parmList := common.ParseStringToUint32List(csvRestrain.RestraionParm)
for parmK, parmV := range parmList {
restrainParm.damageParm[uint32(parmK)+1] = parmV
}
commonBattleParm.corpAtkOrder[csvRestrain.ID] = csvRestrain.AtkOrder
}
//命中参数
commonBattleParm.hitParm = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("BATTLE_HIT_PARM"))
//暴击参数
commonBattleParm.baoJiParm = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("BATTLE_CRIT_PARM"))
//战斗伤害参数
commonBattleParm.battleDamageParm = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("BATTLE_DAMAGE_PARM"))
//暴击额外伤害
commonBattleParm.critDamageParm = CSV.GetGameConfigValueUint32("CRIT_DAMAGE_PARM")
//伤害加减范围
commonBattleParm.attriDamageLimit = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("ATTRI_DAMAGE_LIMIT"))
//特殊行为系数里的参数
commonBattleParm.skillSpecialParm = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("SKILL_SPECIAL_PARM"))
//攻击参数
commonBattleParm.atkParm = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("BATTLE_ATK_PARM"))
//防御参数
commonBattleParm.defParm = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("BATTLE_DEF_PARM"))
//陷阱自毁系数
commonBattleParm.trapLossParm = CSV.GetGameConfigValueUint32("BATTLE_TRAP_LOSS_PARM")
//血量衰减系数
commonBattleParm.hpParm = common.ParseStringToUint32List(
CSV.GetGameConfigValueString("BATTLE_HP_PARM"))
CommonBattleParm = commonBattleParm
}
return CommonBattleParm
}
/**
@brief 战斗准备
*/
func prepareBattlePara( /*dataEntry *proto.ST_GlobalActionEntry_PB*/ battleKey *stBattleKey) (bool,
uint32, *stBattleActionBaseData, *stBattleActionBaseData, *stCommonBattleParm,
*cache.WorldDataEntry, map[uint64]*stUserUnitInfo, map[uint64]*stUserUnitInfo) {
var (
//需要返回的变量
ok bool //结果
targetType uint32 //目标类型
atkBaseData *stBattleActionBaseData //攻击方战斗基本数据
defBaseData *stBattleActionBaseData //防守方战斗基本数据
commonBattleParm *stCommonBattleParm //用于各种公式计算的参数,攻守方通用
worldAssetData *cache.WorldDataEntry //目的地大地图信息
atkOrgiUnitAssetMap map[uint64]*stUserUnitInfo //记录多人攻击玩家的原始兵力资产 key:acitonid value:兵力资产
defOrgiUnitAssetMap map[uint64]*stUserUnitInfo //记录多人防御玩家的原始兵力资产
//无需返回的变量
herosRlt bool
wdata *proto.ST_WorldDataEntry_PB
csvWorldConfig *CSV.CF_WorldEntryConfig_DataEntry
entryType int64
monsterGroupID int64
mainAsset *cache.GlobalActionEntry
monsterAtk bool
)
ok = true
if nil == battleKey {
ok = false
goto endPrepareBattlePara
}
//准备进攻方数据
//进攻方玩家信息
atkBaseData = &stBattleActionBaseData{
actionBaseType: actionBase_Atk,
}
mainAsset = cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(battleKey.actionID)
if mainAsset != nil && mainAsset.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_MACATTCK) {
//怪物攻城
ocfg := CSV.Mgr.CSV_WorldEntryConfig.GetEntryPtr(mainAsset.Actiondata.GetMacMonsterId())
if ocfg == nil {
wlog.Error("CSV_WorldEntryConfig.GetEntryPtr return nil, id:", mainAsset.Actiondata.GetMacMonsterId())
goto endPrepareBattlePara
}
ok, base, def := getMacAtkInfo(battleKey, ocfg.MonsterID)
if !ok {
goto endPrepareBattlePara
}
base.monsterAtk = true
atkBaseData = base
atkOrgiUnitAssetMap = def
monsterAtk = true
} else {
//准备英雄及其技能信息
herosRlt = prepareHeros(atkBaseData, battleKey.UID, battleKey.heroIDList)
if false == herosRlt {
ok = false
goto endPrepareBattlePara
}
//进攻方阵型信息
ok, atkBaseData.formation, atkOrgiUnitAssetMap = prepareUnits(battleKey.actionID,
battleKey.childrenID, battleKey.units, battleKey.formation)
if false == ok {
goto endPrepareBattlePara
}
}
if int32(0) != battleKey.endTileID {
worldAssetData = cache.Instance_GlobalAssetWorldData.GetWorldDataByTileId(battleKey.endTileID)
if worldAssetData == nil {
ok = false
goto endPrepareBattlePara
}
//不允许目的地是自己或者公会的地块
if atkBaseData.userData != nil && isOurForce(atkBaseData.userData.GetUid(), atkBaseData.userData.GetLeagueID(), worldAssetData.GetWorldDataOwner(), worldAssetData.GetLeagueOwner()) {
ok = false
goto endPrepareBattlePara
}
wdata = worldAssetData.GetWorldData()
csvWorldConfig = worldAssetData.GetWorldEntryConfig()
if csvWorldConfig == nil {
ok = false
goto endPrepareBattlePara
}
entryType = csvWorldConfig.EntryType
if (entryType > int64(proto.WorldEntryType_WET_MINE_START) && entryType < int64(proto.WorldEntryType_WET_MINE_END)) ||
entryType == int64(proto.WorldEntryType_WET_BESTATIONED) {
if len(wdata.SimpleEntry.GetGActionList()) == 0 {
ok = false
goto endPrepareBattlePara
}
}
} else {
entryType = int64(proto.WorldEntryType_WET_WILDMONSTER)
monsterGroupID = battleKey.monsterGroupID
targetType = battleKey.targetType
}
//根据地块类型设置目标类型,
//根据不同的地块(即战斗场景)准备防御方的数据
//无论目标类型,进入这里都是要战斗的
switch entryType {
case int64(proto.WorldEntryType_WET_CITY):
fallthrough
case int64(proto.WorldEntryType_WET_CAPITAL_CITY):
fallthrough
case int64(proto.WorldEntryType_WET_SMALL_MIRACLE):
fallthrough
case int64(proto.WorldEntryType_WET_LEAGUE_Center):
fallthrough
case int64(proto.WorldEntryType_WET_BIG_MIRACLE):
{
var npcUnitAsset *proto.ST_UnitAsset_PB = nil
targetType = getWorldDataTargetType(worldAssetData)
npcUnitAsset = wdata.DetailEntry.Detail_City.GetNpcUnits()
defBaseData = &stBattleActionBaseData{
actionBaseType: actionBase_Def,
}
if nil != npcUnitAsset && 0 != len(npcUnitAsset.Units) {
defBaseData.actionBaseType = actionBase_Monster
ok, defBaseData.formation, defOrgiUnitAssetMap = prepareUnits(0, nil, npcUnitAsset, 0)
if false == ok {
goto endPrepareBattlePara
}
} else {
var mainGlobalActionEntry *proto.ST_GlobalActionEntry_PB = nil
actionIDList := make([]uint64, 0) //子行为id
for k, v := range wdata.SimpleEntry.GetGActionList() {
tmpasset := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(v)
if tmpasset == nil {
continue
}
if k == 0 {
mainGlobalActionEntry = tmpasset.Actiondata
ok = prepareHeros(defBaseData, mainGlobalActionEntry.GetUid(), mainGlobalActionEntry.GetHeroIDList())
defBaseData.wall = nil
if false == ok {
goto endPrepareBattlePara
}
}
if tmpasset.Actiondata.GetActiontype() == uint32(proto.ActionType_AT_WORLDMAP_GARRISON) &&
tmpasset.Actiondata.GetStage() == uint32(proto.MapStageType_MST_WORKING) {
actionIDList = append(actionIDList, tmpasset.Actiondata.GetActionid())
}
}
ok, defBaseData.formation, defOrgiUnitAssetMap = prepareUnits(mainGlobalActionEntry.GetActionid(),
actionIDList, mainGlobalActionEntry.GetUnits(), mainGlobalActionEntry.GetFormation())
if false == ok {
goto endPrepareBattlePara
}
}
}
case int64(proto.WorldEntryType_WET_MAINCITY):
{
targetType = targetMainCity
defBaseData = &stBattleActionBaseData{
actionBaseType: actionBase_Def,
}
defBaseData.userData = cache.GetCharinfo(wdata.SimpleEntry.GetUid())
//获取守城英雄ID
var defCityHeroList []uint32
defBaseData.userData.ForeachHero(true, func(heroAsset *proto.ST_HeroEntry_PB) bool {
if heroAsset == nil {
return false
}
if heroAsset.GetHeroStatus() == uint32(proto.HeroStatus_HS_DEFENSE) {
defCityHeroList = append(defCityHeroList, heroAsset.GetId())
}
return true
})
herosRlt := prepareHeros(defBaseData, wdata.SimpleEntry.GetUid(), defCityHeroList)
if false == herosRlt {
ok = false
goto endPrepareBattlePara
}
//防守方阵型信息
for _, v := range defBaseData.userData.CopyGarrisonList() {
//获取援助行为id
tmpGlobalAction := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(v)
if tmpGlobalAction == nil || tmpGlobalAction.Actiondata.GetStage() != uint32(proto.MapStageType_MST_WORKING) {
continue
}
}
ok, defBaseData.formation, defOrgiUnitAssetMap = prepareUnits(wdata.SimpleEntry.GetUid(),
defBaseData.userData.CopyGarrisonList(), defBaseData.userData.GetUnitAsset(), 0) //需要从玩家身上获取阵型
if monsterAtk {
defBaseData.monsterAtk = true
}
if false == ok {
goto endPrepareBattlePara
}
}
case int64(proto.WorldEntryType_WET_MUTIWILDMONSTER):
fallthrough
case int64(proto.WorldEntryType_WET_WILDMONSTER):
fallthrough
case int64(proto.WorldEntryType_WET_SUMMON_MUTIWILDMONSTER):
fallthrough
case int64(proto.WorldEntryType_WET_WILDMONSTEREX):
{
defBaseData = &stBattleActionBaseData{
actionBaseType: actionBase_Monster,
}
if targetType == uint32(targetUnUse) {
targetType = getWorldDataTargetType(worldAssetData)
monsterGroupID = csvWorldConfig.MonsterID
}
//获取怪物的城墙,英雄,战斗单位信息
ok, wall, heroList, unitAsset, formationId, globalAttribute, _, _ := getMonsterBattleUnitInfo(monsterGroupID)
if false == ok {
ok = false
goto endPrepareBattlePara
}
defBaseData.monsterGroupID = monsterGroupID
defBaseData.heroList = heroList
defBaseData.wall = wall
defBaseData.globalAttribute = globalAttribute
ok, defBaseData.formation, defOrgiUnitAssetMap = prepareUnits(0, nil, unitAsset, formationId)
}
case int64(proto.WorldEntryType_WET_BESTATIONED):
{
targetType = targetBestationed
defBaseData = &stBattleActionBaseData{
actionBaseType: actionBase_Def,
}
defBaseData.userData = cache.GetCharinfo(wdata.SimpleEntry.GetUid())
herosRlt := prepareHeros(defBaseData, wdata.SimpleEntry.GetUid(), worldAssetData.GetBeStationedHero())
defBaseData.wall = nil
if false == herosRlt {
ok = false
goto endPrepareBattlePara
}
//防守方阵型信息
for _, k := range worldAssetData.GetGActionList() {
if k == battleKey.actionID {
continue
}
//获取驻扎行为的actionid
tmpGlobalAction := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(k)
if tmpGlobalAction == nil || tmpGlobalAction.Actiondata.GetActiontype() != uint32(proto.ActionType_AT_WORLDMAP_BESTATIONED) {
continue
}
ok, defBaseData.formation, defOrgiUnitAssetMap = prepareUnits(k,
nil, tmpGlobalAction.Actiondata.GetUnits(), worldAssetData.GetBeStationedFormation())
break
}
if false == ok {
goto endPrepareBattlePara
}
}
case int64(proto.WorldEntryType_WET_MINE_COKE):
fallthrough
case int64(proto.WorldEntryType_WET_MINE_CRYSTAL):
fallthrough
case int64(proto.WorldEntryType_WET_MINE_DEUTERIUM):
fallthrough
case int64(proto.WorldEntryType_WET_MINE_GAS):
fallthrough
case int64(proto.WorldEntryType_WET_MINE_METAL):
fallthrough
case int64(proto.WorldEntryType_WET_MINE_GEM):
{
//targetType = targetMine
targetType = getWorldDataTargetType(worldAssetData)
if len(wdata.SimpleEntry.GetGActionList()) == 0 {
ok = false
goto endPrepareBattlePara
}
var mainGlobalActionEntry *proto.ST_GlobalActionEntry_PB = nil
targetSubActionIDList := make([]uint64, 0) //目标子行为id
for _, v := range wdata.SimpleEntry.GetGActionList() {
tmpasset := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(v)
if tmpasset == nil {
continue
}
//不管地块上非采集的行为
if tmpasset.Actiondata.GetActiontype() != uint32(proto.ActionType_AT_WORLDMAP_COLLECT) {
continue
}
//排除掉自己在此地块上的行为
if tmpasset.Actiondata.GetActionid() == battleKey.actionID {
continue
}
tmpUser := cache.GetCharinfo(tmpasset.Actiondata.GetUid())
if nil == tmpUser {
continue
}
//采集点上不是自己人,则开战
var needBattle bool = false
if atkBaseData.userData.GetLeagueID() != tmpasset.Actiondata.GetLeagueID() {
needBattle = true
}
if atkBaseData.userData.GetLeagueID() == 0 || tmpasset.Actiondata.GetLeagueID() == 0 {
needBattle = true
}
if nil == mainGlobalActionEntry {
//准备防御方的英雄及其技能信息
//只取第一个玩家的信息
defBaseData = &stBattleActionBaseData{
actionBaseType: actionBase_Def,
}
mainGlobalActionEntry = tmpasset.Actiondata
herosRlt := prepareHeros(defBaseData, mainGlobalActionEntry.GetUid(), mainGlobalActionEntry.GetHeroIDList())
defBaseData.wall = nil
if false == herosRlt {
ok = false
goto endPrepareBattlePara
}
} else if needBattle && nil != mainGlobalActionEntry {
targetSubActionIDList = append(targetSubActionIDList, tmpasset.Actiondata.GetActionid())
}
}
if mainGlobalActionEntry != nil {
ok, defBaseData.formation, defOrgiUnitAssetMap = prepareUnits(mainGlobalActionEntry.GetActionid(),
targetSubActionIDList, mainGlobalActionEntry.GetUnits(), mainGlobalActionEntry.GetFormation())
}
if false == ok {
goto endPrepareBattlePara
}
}
default:
ok = false
}
// 处理英雄特殊被动技能
if ok {
prepareHeroSpecialPassiveSkill(atkBaseData)
prepareHeroSpecialPassiveSkill(defBaseData)
}
//准备战斗全局的固定参数
commonBattleParm = perpareCommonBattleParm()
endPrepareBattlePara:
return ok, targetType, atkBaseData, defBaseData, commonBattleParm,
worldAssetData, atkOrgiUnitAssetMap, defOrgiUnitAssetMap
}
func prepareHeroSpecialPassiveSkill(atkBaseData *stBattleActionBaseData) {
if nil == atkBaseData || atkBaseData.heroList == nil {
return
}
for _, hero := range atkBaseData.heroList {
tmpSkill := make([]*proto.ST_HeroSkill_PB, 0)
for _, skill := range hero.skillList {
skillCsv := CSV.Mgr.CSV_HeroNewSkills.GetEntryPtr(int64(skill.GetSkillID()))
if skillCsv != nil && skillCsv.SkillType == int64(proto.SkillMainType_ST_PASSIVE) {
tmpMap := common.ParseParameterStringToMap(skillCsv.SkillEffect)
tmpMap1 := common.ParseParameterStringToMap(skillCsv.SkillSubType)
extraMap := common.ParseParameterStringToMap(skillCsv.ExtraParam)
for k, v := range tmpMap {
subType, ok := tmpMap1[k]
if !ok || common.StringToUint32(subType) != uint32(proto.SkillSubType_ST_PASSIVE_BUFF) {
continue
}
if buffType, ok := proto.FightBuffAttibute_value[k]; ok {
// 单位攻击顺序buff
params := common.ParseStringToUint32List(v) //
if len(params) != 3 {
wlog.Error("skill skillEffect err", skillCsv.ID)
continue
}
value, ok := extraMap[k]
if !ok {
wlog.Error("skill skillEffect err", skillCsv.ID)
continue
}
extraParam := common.ParseStringToUint32List(value)
_, heros, corps, traps := getEffectTarget(proto.UnitBattleType_UBT_NOMAL_NONE, params[0], atkBaseData, hero)
for _, corp := range corps {
corp.specialBuff = addSpecialBuff(hero, buffType, skillCsv, extraParam, corp.specialBuff)
}
for _, trap := range traps {
trap.specialBuff = addSpecialBuff(hero, buffType, skillCsv, extraParam, trap.specialBuff)
}
for _, heroInfo := range heros {
heroInfo.specialBuff = addSpecialBuff(hero, buffType, skillCsv, extraParam, heroInfo.specialBuff)
}
}
}
} else {
tmpSkill = append(tmpSkill, skill)
}
}
hero.skillList = tmpSkill
}
}
func addSpecialBuff(hero *stHeroBattleInfo, buffType int32, skillCsv *CSV.CF_HeroNewSkills_DataEntry, params []uint32, buffs []*stFightBuff) []*stFightBuff {
var buff *stFightBuff
for _, v := range buffs {
if v.csvIndex == buffType {
buff = v
break
}
}
if buff != nil {
replace := false
switch buffType {
case int32(proto.FightBuffAttibute_AttConversion), int32(proto.FightBuffAttibute_UnitnumDamage):
buff = nil
case int32(proto.FightBuffAttibute_AttRear), int32(proto.FightBuffAttibute_IgnoreDef):
if buff.params[0] < params[0] {
replace = true
}
case int32(proto.FightBuffAttibute_EneNum):
if buff.params[0] < params[0] {
replace = true
}
}
if replace {
buff.heroID = hero.heroID
buff.csvIndex = buffType
buff.orgiSkillID = skillCsv.ID
//buff.effectValue = uint64(params[2])
buff.params = params
}
}
if buff == nil {
buff = &stFightBuff{}
buff.heroID = hero.heroID
buff.csvIndex = buffType
buff.orgiSkillID = skillCsv.ID
//buff.effectValue = uint64(params[2])
buff.params = params
buffs = append(buffs, buff)
}
return buffs
}
/**
@brief 获取行为的目的地类型
*/
func getBattleTargetType(dataEntry *proto.ST_GlobalActionEntry_PB) uint32 {
worldAssetData := cache.Instance_GlobalAssetWorldData.GetWorldDataByTileId(dataEntry.GetEndTileID())
if worldAssetData == nil {
return targetUnUse
}
return getWorldDataTargetType(worldAssetData)
}
/**
@brief 计算战后大奇迹援军的兵力(老逻辑,未完成)
*/
func calcBigMiracleGarrsonCapAfterBattle(cityData *cache.WorldDataEntry) {
if nil == cityData {
return
}
actionIds := cityData.CopyGActionList()
if len(actionIds) <= 0 {
return
}
actionData := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(actionIds[0])
if actionData == nil || actionData.Actiondata == nil {
return
}
userData := cache.GetCharinfo(actionData.Actiondata.GetUid())
if nil == userData {
return
}
details := make([]uint64, 0)
function := userData.GetBuildingFuctionByConfigType(int64(proto.BuildingType_BT_COMMAND))
capability := common.StringToUint64(function["capability"])
capability = countAdditional(capability, userData, proto.AtttibuteType_MaxAggregation) // 1003;//联盟集结上限(百分比)
var totalCount uint64
for _, v := range actionIds {
tmpAction := cache.Instance_GlobalAssetGlobalAction.GetGlobalActionAsset(v)
if tmpAction == nil || tmpAction.Actiondata == nil {
continue
}
totalCount += countUnitNum(tmpAction.Actiondata.GetUnits())
}
details = append(details, capability)
details = append(details, totalCount)
actionData.Actiondata.Details = details
actionData.Dirty()
}
/**
@brief 战斗后处理主城监狱资产
*/
func processPrisonAfterBattle(atkInfos []*proto.ST_BattleReportDetail_PB, attUserData, defUserData *cache.Info) {
if attUserData == nil || defUserData == nil {
return
}
// 释放领主
tmpList := make(map[uint64]uint32, 0)
totalAttAttack := int64(0)
defUserData.ForeachPrison(true, func(prison *proto.ST_Prison_PB) bool {
if ok, _, bounty := releaseCommanderInPrison(defUserData, prison, 1, attUserData); ok {
tmpList[prison.GetOwner()] = 0
//瓜分赏金
if totalAttAttack == 0 {
for _, v := range atkInfos {
totalAttAttack += v.GetTotalPower()
}
}
if 0 == totalAttAttack {
return true
}
for _, v := range atkInfos {
tmpUser := cache.GetCharinfo(v.GetCommanderReport().GetUid())
if nil != tmpUser {
hijacker := &oss.PrisonHijacker{
Publisher: defUserData.GetUid(),
Recipient: uint64(prison.GetHeroId()),
}
if nil != bounty && bounty.GetW() > 0 {
reward := proto.Clone(bounty).(*proto.ST_Vector4Int_PB)
value := int64(bounty.GetW()) * v.GetTotalPower() / totalAttAttack
if value == 0 {
value = 1
}
reward.W = proto.SetInt32(int32(value))
hijacker.ItemNum = uint32(value)
hijacker.ItemID = uint32(reward.GetY())
statistAsset := tmpUser.GetStatisticsAsset()
statistAsset.UpdateGetRewardNumber(uint64(value))
tmpUser.AddVec4ResourceList([]*proto.ST_Vector4Int_PB{reward}, 1, oss.AddCashSrcBounty)
wlog.Info("分赏金 ", tmpUser.GetUid(), reward)
}
newOssPrison(tmpUser, nil, "", uint32(oss.PAT_Hijack), nil, hijacker)
}
}
}
return true
})
for k := range tmpList {
defUserData.DeletePrisonAsset(k)
}
}
/**
@brief 战斗后处理指挥官抓捕逻辑
*/
func captureCommander(attUserData, defUserData *cache.Info, result bool, targetType uint32) (map[uint64][]*proto.ST_Vector4Int_PB, map[uint64]uint32) {
var (
ret map[uint64][]*proto.ST_Vector4Int_PB
)
beCaptureheroMap := make(map[uint64]uint32, 0)
ret = make(map[uint64][]*proto.ST_Vector4Int_PB)
// 只有进攻主城胜利才抓领主
if !result || targetType != targetMainCity || defUserData == nil || attUserData == nil {
return ret, beCaptureheroMap
}
// 防守方主城等级限制
if defUserData.GetMainCityLevel() < CSV.GetGameConfigValueUint32("PrisonMainCityLevelLimit") {
fmt.Println("防守方主城等级不够", defUserData.GetMainCityLevel())
return ret, beCaptureheroMap
}
// 防守方指挥官状态
if defUserData.GetCommanderStatus() != uint32(proto.HeroStatus_HS_NORMAL) {
fmt.Println("已经被抓或者死亡")
return ret, beCaptureheroMap
}
// 进攻方没有监狱
bid, _ := attUserData.GetMaxBuildingInfoByBuildingConfigType(int64(proto.BuildingType_BT_PRISON))
if bid == 0 {
fmt.Println("进攻方没有监狱")
return ret, beCaptureheroMap
}
// 进攻方监狱已满
buildingfuntion := attUserData.GetBuildingFuctionByConfigType(int64(proto.BuildingType_BT_PRISON))
capability := common.StringToInt(buildingfuntion["capability"])
if attUserData.GetPrisonCount() >= capability {
fmt.Println("监狱已满")
return ret, beCaptureheroMap
}
randomNum := common.GetRandomNum(10000)
if getHeroPercent(targetMainCity) < uint32(randomNum) {
fmt.Println("运气不好,抓不到英雄")
return ret, beCaptureheroMap
}
commanderLevelCfg := CSV.GetCommanderLevelUpCfgByLevel(defUserData.GetLevel())
if commanderLevelCfg == nil {
fmt.Println("配置表错误,抓不到英雄")
return ret, beCaptureheroMap
}
heldtime := uint64(commanderLevelCfg.PrisonHoldTime)
var resourceSpeed = uint32(commanderLevelCfg.ResourceSpeed)
var resourceType uint32
if common.GetRandomNum(2) == 1 {
resourceType = 3
} else {
resourceType = 1
}
prison := &proto.ST_Prison_PB{
Owner: proto.SetUint64(defUserData.GetUid()),
StepStartTime: proto.SetUint64(wtime.GetNow()),
StepRemainTime: proto.SetUint64(heldtime),
ResourceType: proto.SetUint32(resourceType),
ResourceSpeed: proto.SetUint32(resourceSpeed),
}
captureInfo := &proto.ST_Vector4Int_PB{X: proto.SetInt32(int32(proto.VectorType_VT_HERO)),
Y: proto.SetInt32(int32(prison.GetHeroId())),
Z: proto.SetInt32(int32(prison.GetHeroQuality())),
W: proto.SetInt32(int32(prison.GetHeroLevel())),
}
ret[0] = append(ret[0], captureInfo)
attUserData.AddPrisonAsset(prison)
attStatisticeAsset := attUserData.GetStatisticsAsset()
attStatisticeAsset.UpdateArrestHeroNumber(1)
defUserData.SetCommanderStatus(uint32(proto.HeroStatus_HS_IMPRISONED), attUserData.GetUid(), prison.GetStepStartTime(), prison.GetStepRemainTime())
defStatisticeAsset := defUserData.GetStatisticsAsset()
defStatisticeAsset.UpdateCaptiveTimes()
title := common.CreateTips(90000171)
content := common.CreateTips(90000075, uint32(0), attUserData.GetUserName())
defUserData.AddLanguageIDMailAsset(uint32(proto.MailType_MT_SYSTEM), 0, -1, int32(proto.MailSourceType_MST_Hero),
title, content, "", "")
newOssPrison(attUserData, defUserData, "", uint32(oss.PAT_Catch), nil, nil)
newOssPrison(defUserData, attUserData, "", uint32(oss.PAT_BeCatch), nil, nil)
beCaptureheroMap[defUserData.GetUid()] = 1
PushMsg(proto.PushMsgType_PMT_HeroImprison, []interface{}{defUserData, attUserData})
return ret, beCaptureheroMap
}
/**
@brief 获取指挥官抓捕概率
*/
func getHeroPercent(targetType uint32) uint32 {
str := CSV.GetGameConfigValueString("hero_arrest")
percentList := common.ParseStringToUint32List(str)
if len(percentList) < 5 {
return 0
}
var percent uint32
switch targetType {
case targetMainCity:
percent = percentList[0]
case targetWarCity:
fallthrough
case targetLeagueCenter:
fallthrough
case targetRayolCity:
percent = percentList[1]
case targetMonster:
fallthrough
case targetMutiMonster:
percent = percentList[2]
case targetMine, targetMineGem:
percent = percentList[3]
case targetBestationed:
percent = percentList[4]
default:
percent = 0
}
return percent
}
func processMacWorldBattleResult(battleRlt uint32, targetType uint32, actionDataAsset *cache.GlobalActionEntry, battleReport *proto.ST_BattleReport_PB, battleInfo *proto.ST_BattleInfo_PB) {
if battleReport == nil || actionDataAsset == nil {
wlog.Error("processMacWorldBattleResult:", targetType)
return
}
if len(battleReport.GetAtkInfo()) <= 0 || len(battleReport.GetDefInfo()) <= 0 {
wlog.Error("processMacWorldBattleResult < 0 ")
return
}
worldAssetData := cache.Instance_GlobalAssetWorldData.GetWorldDataByTileId(actionDataAsset.Actiondata.GetEndTileID())
if worldAssetData == nil {
return
}
csvWorldConfig := worldAssetData.GetWorldEntryConfig()
if csvWorldConfig == nil {
return
}
actionDataEntry := actionDataAsset.Actiondata
unitChannel := oss.UnitChangeTypePVP
//var attInfo = getBigBrother(battleReport.AtkInfo) //攻击方首回合信息
var defInfo = getBigBrother(battleReport.DefInfo) //防守方首回合信息
if defInfo == nil {
return
}
isMultiuserDef := false //援助
if 1 < len(battleReport.GetDefInfo()) {
isMultiuserDef = true
}
// defUser 可能为nil
var defUser *cache.Info
if defInfo.CommanderReport != nil {
defUser = cache.GetCharinfo(defInfo.GetCommanderReport().GetUid())
}
//failedMax := CSV.GetGameConfigValueUint32("Pirate_Lose")
//if defUser == nil || GetMacMgrInstance().GetFailTms(defUser.GetUid()) >= int32(failedMax) {
// wlog.Info("processMacWorldBattleResult fail times:")
// return
//}
killNum := uint64(0)
defkillInfo := make(map[uint64]*proto.ST_UnitAsset_PB, 2)
for _, v := range battleReport.GetDefInfo() {
_, totalKillUnits, _, _, _, _ := processUnitListReport(v.GetUnitListReport(), v.GetHeroListReport())
for _, v := range totalKillUnits.GetUnits() {
killNum += v.GetUnitnum()
}
defkillInfo[v.GetActionID()] = totalKillUnits
}
origNum := uint64(0)
for _, v := range battleInfo.GetAtkSimpleStartInfo().GetStartUnitList() {
origNum += uint64(v.GetUnitCount())
}
isWin := true //win为false代表防守成功,win为false代表防守失败
coef := float64(CSV.GetGameConfigValueUint32("Pirate_Result")) / 100
if killNum >= uint64(math.Floor(float64(origNum)*coef)) {
isWin = false
}
defInfoLen := len(battleReport.GetDefInfo())
lastRoundDefInfo := battleReport.GetDefInfo()[defInfoLen-1] //防守方最后一回合信息
battleInfo.IsAtkWin = proto.SetBool(isWin)
_, defActionUnitMap, _ := getActionUnitMapByBattleReport(battleReport)
//delete(defActionUnitMap, 0)
//处理战斗后兵种资产
processGlobalActionAfterBattle(defActionUnitMap, worldAssetData, targetType, defUser, actionDataEntry.GetActiontype(), nil, isWin, false)
//处理玩家统计信息
startunits := battleInfo.GetAtkSimpleStartInfo().GetStartUnitList()
kvScore := GetMacMgrInstance().battleEnd(defUser, battleReport, defkillInfo, defInfo, startunits, isWin)
targetBattleNotice := &proto.ST_BattleNotice_PB{IsHaveBattleInfo: proto.SetBool(true)} //被进攻方的战斗结果通知
targetSubBattleNotice := &proto.ST_BattleNotice_PB{IsHaveBattleInfo: proto.SetBool(true)} //援助方的战斗结果通知
defTitleTips := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())} //防守方主要对象收到的信息
defSubTitleTips := &proto.ST_Tips_PB{Timestamp: proto.SetUint64(wtime.GetNow())} //防守方支援对象收到的信息
if isWin {
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 90000092)
defSubTitleTips.ParaUint32 = append(defSubTitleTips.ParaUint32, 90000092)
targetBattleNotice.BattleRlt = proto.SetBool(false)
targetSubBattleNotice.BattleRlt = proto.SetBool(false)
} else {
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 90000091)
defSubTitleTips.ParaUint32 = append(defSubTitleTips.ParaUint32, 90000091)
targetBattleNotice.BattleRlt = proto.SetBool(true)
targetSubBattleNotice.BattleRlt = proto.SetBool(true)
}
switch targetType {
case targetMainCity:
battleReport.DefFailInfo = &proto.ST_DefFailInfo_PB{}
if nil != lastRoundDefInfo.GetWallReport() {
Speed := uint64(CSV.GetGameConfigValueUint32("WALL_BURN_SPEED"))
ProcessMainCityDefenseLogic_MonsterAtk(worldAssetData.GetWorldDataOwner(), isWin, lastRoundDefInfo.WallReport.GetAfterHp(), Speed)
}
defTitleTips.LanguageID = proto.SetUint32(90000011)
defTitleTips.ParaUint32 = append(defTitleTips.ParaUint32, 20000125)
defSubTitleTips.LanguageID = proto.SetUint32(90000011)
defSubTitleTips.ParaUint32 = append(defSubTitleTips.ParaUint32, 71026)
//右下角战斗提示
targetBattleNotice.LanguageID = proto.SetUint32(75550) //$0$攻击了您
strAtkName := ""
ocfg := CSV.Mgr.CSV_WorldEntryConfig.GetEntryPtr(actionDataEntry.GetMacMonsterId())
if ocfg != nil {
strAtkName = CSV.GetLanguageStringByID(ocfg.Name, defUser.GetLanguage())
} else {
wlog.Error("CSV_WorldEntryConfig.GetEntryPtr return nil:", actionDataEntry.GetMacMonsterId())
}
targetBattleNotice.ParaString = append(targetBattleNotice.ParaString, strAtkName)
if isMultiuserDef {
targetSubBattleNotice.LanguageID = proto.SetUint32(75559) //$0$攻击了您援助的$1$
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, strAtkName)
if defUser != nil {
targetSubBattleNotice.ParaString = append(targetBattleNotice.ParaString, defUser.GetUserName())
}
}
}
ossBattleType := oss.OBT_Monster
ossFiledType := uint32(1)
if len(battleReport.AtkInfo) > 1 || len(battleReport.DefInfo) > 1 {
ossFiledType = 2
}
mailType := uint32(proto.MailType_MT_MONSTER_ATK_CITY)
//}
//发送防守方的邮件
defBattleReport := proto.Clone(battleReport).(*proto.ST_BattleReport_PB)
defBattleReport.IsWin = proto.SetBool(!isWin)
defBattleReport.WorldEntryConfigID = proto.SetInt64(actionDataAsset.Actiondata.GetMacMonsterId())
//defBattleReport.MacTid = proto.SetInt32(actionDataAsset.Actiondata.GetEndTileID())
strInfo := string(proto.Marshal(battleInfo))
SFUID := common.GetSFUID()
strSFUID := strconv.FormatInt(SFUID, 10)
for k, v := range battleReport.DefInfo {
tmpUserInfo := cache.GetCharinfo(v.CommanderReport.GetUid())
if tmpUserInfo == nil {
continue
}
score, _ := kvScore[tmpUserInfo.GetUid()]
defBattleReport.DefInfo[k].MacScore = proto.SetUint32(score)
ossBattleType = oss.OBT_PVP
//攻打玩家城市,对发送给主城玩家和支援玩家的邮件标题做区分
//带头大哥和小弟的战斗提示框不同
if v.GetIsBigBrother() {
cache.Instance_BattleInfoListCache.AddBattleInfo(SFUID, &strInfo)
_, mailid := tmpUserInfo.AddLanguageIDMailAsset(mailType, 0, worldAssetData.GetWorldDataTileID(), int32(proto.MailSourceType_MST_Default), defTitleTips, defTitleTips,
string(proto.Marshal(defBattleReport)), strSFUID)
if v.GetIsBigBrother() {
targetBattleNotice.MailID = proto.SetUint64(mailid)
if true == tmpUserInfo.IsRealOnline() {
tmpUserInfo.CreateBattleNotice(SFUID, targetBattleNotice)
}
} else {
targetSubBattleNotice.MailID = proto.SetUint64(mailid)
if true == tmpUserInfo.IsRealOnline() {
tmpUserInfo.CreateBattleNotice(SFUID, targetSubBattleNotice)
}
}
} else {
cache.Instance_BattleInfoListCache.AddBattleInfo(SFUID, &strInfo)
_, mailid := tmpUserInfo.AddLanguageIDMailAsset(mailType, 0, worldAssetData.GetWorldDataTileID(), int32(proto.MailSourceType_MST_Default), defSubTitleTips, defSubTitleTips,
string(proto.Marshal(defBattleReport)), strSFUID)
targetSubBattleNotice.MailID = proto.SetUint64(mailid)
if true == tmpUserInfo.IsRealOnline() {
tmpUserInfo.CreateBattleNotice(SFUID, targetSubBattleNotice)
}
}
newOssBattleRecord(tmpUserInfo, ossBattleType, !isWin, 0, ossFiledType, targetType,
actionDataAsset.Actiondata.GetEndTileID(), v.GetHeroListReport(), v.GetUnitListReport())
for _, u := range v.GetUnitListReport() {
newOssUnitChange(tmpUserInfo, uint32(unitChannel), u.GetUnitID(), int32(u.GetDeath()), int32(u.GetInjured()))
}
}
if defUser != nil {
defUser.CalcPower()
}
/*
if defUser != nil && defUser.GetLeagueID() != 0 {
//logEntry := createLeagueMacBattleLog(defUser, isWin, false)
//if cache.InstanceGlobalAssetLeagueBattleLog.AddLeagueBattleLog(defUser.GetLeagueID(), logEntry) {
// NotifyLeagueBattleLog(defUser.GetLeagueID())
//}
//logEntry.Attacker.MacMonsterId = proto.SetInt64(actionDataAsset.Actiondata.GetMacMonsterId())
}*/
}
func getMacAtkInfo(battleKey *stBattleKey, monsterid int64) (bool, *stBattleActionBaseData, map[uint64]*stUserUnitInfo) {
var defOrgiUnitAssetMap map[uint64]*stUserUnitInfo //记录多人防御玩家的原始兵力资产
worldAssetData := cache.Instance_GlobalAssetWorldData.GetWorldDataByTileId(battleKey.endTileID)
if worldAssetData == nil {
return false, nil, nil
}
atkBaseData := &stBattleActionBaseData{
actionBaseType: actionBase_Atk,
}
//获取怪物的城墙,英雄,战斗单位信息
ok, wall, heroList, unitAsset, formationId, globalAttribute, _, _ := getMonsterBattleUnitInfo(monsterid)
if false == ok {
return false, nil, nil
}
//atkBaseData.monsterGroupID = monsterGroupID
atkBaseData.heroList = heroList
atkBaseData.wall = wall
atkBaseData.globalAttribute = globalAttribute
ok, atkBaseData.formation, defOrgiUnitAssetMap = prepareUnits(battleKey.actionID, nil, unitAsset, formationId)
return true, atkBaseData, defOrgiUnitAssetMap
}
func createLeagueMacBattleLog(defUser *cache.Info, isWid, isMulti bool) *proto.ST_LeagueBattle_Log_Entry {
atkInfo := &proto.ST_LeagueBattle_User{
Lid: proto.SetUint64(uint64(0)),
UserName: proto.SetString(""),
Avatar: proto.SetString(""),
AvatarBoxID: proto.SetUint32(0),
AvatarID: proto.SetString(""),
LeagueShortName: proto.SetString(""),
Uid: proto.SetUint64(0),
}
defInfo := &proto.ST_LeagueBattle_User{
Lid: proto.SetUint64(defUser.GetLeagueID()),
UserName: proto.SetString(defUser.GetUserName()),
Avatar: proto.SetString(defUser.GetAvatar()),
AvatarBoxID: proto.SetUint32(defUser.GetAvatarBoxId()),
AvatarID: proto.SetString(defUser.GetLordIcon()),
LeagueShortName: proto.SetString(defUser.GetLeagueShortName()),
Uid: proto.SetUint64(defUser.GetUid()),
}
logEntry := &proto.ST_LeagueBattle_Log_Entry{
Attacker: atkInfo,
Defer: defInfo,
IsMulti: proto.SetBool(isMulti),
IsWin: proto.SetBool(isWid),
Times: proto.SetInt32(1),
Timestamp: proto.SetUint64(wtime.GetNow()),
}
return logEntry
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。