diff --git a/gs/constant/stamina_cost.go b/gs/constant/stamina_cost.go index 020fe65e..8a8be1ca 100644 --- a/gs/constant/stamina_cost.go +++ b/gs/constant/stamina_cost.go @@ -9,18 +9,19 @@ type StaminaCost struct { CLIMB_JUMP int32 // 攀爬跳跃 DASH int32 // 快速跑步 FLY int32 // 滑翔 - SKIFF_DASH int32 // 浪船加速 SPRINT int32 // 冲刺 SWIM_DASH_START int32 // 快速游泳开始 SWIM_DASH int32 // 快速游泳 SWIMMING int32 // 缓慢游泳 // 恢复耐力 - POWERED_FLY int32 // 滑翔加速(风圈等) - POWERED_SKIFF int32 // 浪船加速(风圈等) - RUN int32 // 正常跑步 - SKIFF int32 // 游艇行驶 - STANDBY int32 // 站立 - WALK int32 // 走路 + POWERED_FLY int32 // 滑翔加速(风圈等) + RUN int32 // 正常跑步 + STANDBY int32 // 站立 + WALK int32 // 走路 + // 载具浪船 + SKIFF_DASH int32 // 浪船加速 + SKIFF_NORMAL int32 // 浪船正常移动 (回复耐力) + POWERED_SKIFF int32 // 浪船加速(风圈等) (回复耐力) // 武器消耗默认值 FIGHT_SWORD_ONE_HAND int32 // 单手剑 FIGHT_POLE int32 // 长枪 @@ -38,17 +39,17 @@ func InitStaminaCostConst() { StaminaCostConst.CLIMB_JUMP = -2500 StaminaCostConst.DASH = -360 StaminaCostConst.FLY = -60 - StaminaCostConst.SKIFF_DASH = -204 StaminaCostConst.SPRINT = -1800 StaminaCostConst.SWIM_DASH_START = -2000 StaminaCostConst.SWIM_DASH = -204 StaminaCostConst.SWIMMING = -400 StaminaCostConst.POWERED_FLY = 500 - StaminaCostConst.POWERED_SKIFF = 500 StaminaCostConst.RUN = 500 - StaminaCostConst.SKIFF = 500 StaminaCostConst.STANDBY = 500 StaminaCostConst.WALK = 500 + StaminaCostConst.SKIFF_DASH = -204 + StaminaCostConst.SKIFF_NORMAL = 500 + StaminaCostConst.POWERED_SKIFF = 500 StaminaCostConst.FIGHT_SWORD_ONE_HAND = -2000 StaminaCostConst.FIGHT_POLE = -2500 StaminaCostConst.FIGHT_CATALYST = -5000 diff --git a/gs/game/user_stamina.go b/gs/game/user_stamina.go index 952a7804..9a228dfa 100644 --- a/gs/game/user_stamina.go +++ b/gs/game/user_stamina.go @@ -55,8 +55,14 @@ func (g *GameManager) HandleAbilityStamina(player *model.Player, entry *proto.Ab if avatarAbility == nil { return } - // 重击对应的耐力消耗 - g.ChargedAttackStamina(player, worldAvatar, avatarAbility) + // 距离技能开始过去的时间 + pastTime := time.Now().UnixMilli() - player.StaminaInfo.LastSkillTime + // 法器角色轻击也会算触发重击消耗 + // 所以通过策略判断 必须距离技能开始过去100ms才算重击 + if player.StaminaInfo.LastSkillId == uint32(avatarAbility.AvatarSkillId) && pastTime > 100 { + // 重击对应的耐力消耗 + g.ChargedAttackStamina(player, worldAvatar, avatarAbility) + } default: break } @@ -117,7 +123,7 @@ func (g *GameManager) ImmediateStamina(player *model.Player, motionState proto.M //logger.LOG.Debug("stamina handle, uid: %v, motionState: %v", player.PlayerID, motionState) // 设置用于持续消耗或恢复耐力的值 - g.SetStaminaCost(player, motionState) + staminaInfo.SetStaminaCost(motionState) // 未改变状态不执行后面 有些仅在动作开始消耗耐力 if motionState == staminaInfo.State { @@ -126,6 +132,7 @@ func (g *GameManager) ImmediateStamina(player *model.Player, motionState proto.M // 记录玩家的动作状态 staminaInfo.State = motionState + logger.LOG.Error("state: %v", motionState.String()) // 根据玩家的状态立刻消耗耐力 switch motionState { @@ -237,7 +244,6 @@ func (g *GameManager) SkillStartStamina(player *model.Player, casterId uint32, s // 获取该技能开始时所需消耗的耐力 costStamina := constant.StaminaCostConst.SKILL_START[skillId] - logger.LOG.Debug("skill start stamina, skillId: %v, cost: %v", skillId, costStamina) // 距离上次处理技能开始耐力消耗过去的时间 pastTime := time.Now().UnixMilli() - staminaInfo.LastSkillTime @@ -248,8 +254,12 @@ func (g *GameManager) SkillStartStamina(player *model.Player, casterId uint32, s // 根据配置消耗耐力 g.UpdateStamina(player, costStamina) + logger.LOG.Debug("skill start stamina, skillId: %v, cost: %v", skillId, costStamina) + // 记录最后释放的技能 - player.StaminaInfo.SetLastSkill(casterId, skillId) + staminaInfo.LastCasterId = casterId + staminaInfo.LastSkillId = skillId + staminaInfo.LastSkillTime = time.Now().UnixMilli() } // SustainStaminaHandler 处理持续耐力消耗 @@ -274,50 +284,6 @@ func (g *GameManager) SustainStaminaHandler(player *model.Player) { g.UpdateStamina(player, staminaInfo.CostStamina) } -// SetStaminaCost 设置动作需要消耗的耐力 -func (g *GameManager) SetStaminaCost(player *model.Player, state proto.MotionState) { - staminaInfo := player.StaminaInfo - - // 根据状态决定要修改的耐力 - // TODO 角色天赋 食物 会影响耐力消耗 - switch state { - // 消耗耐力 - case proto.MotionState_MOTION_STATE_DASH: - // 快速跑步 - staminaInfo.CostStamina = constant.StaminaCostConst.DASH - case proto.MotionState_MOTION_STATE_FLY, proto.MotionState_MOTION_STATE_FLY_FAST, proto.MotionState_MOTION_STATE_FLY_SLOW: - // 滑翔 - staminaInfo.CostStamina = constant.StaminaCostConst.FLY - case proto.MotionState_MOTION_STATE_SWIM_DASH: - // 快速游泳 - staminaInfo.CostStamina = constant.StaminaCostConst.SWIM_DASH - case proto.MotionState_MOTION_STATE_SKIFF_DASH: - // 浪船加速 - // TODO 玩家使用载具时需要用载具的协议发送prop - staminaInfo.CostStamina = constant.StaminaCostConst.SKIFF_DASH - // 恢复耐力 - case proto.MotionState_MOTION_STATE_DANGER_RUN, proto.MotionState_MOTION_STATE_RUN: - // 正常跑步 - staminaInfo.CostStamina = constant.StaminaCostConst.RUN - case proto.MotionState_MOTION_STATE_DANGER_STANDBY_MOVE, proto.MotionState_MOTION_STATE_DANGER_STANDBY, proto.MotionState_MOTION_STATE_LADDER_TO_STANDBY, proto.MotionState_MOTION_STATE_STANDBY_MOVE, proto.MotionState_MOTION_STATE_STANDBY: - // 站立 - staminaInfo.CostStamina = constant.StaminaCostConst.STANDBY - case proto.MotionState_MOTION_STATE_DANGER_WALK, proto.MotionState_MOTION_STATE_WALK: - // 走路 - staminaInfo.CostStamina = constant.StaminaCostConst.WALK - case proto.MotionState_MOTION_STATE_POWERED_FLY: - // 滑翔加速 (风圈等) - staminaInfo.CostStamina = constant.StaminaCostConst.POWERED_FLY - case proto.MotionState_MOTION_STATE_SKIFF_POWERED_DASH: - // 浪船加速 (风圈等) - staminaInfo.CostStamina = constant.StaminaCostConst.POWERED_SKIFF - // 缓慢动作将在客户端发送消息后消耗 - case proto.MotionState_MOTION_STATE_CLIMB, proto.MotionState_MOTION_STATE_SWIM_MOVE: - // 缓慢攀爬 或 缓慢游泳 - staminaInfo.CostStamina = 0 - } -} - // UpdateStamina 更新耐力 当前耐力值 + 消耗的耐力值 func (g *GameManager) UpdateStamina(player *model.Player, staminaCost int32) { // 耐力增加0是没有意义的 @@ -330,10 +296,29 @@ func (g *GameManager) UpdateStamina(player *model.Player, staminaCost int32) { player.StaminaInfo.RestoreDelay = 0 } - // 玩家最大耐力值 - maxStamina := int32(player.PropertiesMap[constant.PlayerPropertyConst.PROP_MAX_STAMINA]) - // 玩家现行耐力值 - curStamina := int32(player.PropertiesMap[constant.PlayerPropertyConst.PROP_CUR_PERSIST_STAMINA]) + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + scene := world.GetSceneById(player.SceneId) + + // 最大耐力值 现行耐力值 + var maxStamina, curStamina int32 + // 玩家是否处于载具中 + var isInVehicle bool + + // 获取载具实体 + entity := g.GetSceneVehicleEntity(scene, player.VehicleInfo.InVehicleEntityId) + // 判断玩家处于载具中 + if entity != nil && g.IsPlayerInVehicle(player, entity.gadgetEntity.gadgetVehicleEntity) { + // 载具耐力 + // 因为载具的耐力需要换算 + // 这里先*100后面要用的时候再换算 为了确保精度 + maxStamina = int32(entity.gadgetEntity.gadgetVehicleEntity.maxStamina * 100) + curStamina = int32(entity.gadgetEntity.gadgetVehicleEntity.curStamina * 100) + isInVehicle = true + } else { + // 角色耐力 + maxStamina = int32(player.PropertiesMap[constant.PlayerPropertyConst.PROP_MAX_STAMINA]) + curStamina = int32(player.PropertiesMap[constant.PlayerPropertyConst.PROP_CUR_PERSIST_STAMINA]) + } // 即将更改为的耐力值 stamina := curStamina + staminaCost @@ -350,15 +335,35 @@ func (g *GameManager) UpdateStamina(player *model.Player, staminaCost int32) { return } - g.SetStamina(player, uint32(stamina)) + if isInVehicle { + // 修改载具现行耐力 + g.SetVehicleStamina(player, entity.gadgetEntity.gadgetVehicleEntity, float32(stamina)/100) + } else { + // 修改玩家现行耐力 + g.SetPlayerStamina(player, uint32(stamina)) + } + } -// SetStamina 设置玩家的耐力 -func (g *GameManager) SetStamina(player *model.Player, stamina uint32) { +// SetVehicleStamina 设置载具的耐力 +func (g *GameManager) SetVehicleStamina(player *model.Player, gadgetVehicleEntity *GadgetVehicleEntity, stamina float32) { + // 设置载具的耐力 + gadgetVehicleEntity.curStamina = stamina + logger.LOG.Debug("vehicle stamina set, stamina: %v", stamina) + + // PacketVehicleStaminaNotify + vehicleStaminaNotify := new(proto.VehicleStaminaNotify) + vehicleStaminaNotify.EntityId = player.VehicleInfo.InVehicleEntityId + vehicleStaminaNotify.CurStamina = stamina + g.SendMsg(cmd.VehicleStaminaNotify, player.PlayerID, player.ClientSeq, vehicleStaminaNotify) +} + +// SetPlayerStamina 设置玩家的耐力 +func (g *GameManager) SetPlayerStamina(player *model.Player, stamina uint32) { + // 设置玩家的耐力 prop := constant.PlayerPropertyConst.PROP_CUR_PERSIST_STAMINA - // 设置玩家的耐力prop player.PropertiesMap[prop] = stamina - //logger.LOG.Debug("player curr stamina: %v", stamina) + logger.LOG.Debug("player stamina set, stamina: %v", stamina) // PacketPlayerPropNotify playerPropNotify := new(proto.PlayerPropNotify) diff --git a/gs/game/user_vehicle.go b/gs/game/user_vehicle.go index 1afe85fc..824c7ce8 100644 --- a/gs/game/user_vehicle.go +++ b/gs/game/user_vehicle.go @@ -6,6 +6,7 @@ import ( "hk4e/pkg/logger" "hk4e/protocol/cmd" "hk4e/protocol/proto" + "time" ) // CreateVehicleReq 创建载具 @@ -15,37 +16,20 @@ func (g *GameManager) CreateVehicleReq(player *model.Player, payloadMsg pb.Messa world := WORLD_MANAGER.GetWorldByID(player.WorldId) scene := world.GetSceneById(player.SceneId) - // TODO req.ScenePointId 验证浪船锚点是否已解锁 + // 创建载具冷却时间 + createVehicleCd := int64(5000) // TODO 冷却时间读取配置表 + if time.Now().UnixMilli()-player.VehicleInfo.LastCreateTime < createVehicleCd { + g.CommonRetError(cmd.VehicleInteractRsp, player, &proto.VehicleInteractRsp{}, proto.Retcode_RET_CREATE_VEHICLE_IN_CD) + return + } + + // TODO req.ScenePointId 验证浪船锚点是否已解锁 Retcode_RET_VEHICLE_POINT_NOT_UNLOCK + + // TODO 验证将要创建的载具位置是否有效 Retcode_RET_CREATE_VEHICLE_POS_INVALID // 清除已创建的载具 - for _, id := range scene.GetEntityIdList() { - entity := scene.GetEntity(id) - // 判断实体类型是否为载具 - if entity.entityType != uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_GADGET) || entity.gadgetEntity.gadgetType != GADGET_TYPE_VEHICLE { - continue - } - // 确保载具Id为将要创建的 (每种载具允许存在1个) - if entity.gadgetEntity.gadgetVehicleEntity.vehicleId != req.VehicleId { - continue - } - // 该载具是否为此玩家的 - if entity.gadgetEntity.gadgetVehicleEntity.owner != player { - continue - } - // 现行角色Guid - avatar, ok := player.AvatarMap[player.TeamConfig.GetActiveAvatarId()] - if !ok { - logger.LOG.Error("avatar is nil, avatarId: %v", player.TeamConfig.GetActiveAvatarId()) - g.CommonRetError(cmd.CreateVehicleRsp, player, &proto.CreateVehicleRsp{}) - return - } - // 确保玩家正在载具中 - if g.IsPlayerInVehicle(player, entity.gadgetEntity.gadgetVehicleEntity) { - // 离开载具 - g.ExitVehicle(player, entity, avatar.Guid) - } - // TODO 删除实体 需要杀死实体 暂时实体模块还没写这个 - // scene.DestroyEntity(entity.id) + if player.VehicleInfo.LastCreateEntityId != 0 { + g.DestroyVehicleEntity(player, scene, req.VehicleId, player.VehicleInfo.LastCreateEntityId) } // 创建载具实体 @@ -54,11 +38,16 @@ func (g *GameManager) CreateVehicleReq(player *model.Player, payloadMsg pb.Messa entityId := scene.CreateEntityGadgetVehicle(player.PlayerID, pos, rot, req.VehicleId) if entityId == 0 { logger.LOG.Error("vehicle entityId is 0, uid: %v", player.PlayerID) - g.CommonRetError(cmd.CreateVehicleRsp, player, &proto.CreateVehicleRsp{}) + g.CommonRetError(cmd.VehicleInteractRsp, player, &proto.VehicleInteractRsp{}) return } GAME_MANAGER.AddSceneEntityNotify(player, proto.VisionType_VISION_TYPE_BORN, []uint32{entityId}, true, false) + // 记录创建的载具信息 + player.VehicleInfo.LastCreateEntityId = entityId + player.VehicleInfo.LastCreateTime = time.Now().UnixMilli() + + // PacketCreateVehicleRsp createVehicleRsp := &proto.CreateVehicleRsp{ VehicleId: req.VehicleId, EntityId: entityId, @@ -66,8 +55,24 @@ func (g *GameManager) CreateVehicleReq(player *model.Player, payloadMsg pb.Messa g.SendMsg(cmd.CreateVehicleRsp, player.PlayerID, player.ClientSeq, createVehicleRsp) } +// GetSceneVehicleEntity 获取场景内的载具实体 +func (g *GameManager) GetSceneVehicleEntity(scene *Scene, entityId uint32) *Entity { + entity := scene.GetEntity(entityId) + if entity == nil { + return nil + } + // 确保实体类型是否为载具 + if entity.entityType == uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_GADGET) && entity.gadgetEntity.gadgetType == GADGET_TYPE_VEHICLE { + return entity + } + return nil +} + // IsPlayerInVehicle 判断玩家是否在载具中 func (g *GameManager) IsPlayerInVehicle(player *model.Player, gadgetVehicleEntity *GadgetVehicleEntity) bool { + if gadgetVehicleEntity == nil { + return false + } for _, p := range gadgetVehicleEntity.memberMap { if p == player { return true @@ -76,28 +81,61 @@ func (g *GameManager) IsPlayerInVehicle(player *model.Player, gadgetVehicleEntit return false } -// EnterVehicle 进入载具 -func (g *GameManager) EnterVehicle(player *model.Player, entity *Entity, avatarGuid uint64) { - // 玩家是否已进入载具 - if g.IsPlayerInVehicle(player, entity.gadgetEntity.gadgetVehicleEntity) { - logger.LOG.Error("vehicle has equal player, uid: %v", player.PlayerID) - g.CommonRetError(cmd.VehicleInteractRsp, player, &proto.VehicleInteractRsp{}) +// DestroyVehicleEntity 删除载具实体 +func (g *GameManager) DestroyVehicleEntity(player *model.Player, scene *Scene, vehicleId uint32, entityId uint32) { + entity := g.GetSceneVehicleEntity(scene, entityId) + if entity == nil { return } - // 找出载具空闲的位置 - pos := uint32(0) - for entity.gadgetEntity.gadgetVehicleEntity.memberMap[pos] != nil { - pos++ + // 确保载具Id为将要创建的 (每种载具允许存在1个) + if entity.gadgetEntity.gadgetVehicleEntity.vehicleId != vehicleId { + return } - // 载具成员记录玩家 - entity.gadgetEntity.gadgetVehicleEntity.memberMap[pos] = player + // 该载具是否为此玩家的 + if entity.gadgetEntity.gadgetVehicleEntity.owner != player { + return + } + // 确保玩家正在载具中 + if g.IsPlayerInVehicle(player, entity.gadgetEntity.gadgetVehicleEntity) { + // 离开载具 + g.ExitVehicle(player, entity, player.AvatarMap[player.TeamConfig.GetActiveAvatarId()].Guid) + } + // 删除已创建的载具 + scene.DestroyEntity(entity.id) + g.RemoveSceneEntityNotifyBroadcast(scene, proto.VisionType_VISION_TYPE_MISS, []uint32{entity.id}) +} +// EnterVehicle 进入载具 +func (g *GameManager) EnterVehicle(player *model.Player, entity *Entity, avatarGuid uint64) { + maxSlot := 1 // TODO 读取配置表 + // 判断载具是否已满 + if len(entity.gadgetEntity.gadgetVehicleEntity.memberMap) >= maxSlot { + g.CommonRetError(cmd.VehicleInteractRsp, player, &proto.VehicleInteractRsp{}, proto.Retcode_RET_VEHICLE_SLOT_OCCUPIED) + return + } + + // 找出载具空闲的位置 + var freePos uint32 + for i := uint32(0); i < uint32(maxSlot); i++ { + p := entity.gadgetEntity.gadgetVehicleEntity.memberMap[i] + // 玩家如果已进入载具重复记录不进行报错 + if p == player || p == nil { + // 载具成员记录玩家 + entity.gadgetEntity.gadgetVehicleEntity.memberMap[i] = player + freePos = i + } + } + + // 记录玩家所在的载具信息 + player.VehicleInfo.InVehicleEntityId = entity.id + + // PacketVehicleInteractRsp vehicleInteractRsp := &proto.VehicleInteractRsp{ InteractType: proto.VehicleInteractType_VEHICLE_INTERACT_TYPE_IN, Member: &proto.VehicleMember{ Uid: player.PlayerID, AvatarGuid: avatarGuid, - Pos: pos, // 应该是多人坐船时的位置? + Pos: freePos, // 应该是多人坐船时的位置? }, EntityId: entity.id, } @@ -109,7 +147,7 @@ func (g *GameManager) ExitVehicle(player *model.Player, entity *Entity, avatarGu // 玩家是否进入载具 if !g.IsPlayerInVehicle(player, entity.gadgetEntity.gadgetVehicleEntity) { logger.LOG.Error("vehicle not has player, uid: %v", player.PlayerID) - g.SendMsg(cmd.VehicleInteractRsp, player.PlayerID, player.ClientSeq, &proto.VehicleInteractRsp{Retcode: int32(proto.Retcode_RET_NOT_IN_VEHICLE)}) + g.CommonRetError(cmd.VehicleInteractRsp, player, &proto.VehicleInteractRsp{}, proto.Retcode_RET_NOT_IN_VEHICLE) return } // 载具成员删除玩家 @@ -120,7 +158,10 @@ func (g *GameManager) ExitVehicle(player *model.Player, entity *Entity, avatarGu delete(entity.gadgetEntity.gadgetVehicleEntity.memberMap, pos) } } + // 清除记录的所在载具信息 + player.VehicleInfo.InVehicleEntityId = 0 + // PacketVehicleInteractRsp vehicleInteractRsp := &proto.VehicleInteractRsp{ InteractType: proto.VehicleInteractType_VEHICLE_INTERACT_TYPE_OUT, Member: &proto.VehicleMember{ @@ -137,34 +178,31 @@ func (g *GameManager) ExitVehicle(player *model.Player, entity *Entity, avatarGu func (g *GameManager) VehicleInteractReq(player *model.Player, payloadMsg pb.Message) { req := payloadMsg.(*proto.VehicleInteractReq) - // 获取载具实体 world := WORLD_MANAGER.GetWorldByID(player.WorldId) - entity := world.GetSceneById(player.SceneId).GetEntity(req.EntityId) + scene := world.GetSceneById(player.SceneId) + + // 获取载具实体 + entity := g.GetSceneVehicleEntity(scene, req.EntityId) if entity == nil { logger.LOG.Error("vehicle entity is nil, entityId: %v", req.EntityId) - g.CommonRetError(cmd.VehicleInteractRsp, player, &proto.VehicleInteractRsp{}) + g.CommonRetError(cmd.VehicleInteractRsp, player, &proto.VehicleInteractRsp{}, proto.Retcode_RET_ENTITY_NOT_EXIST) return } // 判断实体类型是否为载具 if entity.entityType != uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_GADGET) || entity.gadgetEntity.gadgetType != GADGET_TYPE_VEHICLE { logger.LOG.Error("vehicle entity error, entityType: %v", entity.entityType) - g.SendMsg(cmd.VehicleInteractRsp, player.PlayerID, player.ClientSeq, &proto.VehicleInteractRsp{Retcode: int32(proto.Retcode_RET_GADGET_NOT_VEHICLE)}) - return - } - // 现行角色Guid - avatar, ok := player.AvatarMap[player.TeamConfig.GetActiveAvatarId()] - if !ok { - logger.LOG.Error("avatar is nil, avatarId: %v", player.TeamConfig.GetActiveAvatarId()) - g.CommonRetError(cmd.VehicleInteractRsp, player, &proto.VehicleInteractRsp{}) + g.CommonRetError(cmd.VehicleInteractRsp, player, &proto.VehicleInteractRsp{}, proto.Retcode_RET_GADGET_NOT_VEHICLE) return } + avatarGuid := player.AvatarMap[player.TeamConfig.GetActiveAvatarId()].Guid + switch req.InteractType { case proto.VehicleInteractType_VEHICLE_INTERACT_TYPE_IN: // 进入载具 - g.EnterVehicle(player, entity, avatar.Guid) + g.EnterVehicle(player, entity, avatarGuid) case proto.VehicleInteractType_VEHICLE_INTERACT_TYPE_OUT: // 离开载具 - g.ExitVehicle(player, entity, avatar.Guid) + g.ExitVehicle(player, entity, avatarGuid) } } diff --git a/gs/game/world_manager.go b/gs/game/world_manager.go index 6c05345e..597e626a 100644 --- a/gs/game/world_manager.go +++ b/gs/game/world_manager.go @@ -540,6 +540,7 @@ type GadgetGatherEntity struct { type GadgetVehicleEntity struct { vehicleId uint32 owner *model.Player + maxStamina float32 curStamina float32 memberMap map[uint32]*model.Player // uint32 = pos } @@ -752,7 +753,8 @@ func (s *Scene) CreateEntityGadgetVehicle(uid uint32, pos, rot *model.Vector, ve gadgetVehicleEntity: &GadgetVehicleEntity{ vehicleId: vehicleId, owner: player, - curStamina: 240, // TODO 应该也能在配置表找到 + maxStamina: 240, // TODO 应该也能在配置表找到 + curStamina: 240, // TODO 与maxStamina一致 memberMap: make(map[uint32]*model.Player), }, }, diff --git a/gs/model/player.go b/gs/model/player.go index d288c216..0563fa28 100644 --- a/gs/model/player.go +++ b/gs/model/player.go @@ -65,6 +65,7 @@ type Player struct { SceneLoadState int `bson:"-" msgpack:"-"` // 场景加载状态 CoopApplyMap map[uint32]int64 `bson:"-" msgpack:"-"` // 敲门申请的玩家uid及时间 StaminaInfo *StaminaInfo `bson:"-" msgpack:"-"` // 耐力临时数据 + VehicleInfo *VehicleInfo `bson:"-" msgpack:"-"` // 载具临时数据 ClientSeq uint32 `bson:"-" msgpack:"-"` // 客户端发包请求的序号 CombatInvokeHandler *InvokeHandler[proto.CombatInvokeEntry] `bson:"-" msgpack:"-"` // combat转发器 AbilityInvokeHandler *InvokeHandler[proto.AbilityInvokeEntry] `bson:"-" msgpack:"-"` // ability转发器 @@ -79,6 +80,7 @@ func (p *Player) InitAll() { p.GameObjectGuidMap = make(map[uint64]GameObject) p.CoopApplyMap = make(map[uint32]int64) p.StaminaInfo = new(StaminaInfo) + p.VehicleInfo = new(VehicleInfo) p.InitAllAvatar() p.InitAllWeapon() p.InitAllItem() diff --git a/gs/model/stamina.go b/gs/model/stamina.go index 91a481af..2f711279 100644 --- a/gs/model/stamina.go +++ b/gs/model/stamina.go @@ -1,8 +1,8 @@ package model import ( + "hk4e/gs/constant" "hk4e/protocol/proto" - "time" ) type StaminaInfo struct { @@ -14,9 +14,46 @@ type StaminaInfo struct { LastSkillTime int64 // 最后释放技能的时间 } -// SetLastSkill 记录技能以便后续使用 -func (s *StaminaInfo) SetLastSkill(casterId uint32, skillId uint32) { - s.LastCasterId = casterId - s.LastSkillId = skillId - s.LastSkillTime = time.Now().UnixMilli() +// SetStaminaCost 设置动作需要消耗的耐力 +func (s *StaminaInfo) SetStaminaCost(state proto.MotionState) { + // 根据状态决定要修改的耐力 + // TODO 角色天赋 食物 会影响耐力消耗 + switch state { + // 消耗耐力 + case proto.MotionState_MOTION_STATE_DASH: + // 快速跑步 + s.CostStamina = constant.StaminaCostConst.DASH + case proto.MotionState_MOTION_STATE_FLY, proto.MotionState_MOTION_STATE_FLY_FAST, proto.MotionState_MOTION_STATE_FLY_SLOW: + // 滑翔 + s.CostStamina = constant.StaminaCostConst.FLY + case proto.MotionState_MOTION_STATE_SWIM_DASH: + // 快速游泳 + s.CostStamina = constant.StaminaCostConst.SWIM_DASH + case proto.MotionState_MOTION_STATE_SKIFF_DASH: + // 浪船加速 + s.CostStamina = constant.StaminaCostConst.SKIFF_DASH + // 恢复耐力 + case proto.MotionState_MOTION_STATE_DANGER_RUN, proto.MotionState_MOTION_STATE_RUN: + // 正常跑步 + s.CostStamina = constant.StaminaCostConst.RUN + case proto.MotionState_MOTION_STATE_DANGER_STANDBY_MOVE, proto.MotionState_MOTION_STATE_DANGER_STANDBY, proto.MotionState_MOTION_STATE_LADDER_TO_STANDBY, proto.MotionState_MOTION_STATE_STANDBY_MOVE, proto.MotionState_MOTION_STATE_STANDBY: + // 站立 + s.CostStamina = constant.StaminaCostConst.STANDBY + case proto.MotionState_MOTION_STATE_DANGER_WALK, proto.MotionState_MOTION_STATE_WALK: + // 走路 + s.CostStamina = constant.StaminaCostConst.WALK + case proto.MotionState_MOTION_STATE_SKIFF_BOARDING, proto.MotionState_MOTION_STATE_SKIFF_NORMAL: + // 浪船正常移动或停下 + s.CostStamina = constant.StaminaCostConst.SKIFF_NORMAL + case proto.MotionState_MOTION_STATE_POWERED_FLY: + // 滑翔加速 (风圈等) + s.CostStamina = constant.StaminaCostConst.POWERED_FLY + case proto.MotionState_MOTION_STATE_SKIFF_POWERED_DASH: + // 浪船加速 (风圈等) + s.CostStamina = constant.StaminaCostConst.POWERED_SKIFF + // 缓慢动作将在客户端发送消息后消耗 + case proto.MotionState_MOTION_STATE_CLIMB, proto.MotionState_MOTION_STATE_SWIM_MOVE: + // 缓慢攀爬 或 缓慢游泳 + s.CostStamina = 0 + } } diff --git a/gs/model/vehicle.go b/gs/model/vehicle.go new file mode 100644 index 00000000..98930df8 --- /dev/null +++ b/gs/model/vehicle.go @@ -0,0 +1,7 @@ +package model + +type VehicleInfo struct { + InVehicleEntityId uint32 // 玩家所在载具的实体Id + LastCreateTime int64 // 最后一次创建载具的时间 + LastCreateEntityId uint32 // 最后一次创建载具的实体Id +} diff --git a/protocol/cmd/cmd_id_proto_obj_map.go b/protocol/cmd/cmd_id_proto_obj_map.go index 8f11df4d..8323ccb9 100644 --- a/protocol/cmd/cmd_id_proto_obj_map.go +++ b/protocol/cmd/cmd_id_proto_obj_map.go @@ -231,10 +231,11 @@ func (c *CmdProtoMap) registerAllMessage() { c.registerMessage(McoinExchangeHcoinRsp, &proto.McoinExchangeHcoinRsp{}) // 结晶换原石响应 // 载具 - c.registerMessage(CreateVehicleReq, &proto.CreateVehicleReq{}) // 创建载具请求 - c.registerMessage(CreateVehicleRsp, &proto.CreateVehicleRsp{}) // 创建载具响应 - c.registerMessage(VehicleInteractReq, &proto.VehicleInteractReq{}) // 载具交互请求 - c.registerMessage(VehicleInteractRsp, &proto.VehicleInteractRsp{}) // 载具交互响应 + c.registerMessage(CreateVehicleReq, &proto.CreateVehicleReq{}) // 创建载具请求 + c.registerMessage(CreateVehicleRsp, &proto.CreateVehicleRsp{}) // 创建载具响应 + c.registerMessage(VehicleInteractReq, &proto.VehicleInteractReq{}) // 载具交互请求 + c.registerMessage(VehicleInteractRsp, &proto.VehicleInteractRsp{}) // 载具交互响应 + c.registerMessage(VehicleStaminaNotify, &proto.VehicleStaminaNotify{}) // 载具耐力消耗通知 // 乱七八糟 c.registerMessage(MarkMapReq, &proto.MarkMapReq{}) // 标记地图请求