package mapLogic import ( "f1-game/internal/constant" "f1-game/internal/enum" "f1-game/internal/event" "f1-game/internal/pb" "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) castleTimer() { for _, castleTable := range p.CastleTables { p.castleTicker(castleTable) if castleTable.IsDataChanged { castleTable.IsDataChanged = false castleTable.Save2Queue() } } } func (p *actor) castleTicker(castleTable *db.LogicCastleTable) { // 攻城地基的逻辑 if castleTable.CastleType == pb.SysObjType_so_town { p.castleSiegeTownLogic(castleTable) } // 攻城判断 if castleTable.IsBeingSiege() { p.castleSiegeCheck(castleTable) } } func (p *actor) castleSiegeCheck(castleTable *db.LogicCastleTable) { for tileID := range castleTable.SiegeTiles { tileTable := p.TileTables.GetValue(tileID) if !tileTable.HasSiege() { castleTable.RemoveSiegeTile(tileID) } } // 如果没有再被攻城了,通知自动防守部队解散 if !castleTable.IsBeingSiege() { p.castleAutoDefendQuit(castleTable) } } func (p *actor) castleSiegeTownLogic(castleTable *db.LogicCastleTable) { siegeTown := &castleTable.SiegeTown // 未处于攻城阶段 if !siegeTown.IsInSiegeStage() { return } // 更换阶段 if p.nowMillis >= siegeTown.SiegeStageEndTime { switch siegeTown.SiegeStage { case enum.SiegeStage_Prepare: // 宣战 -> 攻城 p.onCastleSiegeTownStart(castleTable) case enum.SiegeStage_Battle: // 攻城 -> 结束 p.onCastleSiegeTownTimeout(castleTable) } } // 未进行攻城 if siegeTown.AutoSiegeStage == enum.AutoSiegeStage_None { return } switch siegeTown.AutoSiegeStage { case enum.AutoSiegeStage_MainForce, enum.AutoSiegeStage_SiegeSquad: { p.castleSiegeTownAutoMainForce(castleTable) if siegeTown.AutoSiegeStage == enum.AutoSiegeStage_SiegeSquad { p.castleSiegeTownAutoSiegeSquad(castleTable) } } case enum.AutoSiegeStage_Siege: { p.castleSiegeTownAutoSiege(castleTable) } } // 判断是否需要切换阶段 castleTable.CheckAutoSiegeStage(p.nowMillis) } // 城池攻城战开始 func (p *actor) onCastleSiegeTownStart(castleTable *db.LogicCastleTable) { siegeTown := &castleTable.SiegeTown // 设置攻城阶段和结束时间 siegeTown.SiegeStage = enum.SiegeStage_Battle siegeTown.SiegeStageEndTime = p.nowMillis + constant.MapCastleSiegeTime castleTable.IsDataChanged = true clog.Debugf( "castle siege town start: SiegeTownObjectID = %d, CastleObjectID = %d, LeagueID = %d, endTime = %s", castleTable.ObjectID, castleTable.ParentObjectID, castleTable.LeagueID, ctime.CreateFromTimestamp(siegeTown.SiegeStageEndTime).ToDateTimeFormat(), ) p.UpdateObjectFull(castleTable.ObjectID, castleTable.Type) // 抛事件 p.PostEvent(event.NewWarUpdate(castleTable.LeagueID, &event.WarUpdateData{ CastleObjectID: castleTable.ParentObjectID, Stage: siegeTown.SiegeStage, StageEndTime: siegeTown.SiegeStageEndTime, MainForceNum: -1, SiegeSquadNum: -1, })) } func (p *actor) onCastleSiegeTownTimeout(castleTable *db.LogicCastleTable) { siegeTown := &castleTable.SiegeTown // 设置为结束 siegeTown.SiegeStage = enum.SiegeStage_End castleTable.ResetSiegeTown(false) clog.Debugf("castle siege timeout: SiegeTownObjectID = %d, CastleObjectID = %d, LeagueID = %d", castleTable.ObjectID, castleTable.ParentObjectID, castleTable.LeagueID) // 抛事件 p.PostEvent(event.NewWarUpdate(castleTable.LeagueID, &event.WarUpdateData{ CastleObjectID: castleTable.ParentObjectID, Stage: siegeTown.SiegeStage, MainForceNum: -1, SiegeSquadNum: -1, })) } // 攻城大营主力自动出兵 // 需要分配两段路径:攻城大营 -> 中间路径 -> 攻城点 func (p *actor) castleSiegeTownAutoMainForce(castleTable *db.LogicCastleTable) { siegeTown := &castleTable.SiegeTown if siegeTown.MainForcePrepareList.Size() == 0 { return } count := len(siegeTown.MainForceDepartPath) for range count { if siegeTown.MainForcePrepareList.IsEmpty() { break } marchObjectID := siegeTown.MainForcePrepareList.Remove(0) marchTable := p.MarchTables.GetValue(marchObjectID) index := siegeTown.MainForceIndex % count // 第一段路径 path1 := siegeTown.MainForceDepartPath[index] segment1 := dbLogic.NewAutoMarchSegment(enum.MarchType_Stay, path1, p.nowMillis, constant.MapMainForceWaitTimePart1) marchTable.AutoMarchInfo.Segments.Add(segment1) // 第二段路径 path2 := siegeTown.MainForceArrivePath[index] segment2 := dbLogic.NewAutoMarchSegment(enum.MarchType_Siege, path2, 0, constant.MapMainForceWaitTimePart2) marchTable.AutoMarchInfo.Segments.Add(segment2) marchTable.MarkStartAutoSiege(castleTable.ParentObjectID) siegeTown.MainForceIndex++ castleTable.IsDataChanged = true } } // 攻城大营拆迁队自动出兵 // 需要分配两段路径:攻城大营 -> 中间路径 -> 攻城点 func (p *actor) castleSiegeTownAutoSiegeSquad(castleTable *db.LogicCastleTable) { siegeTown := &castleTable.SiegeTown if siegeTown.SiegeSquadPrepareList.Size() == 0 { return } count := len(siegeTown.SiegeSquadDepartPath) for range count { if siegeTown.SiegeSquadPrepareList.IsEmpty() { break } marchObjectID := siegeTown.SiegeSquadPrepareList.Remove(0) marchTable := p.MarchTables.GetValue(marchObjectID) index := siegeTown.SiegeSquadIndex % count // 第一段路径 path1 := siegeTown.SiegeSquadDepartPath[index] segment1 := dbLogic.NewAutoMarchSegment(enum.MarchType_Stay, path1, p.nowMillis, constant.MapSiegeSquadWaitTimePart1) marchTable.AutoMarchInfo.Segments.Add(segment1) // 第二段路径 path2 := siegeTown.SiegeSquadArrivePath[index] segment2 := dbLogic.NewAutoMarchSegment(enum.MarchType_Siege, path2, 0, constant.MapSiegeSquadWaitTimePart2) marchTable.AutoMarchInfo.Segments.Add(segment2) marchTable.MarkStartAutoSiege(castleTable.ParentObjectID) siegeTown.SiegeSquadIndex++ castleTable.IsDataChanged = true } } // 攻城大营自动出兵攻城 // 只给两个列表的部队分配一段路径:攻城大营 -> 攻城点 func (p *actor) castleSiegeTownAutoSiege(castleTable *db.LogicCastleTable) { siegeTown := &castleTable.SiegeTown // 给主力分配 if !siegeTown.MainForcePrepareList.IsEmpty() { count := len(siegeTown.DirectPath) for range count { if siegeTown.MainForcePrepareList.IsEmpty() { break } marchObjectID := siegeTown.MainForcePrepareList.Remove(0) marchTable := p.MarchTables.GetValue(marchObjectID) // 一段路径 index := siegeTown.MainForceIndex % count path := siegeTown.DirectPath[index] segment := dbLogic.NewAutoMarchSegment(enum.MarchType_Siege, path, p.nowMillis, constant.MapAutoSiegeWaitTimePart3) marchTable.AutoMarchInfo.Segments.Add(segment) marchTable.MarkStartAutoSiege(castleTable.ParentObjectID) siegeTown.MainForceIndex++ castleTable.IsDataChanged = true } } // 给拆迁队分配 if !siegeTown.SiegeSquadPrepareList.IsEmpty() { count := len(siegeTown.DirectPath) for range count { if siegeTown.SiegeSquadPrepareList.IsEmpty() { break } marchObjectID := siegeTown.SiegeSquadPrepareList.Remove(0) marchTable := p.MarchTables.GetValue(marchObjectID) // 一段路径 index := siegeTown.SiegeSquadIndex % count path := siegeTown.DirectPath[index] segment := dbLogic.NewAutoMarchSegment(enum.MarchType_Siege, path, p.nowMillis, ctime.MillisecondsPerSecond) marchTable.AutoMarchInfo.Segments.Add(segment) marchTable.MarkStartAutoSiege(castleTable.ParentObjectID) siegeTown.SiegeSquadIndex++ castleTable.IsDataChanged = true } } } func (p *actor) castleAutoDefendQuit(castleTable *db.LogicCastleTable) { playerIDs := types.Set[int64]{} for _, marchObjectID := range castleTable.RedeployObjects { marchTable := p.MarchTables.GetValue(marchObjectID) playerIDs.Add(marchTable.PlayerID) } castleTable.AutoDefendList.Clear() castleTable.IsDataChanged = true if !playerIDs.IsEmpty() { for playerID := range playerIDs { mapCall.Player.AutoDefendQuit(playerID, castleTable.ObjectID) } } }