player_equip.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. package player
  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/rand"
  9. nameLocal "f1-game/internal/name/local"
  10. "f1-game/internal/pb"
  11. "f1-game/internal/types"
  12. gameFacade "f1-game/nodes/game/internal/facade"
  13. "f1-game/nodes/game/player/asset"
  14. ao "f1-game/nodes/game/player/asset/origin"
  15. "f1-game/nodes/game/player/equip"
  16. cproto "github.com/cherry-game/cherry/net/proto"
  17. )
  18. func (p *actorPlayer) initEquip() {
  19. p.Local().Register(nameLocal.Player_EquipCraft, p.equipCraft)
  20. p.Local().Register(nameLocal.Player_EquipRandomCraft, p.equipRandomCraft)
  21. p.Local().Register(nameLocal.Player_EquipEnhance, p.equipEnhance)
  22. p.Local().Register(nameLocal.Player_EquipDimantle, p.equipDimantle)
  23. p.Local().Register(nameLocal.Player_EquipSkillActive, p.equipSkillActive)
  24. p.Local().Register(nameLocal.Player_EquipExchangeUnlock, p.equipExchangeUnlock)
  25. }
  26. // equipCraft 装备打造
  27. func (p *actorPlayer) equipCraft(session *cproto.Session, req *pb.I32I32) {
  28. var (
  29. equipID = req.Key
  30. num = int64(req.Value)
  31. )
  32. // 锻造数量错误
  33. if num <= 0 {
  34. p.ResponseCode(session, code.IllegalArgument)
  35. return
  36. }
  37. equipRow, ok := data.Equip.GetByID(equipID)
  38. if !ok {
  39. p.ResponseCode(session, code.ConfigNotFound_Equip)
  40. return
  41. }
  42. costs := equipRow.CalEquipCraftCosts(num)
  43. // 检查材料
  44. errCode := asset.Service().IsAllEnough(p.playerID, costs)
  45. if code.IsFail(errCode) {
  46. p.ResponseCode(session, errCode)
  47. return
  48. }
  49. // 添加装备
  50. addAssets, errCode := asset.Service().Add(p.playerID, equipRow.ID, num, ao.None, true)
  51. if code.IsFail(errCode) {
  52. p.ResponseCode(session, errCode)
  53. return
  54. }
  55. // 扣除材料
  56. _, errCode = asset.Service().Subs(p.playerID, costs, ao.None)
  57. if code.IsFail(errCode) {
  58. p.Warn("equipCraft error: equipID = %d, errCode = %d", equipRow.ID, errCode)
  59. p.ResponseCode(session, errCode)
  60. return
  61. }
  62. // 累计打造次数
  63. equipTable := p.EquipTable()
  64. equipTable.EquipExtend.AddCraftQualityCount(int32(equipRow.Quality), req.Value)
  65. equipTable.Save2Queue()
  66. // 发送打造事件
  67. p.PostEvent(event.NewEquipCraft(p.playerID, addAssets))
  68. // 返回新获得的装备列表
  69. rsp := addAssets.ToAssetListProto()
  70. p.Response(session, &rsp)
  71. }
  72. // equipRandomCraft 装备随机打造
  73. func (p *actorPlayer) equipRandomCraft(session *cproto.Session, req *pb.I32) {
  74. craftNum := req.Value
  75. if craftNum <= 0 {
  76. p.ResponseCode(session, code.IllegalArgument)
  77. return
  78. }
  79. costs := data.Const.GetEquipRandomCraftCost(craftNum)
  80. // 检查材料
  81. errCode := asset.Service().IsAllEnough(p.playerID, costs)
  82. if code.IsFail(errCode) {
  83. p.ResponseCode(session, errCode)
  84. return
  85. }
  86. // 随机craftNum件装备
  87. itemPoolRows, errCode := data.DropPool.Random(data.Const.EquipRandomCraftPoolID, craftNum)
  88. if code.IsFail(errCode) {
  89. p.ResponseCode(session, errCode)
  90. return
  91. }
  92. var (
  93. assets = types.Assets{}
  94. qualityCounts = map[int32]int32{}
  95. )
  96. for _, itemPoolRow := range itemPoolRows {
  97. equipRow, found := data.Equip.GetByID(itemPoolRow.ItemID)
  98. if !found {
  99. p.ResponseCode(session, code.ConfigNotFound_Equip)
  100. return
  101. }
  102. assets.Add(itemPoolRow.ItemID, itemPoolRow.Num)
  103. quality := int32(equipRow.Quality)
  104. qualityCounts[quality] = qualityCounts[quality] + int32(itemPoolRow.Num)
  105. }
  106. // 加资产(装备)
  107. addAssets, errCode := asset.Service().Adds(p.playerID, assets, ao.None, true)
  108. if code.IsFail(errCode) {
  109. p.ResponseCode(session, errCode)
  110. return
  111. }
  112. // 扣除材料
  113. _, errCode = asset.Service().Subs(p.playerID, costs, ao.None)
  114. if code.IsFail(errCode) {
  115. p.Warn("equipRandomCraft error: errCode = %d", errCode)
  116. p.ResponseCode(session, errCode)
  117. return
  118. }
  119. // 累计打造次数
  120. equipTable := p.EquipTable()
  121. for quality, num := range qualityCounts {
  122. equipTable.EquipExtend.AddCraftQualityCount(quality, num)
  123. }
  124. equipTable.Save2Queue()
  125. // 发送打造事件
  126. p.PostEvent(event.NewEquipCraft(p.playerID, addAssets))
  127. // 返回新获得的装备列表
  128. rsp := addAssets.ToAssetListProto()
  129. p.Response(session, &rsp)
  130. }
  131. // equipEnhance 装备强化
  132. func (p *actorPlayer) equipEnhance(session *cproto.Session, req *pb.I64Bool) {
  133. var (
  134. equipTable = p.EquipTable()
  135. equipGUID = req.Key
  136. useMOCoin = req.Value
  137. equip, ok = equipTable.Equips.Get(equipGUID)
  138. )
  139. if !ok {
  140. p.ResponseCode(session, code.EquipNotFound)
  141. return
  142. }
  143. if equip.WearHeroGUID > 0 {
  144. // 检测英雄是否是出战状态
  145. errCode := p.checkHeroCanUpdateEquip(equip.WearHeroGUID)
  146. if code.IsFail(errCode) {
  147. p.ResponseCode(session, errCode)
  148. return
  149. }
  150. }
  151. equipRow, ok := data.Equip.GetByID(equip.EquipID)
  152. if !ok {
  153. p.ResponseCode(session, code.ConfigNotFound_Equip)
  154. return
  155. }
  156. equipLevelRow, ok := data.EquipLevel.GetByQualityLevel(equipRow.Quality, equip.Level)
  157. if !ok {
  158. p.ResponseCode(session, code.ConfigNotFound_EquipLevel)
  159. return
  160. }
  161. // 强化消耗为空,表示已经到了最高级
  162. if equipLevelRow.EnhanceCosts.IsEmpty() {
  163. p.ResponseCode(session, code.EquipLevelMax)
  164. return
  165. }
  166. var (
  167. costs types.Assets
  168. prob = equipLevelRow.SuccessProb
  169. )
  170. costs.AddAssets(equipLevelRow.EnhanceCosts)
  171. // 非100%概率使用MO币的情况
  172. if useMOCoin && prob < constant.RatioBase {
  173. // 计算增加的概率和消耗的MO币
  174. var (
  175. costAssetID = data.Const.EquipEnhanceAddProbCost.ID
  176. curNum = asset.Service().Get(p.playerID, costAssetID)
  177. )
  178. addProb, costCoin := data.Const.CalEquipEnhanceAddProb(prob, curNum)
  179. if costCoin != nil {
  180. costs.AddAssets(costCoin)
  181. prob += addProb
  182. } else {
  183. // 没有使用额外道具提升概率
  184. useMOCoin = false
  185. }
  186. }
  187. // 扣除资源
  188. _, errCode := asset.Service().Subs(p.playerID, costs, ao.None)
  189. if code.IsFail(errCode) {
  190. p.ResponseCode(session, errCode)
  191. return
  192. }
  193. var success bool
  194. // 100% 成功率直接完成
  195. if prob >= constant.RatioBase {
  196. success = true
  197. } else {
  198. success = rand.RangeInt[int32](0, constant.RatioBase) < prob
  199. }
  200. // 不成功
  201. if !success {
  202. // 如果没有使用MO币,返还部分材料
  203. costs := equipLevelRow.EnhanceFailReturn()
  204. if useMOCoin {
  205. // 如果使用了MO币,返还全部材料
  206. costs = equipLevelRow.EnhanceCosts
  207. }
  208. asset.Service().Adds(p.playerID, costs, ao.None, true)
  209. p.ResponseCode(session, code.EquipEnhanceFail)
  210. return
  211. }
  212. equip.Level++
  213. equipTable.EquipExtend.IncrEnhanceCount()
  214. equipTable.EquipExtend.IncrEnhance(equip.Level)
  215. equipTable.Save2Queue()
  216. // 判断装备是否被穿戴,如果被穿戴需要刷新英雄属性
  217. if equip.WearHeroGUID > 0 {
  218. heroTable := p.HeroTable()
  219. heroEntity, found := heroTable.Heroes.Get(equip.WearHeroGUID)
  220. if found {
  221. // 刷新英雄属性
  222. gameFacade.Hero.UpdateAttrs(p.playerID, heroEntity)
  223. heroTable.Save2Queue()
  224. // 推送变更信息
  225. gameFacade.Hero.ChangePush(p.playerID, nil, heroEntity)
  226. }
  227. }
  228. proto := equip.ToProto()
  229. p.PostEvent(event.NewEquipEnhance(p.playerID, proto))
  230. // 发送系统消息
  231. p.PostEvent(event.NewChatSystemMsg(p.playerID, enum.ChatMsgType_equipEnhance, nil, nil, equip.EquipID, equip.Level))
  232. p.Response(session, proto)
  233. }
  234. // equipDimantle 装备分解
  235. func (p *actorPlayer) equipDimantle(session *cproto.Session, req *pb.I64List) {
  236. var (
  237. equipTable = p.EquipTable()
  238. rewards types.Assets
  239. )
  240. for _, equipGUID := range req.List {
  241. equip, ok := equipTable.Equips.Get(equipGUID)
  242. if !ok {
  243. p.ResponseCode(session, code.EquipNotFound)
  244. return
  245. }
  246. // 穿戴中无法分解
  247. if equip.WearHeroGUID > 0 {
  248. p.ResponseCode(session, code.EquipGUIDHasWear)
  249. return
  250. }
  251. equipRow, found := data.Equip.GetByID(equip.EquipID)
  252. if !found {
  253. p.ResponseCode(session, code.ConfigNotFound_Equip)
  254. return
  255. }
  256. equipLevelRow, found := data.EquipLevel.GetByQualityLevel(equipRow.Quality, equip.Level)
  257. if !found {
  258. p.ResponseCode(session, code.ConfigNotFound_EquipLevel)
  259. return
  260. }
  261. // 分解奖励
  262. rewards.AddAssets(equipLevelRow.DimantleRewards)
  263. }
  264. // 加资产
  265. retAssets, errCode := asset.Service().Adds(p.playerID, rewards, ao.None, true)
  266. if code.IsFail(errCode) {
  267. p.ResponseCode(session, errCode)
  268. return
  269. }
  270. equipTable.Equips.Remove(req.List...)
  271. equipDimantleCount := int32(len(req.List))
  272. equipTable.EquipExtend.IncrEquipDimantleCount(equipDimantleCount)
  273. equipTable.Save2Queue()
  274. equip.Service().ChangePush(p.playerID, req.List)
  275. resp := retAssets.ToAssetListProto()
  276. p.Response(session, &resp)
  277. // 发送分解事件
  278. p.PostEvent(event.NewEquipDimantle(p.playerID, equipDimantleCount))
  279. }
  280. // equipSkillActive 装备技能激活
  281. func (p *actorPlayer) equipSkillActive(session *cproto.Session, req *pb.I64) {
  282. var (
  283. equipGUID = req.Value
  284. equipTable = p.EquipTable()
  285. equip, ok = equipTable.Equips.Get(equipGUID)
  286. )
  287. if !ok {
  288. p.ResponseCode(session, code.EquipNotFound)
  289. return
  290. }
  291. // TODO 可能需要判断其它条件: 比如装备在英雄身上,英雄在场景中等
  292. // 是否有可以解锁的专属技能
  293. errCode := equip.IsSkillUnlockable()
  294. if code.IsFail(errCode) {
  295. p.ResponseCode(session, errCode)
  296. return
  297. }
  298. // 扣除道具
  299. costItem := data.Const.EquipSpecailSkillUnlockCost
  300. _, errCode = asset.Service().Sub(p.playerID, costItem.ID, costItem.Num, ao.None)
  301. if code.IsFail(errCode) {
  302. p.ResponseCode(session, errCode)
  303. return
  304. }
  305. // 解锁技能
  306. equip.SpecialSkill.Value = 1
  307. equipTable.Save2Queue()
  308. proto := equip.ToProto()
  309. p.Response(session, proto)
  310. }
  311. // 上架前对装备进行解锁
  312. func (p *actorPlayer) equipExchangeUnlock(session *cproto.Session, req *pb.I64) {
  313. equipGUID := req.Value
  314. if equipGUID < 1 {
  315. p.ResponseCode(session, code.IllegalArgument)
  316. return
  317. }
  318. dbEquip, errCode := equip.Service().GetEquip(p.playerID, equipGUID)
  319. if code.IsFail(errCode) {
  320. p.ResponseCode(session, errCode)
  321. return
  322. }
  323. if dbEquip.State != enum.EquipState_Normal {
  324. p.ResponseCode(session, code.IllegalArgument)
  325. return
  326. }
  327. exchangeGoodsRow, found := data.ExchangeGoods.GetByID(dbEquip.EquipID)
  328. if !found {
  329. p.ResponseCode(session, code.ConfigNotFound_ExchangeGoods)
  330. return
  331. }
  332. cost := exchangeGoodsRow.UnbindCost
  333. if !cost.IsEmpty() {
  334. if errCode := asset.Service().IsAllEnough(p.playerID, cost); code.IsFail(errCode) {
  335. p.ResponseCode(session, errCode)
  336. return
  337. }
  338. asset.Service().Subs(p.playerID, cost, ao.ExchangeEqueipUnlockCost)
  339. }
  340. equip.Service().UpdateEquipStatus(p.playerID, equipGUID, enum.EquipState_Unlock)
  341. p.Debug("equipExchangeUnlock success. equipGUID [%d]", equipGUID)
  342. p.ResponseCode(session, code.OK)
  343. }