Пример #1
0
		/// <summary>
		/// Broadcasts HittingProp in range of creature.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="propEntityId"></param>
		/// <param name="stunTime"></param>
		public static void HittingProp(Creature creature, long propEntityId, int stunTime)
		{
			var pos = creature.GetPosition();

			var packet = new Packet(Op.HittingProp, creature.EntityId);
			packet.PutLong(propEntityId);
			packet.PutInt(stunTime);
			packet.PutFloat(pos.X);
			packet.PutFloat(pos.Y);

			creature.Region.Broadcast(packet, creature);
		}
Пример #2
0
        /// <summary>
        /// Sends BlacksmithingMiniGame to creature's client, which starts
        /// the Blacksmithing mini-game.
        /// </summary>
        /// <remarks>
        /// The position of the dots is relative to the upper left of the
        /// field. They land exactly on those spots after "wavering" for a
        /// moment. This wavering is randomized on the client side and
        /// doesn't affect anything.
        /// 
        /// The time bar is always the same, but the time it takes to fill
        /// up changes based on the "time displacement". The lower the value,
        /// the longer it takes to fill up. Using values that are too high
        /// or too low mess up the calculations and cause confusing results.
        /// The official range seems to be between ~0.81 and ~0.98.
        /// </remarks>
        /// <param name="creature"></param>
        /// <param name="prop"></param>
        /// <param name="item"></param>
        /// <param name="dots"></param>
        /// <param name="deviation"></param>
        public static void BlacksmithingMiniGame(Creature creature, Prop prop, Item item, List<BlacksmithDot> dots, int deviation)
        {
            if (dots == null || dots.Count != 5)
                throw new ArgumentException("5 dots required.");

            var packet = new Packet(Op.BlacksmithingMiniGame, creature.EntityId);

            // Untested if this is actually the deviation/cursor size,
            // but Tailoring does something very similar. Just like with
            // Tailoring, wrong values cause failed games.
            packet.PutShort((short)deviation);

            foreach (var dot in dots)
            {
                packet.PutShort((short)dot.X);
                packet.PutShort((short)dot.Y);
                packet.PutFloat(dot.TimeDisplacement);
                packet.PutShort((short)dot.Deviation);
            }

            packet.PutLong(prop.EntityId);
            packet.PutInt(0);
            packet.PutLong(item.EntityId);
            packet.PutInt(0);

            creature.Client.Send(packet);
        }
Пример #3
0
		/// <summary>
		/// Sends EntrustmentChanceUpdate to creature's client.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="chance"></param>
		/// <param name="unkShort"></param>
		public static void EntrustmentChanceUpdate(Creature creature, float chance, SkillRank skillRank)
		{
			var packet = new Packet(Op.EntrustmentChanceUpdate, creature.EntityId);
			packet.PutFloat(chance);
			packet.PutShort((short)skillRank);

			creature.Client.Send(packet);
		}
Пример #4
0
		/// <summary>
		/// Sends Weather.
		/// </summary>
		private static void Weather(Action<Packet> sender, IWeatherProvider provider)
		{
			var packet = new Packet(Op.Weather, MabiId.Broadcast);
			packet.PutByte(0);
			packet.PutInt(provider.RegionId);

			if (provider is IWeatherProviderTable)
			{
				var table = (IWeatherProviderTable)provider;

				packet.PutByte(0);
				packet.PutInt(table.GroupId);
				packet.PutByte(2);
				packet.PutByte(1);
				packet.PutString("table");
				packet.PutString(table.Name);
				packet.PutLong(0);
				packet.PutByte(0);
			}
			else if (provider is IWeatherProviderConstant)
			{
				var constant = (IWeatherProviderConstant)provider;

				// Packet structure is guessed, even though it works,
				// based on constant_smooth.
				packet.PutByte(2);
				packet.PutByte(0);
				packet.PutByte(1);
				packet.PutString("constant");
				packet.PutFloat(constant.Weather);
				packet.PutLong(0);
				packet.PutByte(0);
			}
			else if (provider is IWeatherProviderConstantSmooth)
			{
				var constantSmooth = (IWeatherProviderConstantSmooth)provider;

				packet.PutByte(2);
				packet.PutByte(0);
				packet.PutByte(1);
				packet.PutString("constant_smooth");
				packet.PutFloat(constantSmooth.Weather);
				packet.PutLong(DateTime.Now); // Start
				packet.PutLong(DateTime.MinValue); // End
				packet.PutFloat(constantSmooth.WeatherBefore);
				packet.PutFloat(constantSmooth.WeatherBefore);
				packet.PutLong(constantSmooth.TransitionTime);
				packet.PutByte(false); // bool? Is table appended? byte? Appended type?
				packet.PutLong(DateTime.MinValue); // End
				packet.PutInt(2);

				// Append a table packet here to go back to that after end

				packet.PutByte(0);
			}

			sender(packet);
		}
