actor_castle.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. package mapLogic
  2. import (
  3. "f1-game/internal/constant"
  4. "f1-game/internal/enum"
  5. "f1-game/internal/event"
  6. "f1-game/internal/pb"
  7. "f1-game/internal/types"
  8. mapCall "f1-game/nodes/map/internal/call"
  9. "f1-game/nodes/map/internal/db"
  10. dbLogic "f1-game/nodes/map/internal/db/data/logic"
  11. ctime "github.com/cherry-game/cherry/extend/time"
  12. clog "github.com/cherry-game/cherry/logger"
  13. )
  14. func (p *actor) castleTimer() {
  15. for _, castleTable := range p.CastleTables {
  16. p.castleTicker(castleTable)
  17. if castleTable.IsDataChanged {
  18. castleTable.IsDataChanged = false
  19. castleTable.Save2Queue()
  20. }
  21. }
  22. }
  23. func (p *actor) castleTicker(castleTable *db.LogicCastleTable) {
  24. // 攻城地基的逻辑
  25. if castleTable.CastleType == pb.SysObjType_so_town {
  26. p.castleSiegeTownLogic(castleTable)
  27. }
  28. // 攻城判断
  29. if castleTable.IsBeingSiege() {
  30. p.castleSiegeCheck(castleTable)
  31. }
  32. }
  33. func (p *actor) castleSiegeCheck(castleTable *db.LogicCastleTable) {
  34. for tileID := range castleTable.SiegeTiles {
  35. tileTable := p.TileTables.GetValue(tileID)
  36. if !tileTable.HasSiege() {
  37. castleTable.RemoveSiegeTile(tileID)
  38. }
  39. }
  40. // 如果没有再被攻城了,通知自动防守部队解散
  41. if !castleTable.IsBeingSiege() {
  42. p.castleAutoDefendQuit(castleTable)
  43. }
  44. }
  45. func (p *actor) castleSiegeTownLogic(castleTable *db.LogicCastleTable) {
  46. siegeTown := &castleTable.SiegeTown
  47. // 未处于攻城阶段
  48. if !siegeTown.IsInSiegeStage() {
  49. return
  50. }
  51. // 更换阶段
  52. if p.nowMillis >= siegeTown.SiegeStageEndTime {
  53. switch siegeTown.SiegeStage {
  54. case enum.SiegeStage_Prepare: // 宣战 -> 攻城
  55. p.onCastleSiegeTownStart(castleTable)
  56. case enum.SiegeStage_Battle: // 攻城 -> 结束
  57. p.onCastleSiegeTownTimeout(castleTable)
  58. }
  59. }
  60. // 未进行攻城
  61. if siegeTown.AutoSiegeStage == enum.AutoSiegeStage_None {
  62. return
  63. }
  64. switch siegeTown.AutoSiegeStage {
  65. case enum.AutoSiegeStage_MainForce, enum.AutoSiegeStage_SiegeSquad:
  66. {
  67. p.castleSiegeTownAutoMainForce(castleTable)
  68. if siegeTown.AutoSiegeStage == enum.AutoSiegeStage_SiegeSquad {
  69. p.castleSiegeTownAutoSiegeSquad(castleTable)
  70. }
  71. }
  72. case enum.AutoSiegeStage_Siege:
  73. {
  74. p.castleSiegeTownAutoSiege(castleTable)
  75. }
  76. }
  77. // 判断是否需要切换阶段
  78. castleTable.CheckAutoSiegeStage(p.nowMillis)
  79. }
  80. // 城池攻城战开始
  81. func (p *actor) onCastleSiegeTownStart(castleTable *db.LogicCastleTable) {
  82. siegeTown := &castleTable.SiegeTown
  83. // 设置攻城阶段和结束时间
  84. siegeTown.SiegeStage = enum.SiegeStage_Battle
  85. siegeTown.SiegeStageEndTime = p.nowMillis + constant.MapCastleSiegeTime
  86. castleTable.IsDataChanged = true
  87. clog.Debugf(
  88. "castle siege town start: SiegeTownObjectID = %d, CastleObjectID = %d, LeagueID = %d, endTime = %s",
  89. castleTable.ObjectID, castleTable.ParentObjectID, castleTable.LeagueID,
  90. ctime.CreateFromTimestamp(siegeTown.SiegeStageEndTime).ToDateTimeFormat(),
  91. )
  92. p.UpdateObjectFull(castleTable.ObjectID, castleTable.Type)
  93. // 抛事件
  94. p.PostEvent(event.NewWarUpdate(castleTable.LeagueID, &event.WarUpdateData{
  95. CastleObjectID: castleTable.ParentObjectID,
  96. Stage: siegeTown.SiegeStage,
  97. StageEndTime: siegeTown.SiegeStageEndTime,
  98. MainForceNum: -1,
  99. SiegeSquadNum: -1,
  100. }))
  101. }
  102. func (p *actor) onCastleSiegeTownTimeout(castleTable *db.LogicCastleTable) {
  103. siegeTown := &castleTable.SiegeTown
  104. // 设置为结束
  105. siegeTown.SiegeStage = enum.SiegeStage_End
  106. castleTable.ResetSiegeTown(false)
  107. clog.Debugf("castle siege timeout: SiegeTownObjectID = %d, CastleObjectID = %d, LeagueID = %d",
  108. castleTable.ObjectID, castleTable.ParentObjectID, castleTable.LeagueID)
  109. // 抛事件
  110. p.PostEvent(event.NewWarUpdate(castleTable.LeagueID, &event.WarUpdateData{
  111. CastleObjectID: castleTable.ParentObjectID,
  112. Stage: siegeTown.SiegeStage,
  113. MainForceNum: -1,
  114. SiegeSquadNum: -1,
  115. }))
  116. }
  117. // 攻城大营主力自动出兵
  118. // 需要分配两段路径:攻城大营 -> 中间路径 -> 攻城点
  119. func (p *actor) castleSiegeTownAutoMainForce(castleTable *db.LogicCastleTable) {
  120. siegeTown := &castleTable.SiegeTown
  121. if siegeTown.MainForcePrepareList.Size() == 0 {
  122. return
  123. }
  124. count := len(siegeTown.MainForceDepartPath)
  125. for range count {
  126. if siegeTown.MainForcePrepareList.IsEmpty() {
  127. break
  128. }
  129. marchObjectID := siegeTown.MainForcePrepareList.Remove(0)
  130. marchTable := p.MarchTables.GetValue(marchObjectID)
  131. index := siegeTown.MainForceIndex % count
  132. // 第一段路径
  133. path1 := siegeTown.MainForceDepartPath[index]
  134. segment1 := dbLogic.NewAutoMarchSegment(enum.MarchType_Stay, path1, p.nowMillis, constant.MapMainForceWaitTimePart1)
  135. marchTable.AutoMarchInfo.Segments.Add(segment1)
  136. // 第二段路径
  137. path2 := siegeTown.MainForceArrivePath[index]
  138. segment2 := dbLogic.NewAutoMarchSegment(enum.MarchType_Siege, path2, 0, constant.MapMainForceWaitTimePart2)
  139. marchTable.AutoMarchInfo.Segments.Add(segment2)
  140. marchTable.MarkStartAutoSiege(castleTable.ParentObjectID)
  141. siegeTown.MainForceIndex++
  142. castleTable.IsDataChanged = true
  143. }
  144. }
  145. // 攻城大营拆迁队自动出兵
  146. // 需要分配两段路径:攻城大营 -> 中间路径 -> 攻城点
  147. func (p *actor) castleSiegeTownAutoSiegeSquad(castleTable *db.LogicCastleTable) {
  148. siegeTown := &castleTable.SiegeTown
  149. if siegeTown.SiegeSquadPrepareList.Size() == 0 {
  150. return
  151. }
  152. count := len(siegeTown.SiegeSquadDepartPath)
  153. for range count {
  154. if siegeTown.SiegeSquadPrepareList.IsEmpty() {
  155. break
  156. }
  157. marchObjectID := siegeTown.SiegeSquadPrepareList.Remove(0)
  158. marchTable := p.MarchTables.GetValue(marchObjectID)
  159. index := siegeTown.SiegeSquadIndex % count
  160. // 第一段路径
  161. path1 := siegeTown.SiegeSquadDepartPath[index]
  162. segment1 := dbLogic.NewAutoMarchSegment(enum.MarchType_Stay, path1, p.nowMillis, constant.MapSiegeSquadWaitTimePart1)
  163. marchTable.AutoMarchInfo.Segments.Add(segment1)
  164. // 第二段路径
  165. path2 := siegeTown.SiegeSquadArrivePath[index]
  166. segment2 := dbLogic.NewAutoMarchSegment(enum.MarchType_Siege, path2, 0, constant.MapSiegeSquadWaitTimePart2)
  167. marchTable.AutoMarchInfo.Segments.Add(segment2)
  168. marchTable.MarkStartAutoSiege(castleTable.ParentObjectID)
  169. siegeTown.SiegeSquadIndex++
  170. castleTable.IsDataChanged = true
  171. }
  172. }
  173. // 攻城大营自动出兵攻城
  174. // 只给两个列表的部队分配一段路径:攻城大营 -> 攻城点
  175. func (p *actor) castleSiegeTownAutoSiege(castleTable *db.LogicCastleTable) {
  176. siegeTown := &castleTable.SiegeTown
  177. // 给主力分配
  178. if !siegeTown.MainForcePrepareList.IsEmpty() {
  179. count := len(siegeTown.DirectPath)
  180. for range count {
  181. if siegeTown.MainForcePrepareList.IsEmpty() {
  182. break
  183. }
  184. marchObjectID := siegeTown.MainForcePrepareList.Remove(0)
  185. marchTable := p.MarchTables.GetValue(marchObjectID)
  186. // 一段路径
  187. index := siegeTown.MainForceIndex % count
  188. path := siegeTown.DirectPath[index]
  189. segment := dbLogic.NewAutoMarchSegment(enum.MarchType_Siege, path, p.nowMillis, constant.MapAutoSiegeWaitTimePart3)
  190. marchTable.AutoMarchInfo.Segments.Add(segment)
  191. marchTable.MarkStartAutoSiege(castleTable.ParentObjectID)
  192. siegeTown.MainForceIndex++
  193. castleTable.IsDataChanged = true
  194. }
  195. }
  196. // 给拆迁队分配
  197. if !siegeTown.SiegeSquadPrepareList.IsEmpty() {
  198. count := len(siegeTown.DirectPath)
  199. for range count {
  200. if siegeTown.SiegeSquadPrepareList.IsEmpty() {
  201. break
  202. }
  203. marchObjectID := siegeTown.SiegeSquadPrepareList.Remove(0)
  204. marchTable := p.MarchTables.GetValue(marchObjectID)
  205. // 一段路径
  206. index := siegeTown.SiegeSquadIndex % count
  207. path := siegeTown.DirectPath[index]
  208. segment := dbLogic.NewAutoMarchSegment(enum.MarchType_Siege, path, p.nowMillis, ctime.MillisecondsPerSecond)
  209. marchTable.AutoMarchInfo.Segments.Add(segment)
  210. marchTable.MarkStartAutoSiege(castleTable.ParentObjectID)
  211. siegeTown.SiegeSquadIndex++
  212. castleTable.IsDataChanged = true
  213. }
  214. }
  215. }
  216. func (p *actor) castleAutoDefendQuit(castleTable *db.LogicCastleTable) {
  217. playerIDs := types.Set[int64]{}
  218. for _, marchObjectID := range castleTable.RedeployObjects {
  219. marchTable := p.MarchTables.GetValue(marchObjectID)
  220. playerIDs.Add(marchTable.PlayerID)
  221. }
  222. castleTable.AutoDefendList.Clear()
  223. castleTable.IsDataChanged = true
  224. if !playerIDs.IsEmpty() {
  225. for playerID := range playerIDs {
  226. mapCall.Player.AutoDefendQuit(playerID, castleTable.ObjectID)
  227. }
  228. }
  229. }