actor_march.go 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427
  1. package mapLogic
  2. import (
  3. "f1-game/internal/code"
  4. "f1-game/internal/constant"
  5. "f1-game/internal/data"
  6. "f1-game/internal/enum"
  7. "f1-game/internal/event"
  8. "f1-game/internal/extend/times"
  9. nameRemote "f1-game/internal/name/remote"
  10. nameRoute "f1-game/internal/name/route"
  11. "f1-game/internal/pb"
  12. "f1-game/internal/sessions"
  13. "f1-game/internal/types"
  14. mapCall "f1-game/nodes/map/internal/call"
  15. "f1-game/nodes/map/internal/db"
  16. dbLogic "f1-game/nodes/map/internal/db/data/logic"
  17. ctime "github.com/cherry-game/cherry/extend/time"
  18. clog "github.com/cherry-game/cherry/logger"
  19. )
  20. func (p *actor) initMarchTypeFuncs() {
  21. p.marchTypeFuncs = map[enum.MarchType]marchTypeFunc{
  22. enum.MarchType_Occupy: p.marchOccupy,
  23. enum.MarchType_Garrison: p.marchGarrison,
  24. enum.MarchType_Crucade: p.marchCrusade,
  25. enum.MarchType_Siege: p.marchSiege,
  26. enum.MarchType_Stay: p.marchStay,
  27. enum.MarchType_Retreat: p.marchRetreat,
  28. enum.MarchType_Redeploy: p.marchRedeploy,
  29. enum.MarchType_SiegeAssemble: p.marchSiegeAssemble,
  30. enum.MarchType_Assemble: p.marchAssemble,
  31. enum.MarchType_Snatch: p.marchSnatch,
  32. enum.MarchType_LegionAssemble: p.marchLegionAssemble,
  33. }
  34. }
  35. func (p *actor) addMarchAOI(marchTable *db.LogicMarchTable) {
  36. marker := marchTable.ToAOIMarker()
  37. mapCall.AOI.Enter(marker)
  38. }
  39. func (p *actor) marchTimer() {
  40. p.updateTime()
  41. for _, marchTable := range p.MarchTables {
  42. p.marchTicker(marchTable)
  43. // 如果行军处于战斗等待状态,检查是否超时,毕竟由于bug导致状态卡死
  44. if marchTable.State == enum.MarchState_BattleWait || marchTable.State == enum.MarchState_Battle {
  45. if p.nowMillis >= marchTable.StateEndTime {
  46. // 战斗等待超时,应该是遇到了某种bug
  47. clog.Warnf("March battle wait timeout, a bug? MarchObjectID = %d, MarchType = %s, Point = %v",
  48. marchTable.ObjectID, enum.GetMarchStateName(marchTable.State), marchTable.Point)
  49. // 让行军对象撤退
  50. p.markMarchRetreat(marchTable, enum.RetreatType_Must, false)
  51. // 打印地块的情况
  52. tileTable := p.TileTables.GetValue(marchTable.GetTileID())
  53. tileTable.PrintMarchList()
  54. }
  55. }
  56. // 有数据变更
  57. if marchTable.IsDataChanged {
  58. p.marchSave(marchTable)
  59. }
  60. }
  61. for _, legionTable := range p.LegionTables {
  62. if legionTable.IsDelete {
  63. p.LegionTables.Remove(legionTable.ObjectID)
  64. } else {
  65. p.legionTicker(legionTable)
  66. }
  67. if legionTable.IsDisband() {
  68. p.legionDisband(legionTable, enum.RetreatType_Retreat, true)
  69. }
  70. if legionTable.IsDataChanged {
  71. p.legionSave(legionTable)
  72. }
  73. }
  74. }
  75. func (p *actor) marchTicker(marchTable *db.LogicMarchTable) {
  76. // 不处理在军团中的行军对象
  77. if !marchTable.IsInLegion() {
  78. if marchTable.IsMoving() {
  79. p.marchMoving(marchTable)
  80. }
  81. // 行军到达执行行军意图指令
  82. if marchTable.IsArrived {
  83. p.marchArrive(marchTable)
  84. }
  85. // 如果行军对象被攻城大营管理,则执行自动行军
  86. if marchTable.AutoMarchInfo.IsAutoSiege {
  87. p.marchAuto(marchTable)
  88. }
  89. }
  90. if marchTable.IsHandleRetreat {
  91. p.startMarchRetreat(marchTable)
  92. }
  93. }
  94. func (p *actor) startMarchRetreat(marchTable *db.LogicMarchTable) {
  95. var (
  96. marchState = enum.GetMarchStateByRetreatType(marchTable.RetreatType)
  97. isRemoveRedeploy = marchTable.IsRemoveRedeploy
  98. )
  99. // 执行自动撤退
  100. mapCall.Player.AutoRetreat(marchTable.PlayerID, marchTable.TeamID, marchState, isRemoveRedeploy)
  101. // 重置自动撤退状态
  102. marchTable.ResetAutoRetreat()
  103. }
  104. func (p *actor) marchMoving(marchTable *db.LogicMarchTable) {
  105. // 到达了
  106. if marchTable.IsMoveArrive() {
  107. marchTable.MarkArrive(true)
  108. return
  109. }
  110. if !marchTable.CanMove(p.nowMillis) {
  111. return
  112. }
  113. // 执行行军移动
  114. p.marchMove(marchTable)
  115. tileTable := p.TileTables.GetValue(marchTable.GetTileID())
  116. // 检查是否发生碰撞
  117. isMet, isAttack := p.isMarchMeet(marchTable, tileTable)
  118. if isMet {
  119. // 执行碰撞处理
  120. p.marchMeet(marchTable, p.TileTables.GetValue(marchTable.GetTileID()), isAttack)
  121. return
  122. }
  123. // 检查建筑是否发生碰撞
  124. buildTable := p.getCollidedBuilding(marchTable, tileTable)
  125. if buildTable != nil {
  126. // 执行建筑碰撞逻辑
  127. p.marchBuildingCollision(marchTable, tileTable, buildTable)
  128. return
  129. }
  130. if marchTable.IsMoveArrive() {
  131. marchTable.MarkArrive(true)
  132. return
  133. }
  134. // 撤退状态和溃退状态不加入行军列表
  135. if !marchTable.IsRetreat() {
  136. // 未行军到达则加入行军列表
  137. tileTable := p.TileTables.GetValue(marchTable.GetTileID())
  138. p.addToTileMarch(marchTable, tileTable)
  139. }
  140. }
  141. // marchAuto 自动行军
  142. func (p *actor) marchAuto(marchTable *db.LogicMarchTable) {
  143. if marchTable.State != enum.MarchState_Stay && marchTable.State != enum.MarchState_SiegeAssemble {
  144. return
  145. }
  146. switch marchTable.AutoMarchInfo.Stage {
  147. case enum.AutoMarch_None:
  148. return
  149. case enum.AutoMarch_Start:
  150. // 通知 MapPlayer 开始自动行军
  151. mapCall.Player.AutoMarchRequest(marchTable.PlayerID, marchTable.LeagueID, marchTable.ObjectID, marchTable.AutoMarchInfo.Segments)
  152. // 切换为等待状态
  153. marchTable.SetAutoMarchStage(enum.AutoMarch_Wait, p.nowMillis)
  154. case enum.AutoMarch_Wait:
  155. // 等待超时直接清除自动行军状态
  156. if p.nowMillis >= marchTable.AutoMarchInfo.StageStartTime+constant.AutoMarchWaitTimeout {
  157. // 清除自动行军状态
  158. marchTable.MarkAutoSiege(false, 0)
  159. return
  160. }
  161. case enum.AutoMarch_Process:
  162. segement := marchTable.AutoMarchInfo.Segments[0]
  163. // 根据自动行军的策略来检查
  164. switch segement.AutoMarchType {
  165. case enum.AutoMarch_WaitGarrisionZero:
  166. // 检查是否有驻城部队
  167. siegeTable, ok := p.SiegeTables.Get(marchTable.TargetObjectID)
  168. if !ok {
  169. clog.Warnf("[marchAuto] SiegeTable not found, marchObjectID = %d, targetObjectID = %d", marchTable.ObjectID, marchTable.TargetObjectID)
  170. marchTable.MarkAutoSiege(false, 0)
  171. return
  172. }
  173. // 如果有驻城部队
  174. if siegeTable.RemainGarrisonArmies() > 0 {
  175. // 如果驻城部队一直未被消灭,给个保底等待时间
  176. if p.nowMillis < segement.ArriveTime+segement.WaitTime {
  177. return
  178. }
  179. }
  180. default:
  181. // 等待超时
  182. if p.nowMillis < segement.ArriveTime+segement.WaitTime {
  183. return
  184. }
  185. }
  186. point := segement.Path[segement.Path.Size()-1]
  187. p.doMarch(marchTable, segement.MarchType, enum.MarchState_March, segement.Path.ToProto(), point.ToProto(), marchTable.TargetObjectID, marchTable.IsAutoRetreat, true)
  188. // 从地块删除行军对象
  189. tileTable := p.TileTables.GetValue(marchTable.GetTileID())
  190. tileTable.RemoveMarchAnywhere(marchTable.ObjectID)
  191. clog.Debugf("[marchAuto] marchObjectID = %d, marchState = %s, marchType = %s, path = %v",
  192. marchTable.ObjectID, enum.GetMarchStateName(marchTable.State), enum.GetMarchTypeName(marchTable.MarchType), segement.Path)
  193. marchTable.AutoMarchInfo.Segments.Remove(0)
  194. if marchTable.AutoMarchInfo.Segments.IsEmpty() {
  195. marchTable.SetAutoMarchStage(enum.AutoMarch_None, p.nowMillis)
  196. }
  197. marchTable.IsDataChanged = true
  198. }
  199. }
  200. // marchMove 移动处理(行军和撤退)
  201. func (p *actor) marchMove(marchTable *db.LogicMarchTable) {
  202. marchTable.MoveNextTile(p.nowMillis)
  203. mapCall.AOI.Move(marchTable.ToAOIMarker())
  204. // 更新军情线
  205. p.updateArmyLine(marchTable)
  206. // 从上一个格子的行军列表移除
  207. if prevTileID, ok := data.PointToTileID(marchTable.PrevPoint.X, marchTable.PrevPoint.Y); ok {
  208. prevTileTable := p.TileTables.GetValue(prevTileID)
  209. prevTileTable.RemoveMarch(marchTable.ObjectID)
  210. p.addTileProcess(prevTileTable)
  211. }
  212. }
  213. // isMarchMeet 检查是否发生碰撞
  214. func (p *actor) isMarchMeet(marchTable *db.LogicMarchTable, tileTable *db.LogicTileTable) (isMet bool, isAttack bool) {
  215. // 撤退的行军对象不会发生碰撞
  216. if marchTable.IsRetreat() {
  217. return false, false
  218. }
  219. // 如果有碰撞,则加入进攻列表,否则加入行军列表
  220. isMet, isAttack = p.isTileMeet(tileTable, marchTable.PlayerID, marchTable.LeagueID)
  221. if isMet {
  222. clog.Debugf("march tile meet result: objectID = %d, meet = %v, attack = %v", marchTable.ObjectID, isMet, isAttack)
  223. }
  224. return
  225. }
  226. func (p *actor) marchMeet(marchTable *db.LogicMarchTable, tileTable *db.LogicTileTable, isAttack bool) {
  227. if isAttack {
  228. tileTable.AddAttackList(marchTable.ObjectID, dbLogic.NewTileMarchInfo(
  229. tileTable.TileID,
  230. marchTable.ObjectID,
  231. p.nowMillis,
  232. ))
  233. // 保存当前状态
  234. marchTable.SaveState(p.nowMillis)
  235. // 设为战斗等待状态
  236. p.updateMarchState(marchTable, enum.MarchState_BattleWait, p.nowMillis+constant.MapMaxBattleWaitTime)
  237. } else {
  238. tileTable.AddMarch(marchTable.ObjectID, dbLogic.NewTileMarchInfo(
  239. tileTable.TileID,
  240. marchTable.ObjectID,
  241. p.nowMillis,
  242. ))
  243. }
  244. }
  245. // marchArrive 行军到达目的地处理
  246. func (p *actor) marchArrive(marchTable *db.LogicMarchTable) {
  247. // 防止在还是移动状态的情况下,tile 还没来得及处理就又一次进入 isArrived 逻辑
  248. marchTable.ClearPath()
  249. marchTable.MarkArrive(false)
  250. clog.Debugf("[marchArrive]: marchObjectID = %d, marchType = %v, marchState = %s, point = %v",
  251. marchTable.ObjectID, enum.GetMarchTypeName(marchTable.MarchType), enum.GetMarchStateName(marchTable.State), marchTable.Point)
  252. // 执行行军意图
  253. if fn, ok := p.marchTypeFuncs[marchTable.MarchType]; ok {
  254. fn(marchTable)
  255. } else {
  256. // 保底,让行军对象停留
  257. p.marchStay(marchTable)
  258. }
  259. // 抛一个行军到达事件
  260. eventData := &event.MarchArriveEventData{
  261. TeamID: marchTable.TeamID,
  262. MarchState: marchTable.State,
  263. }
  264. tileTable := p.TileTables.GetValue(marchTable.GetTileID())
  265. if tileTable.BuildObjectID > 0 {
  266. eventData.TargetObjectID = int64(tileTable.BuildObjectID)
  267. eventData.TargetObjectType = enum.ObjectType_Build
  268. buildTable := p.BuildTables.GetValue(tileTable.BuildObjectID)
  269. eventData.TargetConfigID = buildTable.ConfigID
  270. eventData.TargetObjectLevel = buildTable.Level
  271. } else if tileTable.CastleObjectID > 0 {
  272. eventData.TargetObjectID = tileTable.CastleObjectID
  273. eventData.TargetObjectType = enum.ObjectType_Castle
  274. castleTable := p.CastleTables.GetValue(tileTable.CastleObjectID)
  275. eventData.TargetConfigID = castleTable.ConfigID
  276. eventData.TargetObjectLevel = castleTable.Level
  277. }
  278. p.PostEvent(event.NewMarchArrive(marchTable.PlayerID, eventData))
  279. }
  280. // marchOccupy 行军占领
  281. func (p *actor) marchOccupy(marchTable *db.LogicMarchTable) {
  282. resTable, ok := p.ResTables.Get(marchTable.TargetObjectID)
  283. if !ok {
  284. clog.Debugf("[marchOccupy]: res not found, MarchObjectID = %v, ResObjectID = %v, Point = %v",
  285. marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point)
  286. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  287. return
  288. }
  289. // 不在同一个格子,可能刷新到了别的地方
  290. if !resTable.Point.Equals(&marchTable.Point) {
  291. clog.Debugf("[marchOccupy]: res not this tile, March = (%v, %v), Res = (%v, %v), Point = %v",
  292. marchTable.ObjectID, marchTable.Point, resTable.ObjectID, resTable.Point)
  293. // 加入撤退列表
  294. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  295. return
  296. }
  297. // 检查资源点是否可以被占领
  298. errCode := resTable.CanOccupy(p.nowMillis, marchTable.PlayerID, marchTable.LeagueID)
  299. if code.IsFail(errCode) {
  300. clog.Debugf("[marchOccupy]: res cannot be occupied, MarchObjectID = %v, ResObjectID = %v, Point = %v, Code = %v",
  301. marchTable.ObjectID, resTable.ObjectID, marchTable.Point, errCode)
  302. // 加入撤退列表
  303. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  304. return
  305. }
  306. tileTable := p.TileTables.GetValue(marchTable.GetTileID())
  307. // 放入 TileTable 的占领列表
  308. tileTable.AddOccupy(marchTable.ObjectID, dbLogic.NewTileMarchInfo(
  309. tileTable.TileID,
  310. marchTable.ObjectID,
  311. p.nowMillis,
  312. resTable.ObjectID,
  313. ))
  314. p.updateMarchState(marchTable, enum.MarchState_BattleWait, p.nowMillis+constant.MapMaxBattleWaitTime)
  315. p.addTileProcess(tileTable)
  316. }
  317. // marchGarrison 行军驻守
  318. func (p *actor) marchGarrison(marchTable *db.LogicMarchTable) {
  319. // 驻守目标可以是资源点,建筑,系统城
  320. if buildTable, ok := p.BuildTables.Get(marchTable.TargetObjectID); ok {
  321. p.marchGarrisonBuild(marchTable, buildTable)
  322. return
  323. }
  324. if castleTable, ok := p.CastleTables.Get(marchTable.TargetObjectID); ok {
  325. p.marchGarrisonCastle(marchTable, castleTable)
  326. return
  327. }
  328. if resTable, ok := p.ResTables.Get(marchTable.TargetObjectID); ok {
  329. p.marchGarrisonRes(marchTable, resTable)
  330. return
  331. }
  332. // 没有驻守目标
  333. // 加入撤退列表
  334. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  335. clog.Debugf("[marchGarrison]: no target found, MarchObjectID = %v, TargetObjectID = %d, Point = %v",
  336. marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point)
  337. }
  338. // marchGarrisonRes 行军驻守资源点
  339. func (p *actor) marchGarrisonRes(marchTable *db.LogicMarchTable, resTable *db.LogicResTable) {
  340. // 不在同一格
  341. if !resTable.Point.Equals(&marchTable.Point) {
  342. clog.Debugf("[marchGarrisonRes]: res not in this tile, MarchObjectID = (%v, %v), ResObjectID = (%v, %v)",
  343. marchTable.ObjectID, marchTable.Point, resTable.ObjectID, resTable.Point)
  344. // 加入撤退列表
  345. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  346. return
  347. }
  348. // 检查资源点是否可以被驻守
  349. retCode := resTable.IsGarrisonable(marchTable.PlayerID, marchTable.LeagueID)
  350. if code.IsFail(retCode) {
  351. clog.Debugf("[marchGarrisonRes]: res cannot be garrisoned, MarchObjectID = %v, Point = %v, Code = %v",
  352. marchTable.ObjectID, marchTable.Point, retCode)
  353. // 加入撤退列表
  354. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  355. return
  356. }
  357. // 更新为驻守状态
  358. p.updateMarchState(marchTable, enum.MarchState_Garrison, 0)
  359. // 保存一下驻守状态,因为驻守比较特殊,可攻可守
  360. marchTable.SaveState(p.nowMillis)
  361. // 加入 TileTable 的驻守列表
  362. tileTable := p.TileTables.GetValue(marchTable.GetTileID())
  363. marchInfo := dbLogic.NewTileMarchInfo(
  364. tileTable.TileID,
  365. marchTable.ObjectID,
  366. p.nowMillis,
  367. resTable.ObjectID,
  368. )
  369. tileTable.AddGarrison(marchTable.ObjectID, marchInfo, p.TileTables)
  370. p.addTileProcess(tileTable)
  371. }
  372. // marchGarrisonBuild 行军驻守建筑
  373. func (p *actor) marchGarrisonBuild(marchTable *db.LogicMarchTable, buildTable *db.LogicBuildTable) {
  374. // 检查建筑是否在这个格子上
  375. // TODO: 这里需要根据地编数据上的驻守位置来判断驻守的目标,否则默认为中心点
  376. if !buildTable.Point.Equals(&marchTable.Point) {
  377. clog.Debugf("[marchGarrisonBuild]: build not in this tile, MarchObjectID = (%v, %v), BuildObjectID = (%v, %v)",
  378. marchTable.ObjectID, marchTable.Point, buildTable.ObjectID, buildTable.Point)
  379. // 加入撤退列表
  380. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  381. return
  382. }
  383. // 检查建筑是否可以被驻守
  384. retCode := buildTable.IsGarrisonable(marchTable.PlayerID, marchTable.LeagueID)
  385. if code.IsFail(retCode) {
  386. clog.Debugf("[marchGarrisonBuild]: build cannot be garrisoned, MarchObjectID = %v, BuildObjectID = %v, Point = %v, Code = %v",
  387. marchTable.ObjectID, buildTable.ObjectID, marchTable.Point, retCode)
  388. // 加入撤退列表
  389. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  390. return
  391. }
  392. // 更新为驻守状态
  393. p.updateMarchState(marchTable, enum.MarchState_Garrison, 0)
  394. // 保存一下驻守状态,因为驻守比较特殊,可攻可守
  395. marchTable.SaveState(p.nowMillis)
  396. // 加入 TileTable 的驻守列表
  397. tileTable := p.TileTables.GetValue(marchTable.GetTileID())
  398. marchInfo := dbLogic.NewTileMarchInfo(
  399. tileTable.TileID,
  400. marchTable.ObjectID,
  401. p.nowMillis,
  402. buildTable.ObjectID,
  403. )
  404. tileTable.AddGarrison(marchTable.ObjectID, marchInfo, p.TileTables)
  405. p.addTileProcess(tileTable)
  406. }
  407. // marchGarrisonCastle 行军驻守城池
  408. func (p *actor) marchGarrisonCastle(marchTable *db.LogicMarchTable, castleTable *db.LogicCastleTable) {
  409. // 检查城池是否在这个格子上
  410. // TODO: 这里需要根据地编数据上的驻守位置来判断驻守的目标,否则默认为中心点
  411. if !castleTable.Point.Equals(&marchTable.Point) {
  412. clog.Debugf("[marchGarrisonCastle]: castle not in this tile, MarchObjectID = (%v, %v), CastleObjectID = (%v, %v)",
  413. marchTable.ObjectID, marchTable.Point, castleTable.ObjectID, castleTable.Point)
  414. // 加入撤退列表
  415. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  416. return
  417. }
  418. // 检查城池是否可以被驻守
  419. retCode := castleTable.IsGarrisonable(marchTable.LeagueID)
  420. if code.IsFail(retCode) {
  421. clog.Debugf("[marchGarrisonCastle]: castle cannot be garrisoned, MarchObjectID = %v, CastleObjectID = %v, Point = %v, Code = %v",
  422. marchTable.ObjectID, castleTable.ObjectID, marchTable.Point, retCode)
  423. // 加入撤退列表
  424. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  425. return
  426. }
  427. // 更新为驻守状态
  428. p.updateMarchState(marchTable, enum.MarchState_Garrison, 0)
  429. // 保存一下驻守状态,因为驻守比较特殊,可攻可守
  430. marchTable.SaveState(p.nowMillis)
  431. // 加入 TileTable 的驻守列表
  432. tileTable := p.TileTables.GetValue(marchTable.GetTileID())
  433. marchInfo := dbLogic.NewTileMarchInfo(
  434. tileTable.TileID,
  435. marchTable.ObjectID,
  436. p.nowMillis,
  437. castleTable.ObjectID,
  438. )
  439. tileTable.AddGarrison(marchTable.ObjectID, marchInfo, p.TileTables)
  440. p.addTileProcess(tileTable)
  441. }
  442. // marchCrusade 行军讨伐
  443. func (p *actor) marchCrusade(marchTable *db.LogicMarchTable) {
  444. monsterTable, ok := p.MonsterTables.Get(marchTable.TargetObjectID)
  445. if !ok || !monsterTable.IsAlive {
  446. clog.Debugf("[marchCrusade] Monster not found: MarchObjectID = %d, MonsterObjectID = %d, Point = %v",
  447. marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point)
  448. // 加入撤退列表
  449. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  450. return
  451. }
  452. // 检查怪物是否在这个格子上
  453. if !monsterTable.Point.Equals(&marchTable.Point) {
  454. clog.Debugf("[marchCrusade] Monster not in this tile: March = (%d, %d), Monster = (%d, %v)",
  455. marchTable.ObjectID, marchTable.Point, monsterTable.ObjectID, monsterTable.Point)
  456. // 加入撤退列表
  457. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  458. return
  459. }
  460. // TODO: 判断怪物有没有被讨伐
  461. // 加入讨伐列表
  462. tileTable := p.TileTables.GetValue(marchTable.GetTileID())
  463. tileTable.AddCrusade(marchTable.ObjectID, dbLogic.NewTileMarchInfo(
  464. tileTable.TileID,
  465. marchTable.ObjectID,
  466. p.nowMillis,
  467. monsterTable.ObjectID,
  468. ))
  469. p.addTileProcess(tileTable)
  470. // 设置为战斗状态
  471. p.updateMarchState(marchTable, enum.MarchState_BattleWait, p.nowMillis+constant.MapMaxBattleWaitTime)
  472. }
  473. // marchSiege 行军攻城
  474. func (p *actor) marchSiege(marchTable *db.LogicMarchTable) {
  475. // 攻城可以打建筑或者系统城
  476. if buildTable, ok := p.BuildTables.Get(marchTable.TargetObjectID); ok {
  477. p.marchSiegeBuild(marchTable, buildTable)
  478. return
  479. }
  480. if castleTable, ok := p.CastleTables.Get(marchTable.TargetObjectID); ok {
  481. p.marchSiegeCastle(marchTable, castleTable)
  482. return
  483. }
  484. // 加入撤退列表
  485. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  486. clog.Debugf("[marchSiege]: siege object not found, MarchObjectID = %v, TargetObjectID = %v, Point = %v",
  487. marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point)
  488. }
  489. func (p *actor) marchSiegeBuild(marchTable *db.LogicMarchTable, buildTable *db.LogicBuildTable) {
  490. // 攻城不一样,只要有建筑覆盖的坐标都可以打
  491. // TODO: 可以通过地编数据的攻城点来判断,没有就默认都可以打
  492. if !buildTable.IsCoverPoint(marchTable.X(), marchTable.Y()) {
  493. clog.Debugf("[marchSiegeBuild]: build not in this tile, MarchObjectID = %v, BuildObjectID = %v, Point = %v",
  494. marchTable.ObjectID, buildTable.ObjectID, marchTable.Point)
  495. // 加入撤退列表
  496. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  497. return
  498. }
  499. // 不可以攻城
  500. if !p.canSiegeBuild(marchTable, buildTable) {
  501. clog.Debugf("[marchSiegeBuild]: not siegeable, MarchObjectID = %v, LeagueID = %v, BuildObjectID = %v",
  502. marchTable.ObjectID, marchTable.LeagueID, buildTable.ObjectID)
  503. // 加入撤退列表
  504. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  505. return
  506. }
  507. // 更新为攻城状态
  508. nextTime := p.nowMillis + ctime.MillisecondsPerSecond
  509. p.updateMarchState(marchTable, enum.MarchState_Siege, nextTime)
  510. tileTable := p.TileTables.GetValue(marchTable.GetTileID())
  511. tileMarchInfo := dbLogic.NewTileMarchInfo(
  512. tileTable.TileID,
  513. marchTable.ObjectID,
  514. p.nowMillis,
  515. buildTable.ObjectID,
  516. )
  517. // 设置为首次攻城
  518. tileMarchInfo.IsFirstSiege = true
  519. // 等待一个 ticker
  520. tileMarchInfo.LogicEndTime = nextTime
  521. // 加入攻城列表
  522. tileTable.AddSiege(marchTable.ObjectID, tileMarchInfo)
  523. p.addTileProcess(tileTable)
  524. // 保存攻城点
  525. buildTable.AddSiegeTile(tileTable.TileID)
  526. // TODO: 先简单做,每次都通知一下,后面试试优化
  527. // 通知玩家出来自动防守
  528. // 如果是玩家主城,通知主城被攻击了
  529. switch buildTable.ConfigID {
  530. case constant.MapBuild_MainCity:
  531. mapCall.Player.MainCitySiege(buildTable.PlayerID, buildTable.ObjectID)
  532. case constant.MapBuild_LeaguePoint:
  533. // TODO: 联盟驻地除了通知调用队列的玩家,还有发一个消息给联盟,并通知所有主城在驻地内的玩家
  534. }
  535. // 如果调动列表不为空,通知出来自动防守
  536. if buildTable.RedeployObjects.Size() > 0 {
  537. // 分组
  538. mapPlayerTeams := map[int64][]int32{}
  539. for _, redeployObjectID := range buildTable.RedeployObjects.Values() {
  540. redeployMarchTable, ok := p.MarchTables.Get(redeployObjectID)
  541. if !ok {
  542. continue
  543. }
  544. mapPlayerTeams[redeployMarchTable.PlayerID] = append(mapPlayerTeams[redeployMarchTable.PlayerID], redeployMarchTable.TeamID)
  545. }
  546. // 通知玩家
  547. for playerID, teamIDs := range mapPlayerTeams {
  548. mapCall.Player.AutoDefendRequest(playerID, buildTable.ObjectID, teamIDs)
  549. }
  550. }
  551. }
  552. func (p *actor) marchSiegeCastle(marchTable *db.LogicMarchTable, castleTable *db.LogicCastleTable) {
  553. // 攻城不一样,只要有建筑覆盖的坐标都可以打
  554. // TODO: 可以通过地编数据的攻城点来判断,没有就默认都可以打
  555. if !castleTable.IsCoverPoint(marchTable.X(), marchTable.Y()) {
  556. clog.Debugf("[marchSiegeCastle]: castle not in this tile, MarchObjectID = %v, CastleObjectID = %v, Point = %v",
  557. marchTable.ObjectID, castleTable.ObjectID, marchTable.Point)
  558. // 加入撤退列表
  559. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  560. return
  561. }
  562. // 不可以攻城
  563. if !p.canSiegeCastle(marchTable, castleTable) {
  564. clog.Debugf("[marchSiegeCastle]: not siegeable, MarchObjectID = %v, LeagueID = %v, CastleObjectID = %v",
  565. marchTable.ObjectID, marchTable.LeagueID, castleTable.ObjectID)
  566. // 加入撤退列表
  567. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  568. return
  569. }
  570. // 更新为攻城状态
  571. nextTime := p.nowMillis + ctime.MillisecondsPerSecond
  572. p.updateMarchState(marchTable, enum.MarchState_Siege, nextTime)
  573. tileTable := p.TileTables.GetValue(marchTable.GetTileID())
  574. tileMarchInfo := dbLogic.NewTileMarchInfo(
  575. tileTable.TileID,
  576. marchTable.ObjectID,
  577. p.nowMillis,
  578. castleTable.ObjectID,
  579. )
  580. // 设置为首次攻城
  581. tileMarchInfo.IsFirstSiege = true
  582. // 等待一个 ticker
  583. tileMarchInfo.LogicEndTime = nextTime
  584. // 加入攻城列表
  585. tileTable.AddSiege(marchTable.ObjectID, tileMarchInfo)
  586. p.addTileProcess(tileTable)
  587. // 保存攻城点
  588. castleTable.AddSiegeTile(tileTable.TileID)
  589. // 如果调动列表不为空,通知出来自动防守
  590. if castleTable.RedeployObjects.Size() > 0 {
  591. // 分组
  592. mapPlayerTeams := map[int64][]int32{}
  593. for _, redeployObjectID := range castleTable.RedeployObjects.Values() {
  594. redeployMarchTable, ok := p.MarchTables.Get(redeployObjectID)
  595. if !ok {
  596. continue
  597. }
  598. mapPlayerTeams[redeployMarchTable.PlayerID] = append(mapPlayerTeams[redeployMarchTable.PlayerID], redeployMarchTable.TeamID)
  599. }
  600. // 通知玩家
  601. for playerID, teamIDs := range mapPlayerTeams {
  602. mapCall.Player.AutoDefendRequest(playerID, castleTable.ObjectID, teamIDs)
  603. }
  604. }
  605. }
  606. // marchSnatch 行军掠夺
  607. func (p *actor) marchSnatch(marchTable *db.LogicMarchTable) {
  608. buildTable, ok := p.BuildTables.Get(marchTable.TargetObjectID)
  609. if !ok {
  610. clog.Debugf("[marchSnatch]: build not found, MarchObjectID = %v, TargetObjectID = %v, Point = %v",
  611. marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point)
  612. // 加入撤退列表
  613. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  614. return
  615. }
  616. // 建筑没有覆盖坐标
  617. if !buildTable.IsCoverPoint(marchTable.X(), marchTable.Y()) {
  618. clog.Debugf("[marchSnatch]: not cover point: MarchObjectID = %v, BuildObjectID = %v, Point = %v",
  619. marchTable.ObjectID, buildTable.ObjectID, marchTable.Point)
  620. // 加入撤退列表
  621. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  622. return
  623. }
  624. // 掠夺只能掠夺玩家主城,这个判断在 buildTable.IsSnatchable 里面
  625. // 判断是否可以掠夺
  626. if !buildTable.IsSnatchable(p.nowMillis, marchTable.LeagueID) {
  627. clog.Debugf("[marchSnatch]: build not snatchable, MarchObjectID = %v, BuildObjectID = %v, BuildConfigID = %v, Point = %v",
  628. marchTable.ObjectID, buildTable.ObjectID, buildTable.ConfigID, marchTable.Point)
  629. // 加入撤退列表
  630. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  631. return
  632. }
  633. endTime := p.nowMillis + 1000
  634. // 更新为掠夺状态
  635. p.updateMarchState(marchTable, enum.MarchState_Snatch, endTime)
  636. // 加入地块的掠夺列表
  637. tileTable := p.TileTables.GetValue(marchTable.GetTileID())
  638. tileMarchInfo := dbLogic.NewTileMarchInfo(
  639. tileTable.TileID,
  640. marchTable.ObjectID,
  641. p.nowMillis,
  642. buildTable.ObjectID,
  643. )
  644. // 设置为首次掠夺
  645. tileMarchInfo.IsFirstSiege = true
  646. tileMarchInfo.LogicEndTime = endTime
  647. tileTable.AddSnatch(marchTable.ObjectID, tileMarchInfo)
  648. p.addTileProcess(tileTable)
  649. // 保存攻城点
  650. buildTable.AddSiegeTile(tileTable.TileID)
  651. // TODO: 先简单做,每次都通知一下,后面试试优化
  652. // 通知玩家出来自动防守
  653. // 如果是玩家主城,通知主城被攻击了
  654. if buildTable.ConfigID == constant.MapBuild_MainCity {
  655. mapCall.Player.MainCitySiege(buildTable.PlayerID, buildTable.ObjectID)
  656. }
  657. }
  658. // marchStay 行军停留
  659. func (p *actor) marchStay(marchTable *db.LogicMarchTable) {
  660. // 行军到达后,修改状态为 停留中
  661. p.updateMarchState(marchTable, enum.MarchState_Stay, 0)
  662. // 加入停留队列
  663. tileTable := p.TileTables.GetValue(marchTable.GetTileID())
  664. tileTable.AddStay(marchTable.ObjectID, dbLogic.NewTileMarchInfo(
  665. tileTable.TileID,
  666. marchTable.ObjectID,
  667. p.nowMillis,
  668. ))
  669. // 如果是被攻城大营管理的自动行军
  670. if marchTable.AutoMarchInfo.IsAutoSiege {
  671. // TODO 有没有可能 Segments 为空?
  672. if len(marchTable.AutoMarchInfo.Segments) > 0 {
  673. marchTable.AutoMarchInfo.Segments[0].ArriveTime = p.nowMillis
  674. } else {
  675. clog.Warnf("[marchStay]: no segment, MarchObjectID = %v, Point = %v",
  676. marchTable.ObjectID, marchTable.Point)
  677. }
  678. }
  679. p.addTileProcess(tileTable)
  680. }
  681. // marchRedeploy 行军调动
  682. func (p *actor) marchRedeploy(marchTable *db.LogicMarchTable) {
  683. // 调动可以调动到建筑或者城池
  684. if buildTable, ok := p.BuildTables.Get(marchTable.TargetObjectID); ok {
  685. p.marchRedeployBuild(marchTable, buildTable)
  686. return
  687. }
  688. if castleTable, ok := p.CastleTables.Get(marchTable.TargetObjectID); ok {
  689. p.marchRedeployCastle(marchTable, castleTable)
  690. return
  691. }
  692. // 加入撤退列表
  693. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  694. clog.Debugf("[marchRedeploy]: target not found: MarchObjectID = %v, TargetObjectID = %v, Point = %v",
  695. marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point)
  696. }
  697. func (p *actor) marchRedeployBuild(marchTable *db.LogicMarchTable, buildTable *db.LogicBuildTable) {
  698. // 建筑没有覆盖坐标
  699. if !buildTable.IsCoverPoint(marchTable.X(), marchTable.Y()) {
  700. clog.Debugf("[marchRedeployBuild]: not cover point: MarchObjectID = %v, BuildObjectID = %v, Point = %v",
  701. marchTable.ObjectID, buildTable.ObjectID, marchTable.Point)
  702. // 加入撤退列表
  703. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  704. return
  705. }
  706. // TODO: 判断建筑是否可调动
  707. // 如果原来有调动,删除原来的调动
  708. if marchTable.RedeployObject.Key > 0 {
  709. p.removeMarchRedeploy(marchTable, false, false)
  710. }
  711. marchTable.SetRedeployObjectID(buildTable.ObjectID, buildTable.Type)
  712. p.updateTeam(marchTable, enum.TeamUpdate_Redeploy)
  713. // 修改为调动状态
  714. p.updateMarchState(marchTable, enum.MarchState_Redeploy, 0)
  715. // 如果被调动的建筑正被攻城,加入自动防守
  716. if buildTable.IsBeingSiege() {
  717. mapCall.Player.AutoDefendRequest(marchTable.PlayerID, buildTable.ObjectID, []int32{marchTable.TeamID})
  718. }
  719. }
  720. func (p *actor) marchRedeployCastle(marchTable *db.LogicMarchTable, castleTable *db.LogicCastleTable) {
  721. // 建筑没有覆盖坐标
  722. if !castleTable.IsCoverPoint(marchTable.X(), marchTable.Y()) {
  723. clog.Debugf("[marchRedeployCastle]: not cover point: MarchObjectID = %v, CastleObjectID = %v, Point = %v",
  724. marchTable.ObjectID, castleTable.ObjectID, marchTable.Point)
  725. // 加入撤退列表
  726. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  727. return
  728. }
  729. // TODO: 判断建筑是否可调动
  730. // 如果原来有调动,删除原来的调动
  731. if marchTable.RedeployObject.Key > 0 {
  732. p.removeMarchRedeploy(marchTable, false, false)
  733. }
  734. marchTable.SetRedeployObjectID(castleTable.ObjectID, castleTable.Type)
  735. p.updateTeam(marchTable, enum.TeamUpdate_Redeploy)
  736. // 修改为调动状态
  737. p.updateMarchState(marchTable, enum.MarchState_Redeploy, 0)
  738. // 如果被调动的建筑正被攻城,加入自动防守
  739. if castleTable.IsBeingSiege() {
  740. mapCall.Player.AutoDefendRequest(marchTable.PlayerID, castleTable.ObjectID, []int32{marchTable.TeamID})
  741. }
  742. }
  743. // marchSiegeAssemble 行军攻城集结
  744. func (p *actor) marchSiegeAssemble(marchTable *db.LogicMarchTable) {
  745. // 攻城集结只能集结到卫城
  746. castleTable, ok := p.CastleTables.Get(marchTable.TargetObjectID)
  747. if !ok {
  748. clog.Debugf("[marchSiegeAssemble] Castle not found: MarchObjectID = %d, TargetObjectID = %d, Point = %v",
  749. marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point)
  750. // 加入撤退列表
  751. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  752. return
  753. }
  754. // 不是卫城
  755. if castleTable.CastleType != pb.SysObjType_so_town {
  756. clog.Debugf("[marchSiegeAssemble] not siege town: MarchObjectID = %d, CastleObjectID = %d, ConfigID = %d, Point = %v",
  757. marchTable.ObjectID, castleTable.ObjectID, castleTable.ConfigID, marchTable.Point)
  758. // 加入撤退列表
  759. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  760. return
  761. }
  762. // 没有公会是无法集结的
  763. if marchTable.LeagueID == 0 {
  764. clog.Debugf("[marchSiegeAssemble] not in league: MarchObjectID = %d, Point = %v", marchTable.ObjectID, marchTable.Point)
  765. // 加入撤退列表
  766. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  767. return
  768. }
  769. // 集结途中归属变更了
  770. if castleTable.LeagueID != marchTable.LeagueID {
  771. clog.Debugf("[marchSiegeAssemble] not my league: MarchObjectID = %d, CastleObjectID = %d, Point = %v",
  772. marchTable.ObjectID, castleTable.ObjectID, marchTable.Point)
  773. // 加入撤退列表
  774. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  775. return
  776. }
  777. // 如果原来有调动,删除原来的调动
  778. if marchTable.RedeployObject.Key > 0 {
  779. p.removeMarchRedeploy(marchTable, false, false)
  780. }
  781. marchTable.SetRedeployObjectID(castleTable.ObjectID, castleTable.Type)
  782. p.updateTeam(marchTable, enum.TeamUpdate_Redeploy)
  783. clog.Debugf("add assemble list: MarchObjectID = %d, CastleObjectID = %d", marchTable.ObjectID, castleTable.ObjectID)
  784. // 如果是主力部队,加入主力列表,否则加入拆迁队列表
  785. if marchTable.AutoMarchInfo.IsMainForce {
  786. castleTable.SiegeTown.MainForceList.Add(marchTable.ObjectID)
  787. clog.Debugf("add march to main force list: SiegeCamp = %d, March = %d, Size = %d",
  788. castleTable.ObjectID, marchTable.ObjectID, castleTable.SiegeTown.MainForceList.Size())
  789. } else {
  790. castleTable.SiegeTown.SiegeSquadList.Add(marchTable.ObjectID)
  791. clog.Debugf("add march to siege squad list: SiegeCamp = %d, March = %d, Size = %d",
  792. castleTable.ObjectID, marchTable.ObjectID, castleTable.SiegeTown.SiegeSquadList.Size())
  793. }
  794. castleTable.IsDataChanged = true
  795. // 更改状态为攻城集结状态
  796. p.updateMarchState(marchTable, enum.MarchState_SiegeAssemble, 0)
  797. // 把行军对象标记为自动攻城状态
  798. marchTable.MarkAutoSiege(true, castleTable.ObjectID)
  799. }
  800. // marchAssemble 行军集结
  801. // TODO: 集结得确定一下,TargetObjectID 是不是军团ID,暂时不动
  802. func (p *actor) marchAssemble(marchTable *db.LogicMarchTable) {
  803. // 被踢了
  804. if marchTable.LegionObjectID == 0 {
  805. // 加入撤退列表
  806. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  807. return
  808. }
  809. legionTable, ok := p.LegionTables.Get(marchTable.LegionObjectID)
  810. // 解散了
  811. if !ok {
  812. // 加入撤退列表
  813. p.markMarchRetreat(marchTable, enum.RetreatType_Retreat, false)
  814. return
  815. }
  816. // 设置成员到达
  817. legionTable.SetMemberArrive(marchTable.ObjectID)
  818. // 修改状态为集结状态
  819. p.updateMarchState(marchTable, enum.MarchState_Assemble, 0)
  820. // 离开AOI
  821. p.marchLeaveAOI(marchTable)
  822. clog.Debugf("march assemble arrive: MarchObjectID = %d, LegionID = %d, LegionName = %s, TileID = %d",
  823. marchTable.ObjectID, legionTable.ObjectID, legionTable.LegionName, marchTable.GetTileID())
  824. }
  825. // Deprecated: 暂时不使用,考虑删除
  826. func (p *actor) marchLegionAssemble(marchTable *db.LogicMarchTable) {
  827. }
  828. // marchRetreat 行军撤退
  829. func (p *actor) marchRetreat(marchTable *db.LogicMarchTable) {
  830. // 撤退可以撤退到主城,其它建筑或者系统城(通过调动,攻城集结)
  831. if buildTable, ok := p.BuildTables.Get(marchTable.TargetObjectID); ok {
  832. p.marchRetreatBuild(marchTable, buildTable)
  833. return
  834. }
  835. if castleTable, ok := p.CastleTables.Get(marchTable.TargetObjectID); ok {
  836. p.marchRetreatCastle(marchTable, castleTable)
  837. return
  838. }
  839. clog.Warnf("[marchRetreat]: target not found: MarchObjectID = %d, TargetObjectID = %d, Point = %v",
  840. marchTable.ObjectID, marchTable.TargetObjectID, marchTable.Point)
  841. // 设置为停留, 并不能让他触发碰撞
  842. p.updateMarchState(marchTable, enum.MarchState_Stay, 0)
  843. }
  844. func (p *actor) marchRetreatBuild(marchTable *db.LogicMarchTable, buildTable *db.LogicBuildTable) {
  845. if !buildTable.IsCoverPoint(marchTable.X(), marchTable.Y()) {
  846. clog.Warnf("[marchRetreat]: not cover point: MarchObjectID = %v, BuildObjectID = %v, Point = %v",
  847. marchTable.ObjectID, buildTable.ObjectID, marchTable.Point)
  848. // 设置为停留, 并不能让他触发碰撞
  849. p.updateMarchState(marchTable, enum.MarchState_Stay, 0)
  850. return
  851. }
  852. // 只能撤退到自己或者联盟的建筑
  853. // TODO: 这里应该往外推到建筑外的点
  854. if buildTable.PlayerID != marchTable.PlayerID && buildTable.LeagueID != marchTable.LeagueID {
  855. clog.Warnf("[marchRetreat]: not own or league build: MarchObjectID = %v, BuildObjectID = %v, Point = %v",
  856. marchTable.ObjectID, buildTable.ObjectID, marchTable.Point)
  857. // 设置为停留, 并不能让他触发碰撞
  858. p.updateMarchState(marchTable, enum.MarchState_Stay, 0)
  859. return
  860. }
  861. switch buildTable.ConfigID {
  862. case constant.MapBuild_MainCity: // 主城
  863. {
  864. clog.Debugf("[marchRetreatBuild] Retreat to MainCity: MarchObjectID = %d, BuildObjectID = %d, Point = %v",
  865. marchTable.ObjectID, buildTable.ObjectID, marchTable.Point)
  866. // 改为待命状态
  867. p.updateMarchState(marchTable, enum.MarchState_Standby, 0)
  868. }
  869. case constant.MapBuild_LeaguePoint: // 驻地
  870. {
  871. clog.Debugf("[marchRetreatBuild] Retreat to LeaguePoint: MarchObjectID = %d, BuildObjectID = %d, Point = %v",
  872. marchTable.ObjectID, buildTable.ObjectID, marchTable.Point)
  873. // TODO: 这里应该判断主城是否进入了联盟驻地
  874. // TODO: 这个需求还是有问题
  875. watcherTable := p.WatcherTables.GetValue(marchTable.PlayerID)
  876. mainCity := p.BuildTables.GetValue(watcherTable.MainCity)
  877. if mainCity.IsHide {
  878. // 主城在驻地中,改为待命状态
  879. p.updateMarchState(marchTable, enum.MarchState_Standby, 0)
  880. } else {
  881. // 否则改为调动状态
  882. p.updateMarchState(marchTable, enum.MarchState_Redeploy, 0)
  883. }
  884. }
  885. case constant.MapBuild_SiegeBase: // 攻城大营
  886. {
  887. clog.Debugf("[marchRetreatBuild] Retreat to SiegeBase: MarchObjectID = %d, BuildObjectID = %d, Point = %v",
  888. marchTable.ObjectID, buildTable.ObjectID, marchTable.Point)
  889. // 改为攻城集结状态
  890. p.updateMarchState(marchTable, enum.MarchState_SiegeAssemble, 0)
  891. }
  892. default:
  893. {
  894. clog.Debugf("[marchRetreatBuild] Retreat to %v: MarchObjectID = %d, BuildObjectID = %d, Point = %v",
  895. buildTable.ConfigID, marchTable.ObjectID, buildTable.ObjectID, marchTable.Point)
  896. // 改为调动状态
  897. p.updateMarchState(marchTable, enum.MarchState_Redeploy, 0)
  898. }
  899. }
  900. // 如果被撤退的建筑正被攻城,加入自动防守
  901. if buildTable.IsBeingSiege() {
  902. mapCall.Player.AutoDefendRequest(marchTable.PlayerID, buildTable.ObjectID, []int32{marchTable.TeamID})
  903. }
  904. // 如果不是停留状态,离开地图
  905. if marchTable.State != enum.MarchState_Stay {
  906. mapCall.AOI.Leave(marchTable.ObjectID, enum.ObjectType_March)
  907. }
  908. }
  909. func (p *actor) marchRetreatCastle(marchTable *db.LogicMarchTable, castleTable *db.LogicCastleTable) {
  910. if !castleTable.IsCoverPoint(marchTable.X(), marchTable.Y()) {
  911. clog.Warnf("[marchRetreatCastle]: not cover point: MarchObjectID = %v, CastleObjectID = %v, Point = %v",
  912. marchTable.ObjectID, castleTable.ObjectID, marchTable.Point)
  913. // 设置为停留, 并不能让他触发碰撞
  914. p.updateMarchState(marchTable, enum.MarchState_Stay, 0)
  915. return
  916. }
  917. // 只能撤退到联盟的城池
  918. // TODO: 这里应该往外推到建筑外的点
  919. if castleTable.PlayerID != marchTable.PlayerID && castleTable.LeagueID != marchTable.LeagueID {
  920. clog.Warnf("[marchRetreatCastle]: not league castle: MarchObjectID = %v, CastleObjectID = %v, Point = %v",
  921. marchTable.ObjectID, castleTable.ObjectID, marchTable.Point)
  922. // 设置为停留, 并不能让他触发碰撞
  923. p.updateMarchState(marchTable, enum.MarchState_Stay, 0)
  924. return
  925. }
  926. clog.Debugf("[marchRetreatCastle] Retreat to Castle: MarchObjectID = %d, CastleObjectID = %d, Point = %v",
  927. marchTable.ObjectID, castleTable.ObjectID, marchTable.Point)
  928. // 如果卫城,改为攻城集结状态
  929. if castleTable.CastleType == pb.SysObjType_so_town {
  930. p.updateMarchState(marchTable, enum.MarchState_SiegeAssemble, 0)
  931. } else {
  932. // 改为调动状态
  933. p.updateMarchState(marchTable, enum.MarchState_Redeploy, 0)
  934. }
  935. // 如果被撤退的建筑正被攻城,加入自动防守
  936. if castleTable.IsBeingSiege() {
  937. mapCall.Player.AutoDefendRequest(marchTable.PlayerID, castleTable.ObjectID, []int32{marchTable.TeamID})
  938. }
  939. // 离开地图
  940. mapCall.AOI.Leave(marchTable.ObjectID, enum.ObjectType_March)
  941. }
  942. func (p *actor) marchSave(marchTable *db.LogicMarchTable) {
  943. marchTable.IsDataChanged = false
  944. marchTable.Save2Queue()
  945. }
  946. func (p *actor) updateMarchState(marchTable *db.LogicMarchTable, newState enum.MarchState, endTime int64) {
  947. if endTime > 0 {
  948. clog.Debugf("[updateMarchState] objectID = %d, state = %s -> %s, endTime = %s",
  949. marchTable.ObjectID,
  950. enum.GetMarchStateName(marchTable.State),
  951. enum.GetMarchStateName(newState),
  952. times.MillisToDatetimeFormat(endTime),
  953. )
  954. } else {
  955. clog.Debugf("[updateMarchState] objectID = %d, state = %s -> %s",
  956. marchTable.ObjectID,
  957. enum.GetMarchStateName(marchTable.State), enum.GetMarchStateName(newState))
  958. }
  959. oldState := marchTable.State
  960. marchTable.UpdateState(newState, p.nowMillis, endTime)
  961. p.pushMarchState(marchTable, oldState, newState, false)
  962. p.armyLineMarchState(marchTable, oldState, newState)
  963. }
  964. func (p *actor) updateMarchStateEndTime(marchTable *db.LogicMarchTable, endTime int64) {
  965. clog.Debugf("[updateMarchStateEndTime] objectID = %d, endTime = %s", marchTable.ObjectID, times.MillisToDatetimeFormat(endTime))
  966. marchTable.StateEndTime = endTime
  967. marchTable.IsDataChanged = true
  968. // 推送状态时间
  969. mapCall.AOI.UpdateWithID(marchTable.ObjectID, marchTable.Type, p.newUpdateID(), nameRemote.MapLogic_AOIUpdateMarchState)
  970. }
  971. func (p *actor) restoreMarchState(marchTable *db.LogicMarchTable) {
  972. clog.Debugf("[restoreMarchState] state = %s -> %s, time offset = %v",
  973. enum.GetMarchStateName(marchTable.State),
  974. enum.GetMarchStateName(marchTable.PrevState),
  975. p.nowMillis-marchTable.PrevStateSaveTime)
  976. var (
  977. oldState = marchTable.State
  978. newState = marchTable.PrevState
  979. )
  980. marchTable.RestoreState(p.nowMillis)
  981. p.pushMarchState(marchTable, oldState, newState, false)
  982. }
  983. func (p *actor) restoreMarchStateAndPushAll(marchTable *db.LogicMarchTable) {
  984. clog.Debugf("[restoreMarchStateAndPushAll] state = %s -> %s, time offset = %v",
  985. enum.GetMarchStateName(marchTable.State),
  986. enum.GetMarchStateName(marchTable.PrevState),
  987. p.nowMillis-marchTable.PrevStateSaveTime)
  988. var (
  989. oldState = marchTable.State
  990. newState = marchTable.PrevState
  991. )
  992. marchTable.RestoreState(p.nowMillis)
  993. p.pushMarchState(marchTable, oldState, newState, true)
  994. }
  995. func (p *actor) pushMarchState(marchTable *db.LogicMarchTable, oldState, newState enum.MarchState, isPushAll bool) {
  996. var (
  997. isOldStateInMap = enum.IsInMapState(oldState)
  998. isNewStateInMap = enum.IsInMapState(newState)
  999. )
  1000. // 队伍在地图上的位置发生变化就通知 game player
  1001. if isOldStateInMap != isNewStateInMap {
  1002. if isNewStateInMap {
  1003. p.addMarchAOI(marchTable)
  1004. } else {
  1005. // 先推送Update
  1006. if isPushAll {
  1007. mapCall.AOI.UpdateAll(marchTable.ObjectID, marchTable.Type)
  1008. } else {
  1009. mapCall.AOI.UpdateWithID(marchTable.ObjectID, marchTable.Type, p.newUpdateID(), nameRemote.MapLogic_AOIUpdateMarchState)
  1010. }
  1011. // 再推送Leave
  1012. mapCall.AOI.Leave(marchTable.ObjectID, marchTable.Type)
  1013. }
  1014. } else {
  1015. if isNewStateInMap {
  1016. // 推送march状态给客户端
  1017. if isPushAll {
  1018. mapCall.AOI.UpdateAll(marchTable.ObjectID, marchTable.Type)
  1019. } else {
  1020. mapCall.AOI.UpdateWithID(marchTable.ObjectID, marchTable.Type, p.newUpdateID(), nameRemote.MapLogic_AOIUpdateMarchState)
  1021. }
  1022. } else {
  1023. // 给自己推送数据
  1024. sessions.PushPlayer(marchTable.PlayerID, nameRoute.PushMapPusher_MarchState, marchTable.ToStatusProto())
  1025. }
  1026. }
  1027. // 通知ui更新
  1028. if isPushAll {
  1029. p.PushMapUIMarchUpsert(marchTable.PlayerID, marchTable.ToMapUIProto())
  1030. } else {
  1031. p.PushMapUIMarchState(marchTable.PlayerID, marchTable.ToStatusProto())
  1032. }
  1033. // 更新部队状态为外派或者待命
  1034. if newState == enum.MarchState_Standby || oldState == enum.MarchState_Standby {
  1035. if newState == enum.MarchState_Standby {
  1036. mapCall.Player.MapPlayerUpdateTeamState(marchTable.PlayerID, marchTable.TeamID, enum.TeamState_Standby)
  1037. clog.Debugf("[updateMarchState] objectID = %d, update team state to standby", marchTable.ObjectID)
  1038. } else {
  1039. mapCall.Player.MapPlayerUpdateTeamState(marchTable.PlayerID, marchTable.TeamID, enum.TeamState_Outing)
  1040. clog.Debugf("[updateMarchState] objectID = %d, update team state to outing", marchTable.ObjectID)
  1041. }
  1042. }
  1043. }
  1044. func (p *actor) markMarchRetreat(marchTable *db.LogicMarchTable, retreatType enum.RetreatType, isRemoveRedeploy bool) {
  1045. clog.Debugf("[addMarchToRetreat] objectID = %d, retreatType = %d, isRemoveRedeploy = %v",
  1046. marchTable.ObjectID, retreatType, isRemoveRedeploy)
  1047. // 脱离攻城大营管理
  1048. marchTable.MarkAutoSiege(false, 0)
  1049. // 保底:先把行军状态设置为停留但不推送,也不加入停留列表
  1050. if marchTable.State == enum.MarchState_BattleWait || marchTable.State == enum.MarchState_Battle {
  1051. marchTable.UpdateState(enum.MarchState_Stay, p.nowMillis, 0)
  1052. }
  1053. // 设置了自动回城,或者被击退,或者有资源运输,则加入撤退队列
  1054. if marchTable.IsAutoRetreat ||
  1055. retreatType == enum.RetreatType_Rout ||
  1056. retreatType == enum.RetreatType_Must {
  1057. marchTable.StartAutoRetreat(retreatType, isRemoveRedeploy)
  1058. } else {
  1059. p.marchStay(marchTable)
  1060. }
  1061. }
  1062. func (p *actor) addToTileMarch(marchTable *db.LogicMarchTable, tileTable *db.LogicTileTable) {
  1063. tileTable.AddMarch(marchTable.ObjectID, dbLogic.NewTileMarchInfo(
  1064. tileTable.TileID,
  1065. marchTable.ObjectID,
  1066. p.nowMillis,
  1067. ))
  1068. p.addTileProcess(tileTable)
  1069. }
  1070. func (p *actor) marchSiegeBaseRemove(marchTable *db.LogicMarchTable) {
  1071. if !marchTable.AutoMarchInfo.IsAutoSiege {
  1072. return
  1073. }
  1074. siegeCampID := marchTable.AutoMarchInfo.SiegeCampID
  1075. clog.Debugf("[marchSiegeCampRemove] marchObjectID = %d, siegeCampID = %d", marchTable.ObjectID, siegeCampID)
  1076. if castleTable, ok := p.CastleTables.Get(siegeCampID); ok {
  1077. castleTable.SiegeTown.MainForceList.RemoveValue(marchTable.ObjectID)
  1078. castleTable.SiegeTown.SiegeSquadList.RemoveValue(marchTable.ObjectID)
  1079. castleTable.IsDataChanged = true
  1080. }
  1081. marchTable.MarkAutoSiege(false, 0)
  1082. }
  1083. func (p *actor) checkRedeployLimit(configID, level, redeployCount int32) int32 {
  1084. mapBuildRow, found := data.MapRedeploy.GetByConfigIDLevel(configID, level)
  1085. if found {
  1086. // 没有上限
  1087. if mapBuildRow.RedeployLimit <= 0 {
  1088. return code.OK
  1089. }
  1090. // 判断当前建筑的调动部队
  1091. if redeployCount >= mapBuildRow.RedeployLimit {
  1092. return code.MapBuild_RedeployLimit
  1093. }
  1094. }
  1095. // TODO 找不到 不改原来流程 默认能成功
  1096. return code.OK
  1097. }
  1098. func (p *actor) marchLeaveAOI(marchTable *db.LogicMarchTable) {
  1099. mapCall.AOI.Leave(marchTable.ObjectID, marchTable.Type)
  1100. }
  1101. func (p *actor) marchMoveToPoint(marchTable *db.LogicMarchTable, point types.Point) {
  1102. clog.Debugf("move marchTable to ponit: ObjectID = %d, MarchState = %s, MarchType = %s, Point = %v",
  1103. marchTable.ObjectID, enum.GetMarchStateName(marchTable.State), enum.GetMarchTypeName(marchTable.MarchType), &point,
  1104. )
  1105. // 从旧的 tileTable 中删除
  1106. tileTable := p.TileTables.GetValue(marchTable.GetTileID())
  1107. tileTable.RemoveMarchAnywhere(marchTable.ObjectID)
  1108. p.addTileProcess(tileTable)
  1109. marchTable.Point.Set(&point)
  1110. marchTable.PrevPoint.Set(&point)
  1111. marchTable.ClearPath()
  1112. }
  1113. // removeMarchRedeploy 移除行军调动
  1114. func (p *actor) removeMarchRedeploy(marchTable *db.LogicMarchTable, isTarget, isNotice bool) {
  1115. if isTarget {
  1116. if buildTable, ok := p.BuildTables.Get(marchTable.TargetObjectID); ok {
  1117. buildTable.RemoveRedeploy(marchTable.ObjectID)
  1118. p.UpdateObjectFull(buildTable.ObjectID, buildTable.Type)
  1119. } else if castleTable, ok := p.CastleTables.Get(marchTable.TargetObjectID); ok {
  1120. castleTable.RemoveRedeploy(marchTable.ObjectID)
  1121. p.UpdateObjectFull(castleTable.ObjectID, castleTable.Type)
  1122. }
  1123. } else {
  1124. if buildTable, ok := p.BuildTables.Get(marchTable.RedeployObject.Key); ok {
  1125. buildTable.RemoveRedeploy(marchTable.ObjectID)
  1126. p.UpdateObjectFull(buildTable.ObjectID, buildTable.Type)
  1127. marchTable.SetRedeployObjectID(0, 0)
  1128. if isNotice {
  1129. p.updateTeam(marchTable, enum.TeamUpdate_Redeploy)
  1130. }
  1131. } else if castleTable, ok := p.CastleTables.Get(marchTable.RedeployObject.Key); ok {
  1132. castleTable.RemoveRedeploy(marchTable.ObjectID)
  1133. p.UpdateObjectFull(castleTable.ObjectID, castleTable.Type)
  1134. marchTable.SetRedeployObjectID(0, 0)
  1135. if isNotice {
  1136. p.updateTeam(marchTable, enum.TeamUpdate_Redeploy)
  1137. }
  1138. }
  1139. }
  1140. }
  1141. func (p *actor) updateTeam(marchTable *db.LogicMarchTable, updateType enum.TeamUpdateType) {
  1142. req := &pb.UpdateTeam{
  1143. TeamID: marchTable.TeamID,
  1144. TeamUpdateType: int32(updateType),
  1145. }
  1146. switch updateType {
  1147. case enum.TeamUpdate_Redeploy:
  1148. req.RedeployObjectID = marchTable.RedeployObject.Key
  1149. req.RedeployObjectType = int32(marchTable.RedeployObject.Value)
  1150. }
  1151. mapCall.Player.UpdateTeam(marchTable.PlayerID, req)
  1152. }
  1153. // getCollidedBuilding 获取碰撞的建筑
  1154. func (p *actor) getCollidedBuilding(marchTable *db.LogicMarchTable, tileTable *db.LogicTileTable) *db.LogicBuildTable {
  1155. // 撤退的行军对象不会发生碰撞
  1156. if marchTable.IsRetreat() {
  1157. return nil
  1158. }
  1159. if tileTable.BuildObjectID > 0 {
  1160. buildTable := p.BuildTables.GetValue(tileTable.BuildObjectID)
  1161. if buildTable.ConfigID == constant.MapBuild_Barricade && !buildTable.IsBuilding &&
  1162. !p.isSameLeague(buildTable.LeagueID, marchTable.LeagueID) {
  1163. return buildTable
  1164. }
  1165. }
  1166. return nil
  1167. }
  1168. // marchBuildingCollision 建筑碰撞逻辑
  1169. func (p *actor) marchBuildingCollision(marchTable *db.LogicMarchTable, tileTable *db.LogicTileTable, buildTable *db.LogicBuildTable) {
  1170. if buildTable.ConfigID != constant.MapBuild_Barricade {
  1171. return
  1172. }
  1173. // 保存状态
  1174. marchTable.SaveState(p.nowMillis)
  1175. // 更新为攻城状态
  1176. nextTime := p.nowMillis + ctime.MillisecondsPerSecond
  1177. p.updateMarchState(marchTable, enum.MarchState_Siege, nextTime)
  1178. // 设置拒马为当前目标
  1179. marchTable.TargetObjectID = buildTable.ObjectID
  1180. // 加入攻城列表
  1181. tileMarchInfo := dbLogic.NewTileMarchInfo(
  1182. tileTable.TileID,
  1183. marchTable.ObjectID,
  1184. p.nowMillis,
  1185. buildTable.ObjectID,
  1186. )
  1187. // 设置为首次攻城
  1188. tileMarchInfo.IsFirstSiege = true
  1189. // 等待一个 ticker
  1190. tileMarchInfo.LogicEndTime = nextTime
  1191. // 加入攻城列表
  1192. tileTable.AddSiege(marchTable.ObjectID, tileMarchInfo)
  1193. p.addTileProcess(tileTable)
  1194. }