Пример #5
0
		/// <summary>
		/// Sends SkillRankUp to creature's client.
		/// </summary>
		/// <param name="client"></param>
		/// <param name="creature"></param>
		/// <param name="skill"></param>
		public static void SkillRankUp(Creature creature, Skill skill)
		{
			var packet = new Packet(Op.SkillRankUp, creature.EntityId);
			packet.PutByte(1);
			packet.PutBin(skill.Info);
			packet.PutFloat(0);

			creature.Client.Send(packet);
		}
Пример #6
0
        /// <summary>
        /// Broadcasts Effect in range of creature.
        /// </summary>
        /// <remarks>
        /// Parameters have to be casted to the proper type, use carefully!
        /// </remarks>
        /// <param name="creature"></param>
        /// <param name="parameters"></param>
        public static void Effect(Creature creature, int effectId, params object[] parameters)
        {
            var packet = new Packet(Op.Effect, creature.EntityId);
            packet.PutInt(effectId);
            foreach (var p in parameters)
            {
                if (p is byte) packet.PutByte((byte)p);
                else if (p is bool) packet.PutByte((bool)p);
                else if (p is short) packet.PutShort((short)p);
                else if (p is int) packet.PutInt((int)p);
                else if (p is long) packet.PutLong((long)p);
                else if (p is float) packet.PutFloat((float)p);
                else if (p is string) packet.PutString((string)p);
                else
                    throw new Exception("Unsupported effect parameter: " + p.GetType());
            }

            creature.Region.Broadcast(packet, creature);
        }
Пример #7
0
		/// <summary>
		/// Sends QuestUpdate to creature's client.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="quest"></param>
		public static void QuestUpdate(Creature creature, Quest quest)
		{
			var progress = quest.GetList();

			var packet = new Packet(Op.QuestUpdate, creature.EntityId);
			packet.PutLong(quest.UniqueId);
			packet.PutByte(1);
			packet.PutInt(progress.Count);
			foreach (var p in progress)
			{
				packet.PutInt(p.Count);
				// [180600, NA187 (25.06.2014)] ?
				{
					packet.PutFloat(0);
				}
				packet.PutByte(p.Done);
				packet.PutByte(p.Unlocked);
			}
			packet.PutByte(0);
			packet.PutByte(0);

			creature.Client.Send(packet);
		}
Пример #8
0
		/// <summary>
		/// Sends xInfoRequestR to client.
		/// </summary>
		/// <param name="client"></param>
		/// <param name="op"></param>
		/// <param name="character"></param>
		/// <param name="items"></param>
		public static void CharacterInfoRequestR(LoginClient client, int op, Character character, List<Item> items)
		{
			var packet = new Packet(op, MabiId.Login);
			packet.PutByte(character != null);

			if (character != null)
			{
				packet.PutString(character.Server);
				packet.PutLong(character.EntityId);
				packet.PutByte(1);
				packet.PutString(character.Name);
				packet.PutString("");
				packet.PutString("");
				packet.PutInt(character.Race);
				packet.PutByte(character.SkinColor);
				packet.PutShort(character.EyeType);
				packet.PutByte(character.EyeColor);
				packet.PutByte(character.MouthType);
				packet.PutUInt((uint)character.State);
				packet.PutFloat(character.Height);
				packet.PutFloat(character.Weight);
				packet.PutFloat(character.Upper);
				packet.PutFloat(character.Lower);
				packet.PutInt(0);
				packet.PutInt(0);
				packet.PutInt(0);
				packet.PutByte(0);
				packet.PutInt(0);
				packet.PutByte(0);
				packet.PutInt((int)character.Color1);
				packet.PutInt((int)character.Color2);
				packet.PutInt((int)character.Color3);
				packet.PutFloat(0.0f);
				packet.PutString("");
				packet.PutFloat(49.0f);
				packet.PutFloat(49.0f);
				packet.PutFloat(0.0f);
				packet.PutFloat(49.0f);
				// [180800, NA196 (14.10.2014)] ?
				{
					packet.PutShort(0);
				}
				packet.PutInt(0);
				packet.PutInt(0);
				packet.PutShort(0);
				packet.PutLong(0);
				packet.PutString("");
				packet.PutByte(0);

				packet.PutInt(items.Count);
				foreach (var item in items)
				{
					packet.PutLong(item.Id);
					packet.PutBin(item.Info);
				}

				packet.PutInt(0);  // PetRemainingTime
				packet.PutLong(0); // PetLastTime
				packet.PutLong(0); // PetExpireTime
			}

			client.Send(packet);
		}
