mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-02-04 15:52:27 +08:00
游泳溺水初步
This commit is contained in:
@@ -42,7 +42,7 @@ func InitStaminaCostConst() {
|
||||
StaminaCostConst.DASH = -360
|
||||
StaminaCostConst.FLY = -60
|
||||
StaminaCostConst.SPRINT = -1800
|
||||
StaminaCostConst.SWIM_DASH_START = -2000
|
||||
StaminaCostConst.SWIM_DASH_START = -200
|
||||
StaminaCostConst.SWIM_DASH = -204
|
||||
StaminaCostConst.SWIMMING = -400
|
||||
StaminaCostConst.POWERED_FLY = 500
|
||||
|
||||
@@ -233,6 +233,7 @@ func (t *TickManager) onTick200MilliSecond(now int64) {
|
||||
for _, player := range world.playerMap {
|
||||
GAME_MANAGER.SustainStaminaHandler(player)
|
||||
GAME_MANAGER.VehicleRestoreStaminaHandler(player)
|
||||
GAME_MANAGER.DrownBackHandler(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +239,11 @@ func (g *GameManager) UpdateUserAvatarFightProp(userId uint32, avatarId uint32)
|
||||
logger.Error("player is nil, uid: %v", userId)
|
||||
return
|
||||
}
|
||||
avatar := player.AvatarMap[avatarId]
|
||||
avatar, ok := player.AvatarMap[avatarId]
|
||||
if !ok {
|
||||
logger.Error("avatar is nil, avatarId: %v", avatar)
|
||||
return
|
||||
}
|
||||
avatarFightPropNotify := &proto.AvatarFightPropNotify{
|
||||
AvatarGuid: avatar.Guid,
|
||||
FightPropMap: avatar.FightPropMap,
|
||||
@@ -283,7 +287,7 @@ func (g *GameManager) PacketAvatarInfo(avatar *model.Avatar) *proto.AvatarInfo {
|
||||
Value: &proto.PropValue_Ival{Ival: 0},
|
||||
},
|
||||
},
|
||||
LifeState: 1,
|
||||
LifeState: uint32(avatar.LifeState),
|
||||
EquipGuidList: object.ConvMapToList(avatar.EquipGuidList),
|
||||
FightPropMap: nil,
|
||||
SkillDepotId: avatar.SkillDepotId,
|
||||
|
||||
@@ -113,12 +113,21 @@ func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg p
|
||||
if sceneEntity.avatarEntity != nil {
|
||||
// 玩家实体在移动
|
||||
// 更新玩家的位置信息
|
||||
player.Pos.X = float64(motionInfo.Pos.X)
|
||||
player.Pos.Y = float64(motionInfo.Pos.Y)
|
||||
player.Pos.Z = float64(motionInfo.Pos.Z)
|
||||
player.Rot.X = float64(motionInfo.Rot.X)
|
||||
player.Rot.Y = float64(motionInfo.Rot.Y)
|
||||
player.Rot.Z = float64(motionInfo.Rot.Z)
|
||||
|
||||
switch motionInfo.State {
|
||||
case proto.MotionState_MOTION_STATE_DANGER_RUN, proto.MotionState_MOTION_STATE_RUN,
|
||||
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,
|
||||
proto.MotionState_MOTION_STATE_DANGER_WALK, proto.MotionState_MOTION_STATE_WALK,
|
||||
proto.MotionState_MOTION_STATE_DASH:
|
||||
// 为了实现游泳返回安全位置 但是我觉得这么做肯定会出问题
|
||||
player.Pos.X = float64(motionInfo.Pos.X)
|
||||
player.Pos.Y = float64(motionInfo.Pos.Y)
|
||||
player.Pos.Z = float64(motionInfo.Pos.Z)
|
||||
player.Rot.X = float64(motionInfo.Rot.X)
|
||||
player.Rot.Y = float64(motionInfo.Rot.Y)
|
||||
player.Rot.Z = float64(motionInfo.Rot.Z)
|
||||
|
||||
}
|
||||
|
||||
// 处理耐力消耗
|
||||
g.ImmediateStamina(player, motionInfo.State)
|
||||
|
||||
@@ -476,6 +476,17 @@ func (g *GameManager) AddSceneEntityNotify(player *model.Player, visionType prot
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) EntityFightPropUpdateNotifyBroadcast(scene *Scene, entity *Entity, fightPropId uint32) {
|
||||
for _, player := range scene.playerMap {
|
||||
// PacketEntityFightPropUpdateNotify
|
||||
entityFightPropUpdateNotify := new(proto.EntityFightPropUpdateNotify)
|
||||
entityFightPropUpdateNotify.EntityId = entity.id
|
||||
entityFightPropUpdateNotify.FightPropMap = make(map[uint32]float32)
|
||||
entityFightPropUpdateNotify.FightPropMap[fightPropId] = entity.fightProp[fightPropId]
|
||||
g.SendMsg(cmd.EntityFightPropUpdateNotify, player.PlayerID, player.ClientSeq, entityFightPropUpdateNotify)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketFightPropMapToPbFightPropList(fightPropMap map[uint32]float32) []*proto.FightPropPair {
|
||||
fightPropList := []*proto.FightPropPair{
|
||||
{
|
||||
|
||||
@@ -340,10 +340,6 @@ func (g *GameManager) GetChangeStamina(curStamina int32, maxStamina int32, stami
|
||||
|
||||
// UpdateVehicleStamina 更新载具耐力
|
||||
func (g *GameManager) UpdateVehicleStamina(player *model.Player, vehicleEntity *Entity, staminaCost int32) {
|
||||
// 耐力增加0是没有意义的
|
||||
if staminaCost == 0 {
|
||||
return
|
||||
}
|
||||
staminaInfo := player.StaminaInfo
|
||||
// 添加的耐力大于0为恢复
|
||||
if staminaCost > 0 {
|
||||
@@ -385,11 +381,6 @@ func (g *GameManager) UpdateVehicleStamina(player *model.Player, vehicleEntity *
|
||||
|
||||
// UpdatePlayerStamina 更新玩家耐力
|
||||
func (g *GameManager) UpdatePlayerStamina(player *model.Player, staminaCost int32) {
|
||||
// 耐力增加0是没有意义的
|
||||
if staminaCost == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
staminaInfo := player.StaminaInfo
|
||||
// 添加的耐力大于0为恢复
|
||||
if staminaCost > 0 {
|
||||
@@ -413,6 +404,9 @@ func (g *GameManager) UpdatePlayerStamina(player *model.Player, staminaCost int3
|
||||
// 将被变更的耐力
|
||||
stamina := g.GetChangeStamina(curStamina, maxStamina, staminaCost)
|
||||
|
||||
// 检测玩家是否没耐力后执行溺水
|
||||
g.HandleDrown(player, stamina)
|
||||
|
||||
// 当前无变动不要频繁发包
|
||||
if uint32(curStamina) == stamina {
|
||||
return
|
||||
@@ -422,6 +416,63 @@ func (g *GameManager) UpdatePlayerStamina(player *model.Player, staminaCost int3
|
||||
g.SetPlayerStamina(player, stamina)
|
||||
}
|
||||
|
||||
// DrownBackHandler 玩家溺水返回安全点
|
||||
func (g *GameManager) DrownBackHandler(player *model.Player) {
|
||||
// 溺水返回时间为0代表不进行返回
|
||||
if player.StaminaInfo.DrownBackTime == 0 {
|
||||
return
|
||||
}
|
||||
if time.Now().UnixMilli() >= player.StaminaInfo.DrownBackTime {
|
||||
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
activeAvatar := world.GetPlayerWorldAvatar(player, player.TeamConfig.GetActiveAvatarId())
|
||||
avatarEntity := scene.GetEntity(activeAvatar.avatarEntityId)
|
||||
if avatarEntity == nil {
|
||||
logger.Error("avatar entity is nil, entityId: %v", activeAvatar.avatarEntityId)
|
||||
return
|
||||
}
|
||||
// TODO 目前存在的问题
|
||||
// 传送会显示玩家实体后再传送 返回安全位置写的不是很好可能存在问题
|
||||
// 官服 游戏离线也会回到安全位置
|
||||
|
||||
// 设置角色存活
|
||||
scene.SetEntityLifeState(avatarEntity, constant.LifeStateConst.LIFE_ALIVE, proto.PlayerDieType_PLAYER_DIE_TYPE_NONE)
|
||||
// 传送玩家至安全位置
|
||||
g.TeleportPlayer(player, player.SceneId, player.Pos)
|
||||
|
||||
// 重置溺水返回时间
|
||||
player.StaminaInfo.DrownBackTime = 0
|
||||
// 重置动作状态否则可能会导致多次溺水
|
||||
player.StaminaInfo.State = 0
|
||||
}
|
||||
}
|
||||
|
||||
// HandleDrown 处理玩家溺水
|
||||
func (g *GameManager) HandleDrown(player *model.Player, stamina uint32) {
|
||||
// 溺水需要耐力等于0 返回时间不等于0代表已处理过溺水正在等待返回
|
||||
if stamina != 0 || player.StaminaInfo.DrownBackTime != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
world := WORLD_MANAGER.GetWorldByID(player.WorldId)
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
activeAvatar := world.GetPlayerWorldAvatar(player, player.TeamConfig.GetActiveAvatarId())
|
||||
avatarEntity := scene.GetEntity(activeAvatar.avatarEntityId)
|
||||
if avatarEntity == nil {
|
||||
logger.Error("avatar entity is nil, entityId: %v", activeAvatar.avatarEntityId)
|
||||
return
|
||||
}
|
||||
|
||||
// 确保玩家正在游泳
|
||||
if player.StaminaInfo.State == proto.MotionState_MOTION_STATE_SWIM_MOVE || player.StaminaInfo.State == proto.MotionState_MOTION_STATE_SWIM_DASH {
|
||||
logger.Debug("player drown, curStamina: %v, state: %v", stamina, player.StaminaInfo.State)
|
||||
// 设置角色为死亡
|
||||
scene.SetEntityLifeState(avatarEntity, constant.LifeStateConst.LIFE_DEAD, proto.PlayerDieType_PLAYER_DIE_TYPE_DRAWN)
|
||||
// 溺水返回安全点的时间
|
||||
player.StaminaInfo.DrownBackTime = time.Now().Add(time.Second * 4).UnixMilli()
|
||||
}
|
||||
}
|
||||
|
||||
// SetVehicleStamina 设置载具耐力
|
||||
func (g *GameManager) SetVehicleStamina(player *model.Player, vehicleEntity *Entity, stamina float32) {
|
||||
// 设置载具的耐力
|
||||
@@ -442,14 +493,19 @@ func (g *GameManager) SetPlayerStamina(player *model.Player, stamina uint32) {
|
||||
player.PropertiesMap[prop] = stamina
|
||||
//logger.Debug("player stamina set, stamina: %v", stamina)
|
||||
|
||||
// PacketPlayerPropNotify
|
||||
g.PlayerPropNotify(player, prop)
|
||||
}
|
||||
|
||||
func (g *GameManager) PlayerPropNotify(player *model.Player, playerPropId uint16) {
|
||||
// PacketPlayerPropNotify
|
||||
playerPropNotify := new(proto.PlayerPropNotify)
|
||||
playerPropNotify.PropMap = make(map[uint32]*proto.PropValue)
|
||||
playerPropNotify.PropMap[uint32(prop)] = &proto.PropValue{
|
||||
Type: uint32(prop),
|
||||
Val: int64(player.PropertiesMap[prop]),
|
||||
playerPropNotify.PropMap[uint32(playerPropId)] = &proto.PropValue{
|
||||
Type: uint32(playerPropId),
|
||||
Val: int64(player.PropertiesMap[playerPropId]),
|
||||
Value: &proto.PropValue_Ival{
|
||||
Ival: int64(player.PropertiesMap[prop]),
|
||||
Ival: int64(player.PropertiesMap[playerPropId]),
|
||||
},
|
||||
}
|
||||
g.SendMsg(cmd.PlayerPropNotify, player.PlayerID, player.ClientSeq, playerPropNotify)
|
||||
|
||||
@@ -55,7 +55,7 @@ func (g *GameManager) CreateVehicleReq(player *model.Player, payloadMsg pb.Messa
|
||||
g.CommonRetError(cmd.VehicleInteractRsp, player, &proto.VehicleInteractRsp{})
|
||||
return
|
||||
}
|
||||
GAME_MANAGER.AddSceneEntityNotify(player, proto.VisionType_VISION_TYPE_BORN, []uint32{entityId}, true, false)
|
||||
GAME_MANAGER.AddSceneEntityNotifyBroadcast(player, scene, proto.VisionType_VISION_TYPE_BORN, []*proto.SceneEntityInfo{GAME_MANAGER.PacketSceneEntityInfoGadget(scene, entityId)}, false)
|
||||
|
||||
// 记录创建的载具信息
|
||||
player.VehicleInfo.LastCreateEntityIdMap[req.VehicleId] = entityId
|
||||
@@ -101,7 +101,7 @@ func (g *GameManager) DestroyVehicleEntity(player *model.Player, scene *Scene, v
|
||||
if entity.gadgetEntity.gadgetVehicleEntity.owner != player {
|
||||
return
|
||||
}
|
||||
// 确保玩家正在载具中
|
||||
// 如果玩家正在载具中
|
||||
if g.IsPlayerInVehicle(player, entity.gadgetEntity.gadgetVehicleEntity) {
|
||||
// 离开载具
|
||||
g.ExitVehicle(player, entity, player.AvatarMap[player.TeamConfig.GetActiveAvatarId()].Guid)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"hk4e/protocol/cmd"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
@@ -572,6 +573,7 @@ type GadgetEntity struct {
|
||||
type Entity struct {
|
||||
id uint32
|
||||
scene *Scene
|
||||
lifeState uint16
|
||||
pos *model.Vector
|
||||
rot *model.Vector
|
||||
moveState uint16
|
||||
@@ -617,11 +619,71 @@ func (s *Scene) RemovePlayer(player *model.Player) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scene) SetEntityLifeState(entity *Entity, lifeState uint16, dieType proto.PlayerDieType) {
|
||||
if entity.avatarEntity != nil {
|
||||
// 获取玩家对象
|
||||
player := USER_MANAGER.GetOnlineUser(entity.avatarEntity.uid)
|
||||
if player == nil {
|
||||
logger.Error("player is nil, uid: %v", entity.avatarEntity.uid)
|
||||
return
|
||||
}
|
||||
// 获取角色
|
||||
avatar, ok := player.AvatarMap[entity.avatarEntity.avatarId]
|
||||
if !ok {
|
||||
logger.Error("avatar is nil, avatarId: %v", avatar)
|
||||
return
|
||||
}
|
||||
// 设置角色存活状态
|
||||
avatar.LifeState = lifeState
|
||||
|
||||
// PacketAvatarLifeStateChangeNotify
|
||||
avatarLifeStateChangeNotify := &proto.AvatarLifeStateChangeNotify{
|
||||
LifeState: uint32(avatar.LifeState),
|
||||
AttackTag: "",
|
||||
DieType: dieType,
|
||||
ServerBuffList: nil,
|
||||
MoveReliableSeq: entity.lastMoveReliableSeq,
|
||||
SourceEntityId: 0,
|
||||
AvatarGuid: avatar.Guid,
|
||||
}
|
||||
for _, p := range s.playerMap {
|
||||
GAME_MANAGER.SendMsg(cmd.AvatarLifeStateChangeNotify, p.PlayerID, p.ClientSeq, avatarLifeStateChangeNotify)
|
||||
}
|
||||
} else {
|
||||
// 设置存活状态
|
||||
entity.lifeState = lifeState
|
||||
|
||||
if lifeState == constant.LifeStateConst.LIFE_DEAD {
|
||||
// 设置血量
|
||||
entity.fightProp[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP)] = 0
|
||||
GAME_MANAGER.EntityFightPropUpdateNotifyBroadcast(s, entity, uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP))
|
||||
}
|
||||
|
||||
// PacketLifeStateChangeNotify
|
||||
lifeStateChangeNotify := &proto.LifeStateChangeNotify{
|
||||
EntityId: entity.id,
|
||||
AttackTag: "",
|
||||
MoveReliableSeq: entity.lastMoveReliableSeq,
|
||||
DieType: dieType,
|
||||
LifeState: uint32(entity.lifeState),
|
||||
SourceEntityId: 0,
|
||||
}
|
||||
for _, p := range s.playerMap {
|
||||
GAME_MANAGER.SendMsg(cmd.LifeStateChangeNotify, p.PlayerID, p.ClientSeq, lifeStateChangeNotify)
|
||||
}
|
||||
|
||||
// 删除实体
|
||||
s.DestroyEntity(entity.id)
|
||||
GAME_MANAGER.RemoveSceneEntityNotifyBroadcast(s, proto.VisionType_VISION_TYPE_DIE, []uint32{entity.id})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scene) CreateEntityAvatar(player *model.Player, avatarId uint32) uint32 {
|
||||
entityId := s.world.GetNextWorldEntityId(constant.EntityIdTypeConst.AVATAR)
|
||||
entity := &Entity{
|
||||
id: entityId,
|
||||
scene: s,
|
||||
lifeState: constant.LifeStateConst.LIFE_ALIVE,
|
||||
pos: player.Pos,
|
||||
rot: player.Rot,
|
||||
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
|
||||
@@ -658,6 +720,7 @@ func (s *Scene) CreateEntityWeapon() uint32 {
|
||||
entity := &Entity{
|
||||
id: entityId,
|
||||
scene: s,
|
||||
lifeState: constant.LifeStateConst.LIFE_ALIVE,
|
||||
pos: new(model.Vector),
|
||||
rot: new(model.Vector),
|
||||
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
|
||||
@@ -676,6 +739,7 @@ func (s *Scene) CreateEntityMonster(pos *model.Vector, level uint8, fightProp ma
|
||||
entity := &Entity{
|
||||
id: entityId,
|
||||
scene: s,
|
||||
lifeState: constant.LifeStateConst.LIFE_ALIVE,
|
||||
pos: pos,
|
||||
rot: new(model.Vector),
|
||||
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
|
||||
@@ -703,6 +767,7 @@ func (s *Scene) ClientCreateEntityGadget(pos, rot *model.Vector, entityId uint32
|
||||
entity := &Entity{
|
||||
id: entityId,
|
||||
scene: s,
|
||||
lifeState: constant.LifeStateConst.LIFE_ALIVE,
|
||||
pos: pos,
|
||||
rot: rot,
|
||||
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
|
||||
@@ -736,6 +801,7 @@ func (s *Scene) CreateEntityGadget(pos *model.Vector, gatherId uint32) uint32 {
|
||||
entity := &Entity{
|
||||
id: entityId,
|
||||
scene: s,
|
||||
lifeState: constant.LifeStateConst.LIFE_ALIVE,
|
||||
pos: pos,
|
||||
rot: new(model.Vector),
|
||||
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
|
||||
@@ -770,6 +836,7 @@ func (s *Scene) CreateEntityGadgetVehicle(uid uint32, pos, rot *model.Vector, ve
|
||||
entity := &Entity{
|
||||
id: entityId,
|
||||
scene: s,
|
||||
lifeState: constant.LifeStateConst.LIFE_ALIVE,
|
||||
pos: pos,
|
||||
rot: rot,
|
||||
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
type Avatar struct {
|
||||
AvatarId uint32 `bson:"avatarId"` // 角色id
|
||||
LifeState uint16 `bson:"lifeState"` // 存活状态
|
||||
Level uint8 `bson:"level"` // 等级
|
||||
Exp uint32 `bson:"exp"` // 经验值
|
||||
Promote uint8 `bson:"promote"` // 突破等阶
|
||||
@@ -110,6 +111,7 @@ func (p *Player) AddAvatar(avatarId uint32) {
|
||||
}
|
||||
avatar := &Avatar{
|
||||
AvatarId: avatarId,
|
||||
LifeState: constant.LifeStateConst.LIFE_ALIVE,
|
||||
Level: 1,
|
||||
Exp: 0,
|
||||
Promote: 0,
|
||||
|
||||
@@ -14,6 +14,7 @@ type StaminaInfo struct {
|
||||
LastSkillId uint32 // 最后释放的技能Id
|
||||
LastSkillTime int64 // 最后释放技能的时间
|
||||
LastSkillStartTime int64 // 最后执行开始技能耐力消耗的时间
|
||||
DrownBackTime int64 // 溺水返回安全点的时间
|
||||
}
|
||||
|
||||
// SetStaminaCost 设置动作需要消耗的耐力
|
||||
|
||||
Reference in New Issue
Block a user