package mapLogic import ( "f1-game/internal/code" "f1-game/internal/constant" "f1-game/internal/data" "f1-game/internal/enum" "f1-game/internal/event" "f1-game/internal/extend/times" nameRemote "f1-game/internal/name/remote" nameRoute "f1-game/internal/name/route" "f1-game/internal/pb" "f1-game/internal/sessions" "f1-game/internal/types" mapCall "f1-game/nodes/map/internal/call" "f1-game/nodes/map/internal/db" dbLogic "f1-game/nodes/map/internal/db/data/logic" ctime "github.com/cherry-game/cherry/extend/time" clog "github.com/cherry-game/cherry/logger" ) func (p *actor) initMarchTypeFuncs() { p.marchTypeFuncs = map[enum.MarchType]marchTypeFunc{ enum.MarchType_Occupy: p.marchOccupy, enum.MarchType_Garrison: p.marchGarrison, enum.MarchType_Crucade: p.marchCrusade, enum.MarchType_Siege: p.marchSiege, enum.MarchType_Stay: p.marchStay, enum.MarchType_Retreat: p.marchRetreat, enum.MarchType_Redeploy: p.marchRedeploy, enum.MarchType_SiegeAssemble: p.marchSiegeAssemble, enum.MarchType_Assemble: p.marchAssemble, enum.MarchType_Snatch: p.marchSnatch, enum.MarchType_LegionAssemble: p.marchLegionAssemble, } } func (p *actor) addMarchAOI(marchTable *db.LogicMarchTable) { marker := marchTable.ToAOIMarker() mapCall.AOI.Enter(marker) } func (p *actor) marchTimer() { p.updateTime() for _, marchTable := range p.MarchTables { p.marchTicker(marchTable) // 如果行军处于战斗等待状态,检查是否超时,毕竟由于bug导致状态卡死 if marchTable.State == enum.MarchState_BattleWait || marchTable.State == enum.MarchState_Battle { if p.nowMillis >= marchTable.StateEndTime { // 战斗等待超时,应该是遇到了某种bug clog.Warnf("March battle wait timeout, a bug? MarchObjectID = %d, MarchType = %s, Point = %v", marchTable.ObjectID, enum.GetMarchStateName(marchTable.State), marchTable.Point) // 让行军对象撤退 p.markMarchRetreat(marchTable, enum.RetreatType_Must, false) // 打印地块的情况 tileTable := p.TileTables.GetValue(marchTable.GetTileID()) tileTable.PrintMarchList() } } // 有数据变更 if marchTable.IsDataChanged { p.marchSave(marchTable) } } for _, legionTable := range p.LegionTables { if legionTable.IsDelete { p.LegionTables.Remove(legionTable.ObjectID) } else { p.legionTicker(legionTable) } if legionTable.IsDisband() { p.legionDisband(legionTable, enum.RetreatType_Retreat, true) } if legionTable.IsDataChanged { p.legionSave(legionTable) } } } func (p *actor) marchTicker(marchTable *db.LogicMarchTable) { // 不处理在军团中的行军对象 if !marchTable.IsInLegion() { if marchTable.IsMoving() { p.marchMoving(marchTable) } // 行军到达执行行军意图指令 if marchTable.IsArrived { p.marchArrive(marchTable) } // 如果行军对象被攻城大营管理,则执行自动行军 if marchTable.AutoMarchInfo.IsAutoSiege { p.marchAuto(marchTable) } } if marchTable.IsHandleRetreat { p.startMarchRetreat(marchTable) } } func (p *actor) startMarchRetreat(marchTable *db.LogicMarchTable) { var ( marchState = enum.GetMarchStateByRetreatType(marchTable.RetreatType) isRemoveRedeploy = marchTable.IsRemoveRedeploy ) // 执行自动撤退 mapCall.Player.AutoRetreat(marchTable.PlayerID, marchTable.TeamID, marchState, isRemoveRedeploy) // 重置自动撤退状态 marchTable.ResetAutoRetreat() } func (p *actor) marchMoving(marchTable *db.LogicMarchTable) { // 到达了 if marchTable.IsMoveArrive() { marchTable.MarkArrive(true) return } if !marchTable.CanMove(p.nowMillis) { return } // 执行行军移动 p.marchMove(marchTable) tileTable := p.TileTables.GetValue(marchTable.GetTileID()) // 检查是否发生碰撞 isMet, isAttack := p.isMarchMeet(marchTable, tileTable) if isMet { // 执行碰撞处理 p.marchMeet(marchTable, p.TileTables.GetValue(marchTable.GetTileID()), isAttack) return } // 检查建筑是否发生碰撞 buildTable := p.getCollidedBuilding(marchTable, tileTable) if buildTable != nil { // 执行建筑碰撞逻辑 p.marchBuildingCollision(marchTable, tileTable, buildTable) return } if marchTable.IsMoveArrive() { marchTable.MarkArrive(true) return } // 撤退状态和溃退状态不加入行军列表 if !marchTable.IsRetreat() { // 未行军到达则加入行军列表 tileTable := p.TileTables.GetValue(marchTable.GetTileID()) p.addToTileMarch(marchTable, tileTable) } } // marchAuto 自动行军 func (p *actor) marchAuto(marchTable *db.LogicMarchTable) { if marchTable.State != enum.MarchState_Stay && marchTable.State != enum.MarchState_SiegeAssemble { return } switch marchTable.AutoMarchInfo.Stage { case enum.AutoMarch_None: return case enum.AutoMarch_Start: // 通知 MapPlayer 开始自动行军 mapCall.Player.AutoMarchRequest(marchTable.PlayerID, marchTable.LeagueID, marchTable.ObjectID, marchTable.AutoMarchInfo.Segments) // 切换为等待状态 marchTable.SetAutoMarchStage(enum.AutoMarch_Wait, p.nowMillis) case enum.AutoMarch_Wait: // 等待超时直接清除自动行军状态 if p.nowMillis >= marchTable.AutoMarchInfo.StageStartTime+constant.AutoMarchWaitTimeout { // 清除自动行军状态 marchTable.MarkAutoSiege(false, 0) return } case enum.AutoMarch_Process: segement := marchTable.AutoMarchInfo.Segments[0] // 根据自动行军的策略来检查 switch segement.AutoMarchType { case enum.AutoMarch_WaitGarrisionZero: // 检查是否有驻城部队 siegeTable, ok := p.SiegeTables.Get(marchTable.TargetObjectID) if !ok { clog.Warnf("[marchAuto] SiegeTable not found, marchObjectID = %d, targetObjectID = %d", marchTable.ObjectID, marchTable.TargetObjectID) marchTable.MarkAutoSiege(false, 0) return } // 如果有驻城部队 if siegeTable.RemainGarrisonArmies() > 0 { // 如果驻城部队一直未被消灭,给个保底等待时间 if p.nowMillis < segement.ArriveTime+segement.WaitTime { return } } default: // 等待超时 if p.nowMillis < segement.ArriveTime+segement.WaitTime { return } } point := segement.Path[segement.Path.Size()-1] p.doMarch(marchTable, segement.MarchType, enum.MarchState_March, segement.Path.ToProto(), point.ToProto(), marchTable.TargetObjectID, marchTable.IsAutoRetreat, true) // 从地块删除行军对象 tileTable := p.TileTables.GetValue(marchTable.GetTileID()) tileTable.RemoveMarchAnywhere(marchTable.ObjectID) clog.Debugf("[marchAuto] marchObjectID = %d, marchState = %s, marchType = %s, path = %v", marchTable.ObjectID, enum.GetMarchStateName(marchTable.State), enum.GetMarchTypeName(marchTable.MarchType), segement.Path) marchTable.AutoMarchInfo.Segments.Remove(0) if marchTable.AutoMarchInfo.Segments.IsEmpty() { marchTable.SetAutoMarchStage(enum.AutoMarch_None, p.nowMillis) } marchTable.IsDataChanged = true } } // marchMove 移动处理(行军和撤退) func (p *actor) marchMove(marchTable *db.LogicMarchTable) { marchTable.MoveNextTile(p.nowMillis) mapCall.AOI.Move(marchTable.ToAOIMarker()) // 更新军情线 p.updateArmyLine(marchTable) // 从上一个格子的行军列表移除 if prevTileID, ok := data.PointToTileID(marchTable.PrevPoint.X, marchTable.PrevPoint.Y); ok { prevTileTable := p.TileTables.GetValue(prevTileID) prevTileTable.RemoveMarch(marchTable.ObjectID) p.addTileProcess(prevTileTable) } } // isMarchMeet 检查是否发生碰撞 func (p *actor) isMarchMeet(marchTable *db.LogicMarchTable, tileTable *db.LogicTileTable) (isMet bool, isAttack bool) { // 撤退的行军对象不会发生碰撞 if marchTable.IsRetreat() { return false, false } // 如果有碰撞,则加入进攻列表,否则加入行军列表 isMet, isAttack = p.isTileMeet(tileTable, marchTable.PlayerID, marchTable.LeagueID) if isMet { clog.Debugf("march tile meet result: objectID = %d, meet = %v, attack = %v", marchTable.ObjectID, isMet, isAttack) } return } func (p *actor) marchMeet(marchTable *db.LogicMarchTable, tileTable *db.LogicTileTable, isAttack bool) { if isAttack { tileTable.AddAttackList(marchTable.ObjectID, dbLogic.NewTileMarchInfo( tileTable.TileID, marchTable.ObjectID, p.nowMillis, )) // 保存当前状态 marchTable.SaveState(p.nowMillis) // 设为战斗等待状态 p.updateMarchState(marchTable, enum.MarchState_BattleWait, p.nowMillis+constant.MapMaxBattleWaitTime) } else { tileTable.AddMarch(marchTable.ObjectID, dbLogic.NewTileMarchInfo( tileTable.TileID, marchTable.ObjectID, p.nowMillis, )) } } // marchArrive 行军到达目的地处理 func (p *actor) marchArrive(marchTable *db.LogicMarchTable) { // 防止在还是移动状态的情况下,tile 还没来得及处理就又一次进入 isArrived 逻辑 marchTable.ClearPath() marchTable.MarkArrive(false) clog.Debugf("[marchArrive]: marchObjectID = %d, marchType = %v, marchState = %s, point = %v", marchTable.ObjectID, enum.GetMarchTypeName(marchTable.MarchType), enum.GetMarchStateName(marchTable.State), marchTable.Point) // 执行行军意图 if fn, ok := p.marchTypeFuncs[marchTable.MarchType]; ok { fn(marchTable) } else { // 保底,让行军对象停留 p.marchStay(marchTable) } // 抛一个行军到达事件 eventData := &event.MarchArriveEventData{ TeamID: marchTable.TeamID, MarchState: marchTable.State, } tileTable := p.TileTables.GetValue(marchTable.GetTileID()) if tileTable.BuildObjectID > 0 { eventData.TargetObjectID = int64(tileTable.BuildObjectID) eventData.TargetObjectType = enum.ObjectType_Build buildTable := p.BuildTables.GetValue(tileTable.BuildObjectID) eventData.TargetConfigID = buildTable.ConfigID eventData.TargetObjectLevel = buildTable.Level } else if tileTable.CastleObjectID > 0 { eventData.TargetObjectID = tileTable.CastleObjectID eventData.TargetObjectType = enum.ObjectType_Castle castleTable := p.CastleTables.GetValue(tileTable.CastleObjectID) eventData.TargetConfigID = castleTable.ConfigID eventData.TargetObjectLevel = castleTable.Level } p.PostEvent(event.NewMarchArrive(marchTable.PlayerID, eventData)) } // marchOccupy 行军占领 func (p *actor) marchOccupy(marchTable *db.LogicMarchTable) { resTable, ok := p.ResTables.Get(marchTable.TargetObjectID) if !ok { clog.Debugf("[marchOccupy]: res not found, MarchObjectID = %v, ResObjectID = %v, Point = %v", marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point) p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 不在同一个格子,可能刷新到了别的地方 if !resTable.Point.Equals(&marchTable.Point) { clog.Debugf("[marchOccupy]: res not this tile, March = (%v, %v), Res = (%v, %v), Point = %v", marchTable.ObjectID, marchTable.Point, resTable.ObjectID, resTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 检查资源点是否可以被占领 errCode := resTable.CanOccupy(p.nowMillis, marchTable.PlayerID, marchTable.LeagueID) if code.IsFail(errCode) { clog.Debugf("[marchOccupy]: res cannot be occupied, MarchObjectID = %v, ResObjectID = %v, Point = %v, Code = %v", marchTable.ObjectID, resTable.ObjectID, marchTable.Point, errCode) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } tileTable := p.TileTables.GetValue(marchTable.GetTileID()) // 放入 TileTable 的占领列表 tileTable.AddOccupy(marchTable.ObjectID, dbLogic.NewTileMarchInfo( tileTable.TileID, marchTable.ObjectID, p.nowMillis, resTable.ObjectID, )) p.updateMarchState(marchTable, enum.MarchState_BattleWait, p.nowMillis+constant.MapMaxBattleWaitTime) p.addTileProcess(tileTable) } // marchGarrison 行军驻守 func (p *actor) marchGarrison(marchTable *db.LogicMarchTable) { // 驻守目标可以是资源点,建筑,系统城 if buildTable, ok := p.BuildTables.Get(marchTable.TargetObjectID); ok { p.marchGarrisonBuild(marchTable, buildTable) return } if castleTable, ok := p.CastleTables.Get(marchTable.TargetObjectID); ok { p.marchGarrisonCastle(marchTable, castleTable) return } if resTable, ok := p.ResTables.Get(marchTable.TargetObjectID); ok { p.marchGarrisonRes(marchTable, resTable) return } // 没有驻守目标 // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) clog.Debugf("[marchGarrison]: no target found, MarchObjectID = %v, TargetObjectID = %d, Point = %v", marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point) } // marchGarrisonRes 行军驻守资源点 func (p *actor) marchGarrisonRes(marchTable *db.LogicMarchTable, resTable *db.LogicResTable) { // 不在同一格 if !resTable.Point.Equals(&marchTable.Point) { clog.Debugf("[marchGarrisonRes]: res not in this tile, MarchObjectID = (%v, %v), ResObjectID = (%v, %v)", marchTable.ObjectID, marchTable.Point, resTable.ObjectID, resTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 检查资源点是否可以被驻守 retCode := resTable.IsGarrisonable(marchTable.PlayerID, marchTable.LeagueID) if code.IsFail(retCode) { clog.Debugf("[marchGarrisonRes]: res cannot be garrisoned, MarchObjectID = %v, Point = %v, Code = %v", marchTable.ObjectID, marchTable.Point, retCode) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 更新为驻守状态 p.updateMarchState(marchTable, enum.MarchState_Garrison, 0) // 保存一下驻守状态,因为驻守比较特殊,可攻可守 marchTable.SaveState(p.nowMillis) // 加入 TileTable 的驻守列表 tileTable := p.TileTables.GetValue(marchTable.GetTileID()) marchInfo := dbLogic.NewTileMarchInfo( tileTable.TileID, marchTable.ObjectID, p.nowMillis, resTable.ObjectID, ) tileTable.AddGarrison(marchTable.ObjectID, marchInfo, p.TileTables) p.addTileProcess(tileTable) } // marchGarrisonBuild 行军驻守建筑 func (p *actor) marchGarrisonBuild(marchTable *db.LogicMarchTable, buildTable *db.LogicBuildTable) { // 检查建筑是否在这个格子上 // TODO: 这里需要根据地编数据上的驻守位置来判断驻守的目标,否则默认为中心点 if !buildTable.Point.Equals(&marchTable.Point) { clog.Debugf("[marchGarrisonBuild]: build not in this tile, MarchObjectID = (%v, %v), BuildObjectID = (%v, %v)", marchTable.ObjectID, marchTable.Point, buildTable.ObjectID, buildTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 检查建筑是否可以被驻守 retCode := buildTable.IsGarrisonable(marchTable.PlayerID, marchTable.LeagueID) if code.IsFail(retCode) { clog.Debugf("[marchGarrisonBuild]: build cannot be garrisoned, MarchObjectID = %v, BuildObjectID = %v, Point = %v, Code = %v", marchTable.ObjectID, buildTable.ObjectID, marchTable.Point, retCode) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 更新为驻守状态 p.updateMarchState(marchTable, enum.MarchState_Garrison, 0) // 保存一下驻守状态,因为驻守比较特殊,可攻可守 marchTable.SaveState(p.nowMillis) // 加入 TileTable 的驻守列表 tileTable := p.TileTables.GetValue(marchTable.GetTileID()) marchInfo := dbLogic.NewTileMarchInfo( tileTable.TileID, marchTable.ObjectID, p.nowMillis, buildTable.ObjectID, ) tileTable.AddGarrison(marchTable.ObjectID, marchInfo, p.TileTables) p.addTileProcess(tileTable) } // marchGarrisonCastle 行军驻守城池 func (p *actor) marchGarrisonCastle(marchTable *db.LogicMarchTable, castleTable *db.LogicCastleTable) { // 检查城池是否在这个格子上 // TODO: 这里需要根据地编数据上的驻守位置来判断驻守的目标,否则默认为中心点 if !castleTable.Point.Equals(&marchTable.Point) { clog.Debugf("[marchGarrisonCastle]: castle not in this tile, MarchObjectID = (%v, %v), CastleObjectID = (%v, %v)", marchTable.ObjectID, marchTable.Point, castleTable.ObjectID, castleTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 检查城池是否可以被驻守 retCode := castleTable.IsGarrisonable(marchTable.LeagueID) if code.IsFail(retCode) { clog.Debugf("[marchGarrisonCastle]: castle cannot be garrisoned, MarchObjectID = %v, CastleObjectID = %v, Point = %v, Code = %v", marchTable.ObjectID, castleTable.ObjectID, marchTable.Point, retCode) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 更新为驻守状态 p.updateMarchState(marchTable, enum.MarchState_Garrison, 0) // 保存一下驻守状态,因为驻守比较特殊,可攻可守 marchTable.SaveState(p.nowMillis) // 加入 TileTable 的驻守列表 tileTable := p.TileTables.GetValue(marchTable.GetTileID()) marchInfo := dbLogic.NewTileMarchInfo( tileTable.TileID, marchTable.ObjectID, p.nowMillis, castleTable.ObjectID, ) tileTable.AddGarrison(marchTable.ObjectID, marchInfo, p.TileTables) p.addTileProcess(tileTable) } // marchCrusade 行军讨伐 func (p *actor) marchCrusade(marchTable *db.LogicMarchTable) { monsterTable, ok := p.MonsterTables.Get(marchTable.TargetObjectID) if !ok || !monsterTable.IsAlive { clog.Debugf("[marchCrusade] Monster not found: MarchObjectID = %d, MonsterObjectID = %d, Point = %v", marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 检查怪物是否在这个格子上 if !monsterTable.Point.Equals(&marchTable.Point) { clog.Debugf("[marchCrusade] Monster not in this tile: March = (%d, %d), Monster = (%d, %v)", marchTable.ObjectID, marchTable.Point, monsterTable.ObjectID, monsterTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // TODO: 判断怪物有没有被讨伐 // 加入讨伐列表 tileTable := p.TileTables.GetValue(marchTable.GetTileID()) tileTable.AddCrusade(marchTable.ObjectID, dbLogic.NewTileMarchInfo( tileTable.TileID, marchTable.ObjectID, p.nowMillis, monsterTable.ObjectID, )) p.addTileProcess(tileTable) // 设置为战斗状态 p.updateMarchState(marchTable, enum.MarchState_BattleWait, p.nowMillis+constant.MapMaxBattleWaitTime) } // marchSiege 行军攻城 func (p *actor) marchSiege(marchTable *db.LogicMarchTable) { // 攻城可以打建筑或者系统城 if buildTable, ok := p.BuildTables.Get(marchTable.TargetObjectID); ok { p.marchSiegeBuild(marchTable, buildTable) return } if castleTable, ok := p.CastleTables.Get(marchTable.TargetObjectID); ok { p.marchSiegeCastle(marchTable, castleTable) return } // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) clog.Debugf("[marchSiege]: siege object not found, MarchObjectID = %v, TargetObjectID = %v, Point = %v", marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point) } func (p *actor) marchSiegeBuild(marchTable *db.LogicMarchTable, buildTable *db.LogicBuildTable) { // 攻城不一样,只要有建筑覆盖的坐标都可以打 // TODO: 可以通过地编数据的攻城点来判断,没有就默认都可以打 if !buildTable.IsCoverPoint(marchTable.X(), marchTable.Y()) { clog.Debugf("[marchSiegeBuild]: build not in this tile, MarchObjectID = %v, BuildObjectID = %v, Point = %v", marchTable.ObjectID, buildTable.ObjectID, marchTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 不可以攻城 if !p.canSiegeBuild(marchTable, buildTable) { clog.Debugf("[marchSiegeBuild]: not siegeable, MarchObjectID = %v, LeagueID = %v, BuildObjectID = %v", marchTable.ObjectID, marchTable.LeagueID, buildTable.ObjectID) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 更新为攻城状态 nextTime := p.nowMillis + ctime.MillisecondsPerSecond p.updateMarchState(marchTable, enum.MarchState_Siege, nextTime) tileTable := p.TileTables.GetValue(marchTable.GetTileID()) tileMarchInfo := dbLogic.NewTileMarchInfo( tileTable.TileID, marchTable.ObjectID, p.nowMillis, buildTable.ObjectID, ) // 设置为首次攻城 tileMarchInfo.IsFirstSiege = true // 等待一个 ticker tileMarchInfo.LogicEndTime = nextTime // 加入攻城列表 tileTable.AddSiege(marchTable.ObjectID, tileMarchInfo) p.addTileProcess(tileTable) // 保存攻城点 buildTable.AddSiegeTile(tileTable.TileID) // TODO: 先简单做,每次都通知一下,后面试试优化 // 通知玩家出来自动防守 // 如果是玩家主城,通知主城被攻击了 switch buildTable.ConfigID { case constant.MapBuild_MainCity: mapCall.Player.MainCitySiege(buildTable.PlayerID, buildTable.ObjectID) case constant.MapBuild_LeaguePoint: // TODO: 联盟驻地除了通知调用队列的玩家,还有发一个消息给联盟,并通知所有主城在驻地内的玩家 } // 如果调动列表不为空,通知出来自动防守 if buildTable.RedeployObjects.Size() > 0 { // 分组 mapPlayerTeams := map[int64][]int32{} for _, redeployObjectID := range buildTable.RedeployObjects.Values() { redeployMarchTable, ok := p.MarchTables.Get(redeployObjectID) if !ok { continue } mapPlayerTeams[redeployMarchTable.PlayerID] = append(mapPlayerTeams[redeployMarchTable.PlayerID], redeployMarchTable.TeamID) } // 通知玩家 for playerID, teamIDs := range mapPlayerTeams { mapCall.Player.AutoDefendRequest(playerID, buildTable.ObjectID, teamIDs) } } } func (p *actor) marchSiegeCastle(marchTable *db.LogicMarchTable, castleTable *db.LogicCastleTable) { // 攻城不一样,只要有建筑覆盖的坐标都可以打 // TODO: 可以通过地编数据的攻城点来判断,没有就默认都可以打 if !castleTable.IsCoverPoint(marchTable.X(), marchTable.Y()) { clog.Debugf("[marchSiegeCastle]: castle not in this tile, MarchObjectID = %v, CastleObjectID = %v, Point = %v", marchTable.ObjectID, castleTable.ObjectID, marchTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 不可以攻城 if !p.canSiegeCastle(marchTable, castleTable) { clog.Debugf("[marchSiegeCastle]: not siegeable, MarchObjectID = %v, LeagueID = %v, CastleObjectID = %v", marchTable.ObjectID, marchTable.LeagueID, castleTable.ObjectID) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 更新为攻城状态 nextTime := p.nowMillis + ctime.MillisecondsPerSecond p.updateMarchState(marchTable, enum.MarchState_Siege, nextTime) tileTable := p.TileTables.GetValue(marchTable.GetTileID()) tileMarchInfo := dbLogic.NewTileMarchInfo( tileTable.TileID, marchTable.ObjectID, p.nowMillis, castleTable.ObjectID, ) // 设置为首次攻城 tileMarchInfo.IsFirstSiege = true // 等待一个 ticker tileMarchInfo.LogicEndTime = nextTime // 加入攻城列表 tileTable.AddSiege(marchTable.ObjectID, tileMarchInfo) p.addTileProcess(tileTable) // 保存攻城点 castleTable.AddSiegeTile(tileTable.TileID) // 如果调动列表不为空,通知出来自动防守 if castleTable.RedeployObjects.Size() > 0 { // 分组 mapPlayerTeams := map[int64][]int32{} for _, redeployObjectID := range castleTable.RedeployObjects.Values() { redeployMarchTable, ok := p.MarchTables.Get(redeployObjectID) if !ok { continue } mapPlayerTeams[redeployMarchTable.PlayerID] = append(mapPlayerTeams[redeployMarchTable.PlayerID], redeployMarchTable.TeamID) } // 通知玩家 for playerID, teamIDs := range mapPlayerTeams { mapCall.Player.AutoDefendRequest(playerID, castleTable.ObjectID, teamIDs) } } } // marchSnatch 行军掠夺 func (p *actor) marchSnatch(marchTable *db.LogicMarchTable) { buildTable, ok := p.BuildTables.Get(marchTable.TargetObjectID) if !ok { clog.Debugf("[marchSnatch]: build not found, MarchObjectID = %v, TargetObjectID = %v, Point = %v", marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 建筑没有覆盖坐标 if !buildTable.IsCoverPoint(marchTable.X(), marchTable.Y()) { clog.Debugf("[marchSnatch]: not cover point: MarchObjectID = %v, BuildObjectID = %v, Point = %v", marchTable.ObjectID, buildTable.ObjectID, marchTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 掠夺只能掠夺玩家主城,这个判断在 buildTable.IsSnatchable 里面 // 判断是否可以掠夺 if !buildTable.IsSnatchable(p.nowMillis, marchTable.LeagueID) { clog.Debugf("[marchSnatch]: build not snatchable, MarchObjectID = %v, BuildObjectID = %v, BuildConfigID = %v, Point = %v", marchTable.ObjectID, buildTable.ObjectID, buildTable.ConfigID, marchTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } endTime := p.nowMillis + 1000 // 更新为掠夺状态 p.updateMarchState(marchTable, enum.MarchState_Snatch, endTime) // 加入地块的掠夺列表 tileTable := p.TileTables.GetValue(marchTable.GetTileID()) tileMarchInfo := dbLogic.NewTileMarchInfo( tileTable.TileID, marchTable.ObjectID, p.nowMillis, buildTable.ObjectID, ) // 设置为首次掠夺 tileMarchInfo.IsFirstSiege = true tileMarchInfo.LogicEndTime = endTime tileTable.AddSnatch(marchTable.ObjectID, tileMarchInfo) p.addTileProcess(tileTable) // 保存攻城点 buildTable.AddSiegeTile(tileTable.TileID) // TODO: 先简单做,每次都通知一下,后面试试优化 // 通知玩家出来自动防守 // 如果是玩家主城,通知主城被攻击了 if buildTable.ConfigID == constant.MapBuild_MainCity { mapCall.Player.MainCitySiege(buildTable.PlayerID, buildTable.ObjectID) } } // marchStay 行军停留 func (p *actor) marchStay(marchTable *db.LogicMarchTable) { // 行军到达后,修改状态为 停留中 p.updateMarchState(marchTable, enum.MarchState_Stay, 0) // 加入停留队列 tileTable := p.TileTables.GetValue(marchTable.GetTileID()) tileTable.AddStay(marchTable.ObjectID, dbLogic.NewTileMarchInfo( tileTable.TileID, marchTable.ObjectID, p.nowMillis, )) // 如果是被攻城大营管理的自动行军 if marchTable.AutoMarchInfo.IsAutoSiege { // TODO 有没有可能 Segments 为空? if len(marchTable.AutoMarchInfo.Segments) > 0 { marchTable.AutoMarchInfo.Segments[0].ArriveTime = p.nowMillis } else { clog.Warnf("[marchStay]: no segment, MarchObjectID = %v, Point = %v", marchTable.ObjectID, marchTable.Point) } } p.addTileProcess(tileTable) } // marchRedeploy 行军调动 func (p *actor) marchRedeploy(marchTable *db.LogicMarchTable) { // 调动可以调动到建筑或者城池 if buildTable, ok := p.BuildTables.Get(marchTable.TargetObjectID); ok { p.marchRedeployBuild(marchTable, buildTable) return } if castleTable, ok := p.CastleTables.Get(marchTable.TargetObjectID); ok { p.marchRedeployCastle(marchTable, castleTable) return } // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) clog.Debugf("[marchRedeploy]: target not found: MarchObjectID = %v, TargetObjectID = %v, Point = %v", marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point) } func (p *actor) marchRedeployBuild(marchTable *db.LogicMarchTable, buildTable *db.LogicBuildTable) { // 建筑没有覆盖坐标 if !buildTable.IsCoverPoint(marchTable.X(), marchTable.Y()) { clog.Debugf("[marchRedeployBuild]: not cover point: MarchObjectID = %v, BuildObjectID = %v, Point = %v", marchTable.ObjectID, buildTable.ObjectID, marchTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // TODO: 判断建筑是否可调动 // 如果原来有调动,删除原来的调动 if marchTable.RedeployObject.Key > 0 { p.removeMarchRedeploy(marchTable, false, false) } marchTable.SetRedeployObjectID(buildTable.ObjectID, buildTable.Type) p.updateTeam(marchTable, enum.TeamUpdate_Redeploy) // 修改为调动状态 p.updateMarchState(marchTable, enum.MarchState_Redeploy, 0) // 如果被调动的建筑正被攻城,加入自动防守 if buildTable.IsBeingSiege() { mapCall.Player.AutoDefendRequest(marchTable.PlayerID, buildTable.ObjectID, []int32{marchTable.TeamID}) } } func (p *actor) marchRedeployCastle(marchTable *db.LogicMarchTable, castleTable *db.LogicCastleTable) { // 建筑没有覆盖坐标 if !castleTable.IsCoverPoint(marchTable.X(), marchTable.Y()) { clog.Debugf("[marchRedeployCastle]: not cover point: MarchObjectID = %v, CastleObjectID = %v, Point = %v", marchTable.ObjectID, castleTable.ObjectID, marchTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // TODO: 判断建筑是否可调动 // 如果原来有调动,删除原来的调动 if marchTable.RedeployObject.Key > 0 { p.removeMarchRedeploy(marchTable, false, false) } marchTable.SetRedeployObjectID(castleTable.ObjectID, castleTable.Type) p.updateTeam(marchTable, enum.TeamUpdate_Redeploy) // 修改为调动状态 p.updateMarchState(marchTable, enum.MarchState_Redeploy, 0) // 如果被调动的建筑正被攻城,加入自动防守 if castleTable.IsBeingSiege() { mapCall.Player.AutoDefendRequest(marchTable.PlayerID, castleTable.ObjectID, []int32{marchTable.TeamID}) } } // marchSiegeAssemble 行军攻城集结 func (p *actor) marchSiegeAssemble(marchTable *db.LogicMarchTable) { // 攻城集结只能集结到卫城 castleTable, ok := p.CastleTables.Get(marchTable.TargetObjectID) if !ok { clog.Debugf("[marchSiegeAssemble] Castle not found: MarchObjectID = %d, TargetObjectID = %d, Point = %v", marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 不是卫城 if castleTable.CastleType != pb.SysObjType_so_town { clog.Debugf("[marchSiegeAssemble] not siege town: MarchObjectID = %d, CastleObjectID = %d, ConfigID = %d, Point = %v", marchTable.ObjectID, castleTable.ObjectID, castleTable.ConfigID, marchTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 没有公会是无法集结的 if marchTable.LeagueID == 0 { clog.Debugf("[marchSiegeAssemble] not in league: MarchObjectID = %d, Point = %v", marchTable.ObjectID, marchTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 集结途中归属变更了 if castleTable.LeagueID != marchTable.LeagueID { clog.Debugf("[marchSiegeAssemble] not my league: MarchObjectID = %d, CastleObjectID = %d, Point = %v", marchTable.ObjectID, castleTable.ObjectID, marchTable.Point) // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 如果原来有调动,删除原来的调动 if marchTable.RedeployObject.Key > 0 { p.removeMarchRedeploy(marchTable, false, false) } marchTable.SetRedeployObjectID(castleTable.ObjectID, castleTable.Type) p.updateTeam(marchTable, enum.TeamUpdate_Redeploy) clog.Debugf("add assemble list: MarchObjectID = %d, CastleObjectID = %d", marchTable.ObjectID, castleTable.ObjectID) // 如果是主力部队,加入主力列表,否则加入拆迁队列表 if marchTable.AutoMarchInfo.IsMainForce { castleTable.SiegeTown.MainForceList.Add(marchTable.ObjectID) clog.Debugf("add march to main force list: SiegeCamp = %d, March = %d, Size = %d", castleTable.ObjectID, marchTable.ObjectID, castleTable.SiegeTown.MainForceList.Size()) } else { castleTable.SiegeTown.SiegeSquadList.Add(marchTable.ObjectID) clog.Debugf("add march to siege squad list: SiegeCamp = %d, March = %d, Size = %d", castleTable.ObjectID, marchTable.ObjectID, castleTable.SiegeTown.SiegeSquadList.Size()) } castleTable.IsDataChanged = true // 更改状态为攻城集结状态 p.updateMarchState(marchTable, enum.MarchState_SiegeAssemble, 0) // 把行军对象标记为自动攻城状态 marchTable.MarkAutoSiege(true, castleTable.ObjectID) } // marchAssemble 行军集结 // TODO: 集结得确定一下,TargetObjectID 是不是军团ID,暂时不动 func (p *actor) marchAssemble(marchTable *db.LogicMarchTable) { // 被踢了 if marchTable.LegionObjectID == 0 { // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } legionTable, ok := p.LegionTables.Get(marchTable.LegionObjectID) // 解散了 if !ok { // 加入撤退列表 p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false) return } // 设置成员到达 legionTable.SetMemberArrive(marchTable.ObjectID) // 修改状态为集结状态 p.updateMarchState(marchTable, enum.MarchState_Assemble, 0) // 离开AOI p.marchLeaveAOI(marchTable) clog.Debugf("march assemble arrive: MarchObjectID = %d, LegionID = %d, LegionName = %s, TileID = %d", marchTable.ObjectID, legionTable.ObjectID, legionTable.LegionName, marchTable.GetTileID()) } // Deprecated: 暂时不使用,考虑删除 func (p *actor) marchLegionAssemble(marchTable *db.LogicMarchTable) { } // marchRetreat 行军撤退 func (p *actor) marchRetreat(marchTable *db.LogicMarchTable) { // 撤退可以撤退到主城,其它建筑或者系统城(通过调动,攻城集结) if buildTable, ok := p.BuildTables.Get(marchTable.TargetObjectID); ok { p.marchRetreatBuild(marchTable, buildTable) return } if castleTable, ok := p.CastleTables.Get(marchTable.TargetObjectID); ok { p.marchRetreatCastle(marchTable, castleTable) return } clog.Warnf("[marchRetreat]: target not found: MarchObjectID = %d, TargetObjectID = %d, Point = %v", marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point) // 设置为停留, 并不能让他触发碰撞 p.updateMarchState(marchTable, enum.MarchState_Stay, 0) } func (p *actor) marchRetreatBuild(marchTable *db.LogicMarchTable, buildTable *db.LogicBuildTable) { if !buildTable.IsCoverPoint(marchTable.X(), marchTable.Y()) { clog.Warnf("[marchRetreat]: not cover point: MarchObjectID = %v, BuildObjectID = %v, Point = %v", marchTable.ObjectID, buildTable.ObjectID, marchTable.Point) // 设置为停留, 并不能让他触发碰撞 p.updateMarchState(marchTable, enum.MarchState_Stay, 0) return } // 只能撤退到自己或者联盟的建筑 // TODO: 这里应该往外推到建筑外的点 if buildTable.PlayerID != marchTable.PlayerID && buildTable.LeagueID != marchTable.LeagueID { clog.Warnf("[marchRetreat]: not own or league build: MarchObjectID = %v, BuildObjectID = %v, Point = %v", marchTable.ObjectID, buildTable.ObjectID, marchTable.Point) // 设置为停留, 并不能让他触发碰撞 p.updateMarchState(marchTable, enum.MarchState_Stay, 0) return } switch buildTable.ConfigID { case constant.MapBuild_MainCity: // 主城 { clog.Debugf("[marchRetreatBuild] Retreat to MainCity: MarchObjectID = %d, BuildObjectID = %d, Point = %v", marchTable.ObjectID, buildTable.ObjectID, marchTable.Point) // 改为待命状态 p.updateMarchState(marchTable, enum.MarchState_Standby, 0) } case constant.MapBuild_LeaguePoint: // 驻地 { clog.Debugf("[marchRetreatBuild] Retreat to LeaguePoint: MarchObjectID = %d, BuildObjectID = %d, Point = %v", marchTable.ObjectID, buildTable.ObjectID, marchTable.Point) // TODO: 这里应该判断主城是否进入了联盟驻地 // TODO: 这个需求还是有问题 watcherTable := p.WatcherTables.GetValue(marchTable.PlayerID) mainCity := p.BuildTables.GetValue(watcherTable.MainCity) if mainCity.IsHide { // 主城在驻地中,改为待命状态 p.updateMarchState(marchTable, enum.MarchState_Standby, 0) } else { // 否则改为调动状态 p.updateMarchState(marchTable, enum.MarchState_Redeploy, 0) } } case constant.MapBuild_SiegeBase: // 攻城大营 { clog.Debugf("[marchRetreatBuild] Retreat to SiegeBase: MarchObjectID = %d, BuildObjectID = %d, Point = %v", marchTable.ObjectID, buildTable.ObjectID, marchTable.Point) // 改为攻城集结状态 p.updateMarchState(marchTable, enum.MarchState_SiegeAssemble, 0) } default: { clog.Debugf("[marchRetreatBuild] Retreat to %v: MarchObjectID = %d, BuildObjectID = %d, Point = %v", buildTable.ConfigID, marchTable.ObjectID, buildTable.ObjectID, marchTable.Point) // 改为调动状态 p.updateMarchState(marchTable, enum.MarchState_Redeploy, 0) } } // 如果被撤退的建筑正被攻城,加入自动防守 if buildTable.IsBeingSiege() { mapCall.Player.AutoDefendRequest(marchTable.PlayerID, buildTable.ObjectID, []int32{marchTable.TeamID}) } // 如果不是停留状态,离开地图 if marchTable.State != enum.MarchState_Stay { mapCall.AOI.Leave(marchTable.ObjectID, enum.ObjectType_March) } } func (p *actor) marchRetreatCastle(marchTable *db.LogicMarchTable, castleTable *db.LogicCastleTable) { if !castleTable.IsCoverPoint(marchTable.X(), marchTable.Y()) { clog.Warnf("[marchRetreatCastle]: not cover point: MarchObjectID = %v, CastleObjectID = %v, Point = %v", marchTable.ObjectID, castleTable.ObjectID, marchTable.Point) // 设置为停留, 并不能让他触发碰撞 p.updateMarchState(marchTable, enum.MarchState_Stay, 0) return } // 只能撤退到联盟的城池 // TODO: 这里应该往外推到建筑外的点 if castleTable.PlayerID != marchTable.PlayerID && castleTable.LeagueID != marchTable.LeagueID { clog.Warnf("[marchRetreatCastle]: not league castle: MarchObjectID = %v, CastleObjectID = %v, Point = %v", marchTable.ObjectID, castleTable.ObjectID, marchTable.Point) // 设置为停留, 并不能让他触发碰撞 p.updateMarchState(marchTable, enum.MarchState_Stay, 0) return } clog.Debugf("[marchRetreatCastle] Retreat to Castle: MarchObjectID = %d, CastleObjectID = %d, Point = %v", marchTable.ObjectID, castleTable.ObjectID, marchTable.Point) // 如果卫城,改为攻城集结状态 if castleTable.CastleType == pb.SysObjType_so_town { p.updateMarchState(marchTable, enum.MarchState_SiegeAssemble, 0) } else { // 改为调动状态 p.updateMarchState(marchTable, enum.MarchState_Redeploy, 0) } // 如果被撤退的建筑正被攻城,加入自动防守 if castleTable.IsBeingSiege() { mapCall.Player.AutoDefendRequest(marchTable.PlayerID, castleTable.ObjectID, []int32{marchTable.TeamID}) } // 离开地图 mapCall.AOI.Leave(marchTable.ObjectID, enum.ObjectType_March) } func (p *actor) marchSave(marchTable *db.LogicMarchTable) { marchTable.IsDataChanged = false marchTable.Save2Queue() } func (p *actor) updateMarchState(marchTable *db.LogicMarchTable, newState enum.MarchState, endTime int64) { if endTime > 0 { clog.Debugf("[updateMarchState] objectID = %d, state = %s -> %s, endTime = %s", marchTable.ObjectID, enum.GetMarchStateName(marchTable.State), enum.GetMarchStateName(newState), times.MillisToDatetimeFormat(endTime), ) } else { clog.Debugf("[updateMarchState] objectID = %d, state = %s -> %s", marchTable.ObjectID, enum.GetMarchStateName(marchTable.State), enum.GetMarchStateName(newState)) } oldState := marchTable.State marchTable.UpdateState(newState, p.nowMillis, endTime) p.pushMarchState(marchTable, oldState, newState, false) p.armyLineMarchState(marchTable, oldState, newState) } func (p *actor) updateMarchStateEndTime(marchTable *db.LogicMarchTable, endTime int64) { clog.Debugf("[updateMarchStateEndTime] objectID = %d, endTime = %s", marchTable.ObjectID, times.MillisToDatetimeFormat(endTime)) marchTable.StateEndTime = endTime marchTable.IsDataChanged = true // 推送状态时间 mapCall.AOI.UpdateWithID(marchTable.ObjectID, marchTable.Type, p.newUpdateID(), nameRemote.MapLogic_AOIUpdateMarchState) } func (p *actor) restoreMarchState(marchTable *db.LogicMarchTable) { clog.Debugf("[restoreMarchState] state = %s -> %s, time offset = %v", enum.GetMarchStateName(marchTable.State), enum.GetMarchStateName(marchTable.PrevState), p.nowMillis-marchTable.PrevStateSaveTime) var ( oldState = marchTable.State newState = marchTable.PrevState ) marchTable.RestoreState(p.nowMillis) p.pushMarchState(marchTable, oldState, newState, false) } func (p *actor) restoreMarchStateAndPushAll(marchTable *db.LogicMarchTable) { clog.Debugf("[restoreMarchStateAndPushAll] state = %s -> %s, time offset = %v", enum.GetMarchStateName(marchTable.State), enum.GetMarchStateName(marchTable.PrevState), p.nowMillis-marchTable.PrevStateSaveTime) var ( oldState = marchTable.State newState = marchTable.PrevState ) marchTable.RestoreState(p.nowMillis) p.pushMarchState(marchTable, oldState, newState, true) } func (p *actor) pushMarchState(marchTable *db.LogicMarchTable, oldState, newState enum.MarchState, isPushAll bool) { var ( isOldStateInMap = enum.IsInMapState(oldState) isNewStateInMap = enum.IsInMapState(newState) ) // 队伍在地图上的位置发生变化就通知 game player if isOldStateInMap != isNewStateInMap { if isNewStateInMap { p.addMarchAOI(marchTable) } else { // 先推送Update if isPushAll { mapCall.AOI.UpdateAll(marchTable.ObjectID, marchTable.Type) } else { mapCall.AOI.UpdateWithID(marchTable.ObjectID, marchTable.Type, p.newUpdateID(), nameRemote.MapLogic_AOIUpdateMarchState) } // 再推送Leave mapCall.AOI.Leave(marchTable.ObjectID, marchTable.Type) } } else { if isNewStateInMap { // 推送march状态给客户端 if isPushAll { mapCall.AOI.UpdateAll(marchTable.ObjectID, marchTable.Type) } else { mapCall.AOI.UpdateWithID(marchTable.ObjectID, marchTable.Type, p.newUpdateID(), nameRemote.MapLogic_AOIUpdateMarchState) } } else { // 给自己推送数据 sessions.PushPlayer(marchTable.PlayerID, nameRoute.PushMapPusher_MarchState, marchTable.ToStatusProto()) } } // 通知ui更新 if isPushAll { p.PushMapUIMarchUpsert(marchTable.PlayerID, marchTable.ToMapUIProto()) } else { p.PushMapUIMarchState(marchTable.PlayerID, marchTable.ToStatusProto()) } // 更新部队状态为外派或者待命 if newState == enum.MarchState_Standby || oldState == enum.MarchState_Standby { if newState == enum.MarchState_Standby { mapCall.Player.MapPlayerUpdateTeamState(marchTable.PlayerID, marchTable.TeamID, enum.TeamState_Standby) clog.Debugf("[updateMarchState] objectID = %d, update team state to standby", marchTable.ObjectID) } else { mapCall.Player.MapPlayerUpdateTeamState(marchTable.PlayerID, marchTable.TeamID, enum.TeamState_Outing) clog.Debugf("[updateMarchState] objectID = %d, update team state to outing", marchTable.ObjectID) } } } func (p *actor) markMarchRetreat(marchTable *db.LogicMarchTable, retreatType enum.RetreatType, isRemoveRedeploy bool) { clog.Debugf("[addMarchToRetreat] objectID = %d, retreatType = %d, isRemoveRedeploy = %v", marchTable.ObjectID, retreatType, isRemoveRedeploy) // 脱离攻城大营管理 marchTable.MarkAutoSiege(false, 0) // 保底:先把行军状态设置为停留但不推送,也不加入停留列表 if marchTable.State == enum.MarchState_BattleWait || marchTable.State == enum.MarchState_Battle { marchTable.UpdateState(enum.MarchState_Stay, p.nowMillis, 0) } // 设置了自动回城,或者被击退,或者有资源运输,则加入撤退队列 if marchTable.IsAutoRetreat || retreatType == enum.RetreatType_Rout || retreatType == enum.RetreatType_Must { marchTable.StartAutoRetreat(retreatType, isRemoveRedeploy) } else { p.marchStay(marchTable) } } func (p *actor) addToTileMarch(marchTable *db.LogicMarchTable, tileTable *db.LogicTileTable) { tileTable.AddMarch(marchTable.ObjectID, dbLogic.NewTileMarchInfo( tileTable.TileID, marchTable.ObjectID, p.nowMillis, )) p.addTileProcess(tileTable) } func (p *actor) marchSiegeBaseRemove(marchTable *db.LogicMarchTable) { if !marchTable.AutoMarchInfo.IsAutoSiege { return } siegeCampID := marchTable.AutoMarchInfo.SiegeCampID clog.Debugf("[marchSiegeCampRemove] marchObjectID = %d, siegeCampID = %d", marchTable.ObjectID, siegeCampID) if castleTable, ok := p.CastleTables.Get(siegeCampID); ok { castleTable.SiegeTown.MainForceList.RemoveValue(marchTable.ObjectID) castleTable.SiegeTown.SiegeSquadList.RemoveValue(marchTable.ObjectID) castleTable.IsDataChanged = true } marchTable.MarkAutoSiege(false, 0) } func (p *actor) checkRedeployLimit(configID, level, redeployCount int32) int32 { mapBuildRow, found := data.MapRedeploy.GetByConfigIDLevel(configID, level) if found { // 没有上限 if mapBuildRow.RedeployLimit <= 0 { return code.OK } // 判断当前建筑的调动部队 if redeployCount >= mapBuildRow.RedeployLimit { return code.MapBuild_RedeployLimit } } // TODO 找不到 不改原来流程 默认能成功 return code.OK } func (p *actor) marchLeaveAOI(marchTable *db.LogicMarchTable) { mapCall.AOI.Leave(marchTable.ObjectID, marchTable.Type) } func (p *actor) marchMoveToPoint(marchTable *db.LogicMarchTable, point types.Point) { clog.Debugf("move marchTable to ponit: ObjectID = %d, MarchState = %s, MarchType = %s, Point = %v", marchTable.ObjectID, enum.GetMarchStateName(marchTable.State), enum.GetMarchTypeName(marchTable.MarchType), &point, ) // 从旧的 tileTable 中删除 tileTable := p.TileTables.GetValue(marchTable.GetTileID()) tileTable.RemoveMarchAnywhere(marchTable.ObjectID) p.addTileProcess(tileTable) marchTable.Point.Set(&point) marchTable.PrevPoint.Set(&point) marchTable.ClearPath() } // removeMarchRedeploy 移除行军调动 func (p *actor) removeMarchRedeploy(marchTable *db.LogicMarchTable, isTarget, isNotice bool) { if isTarget { if buildTable, ok := p.BuildTables.Get(marchTable.TargetObjectID); ok { buildTable.RemoveRedeploy(marchTable.ObjectID) p.UpdateObjectFull(buildTable.ObjectID, buildTable.Type) } else if castleTable, ok := p.CastleTables.Get(marchTable.TargetObjectID); ok { castleTable.RemoveRedeploy(marchTable.ObjectID) p.UpdateObjectFull(castleTable.ObjectID, castleTable.Type) } } else { if buildTable, ok := p.BuildTables.Get(marchTable.RedeployObject.Key); ok { buildTable.RemoveRedeploy(marchTable.ObjectID) p.UpdateObjectFull(buildTable.ObjectID, buildTable.Type) marchTable.SetRedeployObjectID(0, 0) if isNotice { p.updateTeam(marchTable, enum.TeamUpdate_Redeploy) } } else if castleTable, ok := p.CastleTables.Get(marchTable.RedeployObject.Key); ok { castleTable.RemoveRedeploy(marchTable.ObjectID) p.UpdateObjectFull(castleTable.ObjectID, castleTable.Type) marchTable.SetRedeployObjectID(0, 0) if isNotice { p.updateTeam(marchTable, enum.TeamUpdate_Redeploy) } } } } func (p *actor) updateTeam(marchTable *db.LogicMarchTable, updateType enum.TeamUpdateType) { req := &pb.UpdateTeam{ TeamID: marchTable.TeamID, TeamUpdateType: int32(updateType), } switch updateType { case enum.TeamUpdate_Redeploy: req.RedeployObjectID = marchTable.RedeployObject.Key req.RedeployObjectType = int32(marchTable.RedeployObject.Value) } mapCall.Player.UpdateTeam(marchTable.PlayerID, req) } // getCollidedBuilding 获取碰撞的建筑 func (p *actor) getCollidedBuilding(marchTable *db.LogicMarchTable, tileTable *db.LogicTileTable) *db.LogicBuildTable { // 撤退的行军对象不会发生碰撞 if marchTable.IsRetreat() { return nil } if tileTable.BuildObjectID > 0 { buildTable := p.BuildTables.GetValue(tileTable.BuildObjectID) if buildTable.ConfigID == constant.MapBuild_Barricade && !buildTable.IsBuilding && !p.isSameLeague(buildTable.LeagueID, marchTable.LeagueID) { return buildTable } } return nil } // marchBuildingCollision 建筑碰撞逻辑 func (p *actor) marchBuildingCollision(marchTable *db.LogicMarchTable, tileTable *db.LogicTileTable, buildTable *db.LogicBuildTable) { if buildTable.ConfigID != constant.MapBuild_Barricade { return } // 保存状态 marchTable.SaveState(p.nowMillis) // 更新为攻城状态 nextTime := p.nowMillis + ctime.MillisecondsPerSecond p.updateMarchState(marchTable, enum.MarchState_Siege, nextTime) // 设置拒马为当前目标 marchTable.TargetObjectID = buildTable.ObjectID // 加入攻城列表 tileMarchInfo := dbLogic.NewTileMarchInfo( tileTable.TileID, marchTable.ObjectID, p.nowMillis, buildTable.ObjectID, ) // 设置为首次攻城 tileMarchInfo.IsFirstSiege = true // 等待一个 ticker tileMarchInfo.LogicEndTime = nextTime // 加入攻城列表 tileTable.AddSiege(marchTable.ObjectID, tileMarchInfo) p.addTileProcess(tileTable) }