Пример #9
0
        /// <summary>
        /// Broadcasts spawn effect (Effect, Spawn) in range of sendFrom.
        /// </summary>
        /// <param name="spawnEffect"></param>
        /// <param name="regionId"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="sender"></param>
        /// <param name="sendFrom">Falls back to sender if null</param>
        public static void SpawnEffect(SpawnEffect spawnEffect, int regionId, int x, int y, Creature sender, Creature sendFrom = null)
        {
            if (sendFrom == null)
                sendFrom = sender;

            var packet = new Packet(Op.Effect, sender.EntityId);
            packet.PutInt(E.Spawn);
            packet.PutInt(regionId);
            packet.PutFloat((float)x);
            packet.PutFloat((float)y);
            packet.PutByte((byte)spawnEffect);

            sender.Region.Broadcast(packet, sendFrom);
        }
Пример #10
0
		/// <summary>
		/// Broadcasts TurnTo in range of creature.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="x"></param>
		/// <param name="y"></param>
		public static void TurnTo(Creature creature, float x, float y)
		{
			var packet = new Packet(Op.TurnTo, creature.EntityId);
			packet.PutFloat(x);
			packet.PutFloat(y);

			creature.Region.Broadcast(packet, creature);
		}
Пример #11
0
		public static void SpinColorWheelR(Creature creature, float result)
		{
			var packet = new Packet(Op.SpinColorWheelR, creature.EntityId);
			packet.PutFloat(result);

			creature.Client.Send(packet);
		}
Пример #12
0
        /// <summary>
        /// Broadcasts CollectAnimation in creature's range.
        /// </summary>
        /// <param name="creature"></param>
        /// <param name="entityId"></param>
        /// <param name="collectId"></param>
        /// <param name="pos"></param>
        public static void CollectAnimation(Creature creature, long entityId, int collectId, Position pos)
        {
            var packet = new Packet(Op.CollectAnimation, creature.EntityId);
            packet.PutLong(entityId);
            packet.PutInt(collectId);
            packet.PutFloat(pos.X);
            packet.PutFloat(pos.Y);
            packet.PutFloat(1);

            creature.Region.Broadcast(packet, creature);
        }
Пример #13
0
        /// <summary>
        /// Sends SkillTrainingUp to creature's client.
        /// </summary>
        /// <param name="creature"></param>
        /// <param name="skill"></param>
        /// <param name="exp">Exp gained</param>
        public static void SkillTrainingUp(Creature creature, Skill skill, float exp, string bonus = "")
        {
            var packet = new Packet(Op.SkillTrainingUp, creature.EntityId);
            packet.PutBin(skill.Info);
            packet.PutFloat(exp);
            packet.PutByte(1);
            packet.PutString(bonus); // (Specialized Skill Bonus: x2)

            creature.Client.Send(packet);
        }
Пример #14
0
        /// <summary>
        /// Sends ProductionSuccessRequestR to creature's client, informing it
        /// about the success rate it requested.
        /// </summary>
        /// <remarks>
        /// This version of the packet is used for Tailoring and Blacksmithing.
        /// </remarks>
        /// <param name="creature"></param>
        /// <param name="skillId">Skill the rate is used for.</param>
        /// <param name="successRate">
        /// Bonus success rate, added to the value calculated by the client,
        /// or the total success rate to use, if totalSuccess is true.
        /// </param>
        /// <param name="totalSuccess">
        /// If true, the client will display the given successRate, if it's false,
        /// it will calculate the default rate itself and add successRate as bonus.
        /// </param>
        public static void ProductionSuccessRequestR(Creature creature, SkillId skillId, float successRate, bool totalSuccess, float unkFloat)
        {
            var gp = new Packet(Op.ProductionSuccessRequestR, creature.EntityId);

            gp.PutByte(1);
            gp.PutUShort((ushort)skillId);
            gp.PutShort(6);
            gp.PutFloat(successRate);
            gp.PutByte(0);
            gp.PutByte(totalSuccess);
            gp.PutFloat(unkFloat);

            creature.Client.Send(gp);
        }
