| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- package player
- import (
- "f1-game/internal/code"
- "f1-game/internal/data"
- nameLocal "f1-game/internal/name/local"
- nameRemote "f1-game/internal/name/remote"
- "f1-game/internal/pb"
- "f1-game/internal/types"
- "f1-game/nodes/game/player/asset"
- ao "f1-game/nodes/game/player/asset/origin"
- "f1-game/nodes/game/player/item"
- cproto "github.com/cherry-game/cherry/net/proto"
- )
- func (p *actorPlayer) initItem() {
- p.Local().Register(nameLocal.Player_ItemUse, p.itemUse)
- p.Local().Register(nameLocal.Player_ItemSale, p.itemSale)
- p.Local().Register(nameLocal.Player_ItemCraft, p.itemCraft)
- p.Local().Register(nameLocal.Player_ItemMedicineUse, p.itemMedicineUse)
- }
- func (p *actorPlayer) itemUse(session *cproto.Session, req *pb.ItemUseRequest) {
- if req.UseNum < 1 {
- p.ResponseCode(session, code.IllegalArgument)
- return
- }
- // 使用的必须是宝箱
- chestRow, found := data.ItemChest.GetByID(req.ItemID)
- if !found {
- p.Warn("[Chest] config not found. id = %d", req.ItemID)
- p.ResponseCode(session, code.ConfigNotFound_ItemChest)
- return
- }
- // 超出单次使用数量上限
- if req.UseNum > data.Const.ItemChestSingleLimit {
- p.ResponseCode(session, code.ItemUseOnceLimit)
- return
- }
- // 消耗的道具是否足够
- if errCode := asset.Service().Enough(p.playerID, req.ItemID, req.UseNum); code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- // 使用道具,获取添加的资源
- addAssets, errCode := item.Service().Use(p.playerID, req, chestRow.DropPoolID, chestRow.UseType)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- // 检查将要添加的资产
- errCode = asset.Service().Check(addAssets)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- // 先扣除消耗道具
- _, errCode = asset.Service().Sub(p.playerID, req.ItemID, req.UseNum, ao.None)
- if code.IsFail(errCode) {
- p.ResponseCode(session, code.ItemDecreaseFail)
- return
- }
- // 添加资源
- retAssets, errCode := asset.Service().Adds(p.playerID, addAssets, ao.UseItem, true)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- // 返回奖励列表(用于展示)
- rsp := retAssets.ToAssetListProto()
- p.Response(session, &rsp)
- p.Debug("[itemUse] result. req = %v, rewards = %v", req, rsp.List)
- }
- // itemSale 道具出售
- func (p *actorPlayer) itemSale(session *cproto.Session, req *pb.Asset) {
- if req.Num < 1 {
- req.Num = 1
- }
- itemRow, found := data.Item.GetByID(req.Id)
- if !found {
- p.ResponseCode(session, code.ConfigNotFound_Item)
- return
- }
- if !itemRow.CanSale || len(itemRow.SalePrice) < 1 {
- p.ResponseCode(session, code.ItemNotForSell)
- return
- }
- _, errCode := asset.Service().Sub(p.playerID, req.Id, req.Num, ao.None)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- rewards := itemRow.GetItemSalePrice(req.Num)
- retAssets, errCode := asset.Service().Adds(p.playerID, rewards, ao.None, true)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- rsp := retAssets.ToAssetListProto()
- p.Response(session, &rsp)
- }
- // itemCraft 道具合成
- func (p *actorPlayer) itemCraft(session *cproto.Session, req *pb.I32I32List) {
- list := req.List
- if len(list) < 1 {
- p.ResponseCode(session, code.ItemCraftEmpty)
- return
- }
- var (
- rewards = types.Assets{}
- tempCosts = map[int32]int64{} // 暂存消耗,key为道具ID,value为消耗数量
- playerID = p.playerID
- )
- for _, kv := range list {
- var (
- itemID = kv.Key
- craftNum = int64(kv.Value)
- )
- if craftNum < 1 {
- p.ResponseCode(session, code.IllegalArgument)
- return
- }
- // 计算合成路径和所需材料,直接修改tempCosts
- errCode := p.calculateCraftCostsWithTemp(playerID, itemID, craftNum, tempCosts)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- // 添加到奖励列表
- rewards.Add(itemID, craftNum)
- }
- // 将暂存的消耗转换为Assets
- costs := types.Assets{}
- for itemID, num := range tempCosts {
- costs.Add(itemID, num)
- }
- // 扣除消耗道具
- _, errCode := asset.Service().Subs(playerID, costs, ao.ItemCraftCost)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- // 添加合成材料
- _, errCode = asset.Service().Adds(playerID, rewards, ao.ItemCraft, true)
- p.ResponseCode(session, errCode)
- }
- // calculateCraftCostsWithTemp 简化版计算合成所需的所有基础材料,直接修改tempCosts
- func (p *actorPlayer) calculateCraftCostsWithTemp(playerID int64, itemID int32, needNum int64, tempCosts map[int32]int64) int32 {
- // 直接计算需要消耗的材料
- var (
- currentItemID = itemID
- currentNeedNum = needNum
- )
- for {
- // 检查该道具是否可以合成
- itemCraftRow, found := data.ItemCraft.GetByID(currentItemID)
- if !found {
- return code.ConfigNotFound_ItemCraft
- }
- // 没有合成消耗不能合成
- if itemCraftRow.CostItemID <= 0 {
- return code.ItemCraftNotCan
- }
- // 不能合成自己
- if itemCraftRow.CostItemID == currentItemID {
- return code.ItemCraftSelf
- }
- // 获取当前道具的库存,减去已经暂存的消耗
- originalHasNum := asset.Service().Get(playerID, itemCraftRow.CostItemID)
- tempConsumed := tempCosts[itemCraftRow.CostItemID]
- hasNum := originalHasNum - tempConsumed
- // 如果库存不足,直接返回错误
- if hasNum < 0 {
- return code.ItemNotEnough
- }
- // 计算可以合成的数量
- canCraftNum := hasNum / itemCraftRow.CostItemNum
- // 计算总需要消耗的材料数量
- totalNeedNum := currentNeedNum * itemCraftRow.CostItemNum
- // 如果当前材料足够,直接添加到tempCosts中并结束
- if canCraftNum >= currentNeedNum {
- tempCosts[itemCraftRow.CostItemID] += totalNeedNum
- return code.OK
- }
- // 当前材料不足,需要合成更多
- // 1. 先使用现有的材料
- if canCraftNum > 0 {
- useNum := canCraftNum * itemCraftRow.CostItemNum
- tempCosts[itemCraftRow.CostItemID] += useNum
- }
- // 2. 计算还需要合成的材料数量,并继续向下查找
- remainingNeed := currentNeedNum - canCraftNum
- if remainingNeed > 0 {
- // 继续处理下一级合成
- currentItemID = itemCraftRow.CostItemID
- currentNeedNum = remainingNeed * itemCraftRow.CostItemNum
- } else {
- // 没有剩余需要,结束
- return code.OK
- }
- }
- }
- // 队伍药品使用
- func (p *actorPlayer) itemMedicineUse(session *cproto.Session, req *pb.I32I32) {
- var (
- teamID = req.Key
- medicineID = req.Value
- itemTable = p.ItemTable()
- playerTable = p.PlayerTable()
- )
- medicineRow, found := data.ItemMedicine.GetByMedicineID(medicineID)
- if !found {
- p.ResponseCode(session, code.ConfigNotFound_Medicine)
- return
- }
- // 检测道具是否足够
- errCode := asset.Service().Enough(p.playerID, medicineID, 1)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- curUseNum, exist := itemTable.MedicineMap[medicineID]
- if !exist {
- curUseNum = 0
- }
- // 使用次数已达上限
- if curUseNum >= medicineRow.DayUseNumLimit {
- p.ResponseCode(session, code.ItemUseNumLimit)
- return
- }
- // 调用map使用药品
- useReq := &pb.I32I32{
- Key: teamID,
- Value: medicineID,
- }
- errCode = p.mapPlayerCallWait(playerTable.Map.MapNodeID, nameRemote.MapPlayer_UseMedicine, useReq)
- if code.IsFail(errCode) {
- p.ResponseCode(session, errCode)
- return
- }
- // 扣除资源
- asset.Service().Sub(p.playerID, medicineID, 1, ao.ItemMedicineUse)
- curUseNum++
- itemTable.MedicineMap[medicineID] = curUseNum
- itemTable.Save2Queue()
- resp := &pb.I32I32{
- Key: medicineID,
- Value: curUseNum,
- }
- p.Response(session, resp)
- }
|