/// <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); }
/// <summary> /// Sends EnterDynamicRegion to creature's client. /// </summary> /// <param name="creature"></param> /// <param name="warpFromRegionId"></param> /// <param name="warpToRegion"></param> public static void EnterDynamicRegion(Creature creature, int warpFromRegionId, Region warpToRegion, int x, int y) { var warpTo = warpToRegion as DynamicRegion; if (warpTo == null) throw new ArgumentException("EnterDynamicRegion requires a dynamic region."); var pos = creature.GetPosition(); var packet = new Packet(Op.EnterDynamicRegion, MabiId.Broadcast); packet.PutLong(creature.EntityId); packet.PutInt(warpFromRegionId); // creature's current region or 0? packet.PutInt(warpToRegion.Id); packet.PutString(warpToRegion.Name); // dynamic region name packet.PutUInt(0x80000000); // bitmask? (|1 = time difference?) packet.PutInt(warpTo.BaseId); packet.PutString(warpTo.BaseName); packet.PutInt(200); // 100|200 (100 changes the lighting?) packet.PutByte(0); // 1 = next is empty? packet.PutString("data/world/{0}/{1}", warpTo.BaseName, warpTo.Variation); packet.PutByte(0); //if (^ true) //{ // pp.PutByte(1); // pp.PutInt(3100); // some region id? //} packet.PutInt(x); // target x pos packet.PutInt(y); // target y pos creature.Client.Send(packet); }
/// <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); }
/// <summary> /// Sends ChannelLoginUnkR to creature's client. /// </summary> /// <param name="creature"></param> public static void ChannelLoginUnkR(Creature creature) { var packet = new Packet(Op.ChannelLoginUnkR, creature.EntityId); packet.PutByte(1); // success? packet.PutInt(0); packet.PutInt(0); creature.Client.Send(packet); }
/// <summary> /// Broadcasts Running|Walking in range of creature. /// </summary> public static void Move(Creature creature, Position from, Position to, bool walking) { var packet = new Packet(!walking ? Op.Running : Op.Walking, creature.EntityId); packet.PutInt(from.X); packet.PutInt(from.Y); packet.PutInt(to.X); packet.PutInt(to.Y); creature.Region.Broadcast(packet, creature); }
/// <summary> /// Sends message as response to login (LoginR). /// </summary> /// <param name="client"></param> /// <param name="format"></param> /// <param name="args"></param> public static void LoginR_Msg(LoginClient client, string format, params object[] args) { var packet = new Packet(Op.LoginR, MabiId.Login); packet.PutByte((byte)LoginResult.Message); packet.PutInt((int)LoginResultMessage.Custom); packet.PutInt(1); packet.PutString(format, args); client.Send(packet); }
/// <summary> /// Sends empty VehicleInfo in range of vehicle. /// </summary> /// <param name="vehicle"></param> public static void VehicleInfo(Creature vehicle) { var packet = new Packet(Op.VehicleInfo, vehicle.EntityId); packet.PutInt(0); packet.PutInt(1); packet.PutLong(vehicle.EntityId); packet.PutInt(32); packet.PutByte(0); vehicle.Region.Broadcast(packet, vehicle); }
/// <summary> /// Sends DyePaletteReqR to creature's client. /// </summary> /// <param name="creature"></param> /// <param name="var1"></param> /// <param name="var2"></param> /// <param name="var3"></param> /// <param name="var4"></param> public static void DyePaletteReqR(Creature creature, int var1, int var2, int var3, int var4) { var packet = new Packet(Op.DyePaletteReqR, creature.EntityId); packet.PutByte(true); packet.PutInt(var1); // PutInt(62); packet.PutInt(var2); // PutInt(123); packet.PutInt(var3); // PutInt(6); packet.PutInt(var4); // PutInt(238); creature.Client.Send(packet); }
/// <summary> /// Broadcasts new prop extension. /// </summary> /// <param name="prop"></param> /// <param name="ext"></param> public static void AddPropExtension(Prop prop, PropExtension ext) { var packet = new Packet(Op.AddPropExtension, prop.EntityId); packet.PutInt((int)ext.SignalType); packet.PutInt((int)ext.EventType); packet.PutString(ext.Name); packet.PutByte(ext.Mode); packet.PutString(ext.Value.ToString()); prop.Region.Broadcast(packet); }
/// <summary> /// Sends empty Weather packet to creature's client. /// </summary> public static void Weather(Creature creature, int regionId, int groupId) { var packet = new Packet(Op.Weather, MabiId.Broadcast); packet.PutByte(0); packet.PutInt(regionId); packet.PutByte(0); packet.PutInt(groupId); packet.PutByte(0); creature.Client.Send(packet); }
/// <summary> /// Sends SpecialLogin to creature's client. /// </summary> /// <remarks> /// One of those packets with a success parameter, /// that don't actually support failing. /// Sends character to a special, client-side-instanced region, /// where he is to meet the given NPC. EnterRegion isn't needed /// for this. /// </remarks> /// <param name="creature"></param> /// <param name="regionId"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="npcEntityId"></param> public static void SpecialLogin(Creature creature, int regionId, int x, int y, long npcEntityId) { var packet = new Packet(Op.SpecialLogin, MabiId.Channel); packet.PutByte(true); packet.PutInt(regionId); packet.PutInt(x); packet.PutInt(y); packet.PutLong(npcEntityId); packet.AddCreatureInfo(creature, CreaturePacketType.Private); creature.Client.Send(packet); }
/// <summary> /// Sends EnterRegion to creature's client. /// </summary> /// <param name="creature"></param> public static void EnterRegion(Creature creature, int regionId, int x, int y) { var pos = creature.GetPosition(); var packet = new Packet(Op.EnterRegion, MabiId.Channel); packet.PutLong(creature.EntityId); packet.PutByte(true); // success? packet.PutInt(regionId); packet.PutInt(x); packet.PutInt(y); creature.Client.Send(packet); }
/// <summary> /// Sends GmcpNpcListR to creature's client. /// </summary> /// <param name="creature"></param> /// <param name="success"></param> public static void GmcpNpcListR(Creature creature, ICollection<Creature> npcs) { var packet = new Packet(Op.GmcpNpcListR, creature.EntityId); packet.PutInt(npcs.Count); foreach (var npc in npcs) { packet.PutInt(npc.Race); // RaceId packet.PutString(npc.Name); // Name packet.PutString(npc.Name); // Local Name packet.PutString(npc.RegionId.ToString()); // Location } creature.Client.Send(packet); }
/// <summary> /// Sends positive PersonalShopSetUpR to creature's client. /// </summary> /// <param name="creature"></param> /// <param name="shopProp"></param> public static void PersonalShopSetUpR(Creature creature, Prop shopProp) { var location = shopProp.GetLocation(); var packet = new Packet(Op.PersonalShopSetUpR, creature.EntityId); packet.PutByte(true); packet.PutLong(shopProp.EntityId); packet.PutByte(1); // no location if 0? packet.PutInt(location.RegionId); packet.PutInt(location.X); packet.PutInt(location.Y); creature.Client.Send(packet); }
/// <summary> /// Sends GmcpNpcListR to creature's client. /// </summary> /// <param name="creature"></param> /// <param name="npcs"></param> public static void GmcpNpcListR(Creature creature, ICollection<Creature> npcs) { var packet = new Packet(Op.GmcpNpcListR, creature.EntityId); packet.PutInt(npcs.Count); foreach (var npc in npcs) { var pos = npc.GetPosition(); packet.PutInt(npc.RegionId); packet.PutString(npc.Name); // Name packet.PutString(npc.Name); // Local Name packet.PutString("{0} @ {1}/{2}", npc.RegionId, pos.X, pos.Y); // Location } creature.Client.Send(packet); }
/// <summary> /// Sends AcceptGiftR to client. /// </summary> /// <param name="client"></param> /// <param name="gift">Negative response if null</param> public static void AcceptGiftR(LoginClient client, Gift gift) { var packet = new Packet(Op.AcceptGiftR, MabiId.Login); packet.PutByte(gift != null); if (gift != null) { packet.PutByte(gift.IsCharacter); packet.PutInt(0); // ? packet.PutInt(0); // ? packet.PutInt(gift.Type); // ? } client.Send(packet); }
/// <summary> /// Sends TradeWait to creature's client. /// </summary> /// <param name="creature"></param> /// <param name="milliseconds"></param> public static void TradeWait(Creature creature, int milliseconds) { var packet = new Packet(Op.TradeWait, creature.EntityId); packet.PutInt(milliseconds); creature.Client.Send(packet); }
/// <summary> /// Sends Internal.ChannelStatus to login server. /// </summary> public static void Internal_ChannelStatus() { var cur = 0;// ChannelServer.Instance.World.GetCharactersCount(); var max = ChannelServer.Instance.Conf.Channel.MaxUsers; var packet = new Packet(Op.Internal.ChannelStatus, 0); packet.PutString(ChannelServer.Instance.Conf.Channel.ChannelServer); packet.PutString(ChannelServer.Instance.Conf.Channel.ChannelName); packet.PutString(ChannelServer.Instance.Conf.Channel.ChannelHost); packet.PutInt(ChannelServer.Instance.Conf.Channel.ChannelPort); packet.PutInt(cur); packet.PutInt(max); packet.PutInt((int)ChannelState.Normal); ChannelServer.Instance.LoginServer.Send(packet); }
/// <summary> /// Sends CharacterLockUpdate to creature's client. /// </summary> /// <remarks> /// The name of this op is guessed, based on its position in the op /// list and its behavior. Originally I thought this might change /// a lock's timeout time, to, for example, reduce the time until /// you can move again, after you attacked something, but after /// testing it, it seems like it actually completely resets the /// locks. /// /// The only known value for the byte is "18" (0x12), which doesn't /// match a known combination of locks, 0x10 being Run and 0x02 being /// unknown, however, 0x18 would be Run|Walk, which would match what /// it's doing. /// </remarks> /// <example> /// Resets movement stun? /// 001 [..............12] Byte : 18 /// 002 [........000005DC] Int : 1500 /// </example> public static void CharacterLockUpdate(Creature creature, byte unkByte, int unkInt) { var packet = new Packet(Op.CharacterLockUpdate, creature.EntityId); packet.PutByte(unkByte); packet.PutInt(unkInt); creature.Client.Send(packet); }
/// <summary> /// Sends PersonalShopCustomerPriceUpdate to creature's client. /// </summary> /// <param name="creature"></param> /// <param name="itemEntityId"></param> /// <param name="price"></param> public static void PersonalShopCustomerPriceUpdate(Creature creature, long itemEntityId, int price) { var packet = new Packet(Op.PersonalShopCustomerPriceUpdate, creature.EntityId); packet.PutLong(itemEntityId); packet.PutInt(price); creature.Client.Send(packet); }
/// <summary> /// Sends PointsUpdate to creature's client. /// </summary> /// <remarks> /// Points = Pon /// </remarks> /// <param name="creature"></param> public static void PointsUpdate(Creature creature, int ponsAmount) { var packet = new Packet(Op.PointsUpdate, MabiId.Channel); packet.PutByte(2); packet.PutInt(ponsAmount); creature.Client.Send(packet); }
/// <summary> /// Broadcasts AssignSittingProp in range of creature. /// </summary> /// <remarks> /// Moves creature into position, to sit down on the prop. /// Pass 0 for the parameters to undo. /// </remarks> /// <param name="creature"></param> /// <param name="propEntityId"></param> /// <param name="unk"></param> public static void AssignSittingProp(Creature creature, long propEntityId, int unk) { var packet = new Packet(Op.AssignSittingProp, creature.EntityId); packet.PutLong(propEntityId); packet.PutInt(unk); creature.Region.Broadcast(packet); }
/// <summary> /// Sends AcquireInfo2 to creature's client. /// </summary> /// <param name="creature"></param> /// <param name="itemEntityId"></param> public static void AcquireFixedDyedItemInfo(Creature creature, long itemEntityId) { var packet = new Packet(Op.AcquireInfo2, creature.EntityId); packet.PutString("<xml type='fixed_color_dyeing' objectid='{0}'/>", itemEntityId); packet.PutInt(3000); creature.Client.Send(packet); }
/// <summary> /// Sends AcquireInfo2 to creature's client. /// </summary> /// <param name="creature"></param> /// <param name="itemEntityId"></param> /// <param name="selected"></param> public static void AcquireDyedItemInfo(Creature creature, long itemEntityId, byte selected) { var packet = new Packet(Op.AcquireInfo2, creature.EntityId); packet.PutString("<xml type='dyeing' objectid='{0}' selected='{1}'/>", itemEntityId, selected); packet.PutInt(3000); creature.Client.Send(packet); }
/// <summary> /// Sends AcquireInfo to creature's client. /// </summary> /// <param name="creature"></param> /// <param name="itemId"></param> /// <param name="amount"></param> public static void AcquireItemInfo(Creature creature, int itemId, int amount) { var packet = new Packet(Op.AcquireInfo, creature.EntityId); packet.PutString("<xml type='item' classid='{0}' value='{1}'/>", itemId, amount); packet.PutInt(3000); creature.Client.Send(packet); }
/// <summary> /// Sends CharacterLock to creature's client. /// </summary> public static void CharacterLock(Creature creature, Locks type) { var packet = new Packet(Op.CharacterLock, creature.EntityId); packet.PutUInt((uint)type); packet.PutInt(0); creature.Client.Send(packet); }
/// <summary> /// Broadcasts ChatSticker in range of creature, activating the sticker. /// </summary> /// <param name="creature"></param> /// <param name="sticker"></param> /// <param name="end"></param> public static void ChatSticker(Creature creature, ChatSticker sticker, DateTime end) { var packet = new Packet(Op.ChatSticker, creature.EntityId); packet.PutInt((int)sticker); packet.PutLong(end); creature.Region.Broadcast(packet, creature); }
/// <summary> /// Broadcasts PetAction in range of pet. /// </summary> /// <param name="pet"></param> /// <param name="action"></param> public static void PetActionEffect(Creature pet, PetAction action) { var packet = new Packet(Op.Effect, pet.EntityId); packet.PutInt(E.PetAction); packet.PutLong(pet.Master.EntityId); packet.PutByte((byte)action); packet.PutByte(0); pet.Region.Broadcast(packet, pet); }
/// <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); }
/// <summary> /// Broadcasts ForceRunTo in creature's range. /// </summary> /// <param name="creature"></param> /// <param name="to"></param> public static void ForceRunTo(Creature creature, Position to) { var pos = creature.GetPosition(); var packet = new Packet(Op.ForceRunTo, creature.EntityId); // From packet.PutInt(pos.X); packet.PutInt(pos.Y); // To packet.PutInt(to.X); packet.PutInt(to.Y); packet.PutByte(1); packet.PutByte(0); creature.Region.Broadcast(packet, creature); }