player_conscript.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. package mapPlayer
  2. import (
  3. actorRemote "f1-game/internal/actor_remote"
  4. "f1-game/internal/code"
  5. "f1-game/internal/constant"
  6. "f1-game/internal/data"
  7. "f1-game/internal/enum"
  8. "f1-game/internal/event"
  9. "f1-game/internal/extend/math"
  10. nameLocal "f1-game/internal/name/local"
  11. "f1-game/internal/pb"
  12. "f1-game/internal/types"
  13. ao "f1-game/nodes/game/player/asset/origin"
  14. "f1-game/nodes/map/internal/db"
  15. mapFacade "f1-game/nodes/map/internal/facade"
  16. "f1-game/nodes/map/player/conscript"
  17. cproto "github.com/cherry-game/cherry/net/proto"
  18. )
  19. func (p *actorPlayer) initConscript() {
  20. p.Local().Register(nameLocal.MapPlayer_ConscriptBegin, p.conscriptBegin)
  21. p.Local().Register(nameLocal.MapPlayer_ConscriptCancel, p.conscriptCancel)
  22. p.Local().Register(nameLocal.MapPlayer_ConscriptUp, p.conscriptUp)
  23. p.Local().Register(nameLocal.MapPlayer_ConscriptUpCancel, p.conscriptUpCancel)
  24. p.Local().Register(nameLocal.MapPlayer_ConscriptAuto, p.conscriptAuto)
  25. }
  26. // 开始征兵
  27. func (p *actorPlayer) conscriptBegin(session *cproto.Session, req *pb.ConscriptRequest) {
  28. var (
  29. playerTable = db.GetMapPlayerTable(p.playerID)
  30. armID = req.ArmID
  31. num = req.Num
  32. )
  33. if num <= 0 {
  34. p.ResponseCode(session, code.ConscriptNumLack)
  35. return
  36. }
  37. armLevelRow, found := data.ArmLevel.GetByID(armID)
  38. if !found {
  39. p.ResponseCode(session, code.ConfigNotExist_Conscript)
  40. return
  41. }
  42. // 当前正在士兵升级
  43. if playerTable.Conscripts.IsConscriptUp() {
  44. p.ResponseCode(session, code.ConscriptUpgradeHandling)
  45. return
  46. }
  47. // 判断征兵不同士兵
  48. if playerTable.Conscripts.IsNotSameConscript(armID) {
  49. p.ResponseCode(session, code.ConscriptHandling)
  50. return
  51. }
  52. // 征兵/升级的等级未解锁
  53. if playerTable.Facilities.CheckAttrsLimit(enum.AttrArmsMaxLevel, armLevelRow.Level) {
  54. p.ResponseCode(session, code.ConscriptLevelLimit)
  55. return
  56. }
  57. var (
  58. playerID = playerTable.PlayerID
  59. // 获取征兵/升级的兵种ID当前数量
  60. curNum = int32(conscript.Service().GetCurTroopNum(playerID))
  61. total = curNum + num + playerTable.Conscripts.Conscript.ConscriptRemain()
  62. )
  63. // 超出最大值
  64. if playerTable.Facilities.CheckAttrsLimit(enum.AttrArmsLimit, total) {
  65. p.ResponseCode(session, code.ConscriptNumLimit)
  66. return
  67. }
  68. // 计算征兵/升级消耗
  69. costs := armLevelRow.CalConscriptAssets(int64(num))
  70. _, errCode := mapFacade.Storage.AssetSubs(playerID, costs, ao.ConscriptCost)
  71. if code.IsFail(errCode) {
  72. p.ResponseCode(session, errCode)
  73. return
  74. }
  75. // 开始征兵/升级
  76. playerTable.Conscripts.StartConscript(armID, num)
  77. playerTable.Save2Queue()
  78. // 推送给客户端
  79. conscript.Service().Push(playerTable, session)
  80. p.ResponseCode(session, code.OK)
  81. }
  82. // 取消征兵
  83. func (p *actorPlayer) conscriptCancel(session *cproto.Session, req *pb.None) {
  84. playerTable := db.GetMapPlayerTable(p.playerID)
  85. // 执行取消征兵
  86. errCode := p.doConscriptCancel(playerTable)
  87. if code.IsFail(errCode) {
  88. p.ResponseCode(session, errCode)
  89. return
  90. }
  91. playerTable.Conscripts.ResetConscript()
  92. // 手动取消征兵 才会取消自动征兵功能
  93. playerTable.Conscripts.Conscript.AutoConscript = false
  94. playerTable.Save2Queue()
  95. conscript.Service().Push(playerTable, session)
  96. p.ResponseCode(session, code.OK)
  97. }
  98. // 执行取消征兵
  99. func (p *actorPlayer) doConscriptCancel(playerTable *db.MapPlayerTable) int32 {
  100. // 当前没有任何操作
  101. if playerTable.Conscripts.IsNotConscriptAction() {
  102. return code.ConscriptNoAction
  103. }
  104. // 当前士兵升级中
  105. if playerTable.Conscripts.IsConscriptUp() {
  106. return code.ConscriptUpgradeHandling
  107. }
  108. var (
  109. armID = playerTable.Conscripts.Conscript.ArmID
  110. remain = int64(playerTable.Conscripts.Conscript.ConscriptRemain())
  111. )
  112. if remain <= 0 {
  113. return code.OK
  114. }
  115. armLevelRow, found := data.ArmLevel.GetByID(armID)
  116. if !found {
  117. return code.ConfigNotExist_Conscript
  118. }
  119. // 按照比例返还征兵材料
  120. returnAssets := armLevelRow.CalConscriptAssets(remain)
  121. for _, asset := range returnAssets {
  122. num := asset.Num
  123. asset.Num = math.Round[float64, int64](float64(num*data.Const.BuildConscriptRefundRatio) / constant.RatioBase)
  124. }
  125. _, errCode := mapFacade.Storage.AssetAdds(playerTable.PlayerID, returnAssets, ao.ConscriptBack)
  126. if code.IsFail(errCode) {
  127. return errCode
  128. }
  129. progress := playerTable.Conscripts.Conscript.Progress
  130. if progress > 0 {
  131. // 提交事件
  132. p.PostEvent(event.NewConscriptTroopSettle(p.playerID, armID, progress))
  133. // 系统消息
  134. actorRemote.GamePlayer.GamePlayerCallSystemMsg(playerTable.GameNodeID, p.playerID, enum.ChatMsgType_conscript, nil, nil, armID, progress)
  135. }
  136. // 重置征兵数据
  137. playerTable.Conscripts.ResetConscript()
  138. return code.OK
  139. }
  140. // 士兵升级
  141. func (p *actorPlayer) conscriptUp(session *cproto.Session, req *pb.ConscriptUpRequest) {
  142. var (
  143. armID = req.ArmID
  144. upArmID = req.UpArmID
  145. num = req.Num
  146. )
  147. if num <= 0 {
  148. p.ResponseCode(session, code.ConscriptUpNumLack)
  149. return
  150. }
  151. armLevelRow, found := data.ArmLevel.GetByID(armID)
  152. if !found {
  153. p.ResponseCode(session, code.ConfigNotExist_Conscript)
  154. return
  155. }
  156. playerTable := db.GetMapPlayerTable(p.playerID)
  157. // 当前正在征兵
  158. if playerTable.Conscripts.IsConscript() {
  159. p.ResponseCode(session, code.ConscriptHandling)
  160. return
  161. }
  162. // 判断当前是否相同士兵升级
  163. if playerTable.Conscripts.IsNotSameConscriptUp(armID, upArmID) {
  164. p.ResponseCode(session, code.ConscriptUpgradeHandling)
  165. return
  166. }
  167. upArmLevelRow, found := data.ArmLevel.GetByID(upArmID)
  168. if !found {
  169. p.ResponseCode(session, code.ConfigNotExist_Conscript)
  170. return
  171. }
  172. // 征兵/升级的等级未解锁
  173. if playerTable.Facilities.CheckAttrsLimit(enum.AttrArmsMaxLevel, upArmLevelRow.Level) {
  174. p.ResponseCode(session, code.ConscriptLevelLimit)
  175. return
  176. }
  177. var (
  178. // 获取征兵/升级的兵种ID当前数量
  179. curNum = int32(conscript.Service().GetCurTroopNum(p.playerID))
  180. total = curNum + playerTable.Conscripts.ConscriptUp.ConscriptUpRemain()
  181. )
  182. // 超出最大值
  183. if playerTable.Facilities.CheckAttrsLimit(enum.AttrArmsLimit, total) {
  184. p.ResponseCode(session, code.ConscriptNumLimit)
  185. return
  186. }
  187. // 获取/扣除升级消耗
  188. upCosts := p.calConscriptUpAssets(armLevelRow, upArmLevelRow, int64(num))
  189. upCosts.Add(armID, int64(num))
  190. _, errCode := mapFacade.Storage.AssetSubs(p.playerID, upCosts, ao.ConscriptUpgradeCost)
  191. if code.IsFail(errCode) {
  192. p.ResponseCode(session, errCode)
  193. return
  194. }
  195. // 开始士兵升级
  196. playerTable.Conscripts.StartConscriptUp(armID, upArmID, num)
  197. playerTable.Save2Queue()
  198. // 推送给客户端
  199. conscript.Service().Push(playerTable, session)
  200. p.ResponseCode(session, code.OK)
  201. }
  202. // 升级取消
  203. func (p *actorPlayer) conscriptUpCancel(session *cproto.Session, req *pb.None) {
  204. playerTable := db.GetMapPlayerTable(p.playerID)
  205. if !playerTable.Conscripts.IsConscriptUp() {
  206. p.ResponseCode(session, code.ConscriptNotUp)
  207. return
  208. }
  209. // 执行士兵升级取消
  210. errCode := p.doConscriptUpCancel(playerTable)
  211. if code.IsFail(errCode) {
  212. p.ResponseCode(session, errCode)
  213. return
  214. }
  215. playerTable.Save2Queue()
  216. // 推送给客户端
  217. conscript.Service().Push(playerTable, session)
  218. p.ResponseCode(session, code.OK)
  219. }
  220. func (p *actorPlayer) doConscriptUpCancel(playerTable *db.MapPlayerTable) int32 {
  221. var (
  222. armID = playerTable.Conscripts.ConscriptUp.ArmID
  223. upArmID = playerTable.Conscripts.ConscriptUp.UpArmID
  224. remain = int64(playerTable.Conscripts.ConscriptUp.ConscriptUpRemain())
  225. )
  226. if remain <= 0 {
  227. return code.OK
  228. }
  229. armLevelRow, found := data.ArmLevel.GetByID(armID)
  230. if !found {
  231. return code.ConfigNotExist_Conscript
  232. }
  233. upArmLevelRow, found := data.ArmLevel.GetByID(upArmID)
  234. if !found {
  235. return code.ConfigNotExist_Conscript
  236. }
  237. // 按照比例返还升级材料
  238. returnAssets := p.calConscriptUpAssets(armLevelRow, upArmLevelRow, remain)
  239. for _, asset := range returnAssets {
  240. num := asset.Num
  241. asset.Num = math.Round[float64, int64](float64(num*data.Const.BuildConscriptRefundRatio) / constant.RatioBase)
  242. }
  243. // 返还升级前士兵按照原数量
  244. returnAssets.Add(armID, remain)
  245. _, errCode := mapFacade.Storage.AssetAdds(p.playerID, returnAssets, ao.ConscriptBack)
  246. if code.IsFail(errCode) {
  247. return errCode
  248. }
  249. progress := playerTable.Conscripts.ConscriptUp.Progress
  250. if progress > 0 {
  251. // 提交事件
  252. p.PostEvent(event.NewConscriptTroopSettle(p.playerID, upArmID, progress))
  253. // 系统消息
  254. actorRemote.GamePlayer.GamePlayerCallSystemMsg(playerTable.GameNodeID, p.playerID, enum.ChatMsgType_conscriptUp, nil, nil, upArmID, progress)
  255. }
  256. // 重置士兵升级数据
  257. playerTable.Conscripts.ResetConscriptUp()
  258. return code.OK
  259. }
  260. // 自动征兵设置
  261. func (p *actorPlayer) conscriptAuto(session *cproto.Session, req *pb.I32) {
  262. var (
  263. armID = req.Value
  264. playerTable = db.GetMapPlayerTable(p.playerID)
  265. autoConscript = !playerTable.Conscripts.Conscript.AutoConscript
  266. )
  267. if playerTable.Conscripts.Conscript.ArmID != armID {
  268. autoConscript = true
  269. }
  270. // 执行自动征兵
  271. if autoConscript {
  272. if armID <= 0 {
  273. p.ResponseCode(session, code.RequestParamsError)
  274. return
  275. }
  276. // 检测是否需要返还征兵材料
  277. errCode := p.checkAutoConscriptReturn(playerTable, armID)
  278. if code.IsFail(errCode) {
  279. p.ResponseCode(session, errCode)
  280. return
  281. }
  282. // 执行自动征兵逻辑
  283. if ok := conscript.Service().AutoConscript(playerTable, armID); !ok {
  284. // 如果因为材料不足而导致自动征兵失败 则设置当前自动征兵的士兵ID 等有材料的时候自动征兵
  285. playerTable.Conscripts.CurState = enum.ConscriptState_Conscript
  286. playerTable.Conscripts.Conscript.ArmID = armID
  287. }
  288. } else {
  289. // 当前是征兵状态 且 已完成 清空自动征兵的士兵ID
  290. if playerTable.Conscripts.IsConscript() && playerTable.Conscripts.Conscript.IsConscriptFinish() {
  291. playerTable.Conscripts.ResetConscript()
  292. }
  293. }
  294. // 设置自动征兵
  295. playerTable.Conscripts.Conscript.AutoConscript = autoConscript
  296. playerTable.Save2Queue()
  297. // 推送给客户端
  298. conscript.Service().Push(playerTable, session)
  299. p.ResponseCode(session, code.OK)
  300. }
  301. // 检测是否需要返还征兵材料
  302. func (p *actorPlayer) checkAutoConscriptReturn(playerTable *db.MapPlayerTable, armID int32) int32 {
  303. if playerTable.Conscripts.IsNotConscriptAction() {
  304. return code.OK
  305. }
  306. // 如果当前是征兵 且征兵士兵ID不相同,则取消原来的兵征兵任务
  307. if playerTable.Conscripts.IsConscript() && playerTable.Conscripts.Conscript.ArmID != armID {
  308. return p.doConscriptCancel(playerTable)
  309. }
  310. // 如果当前是士兵升级逻辑 取消原来的士兵升级任务
  311. if playerTable.Conscripts.IsConscriptUp() {
  312. return p.doConscriptUpCancel(playerTable)
  313. }
  314. return code.OK
  315. }
  316. func (p *actorPlayer) calConscriptUpAssets(curArmLevelRow *data.ArmLevelRow, upArmLevelRow *data.ArmLevelRow, num int64) types.Assets {
  317. var (
  318. assets = curArmLevelRow.CalConscriptAssets(num)
  319. upAssets = upArmLevelRow.CalConscriptAssets(num)
  320. )
  321. for _, asset := range assets {
  322. for _, upAsset := range upAssets {
  323. if upAsset.ID == asset.ID {
  324. upAsset.Num -= asset.Num
  325. }
  326. }
  327. }
  328. finalAssets := types.Assets{}
  329. for _, asset := range upAssets {
  330. if asset.Num > 0 {
  331. finalAssets.Add(asset.ID, asset.Num)
  332. }
  333. }
  334. return finalAssets
  335. }