From cfb001c18afebdc8740a6a64006b0d21326bd84d Mon Sep 17 00:00:00 2001 From: UnKownOwO <80520429@qq.com> Date: Sat, 4 Feb 2023 23:52:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=AD=A6=E5=99=A8=E5=BC=BA=E5=8C=96=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=E8=BF=94=E8=BF=98=E6=9D=90=E6=96=99=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/constant/item_constant.go | 14 ++ gdconf/avatar_promote_data.go | 12 +- gdconf/game_data_config.go | 4 + gdconf/gcg_skill_data.go | 10 +- gdconf/item_data.go | 12 +- gdconf/table_struct_mapping.json | 105 ++++++++ gdconf/weapon_level_data.go | 44 ++++ gdconf/weapon_promote_data.go | 58 +++++ gs/game/player_avatar.go | 22 +- gs/game/player_weapon.go | 345 ++++++++++++++++++++++++++- gs/game/route_manager.go | 2 + gs/model/weapon.go | 9 + protocol/cmd/cmd_id_proto_obj_map.go | 10 +- 13 files changed, 614 insertions(+), 33 deletions(-) create mode 100644 gdconf/weapon_level_data.go create mode 100644 gdconf/weapon_promote_data.go diff --git a/common/constant/item_constant.go b/common/constant/item_constant.go index 2780dd24..0eedbd21 100644 --- a/common/constant/item_constant.go +++ b/common/constant/item_constant.go @@ -3,6 +3,7 @@ package constant var ItemConstantConst *ItemConstant type ItemConstant struct { + // 虚拟物品 HCOIN uint32 // 原石 201 SCOIN uint32 // 摩拉 202 MCOIN uint32 // 创世结晶 203 @@ -11,6 +12,11 @@ type ItemConstant struct { HOME_COIN uint32 // 洞天宝钱 204 PLAYER_EXP uint32 // 冒险阅历 102 VIRTUAL_ITEM_PROP map[uint32]uint16 // 虚拟物品对应玩家的属性 + // 武器强化物品 + WEAPON_UPGRADE_MAGIC uint32 // 精锻用魔矿 104013 + WEAPON_UPGRADE_GOOD uint32 // 精锻用良矿 104012 + WEAPON_UPGRADE_MOTLEY uint32 // 精锻用杂矿 104011 + WEAPON_UPGRADE_MATERIAL []uint32 // 武器强化返还材料列表 } func InitItemConstantConst() { @@ -32,4 +38,12 @@ func InitItemConstantConst() { ItemConstantConst.HOME_COIN: PlayerPropertyConst.PROP_PLAYER_HOME_COIN, ItemConstantConst.PLAYER_EXP: PlayerPropertyConst.PROP_PLAYER_EXP, } + ItemConstantConst.WEAPON_UPGRADE_MAGIC = 104013 + ItemConstantConst.WEAPON_UPGRADE_GOOD = 104012 + ItemConstantConst.WEAPON_UPGRADE_MOTLEY = 104011 + ItemConstantConst.WEAPON_UPGRADE_MATERIAL = []uint32{ + ItemConstantConst.WEAPON_UPGRADE_MAGIC, + ItemConstantConst.WEAPON_UPGRADE_GOOD, + ItemConstantConst.WEAPON_UPGRADE_MOTLEY, + } } diff --git a/gdconf/avatar_promote_data.go b/gdconf/avatar_promote_data.go index cfc2e7ca..4a751abb 100644 --- a/gdconf/avatar_promote_data.go +++ b/gdconf/avatar_promote_data.go @@ -19,6 +19,8 @@ type AvatarPromoteData struct { CostItemCount2 int32 `csv:"CostItemCount2,omitempty"` // [消耗物品]2数量 CostItemId3 int32 `csv:"CostItemId3,omitempty"` // [消耗物品]3ID CostItemCount3 int32 `csv:"CostItemCount3,omitempty"` // [消耗物品]3数量 + CostItemId4 int32 `csv:"CostItemId4,omitempty"` // [消耗物品]4ID + CostItemCount4 int32 `csv:"CostItemCount4,omitempty"` // [消耗物品]4数量 LevelLimit int32 `csv:"LevelLimit,omitempty"` // 解锁等级上限 MinPlayerLevel int32 `csv:"MinPlayerLevel,omitempty"` // 冒险等级要求 @@ -40,10 +42,12 @@ func (g *GameDataConfig) loadAvatarPromoteData() { if !ok { g.AvatarPromoteDataMap[avatarPromoteData.PromoteId] = make(map[int32]*AvatarPromoteData) } - avatarPromoteData.CostItemMap = make(map[uint32]uint32, 3) - avatarPromoteData.CostItemMap[uint32(avatarPromoteData.CostItemId1)] = uint32(avatarPromoteData.CostItemCount1) - avatarPromoteData.CostItemMap[uint32(avatarPromoteData.CostItemId2)] = uint32(avatarPromoteData.CostItemCount2) - avatarPromoteData.CostItemMap[uint32(avatarPromoteData.CostItemId3)] = uint32(avatarPromoteData.CostItemCount3) + avatarPromoteData.CostItemMap = map[uint32]uint32{ + uint32(avatarPromoteData.CostItemId1): uint32(avatarPromoteData.CostItemCount1), + uint32(avatarPromoteData.CostItemId2): uint32(avatarPromoteData.CostItemCount2), + uint32(avatarPromoteData.CostItemId3): uint32(avatarPromoteData.CostItemCount3), + uint32(avatarPromoteData.CostItemId4): uint32(avatarPromoteData.CostItemCount4), + } for itemId, count := range avatarPromoteData.CostItemMap { // 两个值都不能为0 if itemId == 0 || count == 0 { diff --git a/gdconf/game_data_config.go b/gdconf/game_data_config.go index 1eafa815..c9427707 100644 --- a/gdconf/game_data_config.go +++ b/gdconf/game_data_config.go @@ -43,6 +43,8 @@ type GameDataConfig struct { AvatarLevelDataMap map[int32]*AvatarLevelData // 角色等级 AvatarPromoteDataMap map[int32]map[int32]*AvatarPromoteData // 角色突破 PlayerLevelDataMap map[int32]*PlayerLevelData // 玩家等级 + WeaponLevelDataMap map[int32]*WeaponLevelData // 武器等级 + WeaponPromoteDataMap map[int32]map[int32]*WeaponPromoteData // 角色突破 } func InitGameDataConfig() { @@ -119,6 +121,8 @@ func (g *GameDataConfig) load() { g.loadAvatarLevelData() // 角色等级 g.loadAvatarPromoteData() // 角色突破 g.loadPlayerLevelData() // 玩家等级 + g.loadWeaponLevelData() // 武器等级 + g.loadWeaponPromoteData() // 武器突破 } func (g *GameDataConfig) readCsvFileData(fileName string) []byte { diff --git a/gdconf/gcg_skill_data.go b/gdconf/gcg_skill_data.go index 5faf4136..8070e6c7 100644 --- a/gdconf/gcg_skill_data.go +++ b/gdconf/gcg_skill_data.go @@ -2,10 +2,11 @@ package gdconf import ( "fmt" - "github.com/hjson/hjson-go/v4" "hk4e/pkg/logger" "os" + "github.com/hjson/hjson-go/v4" + "github.com/jszwec/csvutil" ) @@ -44,9 +45,10 @@ func (g *GameDataConfig) loadGCGSkillData() { } for _, gcgSkillData := range gcgSkillDataList { // 技能消耗整合进CostMap - gcgSkillData.CostMap = make(map[uint32]uint32, 2) - gcgSkillData.CostMap[uint32(gcgSkillData.CostType1)] = uint32(gcgSkillData.CostValue1) - gcgSkillData.CostMap[uint32(gcgSkillData.CostType2)] = uint32(gcgSkillData.CostValue2) + gcgSkillData.CostMap = map[uint32]uint32{ + uint32(gcgSkillData.CostType1): uint32(gcgSkillData.CostValue1), + uint32(gcgSkillData.CostType2): uint32(gcgSkillData.CostValue2), + } for costType, costValue := range gcgSkillData.CostMap { // 两个值都不能为0 if costType == 0 || costValue == 0 { diff --git a/gdconf/item_data.go b/gdconf/item_data.go index de7cd450..96b023c6 100644 --- a/gdconf/item_data.go +++ b/gdconf/item_data.go @@ -20,11 +20,13 @@ type ItemData struct { MaterialType int32 `csv:"MaterialType,omitempty"` // 材料类型 Use1Param1 string `csv:"Use1Param1,omitempty"` // [使用]1参数1 // 武器 - EquipType int32 `csv:"EquipType,omitempty"` // 武器种类 - EquipLevel int32 `csv:"EquipLevel,omitempty"` // 武器阶数 - SkillAffix1 int32 `csv:"SkillAffix1,omitempty"` // 初始技能词缀1 - SkillAffix2 int32 `csv:"SkillAffix2,omitempty"` // 初始技能词缀2 - SkillAffix []int32 + EquipType int32 `csv:"EquipType,omitempty"` // 武器种类 + EquipLevel int32 `csv:"EquipLevel,omitempty"` // 武器阶数 + SkillAffix1 int32 `csv:"SkillAffix1,omitempty"` // 初始技能词缀1 + SkillAffix2 int32 `csv:"SkillAffix2,omitempty"` // 初始技能词缀2 + PromoteId int32 `csv:"PromoteId,omitempty"` // 武器突破ID + EquipBaseExp int32 `csv:"EquipBaseExp,omitempty"` // 武器初始经验 + SkillAffix []int32 // 圣遗物 ReliquaryType int32 `csv:"ReliquaryType,omitempty"` // 圣遗物类别 } diff --git a/gdconf/table_struct_mapping.json b/gdconf/table_struct_mapping.json index 1afa2d7f..f2f42f96 100644 --- a/gdconf/table_struct_mapping.json +++ b/gdconf/table_struct_mapping.json @@ -521,6 +521,16 @@ "field_name": "SkillAffix2", "field_type": "int32", "origin_name": "初始技能词缀2" + }, + { + "field_name": "PromoteId", + "field_type": "int32", + "origin_name": "武器突破ID" + }, + { + "field_name": "EquipBaseExp", + "field_type": "int32", + "origin_name": "武器初始经验" } ] }, @@ -698,5 +708,100 @@ "origin_name": "升到下一级所需经验" } ] + }, + { + "table_name": "WeaponLevelData", + "field_list": [ + { + "field_name": "Level", + "field_type": "int32", + "origin_name": "等级" + }, + { + "field_name": "ExpByStar1", + "field_type": "int32", + "origin_name": "武器升级经验1" + }, + { + "field_name": "ExpByStar2", + "field_type": "int32", + "origin_name": "武器升级经验2" + }, + { + "field_name": "ExpByStar3", + "field_type": "int32", + "origin_name": "武器升级经验3" + }, + { + "field_name": "ExpByStar4", + "field_type": "int32", + "origin_name": "武器升级经验4" + }, + { + "field_name": "ExpByStar5", + "field_type": "int32", + "origin_name": "武器升级经验5" + } + ] + }, + { + "table_name": "WeaponPromoteData", + "field_list": [ + { + "field_name": "PromoteId", + "field_type": "int32", + "origin_name": "武器突破ID" + }, + { + "field_name": "PromoteLevel", + "field_type": "int32", + "origin_name": "突破等级" + }, + { + "field_name": "CostItemId1", + "field_type": "int32", + "origin_name": "[消耗物品]1ID" + }, + { + "field_name": "CostItemCount1", + "field_type": "int32", + "origin_name": "[消耗物品]1数量" + }, + { + "field_name": "CostItemId2", + "field_type": "int32", + "origin_name": "[消耗物品]2ID" + }, + { + "field_name": "CostItemCount2", + "field_type": "int32", + "origin_name": "[消耗物品]2数量" + }, + { + "field_name": "CostItemId3", + "field_type": "int32", + "origin_name": "[消耗物品]3ID" + }, + { + "field_name": "CostItemCount3", + "field_type": "int32", + "origin_name": "[消耗物品]3数量" + }, + { + "field_name": "CostCoin", + "field_type": "int32", + "origin_name": "突破消耗金币" + }, + { + "field_name": "LevelLimit", + "field_type": "int32", + "origin_name": "突破后解锁等级上限" + }, + { + "field_name": "MinPlayerLevel", + "field_type": "int32", + "origin_name": "冒险等级要求" + } + ] } ] diff --git a/gdconf/weapon_level_data.go b/gdconf/weapon_level_data.go new file mode 100644 index 00000000..f4d71816 --- /dev/null +++ b/gdconf/weapon_level_data.go @@ -0,0 +1,44 @@ +package gdconf + +import ( + "fmt" + "hk4e/pkg/logger" + + "github.com/jszwec/csvutil" +) + +// 武器等级配置表 + +type WeaponLevelData struct { + Level int32 `csv:"Level"` // 等级 + ExpByStar1 int32 `csv:"ExpByStar1,omitempty"` // 武器升级经验1 + ExpByStar2 int32 `csv:"ExpByStar2,omitempty"` // 武器升级经验2 + ExpByStar3 int32 `csv:"ExpByStar3,omitempty"` // 武器升级经验3 + ExpByStar4 int32 `csv:"ExpByStar4,omitempty"` // 武器升级经验4 + ExpByStar5 int32 `csv:"ExpByStar5,omitempty"` // 武器升级经验5 + + ExpByStarMap map[uint32]uint32 // 星级对应武器升级经验 +} + +func (g *GameDataConfig) loadWeaponLevelData() { + g.WeaponLevelDataMap = make(map[int32]*WeaponLevelData) + data := g.readCsvFileData("WeaponLevelData.csv") + var weaponLevelDataList []*WeaponLevelData + err := csvutil.Unmarshal(data, &weaponLevelDataList) + if err != nil { + info := fmt.Sprintf("parse file error: %v", err) + panic(info) + } + for _, weaponLevelData := range weaponLevelDataList { + // list -> map + weaponLevelData.ExpByStarMap = map[uint32]uint32{ + 1: uint32(weaponLevelData.ExpByStar1), + 2: uint32(weaponLevelData.ExpByStar2), + 3: uint32(weaponLevelData.ExpByStar3), + 4: uint32(weaponLevelData.ExpByStar4), + 5: uint32(weaponLevelData.ExpByStar5), + } + g.WeaponLevelDataMap[weaponLevelData.Level] = weaponLevelData + } + logger.Info("WeaponLevelData count: %v", len(g.WeaponLevelDataMap)) +} diff --git a/gdconf/weapon_promote_data.go b/gdconf/weapon_promote_data.go new file mode 100644 index 00000000..5257996a --- /dev/null +++ b/gdconf/weapon_promote_data.go @@ -0,0 +1,58 @@ +package gdconf + +import ( + "fmt" + "hk4e/pkg/logger" + + "github.com/jszwec/csvutil" +) + +// 武器突破配置表 + +type WeaponPromoteData struct { + PromoteId int32 `csv:"PromoteId"` // 武器突破ID + PromoteLevel int32 `csv:"PromoteLevel,omitempty"` // 突破等级 + CostItemId1 int32 `csv:"CostItemId1,omitempty"` // [消耗物品]1ID + CostItemCount1 int32 `csv:"CostItemCount1,omitempty"` // [消耗物品]1数量 + CostItemId2 int32 `csv:"CostItemId2,omitempty"` // [消耗物品]2ID + CostItemCount2 int32 `csv:"CostItemCount2,omitempty"` // [消耗物品]2数量 + CostItemId3 int32 `csv:"CostItemId3,omitempty"` // [消耗物品]3ID + CostItemCount3 int32 `csv:"CostItemCount3,omitempty"` // [消耗物品]3数量 + CostCoin int32 `csv:"CostCoin,omitempty"` // 突破消耗金币 + LevelLimit int32 `csv:"LevelLimit,omitempty"` // 突破后解锁等级上限 + MinPlayerLevel int32 `csv:"MinPlayerLevel,omitempty"` // 冒险等级要求 + + CostItemMap map[uint32]uint32 // 消耗物品列表 +} + +func (g *GameDataConfig) loadWeaponPromoteData() { + g.WeaponPromoteDataMap = make(map[int32]map[int32]*WeaponPromoteData) + data := g.readCsvFileData("WeaponPromoteData.csv") + var weaponPromoteDataList []*WeaponPromoteData + err := csvutil.Unmarshal(data, &weaponPromoteDataList) + if err != nil { + info := fmt.Sprintf("parse file error: %v", err) + panic(info) + } + for _, weaponPromoteData := range weaponPromoteDataList { + // list -> map + _, ok := g.WeaponPromoteDataMap[weaponPromoteData.PromoteId] + if !ok { + g.WeaponPromoteDataMap[weaponPromoteData.PromoteId] = make(map[int32]*WeaponPromoteData) + } + weaponPromoteData.CostItemMap = map[uint32]uint32{ + uint32(weaponPromoteData.CostItemId1): uint32(weaponPromoteData.CostItemCount1), + uint32(weaponPromoteData.CostItemId2): uint32(weaponPromoteData.CostItemCount2), + uint32(weaponPromoteData.CostItemId3): uint32(weaponPromoteData.CostItemCount3), + } + for itemId, count := range weaponPromoteData.CostItemMap { + // 两个值都不能为0 + if itemId == 0 || count == 0 { + delete(weaponPromoteData.CostItemMap, itemId) + } + } + // 通过突破等级找到突破数据 + g.WeaponPromoteDataMap[weaponPromoteData.PromoteId][weaponPromoteData.PromoteLevel] = weaponPromoteData + } + logger.Info("WeaponPromoteData count: %v", len(g.WeaponPromoteDataMap)) +} diff --git a/gs/game/player_avatar.go b/gs/game/player_avatar.go index 96b2440f..7418a84f 100644 --- a/gs/game/player_avatar.go +++ b/gs/game/player_avatar.go @@ -245,7 +245,7 @@ func (g *GameManager) AvatarUpgradeReq(player *model.Player, payloadMsg pb.Messa } // 角色添加经验 - g.UpgradeUserAvatar(player.PlayerID, avatar.AvatarId, expCount) + g.UpgradePlayerAvatar(player, avatar, expCount) avatarUpgradeRsp := &proto.AvatarUpgradeRsp{ CurLevel: uint32(avatar.Level), @@ -257,18 +257,8 @@ func (g *GameManager) AvatarUpgradeReq(player *model.Player, payloadMsg pb.Messa g.SendMsg(cmd.AvatarUpgradeRsp, player.PlayerID, player.ClientSeq, avatarUpgradeRsp) } -// UpgradeUserAvatar 玩家角色升级 -func (g *GameManager) UpgradeUserAvatar(userId uint32, avatarId uint32, expCount uint32) { - player := USER_MANAGER.GetOnlineUser(userId) - if player == nil { - logger.Error("player is nil, uid: %v", userId) - return - } - avatar, ok := player.AvatarMap[avatarId] - if !ok { - logger.Error("avatar error, avatarId: %v", avatarId) - return - } +// UpgradePlayerAvatar 玩家角色升级 +func (g *GameManager) UpgradePlayerAvatar(player *model.Player, avatar *model.Avatar, expCount uint32) { // 获取角色配置表 avatarDataConfig, ok := gdconf.CONF.AvatarDataMap[int32(avatar.AvatarId)] if !ok { @@ -394,6 +384,9 @@ func (g *GameManager) WearUserAvatarEquip(userId uint32, avatarId uint32, weapon weakWorldAvatar.weaponEntityId = scene.CreateEntityWeapon() avatarEquipChangeNotify := g.PacketAvatarEquipChangeNotify(weakAvatar, weakWeapon, weakWorldAvatar.weaponEntityId) g.SendMsg(cmd.AvatarEquipChangeNotify, userId, player.ClientSeq, avatarEquipChangeNotify) + } else { + avatarEquipChangeNotify := g.PacketAvatarEquipChangeNotify(weakAvatar, weakWeapon, 0) + g.SendMsg(cmd.AvatarEquipChangeNotify, userId, player.ClientSeq, avatarEquipChangeNotify) } } else if avatar.EquipWeapon != nil { // 角色当前有武器 @@ -409,6 +402,9 @@ func (g *GameManager) WearUserAvatarEquip(userId uint32, avatarId uint32, weapon worldAvatar.weaponEntityId = scene.CreateEntityWeapon() avatarEquipChangeNotify := g.PacketAvatarEquipChangeNotify(avatar, weapon, worldAvatar.weaponEntityId) g.SendMsg(cmd.AvatarEquipChangeNotify, userId, player.ClientSeq, avatarEquipChangeNotify) + } else { + avatarEquipChangeNotify := g.PacketAvatarEquipChangeNotify(avatar, weapon, 0) + g.SendMsg(cmd.AvatarEquipChangeNotify, userId, player.ClientSeq, avatarEquipChangeNotify) } } diff --git a/gs/game/player_weapon.go b/gs/game/player_weapon.go index 436bb7b7..f1400056 100644 --- a/gs/game/player_weapon.go +++ b/gs/game/player_weapon.go @@ -3,9 +3,14 @@ package game import ( "hk4e/common/constant" "hk4e/gdconf" + "hk4e/gs/model" "hk4e/pkg/logger" "hk4e/protocol/cmd" "hk4e/protocol/proto" + "sort" + "strconv" + + pb "google.golang.org/protobuf/proto" ) func (g *GameManager) GetAllWeaponDataConfig() map[int32]*gdconf.ItemData { @@ -50,7 +55,11 @@ func (g *GameManager) AddUserWeapon(userId uint32, itemId uint32) uint64 { logger.Error("weapon is nil, itemId: %v, weaponId: %v", itemId, weaponId) return 0 } + g.SendMsg(cmd.StoreItemChangeNotify, userId, player.ClientSeq, g.PacketStoreItemChangeNotifyByWeapon(weapon)) + return weaponId +} +func (g *GameManager) PacketStoreItemChangeNotifyByWeapon(weapon *model.Weapon) *proto.StoreItemChangeNotify { storeItemChangeNotify := &proto.StoreItemChangeNotify{ StoreType: proto.StoreType_STORE_PACK, ItemList: make([]*proto.Item, 0), @@ -60,8 +69,8 @@ func (g *GameManager) AddUserWeapon(userId uint32, itemId uint32) uint64 { affixMap[affixId] = uint32(weapon.Refinement) } pbItem := &proto.Item{ - ItemId: itemId, - Guid: player.GetWeaponGuid(weaponId), + ItemId: weapon.ItemId, + Guid: weapon.Guid, Detail: &proto.Item_Equip{ Equip: &proto.Equip{ Detail: &proto.Equip_Weapon{ @@ -78,6 +87,334 @@ func (g *GameManager) AddUserWeapon(userId uint32, itemId uint32) uint64 { }, } storeItemChangeNotify.ItemList = append(storeItemChangeNotify.ItemList, pbItem) - g.SendMsg(cmd.StoreItemChangeNotify, userId, player.ClientSeq, storeItemChangeNotify) - return weaponId + return storeItemChangeNotify +} + +// GetWeaponUpgradeReturnMaterial 获取武器强化返回的材料 +func (g *GameManager) GetWeaponUpgradeReturnMaterial(overflowExp uint32) (returnItemList []*proto.ItemParam) { + returnItemList = make([]*proto.ItemParam, 0, 0) + // 武器强化材料返还 + type materialExpData struct { + ItemId uint32 + Exp uint32 + } + // 武器强化返还材料的经验列表 + materialExpList := make([]*materialExpData, 0, len(constant.ItemConstantConst.WEAPON_UPGRADE_MATERIAL)) + for _, itemId := range constant.ItemConstantConst.WEAPON_UPGRADE_MATERIAL { + // 获取物品配置表 + itemDataConfig, ok := gdconf.CONF.ItemDataMap[int32(itemId)] + if !ok { + logger.Error("item data config error, itemId: %v", constant.ItemConstantConst.SCOIN) + return + } + // 材料将给予的经验数 + itemParam, err := strconv.Atoi(itemDataConfig.Use1Param1) + if err != nil { + logger.Error("parse item param error: %v", err) + return + } + materialExpList = append(materialExpList, &materialExpData{ + ItemId: itemId, + Exp: uint32(itemParam), + }) + } + // 确保能返还的材料从大到小排序 + sort.Slice(materialExpList, func(i, j int) bool { + return materialExpList[i].Exp > materialExpList[j].Exp + }) + // 优先给予经验多的材料 + for _, data := range materialExpList { + // 可以获得的材料个数 + count := overflowExp / data.Exp + if count > 0 { + // 添加到要返还材料的列表 + returnItemList = append(returnItemList, &proto.ItemParam{ + ItemId: data.ItemId, + Count: count, + }) + } + // 武器剩余溢出的经验 + overflowExp = overflowExp % data.Exp + } + return returnItemList +} + +// CalcWeaponUpgradeExpAndCoin 计算使用材料给武器强化后能获得的经验以及摩拉消耗 +func (g *GameManager) CalcWeaponUpgradeExpAndCoin(player *model.Player, itemParamList []*proto.ItemParam, foodWeaponGuidList []uint64) (expCount uint32, coinCost uint32, success bool) { + // 武器经验计算 + for _, weaponGuid := range foodWeaponGuidList { + foodWeapon, ok := player.WeaponMap[player.GetWeaponIdByGuid(weaponGuid)] + if !ok { + logger.Error("food weapon error, weaponGuid: %v", weaponGuid) + return + } + // 确保武器不被任何人装备 否则可能会发生意想不到的问题哦 + if foodWeapon.AvatarId != 0 { + logger.Error("food weapon has been equipped, weaponGuid: %v", weaponGuid) + return + } + // 获取武器配置表 + weaponConfig, ok := gdconf.CONF.ItemDataMap[int32(foodWeapon.ItemId)] + if !ok { + logger.Error("weapon config error, itemId: %v", foodWeapon.ItemId) + return + } + // 武器当前等级的经验 + foodWeaponTotalExp := foodWeapon.Exp + // 计算从1级到武器当前等级所需消耗的经验 + for i := int32(1); i < int32(foodWeapon.Level); i++ { + // 获取武器等级配置表 + weaponLevelConfig, ok := gdconf.CONF.WeaponLevelDataMap[i] + if !ok { + logger.Error("weapon level config error, level: %v", i) + return + } + // 获取武器对应星级的经验 + foodWeaponExp, ok := weaponLevelConfig.ExpByStarMap[uint32(weaponConfig.EquipLevel)] + if !ok { + logger.Error("weapon equip level error, level: %v", weaponConfig.EquipLevel) + return + } + // 增加该等级时的经验 + foodWeaponTotalExp += foodWeaponExp + } + // 将武器总消耗的经验转换为能获得的经验 + expCount += (foodWeaponTotalExp * 4) / 5 + // 增加武器初始经验 + expCount += uint32(weaponConfig.EquipBaseExp) + // 增加摩拉消耗 武器为材料时摩拉的消耗只计算武器初始经验 + coinCost += uint32(weaponConfig.EquipBaseExp) / 10 + } + // 材料经验计算 + for _, param := range itemParamList { + // 获取物品配置表 + itemDataConfig, ok := gdconf.CONF.ItemDataMap[int32(param.ItemId)] + if !ok { + logger.Error("item data config error, itemId: %v", constant.ItemConstantConst.SCOIN) + return + } + // 材料将给予的经验数 + itemParam, err := strconv.Atoi(itemDataConfig.Use1Param1) + if err != nil { + logger.Error("parse item param error: %v", err) + return + } + // 材料的经验 + materialExp := uint32(itemParam) * param.Count + // 增加材料的经验 + expCount += materialExp + // 增加材料的摩拉消耗 + coinCost += materialExp / 10 + } + // 表示计算过程没有报错 + success = true + return +} + +// CalcWeaponUpgrade 计算使用材料给武器强化后的等级经验以及返回的矿石 +func (g *GameManager) CalcWeaponUpgrade(weapon *model.Weapon, expCount uint32) (weaponLevel uint8, weaponExp uint32, returnItemList []*proto.ItemParam, success bool) { + // 获取武器配置表 + weaponConfig, ok := gdconf.CONF.ItemDataMap[int32(weapon.ItemId)] + if !ok { + logger.Error("weapon config error, itemId: %v", weapon.ItemId) + return + } + // 获取武器突破配置表 + weaponPromoteDataMap, ok := gdconf.CONF.WeaponPromoteDataMap[weaponConfig.PromoteId] + if !ok { + logger.Error("weapon promote config error, promoteId: %v", weaponConfig.PromoteId) + return + } + // 获取武器突破等级对应的配置表 + weaponPromoteConfig, ok := weaponPromoteDataMap[int32(weapon.Promote)] + if !ok { + logger.Error("weapon promote config error, promoteLevel: %v", weapon.Promote) + return + } + // 临时武器等级经验添加 + weaponLevel = weapon.Level + weaponExp = weapon.Exp + expCount + for { + // 获取武器等级配置表 + weaponLevelConfig, ok := gdconf.CONF.WeaponLevelDataMap[int32(weaponLevel)] + if !ok { + // 获取不到代表已经到达最大等级 + break + } + // 升级所需经验 + needExp, ok := weaponLevelConfig.ExpByStarMap[uint32(weaponConfig.EquipLevel)] + if !ok { + logger.Error("weapon equip level error, level: %v", weaponConfig.EquipLevel) + return + } + // 武器当前等级未突破则跳出循环 + if weaponLevel >= uint8(weaponPromoteConfig.LevelLimit) { + // 溢出经验返还为材料 + returnItemList = g.GetWeaponUpgradeReturnMaterial(weaponExp) + // 武器未突破溢出的经验处理 + weaponExp = 0 + break + } + // 武器经验小于升级所需的经验则跳出循环 + if weaponExp < needExp { + break + } + // 武器等级提升 + weaponExp -= needExp + weaponLevel++ + } + // 表示计算过程没有报错 + success = true + return +} + +// WeaponUpgradeReq 武器升级请求 +func (g *GameManager) WeaponUpgradeReq(player *model.Player, payloadMsg pb.Message) { + logger.Debug("user weapon upgrade, uid: %v", player.PlayerID) + req := payloadMsg.(*proto.WeaponUpgradeReq) + // 是否拥有武器 + weapon, ok := player.WeaponMap[player.GetWeaponIdByGuid(req.TargetWeaponGuid)] + if !ok { + logger.Error("weapon error, weaponGuid: %v", req.TargetWeaponGuid) + g.CommonRetError(cmd.WeaponUpgradeRsp, player, &proto.WeaponUpgradeRsp{}) + return + } + // 获取武器配置表 + weaponConfig, ok := gdconf.CONF.ItemDataMap[int32(weapon.ItemId)] + if !ok { + logger.Error("weapon config error, itemId: %v", weapon.ItemId) + g.CommonRetError(cmd.WeaponUpgradeRsp, player, &proto.WeaponUpgradeRsp{}) + return + } + // 获取武器突破配置表 + weaponPromoteDataMap, ok := gdconf.CONF.WeaponPromoteDataMap[weaponConfig.PromoteId] + if !ok { + logger.Error("weapon promote config error, promoteId: %v", weaponConfig.PromoteId) + g.CommonRetError(cmd.WeaponUpgradeRsp, player, &proto.WeaponUpgradeRsp{}) + return + } + // 获取武器突破等级对应的配置表 + weaponPromoteConfig, ok := weaponPromoteDataMap[int32(weapon.Promote)] + if !ok { + logger.Error("weapon promote config error, promoteLevel: %v", weapon.Promote) + g.CommonRetError(cmd.WeaponUpgradeRsp, player, &proto.WeaponUpgradeRsp{}) + return + } + // 武器等级是否达到限制 + if weapon.Level >= uint8(weaponPromoteConfig.LevelLimit) { + logger.Error("weapon level ge level limit, level: %v", weapon.Level) + g.CommonRetError(cmd.WeaponUpgradeRsp, player, &proto.WeaponUpgradeRsp{}, proto.Retcode_RET_WEAPON_PROMOTE_LEVEL_EXCEED_LIMIT) + return + } + // 将被消耗的物品列表 + costItemList := make([]*UserItem, 0, len(req.ItemParamList)+1) + // 突破材料是否足够并添加到消耗物品列表 + for _, itemParam := range req.ItemParamList { + costItemList = append(costItemList, &UserItem{ + ItemId: itemParam.ItemId, + ChangeCount: itemParam.Count, + }) + } + // 计算使用材料强化武器后将会获得的经验数 + expCount, coinCost, success := g.CalcWeaponUpgradeExpAndCoin(player, req.ItemParamList, req.FoodWeaponGuidList) + if !success { + logger.Error("calc weapon upgrade exp and coin error, uid: %v", player.PlayerID) + g.CommonRetError(cmd.WeaponUpgradeRsp, player, &proto.WeaponUpgradeRsp{}) + return + } + // 消耗列表添加摩拉的消耗 + costItemList = append(costItemList, &UserItem{ + ItemId: constant.ItemConstantConst.SCOIN, + ChangeCount: coinCost, + }) + // 校验物品是否足够 + for _, item := range costItemList { + if player.GetItemCount(item.ItemId) < item.ChangeCount { + logger.Error("item count not enough, itemId: %v", item.ItemId) + // 摩拉的错误提示与材料不同 + if item.ItemId == constant.ItemConstantConst.SCOIN { + g.CommonRetError(cmd.WeaponUpgradeRsp, player, &proto.WeaponUpgradeRsp{}, proto.Retcode_RET_SCOIN_NOT_ENOUGH) + } + g.CommonRetError(cmd.WeaponUpgradeRsp, player, &proto.WeaponUpgradeRsp{}, proto.Retcode_RET_ITEM_COUNT_NOT_ENOUGH) + return + } + } + // 消耗升级材料和摩拉 + GAME_MANAGER.CostUserItem(player.PlayerID, costItemList) + // 武器升级前的信息 + oldLevel := weapon.Level + + // 计算武器使用材料升级后的等级经验以及返回的矿石 + weaponLevel, weaponExp, returnItemList, success := g.CalcWeaponUpgrade(weapon, expCount) + if !success { + logger.Error("calc weapon upgrade error, uid: %v", player.PlayerID) + g.CommonRetError(cmd.CalcWeaponUpgradeReturnItemsRsp, player, &proto.CalcWeaponUpgradeReturnItemsRsp{}) + return + } + + // 武器添加经验 + weapon.Level = weaponLevel + weapon.Exp = weaponExp + // 更新武器的物品数据 + g.SendMsg(cmd.StoreItemChangeNotify, player.PlayerID, player.ClientSeq, g.PacketStoreItemChangeNotifyByWeapon(weapon)) + + // 获取持有该武器的角色 + avatar, ok := player.AvatarMap[weapon.AvatarId] + // 武器可能没被任何角色装备 仅在被装备时更新面板 + if ok { + // 角色更新面板 + player.InitAvatarFightProp(avatar) + } + + // 将给予的材料列表 + addItemList := make([]*UserItem, 0, len(returnItemList)) + for _, param := range returnItemList { + addItemList = append(addItemList, &UserItem{ + ItemId: param.ItemId, + ChangeCount: param.Count, + }) + } + // 给予玩家返回的矿石 + GAME_MANAGER.AddUserItem(player.PlayerID, addItemList, false, 0) + + weaponUpgradeRsp := &proto.WeaponUpgradeRsp{ + CurLevel: uint32(weapon.Level), + OldLevel: uint32(oldLevel), + ItemParamList: returnItemList, + TargetWeaponGuid: req.TargetWeaponGuid, + } + g.SendMsg(cmd.WeaponUpgradeRsp, player.PlayerID, player.ClientSeq, weaponUpgradeRsp) +} + +// CalcWeaponUpgradeReturnItemsReq 计算武器升级返回矿石请求 +func (g *GameManager) CalcWeaponUpgradeReturnItemsReq(player *model.Player, payloadMsg pb.Message) { + logger.Debug("user calc weapon upgrade, uid: %v", player.PlayerID) + req := payloadMsg.(*proto.CalcWeaponUpgradeReturnItemsReq) + // 是否拥有武器 + weapon, ok := player.WeaponMap[player.GetWeaponIdByGuid(req.TargetWeaponGuid)] + if !ok { + logger.Error("weapon error, weaponGuid: %v", req.TargetWeaponGuid) + g.CommonRetError(cmd.CalcWeaponUpgradeReturnItemsRsp, player, &proto.CalcWeaponUpgradeReturnItemsRsp{}) + return + } + // 计算使用材料强化武器后将会获得的经验数 + expCount, _, success := g.CalcWeaponUpgradeExpAndCoin(player, req.ItemParamList, req.FoodWeaponGuidList) + if !success { + logger.Error("calc weapon upgrade exp and coin error, uid: %v", player.PlayerID) + g.CommonRetError(cmd.CalcWeaponUpgradeReturnItemsRsp, player, &proto.CalcWeaponUpgradeReturnItemsRsp{}) + return + } + // 计算武器使用材料升级后的等级经验以及返回的矿石 + _, _, returnItemList, success := g.CalcWeaponUpgrade(weapon, expCount) + if !success { + logger.Error("calc weapon upgrade error, weaponGuid: %v", req.TargetWeaponGuid) + g.CommonRetError(cmd.CalcWeaponUpgradeReturnItemsRsp, player, &proto.CalcWeaponUpgradeReturnItemsRsp{}) + return + } + + calcWeaponUpgradeReturnItemsRsp := &proto.CalcWeaponUpgradeReturnItemsRsp{ + ItemParamList: returnItemList, + TargetWeaponGuid: req.TargetWeaponGuid, + } + g.SendMsg(cmd.CalcWeaponUpgradeReturnItemsRsp, player.PlayerID, player.ClientSeq, calcWeaponUpgradeReturnItemsRsp) } diff --git a/gs/game/route_manager.go b/gs/game/route_manager.go index c3811782..c41d251b 100644 --- a/gs/game/route_manager.go +++ b/gs/game/route_manager.go @@ -131,6 +131,8 @@ func (r *RouteManager) initRoute() { r.registerRouter(cmd.ObstacleModifyNotify, GAME_MANAGER.ObstacleModifyNotify) r.registerRouter(cmd.AvatarUpgradeReq, GAME_MANAGER.AvatarUpgradeReq) r.registerRouter(cmd.AvatarPromoteReq, GAME_MANAGER.AvatarPromoteReq) + r.registerRouter(cmd.CalcWeaponUpgradeReturnItemsReq, GAME_MANAGER.CalcWeaponUpgradeReturnItemsReq) + r.registerRouter(cmd.WeaponUpgradeReq, GAME_MANAGER.WeaponUpgradeReq) } func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) { diff --git a/gs/model/weapon.go b/gs/model/weapon.go index 97df1201..ca55754e 100644 --- a/gs/model/weapon.go +++ b/gs/model/weapon.go @@ -43,6 +43,15 @@ func (p *Player) GetWeaponGuid(weaponId uint64) uint64 { return weaponInfo.Guid } +func (p *Player) GetWeaponIdByGuid(guid uint64) uint64 { + for weaponId, weapon := range p.WeaponMap { + if guid == weapon.Guid { + return weaponId + } + } + return 0 +} + func (p *Player) GetWeapon(weaponId uint64) *Weapon { return p.WeaponMap[weaponId] } diff --git a/protocol/cmd/cmd_id_proto_obj_map.go b/protocol/cmd/cmd_id_proto_obj_map.go index 9b9b14dd..1d425387 100644 --- a/protocol/cmd/cmd_id_proto_obj_map.go +++ b/protocol/cmd/cmd_id_proto_obj_map.go @@ -235,9 +235,13 @@ func (c *CmdProtoMap) registerAllMessage() { c.registerMessage(StoreItemDelNotify, &proto.StoreItemDelNotify{}) // 背包道具删除通知 // 装备 - c.registerMessage(WearEquipReq, &proto.WearEquipReq{}) // 装备穿戴请求 - c.registerMessage(WearEquipRsp, &proto.WearEquipRsp{}) // 装备穿戴响应 - c.registerMessage(AvatarEquipChangeNotify, &proto.AvatarEquipChangeNotify{}) // 角色装备改变通知 + c.registerMessage(WearEquipReq, &proto.WearEquipReq{}) // 装备穿戴请求 + c.registerMessage(WearEquipRsp, &proto.WearEquipRsp{}) // 装备穿戴响应 + c.registerMessage(AvatarEquipChangeNotify, &proto.AvatarEquipChangeNotify{}) // 角色装备改变通知 + c.registerMessage(CalcWeaponUpgradeReturnItemsReq, &proto.CalcWeaponUpgradeReturnItemsReq{}) // 计算武器升级返回矿石请求 + c.registerMessage(CalcWeaponUpgradeReturnItemsRsp, &proto.CalcWeaponUpgradeReturnItemsRsp{}) // 计算武器升级返回矿石响应 + c.registerMessage(WeaponUpgradeReq, &proto.WeaponUpgradeReq{}) // 武器升级请求 + c.registerMessage(WeaponUpgradeRsp, &proto.WeaponUpgradeRsp{}) // 武器升级响应 // 商店 c.registerMessage(GetShopmallDataReq, &proto.GetShopmallDataReq{}) // 商店信息请求