diff --git a/common/constant/item_constant.go b/common/constant/item_constant.go index cb4cee02..2780dd24 100644 --- a/common/constant/item_constant.go +++ b/common/constant/item_constant.go @@ -3,12 +3,14 @@ package constant var ItemConstantConst *ItemConstant type ItemConstant struct { - HCOIN uint32 // 原石 201 - SCOIN uint32 // 摩拉 202 - MCOIN uint32 // 创世结晶 203 - RESIN uint32 // 树脂 106 - LEGENDARY_KEY uint32 // 传说任务钥匙 107 - HOME_COIN uint32 // 洞天宝钱 204 + HCOIN uint32 // 原石 201 + SCOIN uint32 // 摩拉 202 + MCOIN uint32 // 创世结晶 203 + RESIN uint32 // 树脂 106 + LEGENDARY_KEY uint32 // 传说任务钥匙 107 + HOME_COIN uint32 // 洞天宝钱 204 + PLAYER_EXP uint32 // 冒险阅历 102 + VIRTUAL_ITEM_PROP map[uint32]uint16 // 虚拟物品对应玩家的属性 } func InitItemConstantConst() { @@ -20,4 +22,14 @@ func InitItemConstantConst() { ItemConstantConst.RESIN = 106 ItemConstantConst.LEGENDARY_KEY = 207 ItemConstantConst.HOME_COIN = 204 + ItemConstantConst.PLAYER_EXP = 102 + ItemConstantConst.VIRTUAL_ITEM_PROP = map[uint32]uint16{ + ItemConstantConst.HCOIN: PlayerPropertyConst.PROP_PLAYER_HCOIN, + ItemConstantConst.SCOIN: PlayerPropertyConst.PROP_PLAYER_SCOIN, + ItemConstantConst.MCOIN: PlayerPropertyConst.PROP_PLAYER_MCOIN, + ItemConstantConst.RESIN: PlayerPropertyConst.PROP_PLAYER_RESIN, + ItemConstantConst.LEGENDARY_KEY: PlayerPropertyConst.PROP_PLAYER_LEGENDARY_KEY, + ItemConstantConst.HOME_COIN: PlayerPropertyConst.PROP_PLAYER_HOME_COIN, + ItemConstantConst.PLAYER_EXP: PlayerPropertyConst.PROP_PLAYER_EXP, + } } diff --git a/gdconf/avatar_data.go b/gdconf/avatar_data.go index 1d67ff90..89d02e02 100644 --- a/gdconf/avatar_data.go +++ b/gdconf/avatar_data.go @@ -25,6 +25,7 @@ type AvatarData struct { InitialWeapon int32 `csv:"InitialWeapon,omitempty"` // 初始武器 WeaponType int32 `csv:"WeaponType,omitempty"` // 武器种类 SkillDepotId int32 `csv:"SkillDepotId,omitempty"` // 技能库ID + PromoteId int32 `csv:"PromoteId,omitempty"` // 角色突破ID AbilityHashCodeList []int32 } diff --git a/gdconf/avatar_promote_data.go b/gdconf/avatar_promote_data.go index 08f61d94..cfc2e7ca 100644 --- a/gdconf/avatar_promote_data.go +++ b/gdconf/avatar_promote_data.go @@ -10,13 +10,23 @@ import ( // 角色突破配置表 type AvatarPromoteData struct { - PromoteId int32 `csv:"PromoteId"` // 角色突破ID - PromoteLevel int32 `csv:"PromoteLevel,omitempty"` // 突破等级 - LevelLimit int32 `csv:"LevelLimit,omitempty"` // 解锁等级上限 + PromoteId int32 `csv:"PromoteId"` // 角色突破ID + PromoteLevel int32 `csv:"PromoteLevel,omitempty"` // 突破等级 + CostCoin int32 `csv:"CostCoin,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数量 + LevelLimit int32 `csv:"LevelLimit,omitempty"` // 解锁等级上限 + MinPlayerLevel int32 `csv:"MinPlayerLevel,omitempty"` // 冒险等级要求 + + CostItemMap map[uint32]uint32 // 消耗物品列表 } func (g *GameDataConfig) loadAvatarPromoteData() { - g.AvatarPromoteDataMap = make(map[int32]*AvatarPromoteData) + g.AvatarPromoteDataMap = make(map[int32]map[int32]*AvatarPromoteData) data := g.readCsvFileData("AvatarPromoteData.csv") var avatarPromoteDataList []*AvatarPromoteData err := csvutil.Unmarshal(data, &avatarPromoteDataList) @@ -26,7 +36,22 @@ func (g *GameDataConfig) loadAvatarPromoteData() { } for _, avatarPromoteData := range avatarPromoteDataList { // list -> map - g.AvatarPromoteDataMap[avatarPromoteData.PromoteLevel] = avatarPromoteData + _, ok := g.AvatarPromoteDataMap[avatarPromoteData.PromoteId] + 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) + for itemId, count := range avatarPromoteData.CostItemMap { + // 两个值都不能为0 + if itemId == 0 || count == 0 { + delete(avatarPromoteData.CostItemMap, itemId) + } + } + // 通过突破等级找到突破数据 + g.AvatarPromoteDataMap[avatarPromoteData.PromoteId][avatarPromoteData.PromoteLevel] = avatarPromoteData } logger.Info("AvatarPromoteData count: %v", len(g.AvatarPromoteDataMap)) } diff --git a/gdconf/game_data_config.go b/gdconf/game_data_config.go index 53e65644..1eafa815 100644 --- a/gdconf/game_data_config.go +++ b/gdconf/game_data_config.go @@ -24,24 +24,25 @@ type GameDataConfig struct { jsonPrefix string luaPrefix string // 配置表数据 - AvatarDataMap map[int32]*AvatarData // 角色 - AvatarSkillDataMap map[int32]*AvatarSkillData // 角色技能 - AvatarSkillDepotDataMap map[int32]*AvatarSkillDepotData // 角色技能库 - DropGroupDataMap map[int32]*DropGroupData // 掉落组 - GCGCharDataMap map[int32]*GCGCharData // 角色卡牌 - GCGSkillDataMap map[int32]*GCGSkillData // 卡牌技能 - SceneDataMap map[int32]*SceneData // 场景 - ScenePointMap map[int32]*ScenePoint // 场景传送点 - SceneTagDataMap map[int32]*SceneTagData // 场景地图图标 - SceneMap map[int32]*Scene // 场景详情 - WorldAreaDataMap map[int32]*WorldAreaData // 世界区域 - GatherDataMap map[int32]*GatherData // 采集物 - GatherDataPointTypeMap map[int32]*GatherData // 采集物场景节点索引 - FetterDataMap map[int32]*FetterData // 角色资料解锁 - FetterDataAvatarIdMap map[int32][]int32 // 角色资料解锁角色id索引 - ItemDataMap map[int32]*ItemData // 统一道具 - AvatarLevelDataMap map[int32]*AvatarLevelData // 角色等级 - AvatarPromoteDataMap map[int32]*AvatarPromoteData // 角色突破 + AvatarDataMap map[int32]*AvatarData // 角色 + AvatarSkillDataMap map[int32]*AvatarSkillData // 角色技能 + AvatarSkillDepotDataMap map[int32]*AvatarSkillDepotData // 角色技能库 + DropGroupDataMap map[int32]*DropGroupData // 掉落组 + GCGCharDataMap map[int32]*GCGCharData // 角色卡牌 + GCGSkillDataMap map[int32]*GCGSkillData // 卡牌技能 + SceneDataMap map[int32]*SceneData // 场景 + ScenePointMap map[int32]*ScenePoint // 场景传送点 + SceneTagDataMap map[int32]*SceneTagData // 场景地图图标 + SceneMap map[int32]*Scene // 场景详情 + WorldAreaDataMap map[int32]*WorldAreaData // 世界区域 + GatherDataMap map[int32]*GatherData // 采集物 + GatherDataPointTypeMap map[int32]*GatherData // 采集物场景节点索引 + FetterDataMap map[int32]*FetterData // 角色资料解锁 + FetterDataAvatarIdMap map[int32][]int32 // 角色资料解锁角色id索引 + ItemDataMap map[int32]*ItemData // 统一道具 + AvatarLevelDataMap map[int32]*AvatarLevelData // 角色等级 + AvatarPromoteDataMap map[int32]map[int32]*AvatarPromoteData // 角色突破 + PlayerLevelDataMap map[int32]*PlayerLevelData // 玩家等级 } func InitGameDataConfig() { @@ -117,6 +118,7 @@ func (g *GameDataConfig) load() { g.loadItemData() // 统一道具 g.loadAvatarLevelData() // 角色等级 g.loadAvatarPromoteData() // 角色突破 + g.loadPlayerLevelData() // 玩家等级 } func (g *GameDataConfig) readCsvFileData(fileName string) []byte { diff --git a/gdconf/player_level_data.go b/gdconf/player_level_data.go new file mode 100644 index 00000000..d51ac708 --- /dev/null +++ b/gdconf/player_level_data.go @@ -0,0 +1,31 @@ +package gdconf + +import ( + "fmt" + "hk4e/pkg/logger" + + "github.com/jszwec/csvutil" +) + +// 玩家等级配置表 + +type PlayerLevelData struct { + Level int32 `csv:"Level"` // 等级 + Exp int32 `csv:"Exp,omitempty"` // 升到下一级所需经验 +} + +func (g *GameDataConfig) loadPlayerLevelData() { + g.PlayerLevelDataMap = make(map[int32]*PlayerLevelData) + data := g.readCsvFileData("PlayerLevelData.csv") + var playerLevelDataList []*PlayerLevelData + err := csvutil.Unmarshal(data, &playerLevelDataList) + if err != nil { + info := fmt.Sprintf("parse file error: %v", err) + panic(info) + } + for _, playerLevelData := range playerLevelDataList { + // list -> map + g.PlayerLevelDataMap[playerLevelData.Level] = playerLevelData + } + logger.Info("PlayerLevelData count: %v", len(g.PlayerLevelDataMap)) +} diff --git a/gdconf/table_struct_mapping.json b/gdconf/table_struct_mapping.json index 056a9a30..1afa2d7f 100644 --- a/gdconf/table_struct_mapping.json +++ b/gdconf/table_struct_mapping.json @@ -56,6 +56,11 @@ "field_name": "SkillDepotId", "field_type": "int32", "origin_name": "技能库ID" + }, + { + "field_name": "PromoteId", + "field_type": "int32", + "origin_name": "角色突破ID" } ] }, @@ -622,10 +627,75 @@ "field_type": "int32", "origin_name": "突破等级" }, + { + "field_name": "CostCoin", + "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": "CostItemId4", + "field_type": "int32", + "origin_name": "[消耗物品]4ID" + }, + { + "field_name": "CostItemCount4", + "field_type": "int32", + "origin_name": "[消耗物品]4数量" + }, { "field_name": "LevelLimit", "field_type": "int32", "origin_name": "解锁等级上限" + }, + { + "field_name": "MinPlayerLevel", + "field_type": "int32", + "origin_name": "冒险等级要求" + } + ] + }, + { + "table_name": "PlayerLevelData", + "field_list": [ + { + "field_name": "Level", + "field_type": "int32", + "origin_name": "等级" + }, + { + "field_name": "Exp", + "field_type": "int32", + "origin_name": "升到下一级所需经验" } ] } diff --git a/gs/game/player_avatar.go b/gs/game/player_avatar.go index d8ae1eaa..eed385a2 100644 --- a/gs/game/player_avatar.go +++ b/gs/game/player_avatar.go @@ -67,6 +67,82 @@ func (g *GameManager) AddUserAvatar(userId uint32, avatarId uint32) { g.SendMsg(cmd.AvatarAddNotify, userId, player.ClientSeq, avatarAddNotify) } +// AvatarPromoteReq 角色突破请求 +func (g *GameManager) AvatarPromoteReq(player *model.Player, payloadMsg pb.Message) { + logger.Debug("user promote, uid: %v", player.PlayerID) + req := payloadMsg.(*proto.AvatarPromoteReq) + // 是否拥有角色 + avatar, ok := player.AvatarMap[player.GetAvatarIdByGuid(req.Guid)] + if !ok { + logger.Error("avatar error, avatarGuid: %v", req.Guid) + g.CommonRetError(cmd.AvatarPromoteRsp, player, &proto.AvatarUpgradeRsp{}, proto.Retcode_RET_CAN_NOT_FIND_AVATAR) + return + } + // 获取角色配置表 + avatarDataConfig, ok := gdconf.CONF.AvatarDataMap[int32(avatar.AvatarId)] + if !ok { + logger.Error("avatar config error, avatarId: %v", avatar.AvatarId) + g.CommonRetError(cmd.AvatarPromoteRsp, player, &proto.AvatarUpgradeRsp{}) + return + } + // 获取角色突破配置表 + avatarPromoteDataMap, ok := gdconf.CONF.AvatarPromoteDataMap[avatarDataConfig.PromoteId] + if !ok { + logger.Error("avatar promote config error, promoteId: %v", avatarDataConfig.PromoteId) + g.CommonRetError(cmd.AvatarPromoteRsp, player, &proto.AvatarUpgradeRsp{}) + return + } + // 获取角色突破下一级的配置表 + avatarPromoteConfig, ok := avatarPromoteDataMap[int32(avatar.Promote+1)] + if !ok { + logger.Error("avatar promote config error, promoteLevel: %v", avatar.Promote) + g.CommonRetError(cmd.AvatarPromoteRsp, player, &proto.AvatarUpgradeRsp{}) + return + } + // 将被消耗的物品列表 + costItemList := make([]*UserItem, 0, len(avatarPromoteConfig.CostItemMap)+1) + // 突破材料是否足够并添加到消耗物品列表 + for itemId, count := range avatarPromoteConfig.CostItemMap { + costItemList = append(costItemList, &UserItem{ + ItemId: itemId, + ChangeCount: count, + }) + } + // 消耗列表添加摩拉的消耗 + costItemList = append(costItemList, &UserItem{ + ItemId: constant.ItemConstantConst.SCOIN, + ChangeCount: uint32(avatarPromoteConfig.CostCoin), + }) + // 突破材料以及摩拉是否足够 + for _, item := range costItemList { + if player.GetItemCount(item.ItemId) < item.ChangeCount { + logger.Error("item count not enough, itemId: %v", item.ItemId) + g.CommonRetError(cmd.AvatarPromoteRsp, player, &proto.AvatarPromoteRsp{}, proto.Retcode_RET_SCOIN_NOT_ENOUGH) + return + } + } + // 冒险等级是否符合要求 + if player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL] < uint32(avatarPromoteConfig.MinPlayerLevel) { + logger.Error("player level not enough, level: %v", player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL]) + g.CommonRetError(cmd.AvatarPromoteRsp, player, &proto.AvatarPromoteRsp{}) + return + } + // 消耗突破材料和摩拉 + GAME_MANAGER.CostUserItem(player.PlayerID, costItemList) + + // 角色突破等级+1 + avatar.Promote++ + // 角色更新面板 + player.InitAvatarFightProp(avatar) + // 角色属性表更新通知 + g.SendMsg(cmd.AvatarPropNotify, player.PlayerID, player.ClientSeq, g.PacketAvatarPropNotify(avatar)) + + avatarPromoteRsp := &proto.AvatarPromoteRsp{ + Guid: req.Guid, + } + g.SendMsg(cmd.AvatarPromoteRsp, player.PlayerID, player.ClientSeq, avatarPromoteRsp) +} + // AvatarUpgradeReq 角色升级请求 func (g *GameManager) AvatarUpgradeReq(player *model.Player, payloadMsg pb.Message) { logger.Debug("user upgrade, uid: %v", player.PlayerID) @@ -106,8 +182,22 @@ func (g *GameManager) AvatarUpgradeReq(player *model.Player, payloadMsg pb.Messa g.CommonRetError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}, proto.Retcode_RET_SCOIN_NOT_ENOUGH) return } + // 获取角色配置表 + avatarDataConfig, ok := gdconf.CONF.AvatarDataMap[int32(avatar.AvatarId)] + if !ok { + logger.Error("avatar config error, avatarId: %v", avatar.AvatarId) + g.CommonRetError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}) + return + } // 获取角色突破配置表 - avatarPromoteConfig, ok := gdconf.CONF.AvatarPromoteDataMap[int32(avatar.Promote)] + avatarPromoteDataMap, ok := gdconf.CONF.AvatarPromoteDataMap[avatarDataConfig.PromoteId] + if !ok { + logger.Error("avatar promote config error, promoteId: %v", avatarDataConfig.PromoteId) + g.CommonRetError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}) + return + } + // 获取角色突破等级对应的配置表 + avatarPromoteConfig, ok := avatarPromoteDataMap[int32(avatar.Promote)] if !ok { logger.Error("avatar promote config error, promoteLevel: %v", avatar.Promote) g.CommonRetError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}) @@ -115,8 +205,8 @@ func (g *GameManager) AvatarUpgradeReq(player *model.Player, payloadMsg pb.Messa } // 角色等级是否达到限制 if avatar.Level >= uint8(avatarPromoteConfig.LevelLimit) { - logger.Error("avatar promote config error, promoteLevel: %v", avatar.Promote) - g.CommonRetError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}, proto.Retcode_RET_AVATAR_LIMIT_LEVEL_ERROR) + logger.Error("avatar level ge level limit, level: %v", avatar.Level) + g.CommonRetError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}) return } // 消耗升级材料以及摩拉 @@ -136,8 +226,10 @@ func (g *GameManager) AvatarUpgradeReq(player *model.Player, payloadMsg pb.Messa for propType, propValue := range avatar.FightPropMap { oldFightPropMap[propType] = propValue } + // 角色添加经验 g.UpgradeUserAvatar(player.PlayerID, avatar.AvatarId, expCount) + avatarUpgradeRsp := &proto.AvatarUpgradeRsp{ CurLevel: uint32(avatar.Level), OldLevel: uint32(oldLevel), @@ -148,7 +240,7 @@ func (g *GameManager) AvatarUpgradeReq(player *model.Player, payloadMsg pb.Messa g.SendMsg(cmd.AvatarUpgradeRsp, player.PlayerID, player.ClientSeq, avatarUpgradeRsp) } -// UpgradeUserAvatar 用户角色升级 +// UpgradeUserAvatar 玩家角色升级 func (g *GameManager) UpgradeUserAvatar(userId uint32, avatarId uint32, expCount uint32) { player := USER_MANAGER.GetOnlineUser(userId) if player == nil { @@ -160,11 +252,22 @@ func (g *GameManager) UpgradeUserAvatar(userId uint32, avatarId uint32, expCount logger.Error("avatar error, avatarId: %v", avatarId) return } + // 获取角色配置表 + avatarDataConfig, ok := gdconf.CONF.AvatarDataMap[int32(avatar.AvatarId)] + if !ok { + logger.Error("avatar config error, avatarId: %v", avatar.AvatarId) + return + } // 获取角色突破配置表 - avatarPromoteConfig, ok := gdconf.CONF.AvatarPromoteDataMap[int32(avatar.Promote)] + avatarPromoteDataMap, ok := gdconf.CONF.AvatarPromoteDataMap[avatarDataConfig.PromoteId] + if !ok { + logger.Error("avatar promote config error, promoteId: %v", avatarDataConfig.PromoteId) + return + } + // 获取角色突破等级对应的配置表 + avatarPromoteConfig, ok := avatarPromoteDataMap[int32(avatar.Promote)] if !ok { logger.Error("avatar promote config error, promoteLevel: %v", avatar.Promote) - g.CommonRetError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}) return } // 角色增加经验 @@ -174,19 +277,17 @@ func (g *GameManager) UpgradeUserAvatar(userId uint32, avatarId uint32, expCount // 获取角色等级配置表 avatarLevelConfig, ok := gdconf.CONF.AvatarLevelDataMap[int32(avatar.Level)] if !ok { - logger.Error("avatar level config error, level: %v", avatar.Level) - g.CommonRetError(cmd.AvatarUpgradeRsp, player, &proto.AvatarUpgradeRsp{}) - return + // 获取不到代表已经到达最大等级 + break + } + // 角色当前等级未突破则跳出循环 + if avatar.Level >= uint8(avatarPromoteConfig.LevelLimit) { + // 角色未突破溢出的经验处理 + avatar.Exp = 0 + break } // 角色经验小于升级所需的经验则跳出循环 - if avatar.Exp > uint32(avatarLevelConfig.Exp) { - // 角色当前等级未突破则跳出循环 - if avatar.Level >= uint8(avatarPromoteConfig.LevelLimit) { - // 角色未突破溢出的经验处理 - avatar.Exp = uint32(avatarLevelConfig.Exp) - break - } - } else { + if avatar.Exp < uint32(avatarLevelConfig.Exp) { break } // 角色等级提升 diff --git a/gs/game/player_base.go b/gs/game/player_base.go new file mode 100644 index 00000000..54533b22 --- /dev/null +++ b/gs/game/player_base.go @@ -0,0 +1,57 @@ +package game + +import ( + "hk4e/common/constant" + "hk4e/gdconf" + "hk4e/pkg/logger" + "hk4e/protocol/cmd" + "hk4e/protocol/proto" +) + +// AddUserPlayerExp 基于玩家冒险阅历 +func (g *GameManager) AddUserPlayerExp(userId uint32, expCount uint32) { + player := USER_MANAGER.GetOnlineUser(userId) + if player == nil { + logger.Error("player is nil, uid: %v", userId) + return + } + // 玩家增加冒险阅历 + player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_EXP] += expCount + // 玩家升级 + for { + playerLevel := player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL] + // 读取玩家等级配置表 + playerLevelConfig, ok := gdconf.CONF.PlayerLevelDataMap[int32(playerLevel)] + if !ok { + // 获取不到代表已经到达最大等级 + break + } + // 玩家冒险阅历不足则跳出循环 + if player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_EXP] < uint32(playerLevelConfig.Exp) { + break + } + // 玩家增加冒险等阶 + player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL]++ + player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_EXP] -= uint32(playerLevelConfig.Exp) + + // 更新玩家属性 + playerPropNotify := &proto.PlayerPropNotify{ + PropMap: make(map[uint32]*proto.PropValue), + } + playerPropNotify.PropMap[uint32(constant.PlayerPropertyConst.PROP_PLAYER_LEVEL)] = &proto.PropValue{ + Type: uint32(constant.PlayerPropertyConst.PROP_PLAYER_LEVEL), + Val: int64(player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL]), + Value: &proto.PropValue_Ival{ + Ival: int64(player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL]), + }, + } + playerPropNotify.PropMap[uint32(constant.PlayerPropertyConst.PROP_PLAYER_EXP)] = &proto.PropValue{ + Type: uint32(constant.PlayerPropertyConst.PROP_PLAYER_EXP), + Val: int64(player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_EXP]), + Value: &proto.PropValue_Ival{ + Ival: int64(player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_EXP]), + }, + } + g.SendMsg(cmd.PlayerPropNotify, userId, player.ClientSeq, playerPropNotify) + } +} diff --git a/gs/game/player_item.go b/gs/game/player_item.go index 0769268c..c2879921 100644 --- a/gs/game/player_item.go +++ b/gs/game/player_item.go @@ -48,14 +48,46 @@ func (g *GameManager) GetAllItemDataConfig() map[int32]*gdconf.ItemData { return allItemDataConfig } +// AddUserItem 玩家添加物品 func (g *GameManager) AddUserItem(userId uint32, itemList []*UserItem, isHint bool, hintReason uint16) { player := USER_MANAGER.GetOnlineUser(userId) if player == nil { logger.Error("player is nil, uid: %v", userId) return } + playerPropNotify := &proto.PlayerPropNotify{ + PropMap: make(map[uint32]*proto.PropValue), + } for _, userItem := range itemList { - player.AddItem(userItem.ItemId, userItem.ChangeCount) + // 物品为虚拟物品则另外处理 + switch userItem.ItemId { + case constant.ItemConstantConst.RESIN, constant.ItemConstantConst.LEGENDARY_KEY, constant.ItemConstantConst.HCOIN, + constant.ItemConstantConst.SCOIN, constant.ItemConstantConst.MCOIN, constant.ItemConstantConst.HOME_COIN: + // 树脂 传说任务钥匙 原石 摩拉 创世结晶 洞天宝钱 + prop, ok := constant.ItemConstantConst.VIRTUAL_ITEM_PROP[userItem.ItemId] + if !ok { + continue + } + // 角色属性物品数量增加 + player.PropertiesMap[prop] += userItem.ChangeCount + + playerPropNotify.PropMap[uint32(prop)] = &proto.PropValue{ + Type: uint32(prop), + Val: int64(player.PropertiesMap[prop]), + Value: &proto.PropValue_Ival{ + Ival: int64(player.PropertiesMap[prop]), + }, + } + case constant.ItemConstantConst.PLAYER_EXP: + // 冒险阅历 + g.AddUserPlayerExp(userId, userItem.ChangeCount) + default: + // 普通物品直接进背包 + player.AddItem(userItem.ItemId, userItem.ChangeCount) + } + } + if len(playerPropNotify.PropMap) > 0 { + g.SendMsg(cmd.PlayerPropNotify, userId, player.ClientSeq, playerPropNotify) } storeItemChangeNotify := &proto.StoreItemChangeNotify{ @@ -93,26 +125,6 @@ func (g *GameManager) AddUserItem(userId uint32, itemList []*UserItem, isHint bo } g.SendMsg(cmd.ItemAddHintNotify, userId, player.ClientSeq, itemAddHintNotify) } - - playerPropNotify := &proto.PlayerPropNotify{ - PropMap: make(map[uint32]*proto.PropValue), - } - for _, userItem := range itemList { - isVirtualItem, prop := player.GetVirtualItemProp(userItem.ItemId) - if !isVirtualItem { - continue - } - playerPropNotify.PropMap[uint32(prop)] = &proto.PropValue{ - Type: uint32(prop), - Val: int64(player.PropertiesMap[prop]), - Value: &proto.PropValue_Ival{ - Ival: int64(player.PropertiesMap[prop]), - }, - } - } - if len(playerPropNotify.PropMap) > 0 { - g.SendMsg(cmd.PlayerPropNotify, userId, player.ClientSeq, playerPropNotify) - } } func (g *GameManager) CostUserItem(userId uint32, itemList []*UserItem) { @@ -121,8 +133,42 @@ func (g *GameManager) CostUserItem(userId uint32, itemList []*UserItem) { logger.Error("player is nil, uid: %v", userId) return } + playerPropNotify := &proto.PlayerPropNotify{ + PropMap: make(map[uint32]*proto.PropValue), + } for _, userItem := range itemList { - player.CostItem(userItem.ItemId, userItem.ChangeCount) + // 物品为虚拟物品则另外处理 + switch userItem.ItemId { + case constant.ItemConstantConst.RESIN, constant.ItemConstantConst.LEGENDARY_KEY, constant.ItemConstantConst.HCOIN, + constant.ItemConstantConst.SCOIN, constant.ItemConstantConst.MCOIN, constant.ItemConstantConst.HOME_COIN: + // 树脂 传说任务钥匙 原石 摩拉 创世结晶 洞天宝钱 + prop, ok := constant.ItemConstantConst.VIRTUAL_ITEM_PROP[userItem.ItemId] + if !ok { + continue + } + // 角色属性物品数量增加 + if player.PropertiesMap[prop] < userItem.ChangeCount { + player.PropertiesMap[prop] = 0 + } else { + player.PropertiesMap[prop] -= userItem.ChangeCount + } + + playerPropNotify.PropMap[uint32(prop)] = &proto.PropValue{ + Type: uint32(prop), + Val: int64(player.PropertiesMap[prop]), + Value: &proto.PropValue_Ival{ + Ival: int64(player.PropertiesMap[prop]), + }, + } + case constant.ItemConstantConst.PLAYER_EXP: + // 冒险阅历应该也没人会去扣吧? + default: + // 普通物品直接扣除 + player.CostItem(userItem.ItemId, userItem.ChangeCount) + } + } + if len(playerPropNotify.PropMap) > 0 { + g.SendMsg(cmd.PlayerPropNotify, userId, player.ClientSeq, playerPropNotify) } storeItemChangeNotify := &proto.StoreItemChangeNotify{ @@ -163,24 +209,4 @@ func (g *GameManager) CostUserItem(userId uint32, itemList []*UserItem) { if len(storeItemDelNotify.GuidList) > 0 { g.SendMsg(cmd.StoreItemDelNotify, userId, player.ClientSeq, storeItemDelNotify) } - - playerPropNotify := &proto.PlayerPropNotify{ - PropMap: make(map[uint32]*proto.PropValue), - } - for _, userItem := range itemList { - isVirtualItem, prop := player.GetVirtualItemProp(userItem.ItemId) - if !isVirtualItem { - continue - } - playerPropNotify.PropMap[uint32(prop)] = &proto.PropValue{ - Type: uint32(prop), - Val: int64(player.PropertiesMap[prop]), - Value: &proto.PropValue_Ival{ - Ival: int64(player.PropertiesMap[prop]), - }, - } - } - if len(playerPropNotify.PropMap) > 0 { - g.SendMsg(cmd.PlayerPropNotify, userId, player.ClientSeq, playerPropNotify) - } } diff --git a/gs/game/route_manager.go b/gs/game/route_manager.go index c681f3ef..c3811782 100644 --- a/gs/game/route_manager.go +++ b/gs/game/route_manager.go @@ -130,6 +130,7 @@ func (r *RouteManager) initRoute() { r.registerRouter(cmd.GCGOperationReq, GAME_MANAGER.GCGOperationReq) r.registerRouter(cmd.ObstacleModifyNotify, GAME_MANAGER.ObstacleModifyNotify) r.registerRouter(cmd.AvatarUpgradeReq, GAME_MANAGER.AvatarUpgradeReq) + r.registerRouter(cmd.AvatarPromoteReq, GAME_MANAGER.AvatarPromoteReq) } func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) { diff --git a/gs/model/item.go b/gs/model/item.go index f4cd0be0..eaab0abd 100644 --- a/gs/model/item.go +++ b/gs/model/item.go @@ -1,8 +1,6 @@ package model -import ( - "hk4e/common/constant" -) +import "hk4e/common/constant" type Item struct { ItemId uint32 `bson:"itemId"` // 道具id @@ -26,8 +24,8 @@ func (p *Player) GetItemGuid(itemId uint32) uint64 { } func (p *Player) GetItemCount(itemId uint32) uint32 { - isVirtualItem, prop := p.GetVirtualItemProp(itemId) - if isVirtualItem { + prop, ok := constant.ItemConstantConst.VIRTUAL_ITEM_PROP[itemId] + if ok { value := p.PropertiesMap[prop] return value } else { @@ -39,73 +37,28 @@ func (p *Player) GetItemCount(itemId uint32) uint32 { } } -// 虚拟道具如下 实际值存在玩家的属性上 -// 原石 201 -// 摩拉 202 -// 创世结晶 203 -// 树脂 106 -// 传说任务钥匙 107 -// 洞天宝钱 204 - -func (p *Player) GetVirtualItemProp(itemId uint32) (isVirtualItem bool, prop uint16) { - switch itemId { - case 106: - return true, constant.PlayerPropertyConst.PROP_PLAYER_RESIN - case 107: - return true, constant.PlayerPropertyConst.PROP_PLAYER_LEGENDARY_KEY - case 201: - return true, constant.PlayerPropertyConst.PROP_PLAYER_HCOIN - case 202: - return true, constant.PlayerPropertyConst.PROP_PLAYER_SCOIN - case 203: - return true, constant.PlayerPropertyConst.PROP_PLAYER_MCOIN - case 204: - return true, constant.PlayerPropertyConst.PROP_PLAYER_HOME_COIN - default: - return false, 0 - } -} - func (p *Player) AddItem(itemId uint32, count uint32) { - isVirtualItem, prop := p.GetVirtualItemProp(itemId) - if isVirtualItem { - value := p.PropertiesMap[prop] - value += count - p.PropertiesMap[prop] = value - } else { - itemInfo := p.ItemMap[itemId] - if itemInfo == nil { - itemInfo = &Item{ - ItemId: itemId, - Count: 0, - Guid: p.GetNextGameObjectGuid(), - } + itemInfo := p.ItemMap[itemId] + if itemInfo == nil { + itemInfo = &Item{ + ItemId: itemId, + Count: 0, + Guid: p.GetNextGameObjectGuid(), } - itemInfo.Count += count - p.ItemMap[itemId] = itemInfo } + itemInfo.Count += count + p.ItemMap[itemId] = itemInfo } func (p *Player) CostItem(itemId uint32, count uint32) { - isVirtualItem, prop := p.GetVirtualItemProp(itemId) - if isVirtualItem { - value := p.PropertiesMap[prop] - if value < count { - value = 0 - } else { - value -= count - } - p.PropertiesMap[prop] = value - } else { - itemInfo := p.ItemMap[itemId] - if itemInfo == nil { - return - } - if itemInfo.Count < count { - itemInfo.Count = 0 - } else { - itemInfo.Count -= count - } - p.ItemMap[itemId] = itemInfo + itemInfo := p.ItemMap[itemId] + if itemInfo == nil { + return } + if itemInfo.Count < count { + itemInfo.Count = 0 + } else { + itemInfo.Count -= count + } + p.ItemMap[itemId] = itemInfo } diff --git a/protocol/cmd/cmd_id_proto_obj_map.go b/protocol/cmd/cmd_id_proto_obj_map.go index 9f239315..9b9b14dd 100644 --- a/protocol/cmd/cmd_id_proto_obj_map.go +++ b/protocol/cmd/cmd_id_proto_obj_map.go @@ -224,6 +224,8 @@ func (c *CmdProtoMap) registerAllMessage() { c.registerMessage(AvatarUpgradeReq, &proto.AvatarUpgradeReq{}) // 角色升级请求 c.registerMessage(AvatarUpgradeRsp, &proto.AvatarUpgradeRsp{}) // 角色升级通知 c.registerMessage(AvatarPropNotify, &proto.AvatarPropNotify{}) // 角色属性表更新通知 + c.registerMessage(AvatarPromoteReq, &proto.AvatarPromoteReq{}) // 角色突破请求 + c.registerMessage(AvatarPromoteRsp, &proto.AvatarPromoteRsp{}) // 角色突破响应 // 背包与道具 c.registerMessage(PlayerStoreNotify, &proto.PlayerStoreNotify{}) // 玩家背包数据通知