package mapLogic import ( "f1-game/internal/constant" "f1-game/internal/data" "f1-game/internal/enum" "f1-game/internal/extend/times" "f1-game/internal/pb" mapCall "f1-game/nodes/map/internal/call" "f1-game/nodes/map/internal/db" mapTypes "f1-game/nodes/map/internal/types" clog "github.com/cherry-game/cherry/logger" ) func (p *actor) legionTicker(legionTable *db.LogicLegionTable) { // 集结等待中 if legionTable.LegionState == enum.LegionState_AssembleWait { p.legionAssembleWait(legionTable) return } // 集结完成 if legionTable.LegionState == enum.LegionState_AssembleFinish { p.legionAssembleFinish(legionTable) return } // 集结行军 if legionTable.LegionState == enum.LegionState_AssembleMarch { p.legionAssembleMove(legionTable) return } } // 军团集结等待 func (p *actor) legionAssembleWait(legionTable *db.LogicLegionTable) { // 如果集结时间到了,就立即出发 if p.nowMillis >= legionTable.AssembleEndTime { clog.Debugf("assemble timeout: LegionObjectID = %d, Target = (%d %v)", legionTable.ObjectID, legionTable.TargetObjectID, legionTable.TargetPoint) p.updateLegionState(legionTable, enum.LegionState_AssembleFinish, 0) return } // 检查成员是否已满,如果没满,就继续等待 if len(legionTable.Members) < data.Const.MapAssembleMemberNum { return } // 检查所有成员是否都到达了 for _, member := range legionTable.Members { if !member.Value { return } } clog.Debugf("assemble all ready: LegionObjectID = %d, Target = (%d %v)", legionTable.ObjectID, legionTable.TargetObjectID, legionTable.TargetPoint) // 成员满了,且都到达了,就出发 p.updateLegionState(legionTable, enum.LegionState_AssembleFinish, 0) } // 军团集结完成 func (p *actor) legionAssembleFinish(legionTable *db.LogicLegionTable) { clog.Debugf("assemble finish, LegionObjectID = %d, MemberSize = %d", legionTable.ObjectID, len(legionTable.Members)) // 集结时间结束,只有一个成员,就解散 if len(legionTable.Members) == 1 { p.legionDisband(legionTable, enum.RetreatType_Retreat, true) return } for _, member := range legionTable.Members { if !member.Value { marchTable := p.MarchTables.GetValue(member.Key) // 可能发生了碰撞 if marchTable.State != enum.MarchState_MarchAssemble { return } // 如果是行军集结状态,就直接到达 p.marchMoveToPoint(marchTable, legionTable.Point) // 集结逻辑 p.marchAssemble(marchTable) } } // 更新状态 stateEndTime := p.nowMillis + int64(len(legionTable.Path)-1)*legionTable.Speed + constant.TickOffset_March p.updateLegionState(legionTable, enum.LegionState_AssembleMarch, stateEndTime) // 同时更新行军对象的状态 for _, member := range legionTable.Members { marchTable := p.MarchTables.GetValue(member.Key) marchTable.Start(legionTable.MarchType, enum.MarchState_Assemble, legionTable.Path, legionTable.Speed, p.nowMillis, marchTable.IsAutoRetreat) } // 通知联盟 mapCall.League.AssembleUpdate(legionTable.LeagueID, &pb.AssembleUpdate{ LegionObjectID: legionTable.ObjectID, IsDepart: true, }) } // 军团集结行军 func (p *actor) legionAssembleMove(legionTable *db.LogicLegionTable) { if legionTable.IsMoving() { p.legionAssembleMoving(legionTable) } if legionTable.IsArrived { p.legionArrive(legionTable) } } func (p *actor) legionAssembleMoving(legionTable *db.LogicLegionTable) { // 到达了 if legionTable.IsMoveArrive() { p.legionMarkArrive(legionTable) return } if !legionTable.CanMove(p.nowMillis) { return } // 移动军团 p.legionMove(legionTable) // TODO: 暂时屏蔽军团碰撞功能 // tileTable := p.TileTables.GetValue(legionTable.GetTileID()) // // 检查是否发生碰撞 // isMet, isAttack := p.isLegionMarchMeet(legionTable, tileTable) // if isMet { // p.legionMeet(legionTable, tileTable, isAttack) // return // } // if legionTable.IsMoveArrive() { // p.legionMarkArrive(legionTable) // } else { // p.addLegionToTileMarch(legionTable, tileTable) // } } // isLegionMarchMeet 检查是否发生碰撞 func (p *actor) isLegionMarchMeet(legionTable *db.LogicLegionTable, tileTable *db.LogicTileTable) (isMet bool, isAttack bool) { // 如果有碰撞,则加入进攻列表,否则加入行军列表 isMet, isAttack = p.isTileMeet(tileTable, 0, legionTable.LeagueID) if isMet { clog.Debugf("legion march tile meet result: objectID = %d, meet = %v, attack = %v", legionTable.ObjectID, isMet, isAttack) } return } func (p *actor) legionArrive(legionTable *db.LogicLegionTable) { clog.Debugf("[legionArrive]: legionObjectID = %d, marchType = %v, point = %v", legionTable.ObjectID, enum.GetMarchTypeName(legionTable.MarchType), legionTable.Point) // 防止在还是移动状态的情况下,tile 还没来得及处理就又一次进入 isArrived 逻辑 legionTable.ClearPath() legionTable.IsArrived = false for _, member := range legionTable.Members { marchTable := p.MarchTables.GetValue(member.Key) marchTable.ClearPath() marchTable.IsArrived = false } // 处理集结到达后的逻辑 switch legionTable.MarchType { case enum.MarchType_Crucade: // 讨伐 p.legionCrucade(legionTable) case enum.MarchType_Siege: // 攻城 p.legionSiege(legionTable) default: // 否则解散 p.legionDisband(legionTable, enum.RetreatType_Retreat, true) } } func (p *actor) legionCrucade(legionTable *db.LogicLegionTable) { clog.Debugf("legion crucade: LegionObjectID = %d, Target = (%d %v)", legionTable.ObjectID, legionTable.TargetObjectID, legionTable.TargetPoint) tileTable := p.TileTables.GetValue(legionTable.GetTileID()) monsterTable, ok := p.getMonsterTableInTile(tileTable) if !ok { clog.Debugf("[legionCrucade] Monster not found: MarchObjectID = %d, Point = %v", legionTable.ObjectID, tileTable.Point) p.legionDisband(legionTable, enum.RetreatType_Retreat, true) return } // 刷了新的怪物 if monsterTable.ObjectID != legionTable.TargetObjectID { clog.Debugf("[legionCrucade] Monster not match: MarchObjectID = %d, Point = %v, Target = %d, Found = %d", legionTable.ObjectID, tileTable.Point, legionTable.TargetObjectID, monsterTable.ObjectID) p.legionDisband(legionTable, enum.RetreatType_Retreat, true) return } // 加入讨伐列表 tileTable.AddCrusade(legionTable.ObjectID, mapTypes.NewTileLegionInfo( tileTable.TileID, legionTable.ObjectID, p.nowMillis, legionTable.MemberIDList(), )) // 设置为战斗状态 p.updateLegionState(legionTable, enum.LegionState_BattleWait, 0) p.addTileProcess(tileTable) } func (p *actor) legionSiege(legionTable *db.LogicLegionTable) { clog.Debugf("legion siege: LegionObjectID = %d, Target = (%d %v)", legionTable.ObjectID, legionTable.TargetObjectID, legionTable.TargetPoint) tileTable := p.TileTables.GetValue(legionTable.GetTileID()) mapSiegeObject, ok := p.getSiegeTable(tileTable) if !ok { clog.Debugf("[legionSiege]: siege not found, MarchObjectID = %v, Point = %v", legionTable.ObjectID, legionTable.Point) p.legionDisband(legionTable, enum.RetreatType_Retreat, true) return } // 不可以攻城 if !p.canLegionSiege(legionTable, mapSiegeObject) { clog.Debugf("[legionSiege]: not siegeable, MarchObjectID = %v, LeagueID = %v, SiegeObject = %v", legionTable.ObjectID, legionTable.LeagueID, mapSiegeObject) p.legionDisband(legionTable, enum.RetreatType_Retreat, true) return } // 更新为攻城状态 p.updateLegionState(legionTable, enum.LegionState_Siege, 0) tileLegionInfo := mapTypes.NewTileLegionInfo( tileTable.TileID, legionTable.ObjectID, p.nowMillis, legionTable.MemberIDList(), ) // 设置为首次攻城 tileLegionInfo.IsFirstSiege = true // 等待一个 ticker tileLegionInfo.LogicEndTime = p.nowMillis + 1000 // 加入攻城列表 tileTable.AddSiege(legionTable.ObjectID, tileLegionInfo) p.addTileProcess(tileTable) } // TODO 先不支持集结攻城 func (p *actor) canLegionSiege(legionTable *db.LogicLegionTable, siegeTable *db.LogicSiegeTable) bool { // // 判断建筑是否可以攻打 // if buildTable, ok := siegeObject.(*db.MapBuildTable); ok { // return buildTable.LeagueID != legionTable.LeagueID // } // // 判断城池是否可以攻打 // if castleTable, ok := siegeObject.(*db.MapCastleTable); ok { // // 己方城池不可攻打 // if castleTable.LeagueID == legionTable.LeagueID { // return false // } // // 没有占领攻城大营不可攻打 // siegeInfo, ok := castleTable.SiegeInfo.Get(legionTable.LeagueID) // if !ok { // return false // } // // 不在攻城时间内不可攻打 // return siegeInfo.Stage == enum.SiegeStage_Battle // } return false } func (p *actor) legionSiegeFail(legionTable *db.LogicLegionTable, tileTable *db.LogicTileTable) { // 移除攻城列表 tileTable.RemoveSiege(legionTable.ObjectID) // 解散 p.legionDisband(legionTable, enum.RetreatType_Rout, true) } func (p *actor) addLegionToTileMarch(legionTable *db.LogicLegionTable, tileTable *db.LogicTileTable) { for _, member := range legionTable.Members { marchTable := p.MarchTables.GetValue(member.Key) p.addToTileMarch(marchTable, tileTable) } } func (p *actor) legionMeet(legionTable *db.LogicLegionTable, tileTable *db.LogicTileTable, isAttack bool) { clog.Debugf("legion meet: LegionObjectID = %d, Target = (%d %v)", legionTable.ObjectID, legionTable.TargetObjectID, legionTable.TargetPoint) if isAttack { tileTable.AddAttackList(legionTable.ObjectID, mapTypes.NewTileLegionInfo( tileTable.TileID, legionTable.ObjectID, p.nowMillis, legionTable.MemberIDList(), )) // 保存当前状态 legionTable.SaveState(p.nowMillis) // 设为战斗等待状态 p.updateLegionState(legionTable, enum.LegionState_BattleWait, 0) } else { tileTable.AddMarch(legionTable.ObjectID, mapTypes.NewTileLegionInfo( tileTable.TileID, legionTable.ObjectID, p.nowMillis, legionTable.MemberIDList(), )) } } func (p *actor) legionMove(legionTable *db.LogicLegionTable) { legionTable.MoveNextTile(p.nowMillis) for _, member := range legionTable.Members { marchTable := p.MarchTables.GetValue(member.Key) marchTable.MoveNextTile(p.nowMillis) } mapCall.AOI.Move(legionTable.ToAOIMarker()) // 从上一个格子的行军列表移除 if prevTileID, ok := data.PointToTileID(legionTable.PrevPoint.X, legionTable.PrevPoint.Y); ok { prevTileTable := p.TileTables.GetValue(prevTileID) prevTileTable.RemoveMarch(legionTable.ObjectID) p.addTileProcess(prevTileTable) } clog.Debugf("Legion move: LegionObjectID = %d, Point = %v", legionTable.ObjectID, legionTable.Point) } func (p *actor) legionMarkArrive(legionTable *db.LogicLegionTable) { clog.Debugf("legion move arrive: LegionObjectID = %d, Target = (%d %v)", legionTable.ObjectID, legionTable.TargetObjectID, legionTable.TargetPoint) for _, member := range legionTable.Members { marchTable := p.MarchTables.GetValue(member.Key) marchTable.MarkArrive(true) } legionTable.IsArrived = true legionTable.IsDataChanged = true } func (p *actor) legionSave(legionTable *db.LogicLegionTable) { legionTable.IsDataChanged = false legionTable.Save2Queue() } // 军团解散 func (p *actor) legionDisband(legionTable *db.LogicLegionTable, restreatType enum.RetreatType, notice bool) { clog.Debugf("[legionDisband] LegionObjectID = %d", legionTable.ObjectID) for _, member := range legionTable.Members { marchTable := p.MarchTables.GetValue(member.Key) marchTable.SetLegionObjectID(0) // 到达的成员撤退 if member.Value { p.addMarchToRetreat(marchTable, restreatType, false) } } legionTable.IsDelete = true legionTable.IsDataChanged = true // 离开aoi p.legionLeaveAOI(legionTable) // 通知联盟 if notice { mapCall.League.AssembleUpdate(legionTable.LeagueID, &pb.AssembleUpdate{ LegionObjectID: legionTable.ObjectID, IsDisband: true, }) } } func (p *actor) updateLegionState(legionTable *db.LogicLegionTable, newState enum.LegionState, endTime int64) { if endTime > 0 { clog.Debugf("[updateLegionState] objectID = %d, state = %s -> %s, endTime = %s", legionTable.ObjectID, enum.GetLegionStateName(legionTable.LegionState), enum.GetLegionStateName(newState), times.MillisToDatetimeFormat(endTime), ) } else { clog.Debugf("[updateLegionState] objectID = %d, state = %s -> %s", legionTable.ObjectID, enum.GetLegionStateName(legionTable.LegionState), enum.GetLegionStateName(newState)) } legionTable.UpdateLegionState(newState) legionTable.UpdateMarchState(enum.GetMarchStateByLegionState(newState), p.nowMillis, endTime) p.UpdateObjectFull(legionTable.ObjectID, legionTable.Type) } // func (p *actor) restoreLegionState(legionTable *db.MapLegionTable) { // clog.Debugf("[restoreLegionState] state = %s -> %s, time offset = %v", // enum.GetLegionStateName(legionTable.LegionState), // enum.GetLegionStateName(legionTable.PrevState), // p.nowMillis-legionTable.PrevStateSaveTime) // legionTable.RestoreState(p.nowMillis) // // 推送march状态给客户端 // // mapCall.Pusher.MapMarchStateWatcherPush(marchTable.ObjectID) // } func (p *actor) addLegionAOI(legionTable *db.LogicLegionTable) { marker := legionTable.ToAOIMarker() mapCall.AOI.Enter(marker) } func (p *actor) legionLeaveAOI(legionTable *db.LogicLegionTable) { mapCall.AOI.Leave(legionTable.ObjectID, legionTable.Type) } func (p *actor) legionMemberQuit(legionTable *db.LogicLegionTable, marchObjectID int64) { legionTable.RemoveMember(marchObjectID) if legionTable.LeadObjectID == marchObjectID && legionTable.LegionState == enum.LegionState_AssembleWait || len(legionTable.Members) == 0 { p.legionDisband(legionTable, enum.RetreatType_Must, true) } else { mapCall.League.AssembleUpdate(legionTable.LeagueID, &pb.AssembleUpdate{ LegionObjectID: legionTable.ObjectID, QuitMember: marchObjectID, }) } legionTable.IsDataChanged = true }