Пример #15
0
        /// <summary>
        /// Sends FishingActionRequired to creature's client.
        /// </summary>
        /// <param name="creature"></param>
        /// <param name="catchSize"></param>
        /// <param name="time">The time you have to react.</param>
        /// <param name="fishSpeed">Fish speed for manual catching, 0 = no movement, 3+ = pretty challenging.</param>
        public static void FishingActionRequired(Creature creature, CatchSize catchSize, int time, float fishSpeed)
        {
            var packet = new Packet(Op.FishingActionRequired, creature.EntityId);
            packet.PutByte((byte)catchSize);
            packet.PutInt(time);
            packet.PutFloat(fishSpeed);

            creature.Client.Send(packet);
        }
Пример #16
0
		/// <summary>
		/// Broadcasts PlayDead in range of creature.
		/// </summary>
		/// <param name="creature"></param>
		public static void PlayDead(Creature creature)
		{
			var pos = creature.GetPosition();

			var packet = new Packet(Op.PlayDead, creature.EntityId);
			packet.PutByte(true); // ?
			packet.PutFloat(pos.X);
			packet.PutFloat(pos.Y);
			packet.PutInt(5000);

			creature.Region.Broadcast(packet, creature);
		}
Пример #17
0
		/// <summary>
		/// Broadcasts Effect in range of creature, with the given packet id.
		/// </summary>
		/// <remarks>
		/// Parameters have to be casted to the proper type, use carefully!
		/// </remarks>
		/// <param name="id"></param>
		/// <param name="entity"></param>
		/// <param name="delay">Delay in milliseconds</param>
		/// <param name="effectId"></param>
		/// <param name="parameters"></param>
		public static void EffectDelayed(long id, Entity entity, int delay, int effectId, params object[] parameters)
		{
			var packet = new Packet(Op.EffectDelayed, id);
			packet.PutInt(delay);
			packet.PutInt(effectId);
			foreach (var p in parameters)
			{
				if (p is byte) packet.PutByte((byte)p);
				else if (p is bool) packet.PutByte((bool)p);
				else if (p is short) packet.PutShort((short)p);
				else if (p is ushort) packet.PutUShort((ushort)p);
				else if (p is int) packet.PutInt((int)p);
				else if (p is uint) packet.PutUInt((uint)p);
				else if (p is long) packet.PutLong((long)p);
				else if (p is ulong) packet.PutULong((ulong)p);
				else if (p is float) packet.PutFloat((float)p);
				else if (p is string) packet.PutString((string)p);
				else
					throw new Exception("Unsupported effect parameter: " + p.GetType());
			}

			entity.Region.Broadcast(packet, entity);
		}
Пример #18
0
		/// <summary>
		/// Sends StabilityMeterUpdate to receiver, containing meter information
		/// of creature.
		/// </summary>
		/// <param name="receiver"></param>
		/// <param name="creature"></param>
		public static void StabilityMeterUpdate(Creature receiver, Creature creature)
		{
			var packet = new Packet(Op.StabilityMeterUpdate, receiver.EntityId);
			packet.PutLong(creature.EntityId);
			packet.PutFloat(creature.Stability);
			packet.PutByte(1);

			receiver.Client.Send(packet);
		}
