actor_legion.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. package mapLogic
  2. import (
  3. "f1-game/internal/constant"
  4. "f1-game/internal/data"
  5. "f1-game/internal/enum"
  6. "f1-game/internal/extend/times"
  7. "f1-game/internal/pb"
  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. clog "github.com/cherry-game/cherry/logger"
  12. )
  13. func (p *actor) legionTicker(legionTable *db.LogicLegionTable) {
  14. // 集结等待中
  15. if legionTable.LegionState == enum.LegionState_AssembleWait {
  16. p.legionAssembleWait(legionTable)
  17. return
  18. }
  19. // 集结完成
  20. if legionTable.LegionState == enum.LegionState_AssembleFinish {
  21. p.legionAssembleFinish(legionTable)
  22. return
  23. }
  24. // 集结行军
  25. if legionTable.LegionState == enum.LegionState_AssembleMarch {
  26. p.legionAssembleMove(legionTable)
  27. return
  28. }
  29. }
  30. // 军团集结等待
  31. func (p *actor) legionAssembleWait(legionTable *db.LogicLegionTable) {
  32. // 如果集结时间到了,就立即出发
  33. if p.nowMillis >= legionTable.AssembleEndTime {
  34. clog.Debugf("assemble timeout: LegionObjectID = %d, Target = (%d %v)",
  35. legionTable.ObjectID, legionTable.TargetObjectID, legionTable.TargetPoint)
  36. p.updateLegionState(legionTable, enum.LegionState_AssembleFinish, 0)
  37. return
  38. }
  39. // 检查成员是否已满,如果没满,就继续等待
  40. if len(legionTable.Members) < data.Const.MapAssembleMemberNum {
  41. return
  42. }
  43. // 检查所有成员是否都到达了
  44. for _, member := range legionTable.Members {
  45. if !member.Value {
  46. return
  47. }
  48. }
  49. clog.Debugf("assemble all ready: LegionObjectID = %d, Target = (%d %v)",
  50. legionTable.ObjectID, legionTable.TargetObjectID, legionTable.TargetPoint)
  51. // 成员满了,且都到达了,就出发
  52. p.updateLegionState(legionTable, enum.LegionState_AssembleFinish, 0)
  53. }
  54. // 军团集结完成
  55. func (p *actor) legionAssembleFinish(legionTable *db.LogicLegionTable) {
  56. clog.Debugf("assemble finish, LegionObjectID = %d, MemberSize = %d", legionTable.ObjectID, len(legionTable.Members))
  57. // 集结时间结束,只有一个成员,就解散
  58. if len(legionTable.Members) == 1 {
  59. p.legionDisband(legionTable, enum.RetreatType_Retreat, true)
  60. return
  61. }
  62. for _, member := range legionTable.Members {
  63. if !member.Value {
  64. marchTable := p.MarchTables.GetValue(member.Key)
  65. // 可能发生了碰撞
  66. if marchTable.State != enum.MarchState_MarchAssemble {
  67. return
  68. }
  69. // 如果是行军集结状态,就直接到达
  70. p.marchMoveToPoint(marchTable, legionTable.Point)
  71. // 集结逻辑
  72. p.marchAssemble(marchTable)
  73. }
  74. }
  75. // 更新状态
  76. stateEndTime := p.nowMillis + int64(len(legionTable.Path)-1)*legionTable.Speed + constant.TickOffset_March
  77. p.updateLegionState(legionTable, enum.LegionState_AssembleMarch, stateEndTime)
  78. // 同时更新行军对象的状态
  79. for _, member := range legionTable.Members {
  80. marchTable := p.MarchTables.GetValue(member.Key)
  81. marchTable.Start(legionTable.MarchType, enum.MarchState_Assemble, legionTable.Path, legionTable.Speed, p.nowMillis, marchTable.IsAutoRetreat)
  82. }
  83. // 通知联盟
  84. mapCall.League.AssembleUpdate(legionTable.LeagueID, &pb.AssembleUpdate{
  85. LegionObjectID: legionTable.ObjectID,
  86. IsDepart: true,
  87. })
  88. }
  89. // 军团集结行军
  90. func (p *actor) legionAssembleMove(legionTable *db.LogicLegionTable) {
  91. if legionTable.IsMoving() {
  92. p.legionAssembleMoving(legionTable)
  93. }
  94. if legionTable.IsArrived {
  95. p.legionArrive(legionTable)
  96. }
  97. }
  98. func (p *actor) legionAssembleMoving(legionTable *db.LogicLegionTable) {
  99. // 到达了
  100. if legionTable.IsMoveArrive() {
  101. p.legionMarkArrive(legionTable)
  102. return
  103. }
  104. if !legionTable.CanMove(p.nowMillis) {
  105. return
  106. }
  107. // 移动军团
  108. p.legionMove(legionTable)
  109. // TODO: 暂时屏蔽军团碰撞功能
  110. // tileTable := p.TileTables.GetValue(legionTable.GetTileID())
  111. // // 检查是否发生碰撞
  112. // isMet, isAttack := p.isLegionMarchMeet(legionTable, tileTable)
  113. // if isMet {
  114. // p.legionMeet(legionTable, tileTable, isAttack)
  115. // return
  116. // }
  117. // if legionTable.IsMoveArrive() {
  118. // p.legionMarkArrive(legionTable)
  119. // } else {
  120. // p.addLegionToTileMarch(legionTable, tileTable)
  121. // }
  122. }
  123. // isLegionMarchMeet 检查是否发生碰撞
  124. func (p *actor) isLegionMarchMeet(legionTable *db.LogicLegionTable, tileTable *db.LogicTileTable) (isMet bool, isAttack bool) {
  125. // 如果有碰撞,则加入进攻列表,否则加入行军列表
  126. isMet, isAttack = p.isTileMeet(tileTable, 0, legionTable.LeagueID)
  127. if isMet {
  128. clog.Debugf("legion march tile meet result: objectID = %d, meet = %v, attack = %v", legionTable.ObjectID, isMet, isAttack)
  129. }
  130. return
  131. }
  132. func (p *actor) legionArrive(legionTable *db.LogicLegionTable) {
  133. clog.Debugf("[legionArrive]: legionObjectID = %d, marchType = %v, point = %v",
  134. legionTable.ObjectID, enum.GetMarchTypeName(legionTable.MarchType), legionTable.Point)
  135. // 防止在还是移动状态的情况下,tile 还没来得及处理就又一次进入 isArrived 逻辑
  136. legionTable.ClearPath()
  137. legionTable.IsArrived = false
  138. for _, member := range legionTable.Members {
  139. marchTable := p.MarchTables.GetValue(member.Key)
  140. marchTable.ClearPath()
  141. marchTable.IsArrived = false
  142. }
  143. // 处理集结到达后的逻辑
  144. switch legionTable.MarchType {
  145. case enum.MarchType_Crucade:
  146. // 讨伐
  147. p.legionCrucade(legionTable)
  148. case enum.MarchType_Siege:
  149. // 攻城
  150. p.legionSiege(legionTable)
  151. default:
  152. // 否则解散
  153. p.legionDisband(legionTable, enum.RetreatType_Retreat, true)
  154. }
  155. }
  156. func (p *actor) legionCrucade(legionTable *db.LogicLegionTable) {
  157. clog.Debugf("legion crucade: LegionObjectID = %d, Target = (%d %v)",
  158. legionTable.ObjectID, legionTable.TargetObjectID, legionTable.TargetPoint)
  159. tileTable := p.TileTables.GetValue(legionTable.GetTileID())
  160. monsterTable, ok := p.getMonsterTableInTile(tileTable)
  161. if !ok {
  162. clog.Debugf("[legionCrucade] Monster not found: MarchObjectID = %d, Point = %v", legionTable.ObjectID, tileTable.Point)
  163. p.legionDisband(legionTable, enum.RetreatType_Retreat, true)
  164. return
  165. }
  166. // 刷了新的怪物
  167. if monsterTable.ObjectID != legionTable.TargetObjectID {
  168. clog.Debugf("[legionCrucade] Monster not match: MarchObjectID = %d, Point = %v, Target = %d, Found = %d",
  169. legionTable.ObjectID, tileTable.Point, legionTable.TargetObjectID, monsterTable.ObjectID)
  170. p.legionDisband(legionTable, enum.RetreatType_Retreat, true)
  171. return
  172. }
  173. // 加入讨伐列表
  174. tileTable.AddCrusade(legionTable.ObjectID, dbLogic.NewTileLegionInfo(
  175. tileTable.TileID,
  176. legionTable.ObjectID,
  177. p.nowMillis,
  178. legionTable.MemberIDList(),
  179. ))
  180. // 设置为战斗状态
  181. p.updateLegionState(legionTable, enum.LegionState_BattleWait, 0)
  182. p.addTileProcess(tileTable)
  183. }
  184. func (p *actor) legionSiege(legionTable *db.LogicLegionTable) {
  185. clog.Debugf("legion siege: LegionObjectID = %d, Target = (%d %v)",
  186. legionTable.ObjectID, legionTable.TargetObjectID, legionTable.TargetPoint)
  187. tileTable := p.TileTables.GetValue(legionTable.GetTileID())
  188. mapSiegeObject, ok := p.getSiegeTable(tileTable)
  189. if !ok {
  190. clog.Debugf("[legionSiege]: siege not found, MarchObjectID = %v, Point = %v", legionTable.ObjectID, legionTable.Point)
  191. p.legionDisband(legionTable, enum.RetreatType_Retreat, true)
  192. return
  193. }
  194. // 不可以攻城
  195. if !p.canLegionSiege(legionTable, mapSiegeObject) {
  196. clog.Debugf("[legionSiege]: not siegeable, MarchObjectID = %v, LeagueID = %v, SiegeObject = %v",
  197. legionTable.ObjectID, legionTable.LeagueID, mapSiegeObject)
  198. p.legionDisband(legionTable, enum.RetreatType_Retreat, true)
  199. return
  200. }
  201. // 更新为攻城状态
  202. p.updateLegionState(legionTable, enum.LegionState_Siege, 0)
  203. tileLegionInfo := dbLogic.NewTileLegionInfo(
  204. tileTable.TileID,
  205. legionTable.ObjectID,
  206. p.nowMillis,
  207. legionTable.MemberIDList(),
  208. )
  209. // 设置为首次攻城
  210. tileLegionInfo.IsFirstSiege = true
  211. // 等待一个 ticker
  212. tileLegionInfo.LogicEndTime = p.nowMillis + 1000
  213. // 加入攻城列表
  214. tileTable.AddSiege(legionTable.ObjectID, tileLegionInfo)
  215. p.addTileProcess(tileTable)
  216. }
  217. // TODO 先不支持集结攻城
  218. func (p *actor) canLegionSiege(legionTable *db.LogicLegionTable, siegeTable *db.LogicSiegeTable) bool {
  219. // // 判断建筑是否可以攻打
  220. // if buildTable, ok := siegeObject.(*db.MapBuildTable); ok {
  221. // return buildTable.LeagueID != legionTable.LeagueID
  222. // }
  223. // // 判断城池是否可以攻打
  224. // if castleTable, ok := siegeObject.(*db.MapCastleTable); ok {
  225. // // 己方城池不可攻打
  226. // if castleTable.LeagueID == legionTable.LeagueID {
  227. // return false
  228. // }
  229. // // 没有占领攻城大营不可攻打
  230. // siegeInfo, ok := castleTable.SiegeInfo.Get(legionTable.LeagueID)
  231. // if !ok {
  232. // return false
  233. // }
  234. // // 不在攻城时间内不可攻打
  235. // return siegeInfo.Stage == enum.SiegeStage_Battle
  236. // }
  237. return false
  238. }
  239. func (p *actor) legionSiegeFail(legionTable *db.LogicLegionTable, tileTable *db.LogicTileTable) {
  240. // 移除攻城列表
  241. tileTable.RemoveSiege(legionTable.ObjectID)
  242. // 解散
  243. p.legionDisband(legionTable, enum.RetreatType_Rout, true)
  244. }
  245. func (p *actor) addLegionToTileMarch(legionTable *db.LogicLegionTable, tileTable *db.LogicTileTable) {
  246. for _, member := range legionTable.Members {
  247. marchTable := p.MarchTables.GetValue(member.Key)
  248. p.addToTileMarch(marchTable, tileTable)
  249. }
  250. }
  251. func (p *actor) legionMeet(legionTable *db.LogicLegionTable, tileTable *db.LogicTileTable, isAttack bool) {
  252. clog.Debugf("legion meet: LegionObjectID = %d, Target = (%d %v)",
  253. legionTable.ObjectID, legionTable.TargetObjectID, legionTable.TargetPoint)
  254. if isAttack {
  255. tileTable.AddAttackList(legionTable.ObjectID, dbLogic.NewTileLegionInfo(
  256. tileTable.TileID,
  257. legionTable.ObjectID,
  258. p.nowMillis,
  259. legionTable.MemberIDList(),
  260. ))
  261. // 保存当前状态
  262. legionTable.SaveState(p.nowMillis)
  263. // 设为战斗等待状态
  264. p.updateLegionState(legionTable, enum.LegionState_BattleWait, 0)
  265. } else {
  266. tileTable.AddMarch(legionTable.ObjectID, dbLogic.NewTileLegionInfo(
  267. tileTable.TileID,
  268. legionTable.ObjectID,
  269. p.nowMillis,
  270. legionTable.MemberIDList(),
  271. ))
  272. }
  273. }
  274. func (p *actor) legionMove(legionTable *db.LogicLegionTable) {
  275. legionTable.MoveNextTile(p.nowMillis)
  276. for _, member := range legionTable.Members {
  277. marchTable := p.MarchTables.GetValue(member.Key)
  278. marchTable.MoveNextTile(p.nowMillis)
  279. }
  280. mapCall.AOI.Move(legionTable.ToAOIMarker())
  281. // 从上一个格子的行军列表移除
  282. if prevTileID, ok := data.PointToTileID(legionTable.PrevPoint.X, legionTable.PrevPoint.Y); ok {
  283. prevTileTable := p.TileTables.GetValue(prevTileID)
  284. prevTileTable.RemoveMarch(legionTable.ObjectID)
  285. p.addTileProcess(prevTileTable)
  286. }
  287. clog.Debugf("Legion move: LegionObjectID = %d, Point = %v", legionTable.ObjectID, legionTable.Point)
  288. }
  289. func (p *actor) legionMarkArrive(legionTable *db.LogicLegionTable) {
  290. clog.Debugf("legion move arrive: LegionObjectID = %d, Target = (%d %v)",
  291. legionTable.ObjectID, legionTable.TargetObjectID, legionTable.TargetPoint)
  292. for _, member := range legionTable.Members {
  293. marchTable := p.MarchTables.GetValue(member.Key)
  294. marchTable.MarkArrive(true)
  295. }
  296. legionTable.IsArrived = true
  297. legionTable.IsDataChanged = true
  298. }
  299. func (p *actor) legionSave(legionTable *db.LogicLegionTable) {
  300. legionTable.IsDataChanged = false
  301. legionTable.Save2Queue()
  302. }
  303. // 军团解散
  304. func (p *actor) legionDisband(legionTable *db.LogicLegionTable, restreatType enum.RetreatType, notice bool) {
  305. clog.Debugf("[legionDisband] LegionObjectID = %d", legionTable.ObjectID)
  306. for _, member := range legionTable.Members {
  307. marchTable := p.MarchTables.GetValue(member.Key)
  308. marchTable.SetLegionObjectID(0)
  309. // 到达的成员撤退
  310. if member.Value {
  311. p.markMarchRetreat(marchTable, restreatType, false)
  312. }
  313. }
  314. legionTable.IsDelete = true
  315. legionTable.IsDataChanged = true
  316. // 离开aoi
  317. p.legionLeaveAOI(legionTable)
  318. // 通知联盟
  319. if notice {
  320. mapCall.League.AssembleUpdate(legionTable.LeagueID, &pb.AssembleUpdate{
  321. LegionObjectID: legionTable.ObjectID,
  322. IsDisband: true,
  323. })
  324. }
  325. }
  326. func (p *actor) updateLegionState(legionTable *db.LogicLegionTable, newState enum.LegionState, endTime int64) {
  327. if endTime > 0 {
  328. clog.Debugf("[updateLegionState] objectID = %d, state = %s -> %s, endTime = %s",
  329. legionTable.ObjectID,
  330. enum.GetLegionStateName(legionTable.LegionState),
  331. enum.GetLegionStateName(newState),
  332. times.MillisToDatetimeFormat(endTime),
  333. )
  334. } else {
  335. clog.Debugf("[updateLegionState] objectID = %d, state = %s -> %s",
  336. legionTable.ObjectID,
  337. enum.GetLegionStateName(legionTable.LegionState), enum.GetLegionStateName(newState))
  338. }
  339. legionTable.UpdateLegionState(newState)
  340. legionTable.UpdateMarchState(enum.GetMarchStateByLegionState(newState), p.nowMillis, endTime)
  341. p.UpdateObjectFull(legionTable.ObjectID, legionTable.Type)
  342. }
  343. // func (p *actor) restoreLegionState(legionTable *db.MapLegionTable) {
  344. // clog.Debugf("[restoreLegionState] state = %s -> %s, time offset = %v",
  345. // enum.GetLegionStateName(legionTable.LegionState),
  346. // enum.GetLegionStateName(legionTable.PrevState),
  347. // p.nowMillis-legionTable.PrevStateSaveTime)
  348. // legionTable.RestoreState(p.nowMillis)
  349. // // 推送march状态给客户端
  350. // // mapCall.Pusher.MapMarchStateWatcherPush(marchTable.ObjectID)
  351. // }
  352. func (p *actor) addLegionAOI(legionTable *db.LogicLegionTable) {
  353. marker := legionTable.ToAOIMarker()
  354. mapCall.AOI.Enter(marker)
  355. }
  356. func (p *actor) legionLeaveAOI(legionTable *db.LogicLegionTable) {
  357. mapCall.AOI.Leave(legionTable.ObjectID, legionTable.Type)
  358. }
  359. func (p *actor) legionMemberQuit(legionTable *db.LogicLegionTable, marchObjectID int64) {
  360. legionTable.RemoveMember(marchObjectID)
  361. if legionTable.LeadObjectID == marchObjectID && legionTable.LegionState == enum.LegionState_AssembleWait || len(legionTable.Members) == 0 {
  362. p.legionDisband(legionTable, enum.RetreatType_Must, true)
  363. } else {
  364. mapCall.League.AssembleUpdate(legionTable.LeagueID, &pb.AssembleUpdate{
  365. LegionObjectID: legionTable.ObjectID,
  366. QuitMember: marchObjectID,
  367. })
  368. }
  369. legionTable.IsDataChanged = true
  370. }