private Task StartRegen(StatId statId, StatId regenStatId, StatId timeStatId) { // TODO: merge regen updates with larger packets return(Task.Run(async() => { while (true) { await Task.Delay(Stats[timeStatId].Total); lock (Stats) { if (Stats[statId].Total >= Stats[statId].Bonus) { return; } // TODO: Check if regen-enabled AddStatRegen(statId, regenStatId); Value.Session?.FieldManager.BroadcastPacket(StatPacket.UpdateStats(this, statId)); if (Value.Party != null) { Value.Party.BroadcastPacketParty(PartyPacket.UpdateHitpoints(Value)); } } } })); }
private Task StartHealingSpot() { return(Task.Run(async() => { while (!State.Players.IsEmpty) { foreach (IFieldObject <HealingSpot> healingSpot in State.HealingSpots.Values) { CoordS healingCoord = healingSpot.Value.Coord; foreach (IFieldObject <Player> player in State.Players.Values) { if ((healingCoord - player.Coord.ToShort()).Length() < Block.BLOCK_SIZE * 2 && healingCoord.Z == player.Coord.ToShort().Z - 1) // 3x3x1 area { int healAmount = (int)(player.Value.Stats[PlayerStatId.Hp].Max * 0.03); Status status = new Status(new SkillCast(70000018, 1, 0, 1), owner: player.ObjectId, source: healingSpot.ObjectId, duration: 100, stacks: 1); player.Value.Session.Send(BuffPacket.SendBuff(0, status)); BroadcastPacket(SkillDamagePacket.ApplyHeal(status, healAmount)); player.Value.Session.Player.Stats.Increase(PlayerStatId.Hp, healAmount); player.Value.Session.Send(StatPacket.UpdateStats(player, PlayerStatId.Hp)); } } } await Task.Delay(1000); } })); }
public static void UpdatePlayer(GameSession session, SyncState[] syncStates) { CoordF coord = syncStates[0].Coord.ToFloat(); CoordF closestBlock = Block.ClosestBlock(coord); closestBlock.Z -= Block.BLOCK_SIZE; // Get block under player if (IsCoordSafe(session, syncStates[0].Coord, closestBlock)) { session.Player.SafeBlock = closestBlock; } session.FieldPlayer.Coord = syncStates[0].Coord.ToFloat(); CoordF rotation = new CoordF(); rotation.Z = syncStates[0].Rotation / 10; session.FieldPlayer.Rotation = rotation; if (IsOutOfBounds(session.FieldPlayer.Coord, session.FieldManager.BoundingBox)) { int currentHp = session.Player.Stats[PlayerStatId.Hp].Current; int fallDamage = currentHp * Math.Clamp(currentHp * 4 / 100 - 1, 0, 25) / 100; // TODO: Create accurate damage model CoordF safeBlock = session.Player.SafeBlock; safeBlock.Z += Block.BLOCK_SIZE + 1; // Without this player will spawn inside the block session.Player.ConsumeHp(fallDamage); session.Send(UserMoveByPortalPacket.Move(session.FieldPlayer, safeBlock, session.Player.Rotation)); session.Send(StatPacket.UpdateStats(session.FieldPlayer, PlayerStatId.Hp)); session.Send(FallDamagePacket.FallDamage(session, fallDamage)); } // not sure if this needs to be synced here session.Player.Animation = syncStates[0].Animation1; }
private Task StartRegen(PlayerStatId statId, PlayerStatId regenStatId, PlayerStatId timeStatId) { // TODO: merge regen updates with larger packets return(Task.Run(async() => { while (true) { await Task.Delay(Stats[timeStatId].Current); lock (Stats) { if (Stats[statId].Current >= Stats[statId].Max) { return; } // TODO: Check if regen-enabled Stats[statId] = AddStatRegen(statId, regenStatId); Session?.FieldManager.BroadcastPacket(StatPacket.UpdateStats(Session.FieldPlayer, statId)); if (Party != null) { Party.BroadcastPacketParty(PartyPacket.UpdateHitpoints(this)); } } } })); }
public override void Handle(GameSession session, PacketReader packet) { byte function = packet.ReadByte(); // Unknown what this is for session.ServerTick = packet.ReadInt(); session.ClientTick = packet.ReadInt(); byte segments = packet.ReadByte(); if (segments < 1) { return; } SyncState[] syncStates = new SyncState[segments]; for (int i = 0; i < segments; i++) { syncStates[i] = packet.ReadSyncState(); packet.ReadInt(); // ClientTicks packet.ReadInt(); // ServerTicks } Packet syncPacket = SyncStatePacket.UserSync(session.FieldPlayer, syncStates); session.FieldManager.BroadcastPacket(syncPacket, session); CoordF coord = syncStates[0].Coord.ToFloat(); CoordF closestBlock = Block.ClosestBlock(coord); closestBlock.Z -= Block.BLOCK_SIZE; // Get block under player if (IsCoordSafe(session, syncStates[0].Coord, closestBlock)) { session.Player.SafeBlock = closestBlock; } session.FieldPlayer.Coord = syncStates[0].Coord.ToFloat(); CoordF rotation = new CoordF(); rotation.Z = syncStates[0].Rotation / 10; session.FieldPlayer.Rotation = rotation; if (IsOutOfBounds(session.FieldPlayer.Coord, session.FieldManager.BoundingBox)) { int currentHp = session.Player.Stats[PlayerStatId.Hp].Current; int fallDamage = currentHp * Math.Clamp(currentHp * 4 / 100 - 1, 0, 25) / 100; // TODO: Create accurate damage model CoordF safeBlock = session.Player.SafeBlock; safeBlock.Z += Block.BLOCK_SIZE + 1; // Without this player will spawn inside the block session.Player.ConsumeHp(fallDamage); session.Send(UserMoveByPortalPacket.Move(session, safeBlock, session.Player.Rotation)); session.Send(StatPacket.UpdateStats(session.FieldPlayer, PlayerStatId.Hp)); session.Send(FallDamagePacket.FallDamage(session, fallDamage)); } // not sure if this needs to be synced here session.Player.Animation = syncStates[0].Animation1; }
public override void Handle(GameSession session, PacketReader packet) { MountMetadata metadata = MountMetadataStorage.GetMountMetadata(session.Player.Mount.Value.Id); if (metadata is null) { return; } session.Player.FieldPlayer.ConsumeStamina(metadata.RunConsumeEp, noRegen: true); session.Send(StatPacket.UpdateStats(session.Player.FieldPlayer, StatAttribute.Stamina)); }
public override void RecoverHp(int amount) { if (amount <= 0) { return; } lock (Stats) { Stat stat = Stats[StatId.Hp]; if (stat.Total < stat.Bonus) { stat.Increase(Math.Min(amount, stat.Bonus - stat.Total)); Value.Session.Send(StatPacket.UpdateStats(this, StatId.Hp)); } } }
public void RecoverStamina(int amount) { if (amount <= 0) { return; } lock (Stats) { PlayerStat stat = Stats[PlayerStatId.Stamina]; if (stat.Current < stat.Max) { Stats.Increase(PlayerStatId.Stamina, Math.Min(amount, stat.Max - stat.Current)); Session.Send(StatPacket.UpdateStats(Session.FieldPlayer, PlayerStatId.Stamina)); } } }
private Task StartRegen(PlayerStatId statId, PlayerStatId regenStatId, PlayerStatId timeStatId) { return(Task.Run(async() => { await Task.Delay(Stats[timeStatId].Current); // TODO: Check if regen-enabled while (Stats[statId].Current < Stats[statId].Max) { lock (Stats) { Stats[statId] = AddStatRegen(statId, regenStatId); Session.Send(StatPacket.UpdateStats(Session.FieldPlayer, statId)); } await Task.Delay(Stats[timeStatId].Current); } })); }
private void HealingSpot() { foreach (IFieldObject <HealingSpot> healingSpot in State.HealingSpots.Values) { CoordS healingCoord = healingSpot.Value.Coord; foreach (IFieldObject <Player> player in State.Players.Values) { if ((healingCoord - player.Coord.ToShort()).Length() < Block.BLOCK_SIZE * 2 && healingCoord.Z == player.Coord.ToShort().Z - 1) // 3x3x1 area { int healAmount = (int)(player.Value.Stats[PlayerStatId.Hp].Max * 0.03); Status status = new Status(new SkillCast(70000018, 1, 0, 1), target: player.ObjectId, source: healingSpot.ObjectId, stacks: 1); player.Value.Session.Send(BuffPacket.SendBuff(0, status)); BroadcastPacket(SkillDamagePacket.Heal(status, healAmount)); player.Value.Session.Player.Stats.Increase(PlayerStatId.Hp, healAmount); player.Value.Session.Send(StatPacket.UpdateStats(player, PlayerStatId.Hp)); } } } }
private Task StartHealingSpot(GameSession session, IFieldObject <Player> player) { int healAmount = 30; Status status = new Status(new SkillCast(70000018, 1, 0, 1), player.ObjectId, player.ObjectId, 1, healAmount); return(Task.Run(async() => { while (!State.Players.IsEmpty) { CoordS healingCoord = MapEntityStorage.GetHealingSpot(MapId); if ((healingCoord - player.Coord.ToShort()).Length() < Block.BLOCK_SIZE * 2 && healingCoord.Z == player.Coord.ToShort().Z - 1) // 3x3x1 area { session.Send(BuffPacket.SendBuff(0, status)); session.Send(SkillDamagePacket.ApplyHeal(player, status)); session.Player.Stats.Increase(PlayerStatId.Hp, healAmount); session.Send(StatPacket.UpdateStats(player, PlayerStatId.Hp)); } await Task.Delay(1000); } })); }
private Task StartRegen(PlayerStatId statId, PlayerStatId regenStatId, PlayerStatId timeStatId) { // TODO: merge regen updates with larger packets return(Task.Run(async() => { while (true) { await Task.Delay(Stats[timeStatId].Current); lock (Stats) { if (Stats[statId].Current >= Stats[statId].Max) { return; } // TODO: Check if regen-enabled Stats[statId] = AddStatRegen(statId, regenStatId); Session.Send(StatPacket.UpdateStats(Session.FieldPlayer, statId)); } } })); }
private static void HandleDamage(GameSession session, PacketReader packet) { List <(IFieldObject <Mob>, DamageHandler)> mobs = new List <(IFieldObject <Mob>, DamageHandler)>(); long skillSN = packet.ReadLong(); int attackCounter = packet.ReadInt(); int playerObjectId = packet.ReadInt(); CoordF position = packet.Read <CoordF>(); CoordF impactPos = packet.Read <CoordF>(); CoordF rotation = packet.Read <CoordF>(); int attackPoint = packet.ReadByte(); byte count = packet.ReadByte(); packet.ReadInt(); bool isCrit = DamageHandler.RollCrit(session.Player.Stats[PlayerStatId.CritRate].Current); for (int i = 0; i < count; i++) { int entity = packet.ReadInt(); packet.ReadByte(); IFieldObject <Mob> mob = session.FieldManager.State.Mobs.GetValueOrDefault(entity); if (mob == null) { continue; } DamageHandler damage = DamageHandler.CalculateDamage(session.FieldPlayer.Value.SkillCast, session.FieldPlayer.Value, mob.Value, isCrit); mob.Value.Damage(damage.Damage); session.Send(StatPacket.UpdateMobStats(mob)); if (mob.Value.IsDead) { HandleMobKill(session, mob); } mobs.Add((mob, damage)); // TODO: Check if the skill is a debuff for an entity SkillCast skillCast = session.FieldPlayer.Value.SkillCast; if (skillCast.IsDebuffElement() || skillCast.IsDebuffToEntity() || skillCast.IsDebuffElement()) { Status status = new Status(session.FieldPlayer.Value.SkillCast, mob.ObjectId, session.FieldPlayer.ObjectId, 1); StatusHandler.Handle(session, status); } } // TODO: Verify if its the player or an ally if (session.FieldPlayer.Value.SkillCast.IsHeal()) { Status status = new Status(session.FieldPlayer.Value.SkillCast, session.FieldPlayer.ObjectId, session.FieldPlayer.ObjectId, 1); StatusHandler.Handle(session, status); // TODO: Heal based on stats session.FieldManager.BroadcastPacket(SkillDamagePacket.Heal(status, 50)); session.FieldPlayer.Value.Stats.Increase(PlayerStatId.Hp, 50); session.Send(StatPacket.UpdateStats(session.FieldPlayer, PlayerStatId.Hp)); } else { session.FieldManager.BroadcastPacket(SkillDamagePacket.Damage(skillSN, attackCounter, position, rotation, session.FieldPlayer, mobs)); } }
private static void HandleDamage(GameSession session, PacketReader packet) { long skillSN = packet.ReadLong(); int attackCounter = packet.ReadInt(); int playerObjectId = packet.ReadInt(); CoordF position = packet.Read <CoordF>(); CoordF impactPos = packet.Read <CoordF>(); CoordF rotation = packet.Read <CoordF>(); int attackPoint = packet.ReadByte(); byte count = packet.ReadByte(); packet.ReadInt(); IFieldActor <Player> fieldPlayer = session.Player.FieldPlayer; bool isCrit = DamageHandler.RollCrit(session.Player.Stats[StatId.CritRate].Total); // TODO: Check if skillSN matches server's current skill for the player // TODO: Verify if its the player or an ally if (fieldPlayer.SkillCast.IsHeal()) { Status status = new(fieldPlayer.SkillCast, fieldPlayer.ObjectId, fieldPlayer.ObjectId, 1); StatusHandler.Handle(session, status); // TODO: Heal based on stats session.FieldManager.BroadcastPacket(SkillDamagePacket.Heal(status, 50)); fieldPlayer.Stats[StatId.Hp].Increase(50); session.Send(StatPacket.UpdateStats(fieldPlayer, StatId.Hp)); } else { List <DamageHandler> damages = new(); for (int i = 0; i < count; i++) { int entityId = packet.ReadInt(); packet.ReadByte(); IFieldActor <NpcMetadata> mob = session.FieldManager.State.Mobs.GetValueOrDefault(entityId); if (mob == null) { continue; } DamageHandler damage = DamageHandler.CalculateDamage(fieldPlayer.SkillCast, fieldPlayer, mob, isCrit); mob.Damage(damage); // TODO: Move logic to Damage() session.FieldManager.BroadcastPacket(StatPacket.UpdateMobStats(mob)); if (mob.IsDead) { HandleMobKill(session, mob); } damages.Add(damage); // TODO: Check if the skill is a debuff for an entity SkillCast skillCast = fieldPlayer.SkillCast; if (skillCast.IsDebuffElement() || skillCast.IsDebuffToEntity() || skillCast.IsDebuffElement()) { Status status = new(fieldPlayer.SkillCast, mob.ObjectId, fieldPlayer.ObjectId, 1); StatusHandler.Handle(session, status); } } session.FieldManager.BroadcastPacket(SkillDamagePacket.Damage(skillSN, attackCounter, position, rotation, fieldPlayer, damages)); } }
public virtual void Heal(GameSession session, Status status, int amount) { session.FieldManager.BroadcastPacket(SkillDamagePacket.Heal(status, amount)); Stats[StatAttribute.Hp].AddValue(amount); session.Send(StatPacket.UpdateStats(this, StatAttribute.Hp)); }