Пример #19
0
		/// <summary>
		/// Sends StatUpdatePublic to creature's in range,
		/// or StatUpdatePrivate to creature's client.
		/// </summary>
		/// <remarks>
		/// In private mode this packet has simply 4 lists.
		/// - A list of stats and their (new) values.
		/// - A list of (new) regens.
		/// - A list of regens to remove (by id).
		/// - A list of regens to update, with new change and max values.
		/// (The last one is speculation.)
		/// Since it's private, it's only sent to the creature's client,
		/// and they get every stat and regen.
		/// 
		/// In public mode the same information is sent, but limited to stats
		/// like life, that's required for displaying life bars for others.
		/// It also has 3 more lists, that seem to do almost the same as the
		/// last 3 of private, regens, removing, and updating.
		/// - Some regens are sent in the first list, some in the second.
		///   (Like life vs injuries when using Rest.)
		/// - Regens that are to be removed are sent in both lists.
		/// - Updates are only sent in the first list.
		/// More research is required, to find out what the second lists
		/// actually do.
		/// </remarks>
		public static void StatUpdate(Creature creature, StatUpdateType type, ICollection<Stat> stats, ICollection<StatRegen> regens, ICollection<StatRegen> regensRemove, ICollection<StatRegen> regensUpdate)
		{
			var packet = new Packet(type == StatUpdateType.Public ? Op.StatUpdatePublic : Op.StatUpdatePrivate, creature.EntityId);
			packet.PutByte((byte)type);

			// Stats
			if (stats == null)
				packet.PutInt(0);
			else
			{
				packet.PutInt(stats.Count);
				foreach (var stat in stats)
				{
					packet.PutInt((int)stat);
					switch (stat)
					{
						case Stat.Height: packet.PutFloat(creature.Height); break;
						case Stat.Weight: packet.PutFloat(creature.Weight); break;
						case Stat.Upper: packet.PutFloat(creature.Upper); break;
						case Stat.Lower: packet.PutFloat(creature.Lower); break;

						case Stat.CombatPower: packet.PutFloat(creature.CombatPower); break;
						case Stat.Level: packet.PutShort(creature.Level); break;
						case Stat.AbilityPoints: packet.PutShort(creature.AbilityPoints); break;
						case Stat.Experience: packet.PutLong(AuraData.ExpDb.CalculateRemaining(creature.Level, creature.Exp) * 1000); break;

						case Stat.Life: packet.PutFloat(creature.Life); break;
						case Stat.LifeMax: packet.PutFloat(creature.LifeMaxBaseTotal); break;
						case Stat.LifeMaxMod: packet.PutFloat(creature.StatMods.Get(Stat.LifeMaxMod)); break;
						case Stat.LifeInjured: packet.PutFloat(creature.LifeInjured); break;
						case Stat.LifeMaxFoodMod: packet.PutFloat(creature.LifeFoodMod); break;
						case Stat.Mana: packet.PutFloat(creature.Mana); break;
						case Stat.ManaMax: packet.PutFloat(creature.ManaMaxBaseTotal); break;
						case Stat.ManaMaxMod: packet.PutFloat(creature.StatMods.Get(Stat.ManaMaxMod)); break;
						case Stat.ManaMaxFoodMod: packet.PutFloat(creature.ManaFoodMod); break;
						case Stat.Stamina: packet.PutFloat(creature.Stamina); break;
						case Stat.Hunger: packet.PutFloat(creature.StaminaHunger); break;
						case Stat.StaminaMax: packet.PutFloat(creature.StaminaMaxBaseTotal); break;
						case Stat.StaminaMaxMod: packet.PutFloat(creature.StatMods.Get(Stat.StaminaMaxMod)); break;
						case Stat.StaminaMaxFoodMod: packet.PutFloat(creature.StaminaFoodMod); break;

						case Stat.StrMod: packet.PutFloat(creature.StatMods.Get(Stat.StrMod)); break;
						case Stat.DexMod: packet.PutFloat(creature.StatMods.Get(Stat.DexMod)); break;
						case Stat.IntMod: packet.PutFloat(creature.StatMods.Get(Stat.IntMod)); break;
						case Stat.LuckMod: packet.PutFloat(creature.StatMods.Get(Stat.LuckMod)); break;
						case Stat.WillMod: packet.PutFloat(creature.StatMods.Get(Stat.WillMod)); break;
						case Stat.Str: packet.PutFloat(creature.StrBaseTotal); break;
						case Stat.Int: packet.PutFloat(creature.IntBaseTotal); break;
						case Stat.Dex: packet.PutFloat(creature.DexBaseTotal); break;
						case Stat.Will: packet.PutFloat(creature.WillBaseTotal); break;
						case Stat.Luck: packet.PutFloat(creature.LuckBaseTotal); break;
						case Stat.StrFoodMod: packet.PutFloat(creature.StrFoodMod); break;
						case Stat.DexFoodMod: packet.PutFloat(creature.DexFoodMod); break;
						case Stat.IntFoodMod: packet.PutFloat(creature.IntFoodMod); break;
						case Stat.LuckFoodMod: packet.PutFloat(creature.LuckFoodMod); break;
						case Stat.WillFoodMod: packet.PutFloat(creature.WillFoodMod); break;

						case Stat.DefenseBase: packet.PutShort((short)creature.DefenseBase); break;
						case Stat.ProtectionBase: packet.PutFloat(creature.ProtectionBase); break;
						case Stat.DefenseBaseMod: packet.PutShort((short)(creature.DefenseBaseModClient); break; //Since client already updates Defense, remove the STR defense from showing if combat renewal is off.
						case Stat.ProtectionBaseMod: packet.PutFloat(creature.ProtectionBaseMod); break;
						case Stat.DefenseMod: packet.PutShort((short)creature.DefenseMod); break;
						case Stat.ProtectionMod: packet.PutFloat(creature.ProtectionMod); break;

						case Stat.BalanceBase: packet.PutShort((short)(creature.BalanceBase)); break;
						case Stat.BalanceBaseMod: packet.PutShort((short)(creature.BalanceBaseMod)); break;

						case Stat.RightBalanceMod: packet.PutShort((short)creature.RightBalanceMod); break;
						case Stat.LeftBalanceMod: packet.PutShort((short)creature.LeftBalanceMod); break;

						case Stat.CriticalBase: packet.PutFloat(creature.CriticalBase); break;
						case Stat.CriticalBaseMod: packet.PutFloat(creature.CriticalBaseMod); break;

						case Stat.RightCriticalMod: packet.PutFloat(creature.RightCriticalMod); break;
						case Stat.LeftCriticalMod: packet.PutFloat(creature.LeftCriticalMod); break;

						case Stat.AttackMinBase: packet.PutShort((short)creature.AttackMinBase); break;
						case Stat.AttackMaxBase: packet.PutShort((short)creature.AttackMaxBase); break;

						case Stat.AttackMinBaseMod: packet.PutShort((short)creature.AttackMinBaseMod); break;
						case Stat.AttackMaxBaseMod: packet.PutShort((short)creature.AttackMaxBaseMod); break;

						case Stat.AttackMinMod: packet.PutShort((short)creature.AttackMinMod); break;
						case Stat.AttackMaxMod: packet.PutShort((short)creature.AttackMaxMod); break;

						case Stat.RightAttackMinMod: packet.PutShort((short)creature.RightAttackMinMod); break;
						case Stat.RightAttackMaxMod: packet.PutShort((short)creature.RightAttackMaxMod); break;

						case Stat.LeftAttackMinMod: packet.PutShort((short)creature.LeftAttackMinMod); break;
						case Stat.LeftAttackMaxMod: packet.PutShort((short)creature.LeftAttackMaxMod); break;

						case Stat.InjuryMinBaseMod: packet.PutShort((short)creature.InjuryMinBaseMod); break;
						case Stat.InjuryMaxBaseMod: packet.PutShort((short)creature.InjuryMaxBaseMod); break;

						case Stat.Age: packet.PutShort((short)creature.Age); break;

						// Client might crash with a mismatching value, 
						// take a chance and put an int by default.
						default:
							Log.Warning("StatUpdate: Unknown stat '{0}'.", stat);
							packet.PutInt(0);
							break;
					}
				}
			}

			// Regens
			if (regens == null)
				packet.PutInt(0);
			else
			{
				packet.PutInt(regens.Count);
				foreach (var regen in regens)
					packet.AddRegen(regen);
			}

			// Regens to Remove
			if (regensRemove == null)
				packet.PutInt(0);
			else
			{
				packet.PutInt(regensRemove.Count);
				foreach (var regen in regensRemove)
					packet.PutInt(regen.Id);
			}

			// ?
			// Maybe update of change and max?
			if (regensUpdate == null)
				packet.PutInt(0);
			else
			{
				packet.PutInt(regensUpdate.Count);
				foreach (var regen in regensUpdate)
				{
					packet.PutInt(regen.Id);
					packet.PutFloat(regen.Change);
					packet.PutFloat(regen.Max);
				}
			}

			if (type == StatUpdateType.Public)
			{
				// Another list of regens...?
				packet.PutInt(0);

				if (regensRemove == null)
					packet.PutInt(0);
				else
				{
					// Regens to Remove (again...?)
					packet.PutInt(regensRemove.Count);
					foreach (var regen in regensRemove)
						packet.PutInt(regen.Id);
				}

				// Update?
				packet.PutInt(0);
			}

			if (type == StatUpdateType.Private)
				creature.Client.Send(packet);
			else if (creature.Region != Region.Limbo)
				creature.Region.Broadcast(packet, creature);
		}