Example #1
0
        // Writes approximately: (100 + info._Stats.Count * 8 + info.EffectsList.Count * 6 + info.SpellId > 0 ? 8 : 1 + info.Type == 23 ? info.Crafts.Count * 3 : 1 + info.Description.Length + info.TalismanSlots * 47)
        public static void BuildItem(ref PacketOut Out, Item itm, Item_Info info, MailItem mail, ushort SlotId, ushort Count, Player Plr = null, bool frombuildrepairitem = false)
        {
            SlotId = SlotId == 0 ? (itm?.SlotId ?? SlotId) : SlotId;
            Count  = Count == 0 ? (itm?.Count ?? Count) : Count;
            info   = info ?? itm?.Info;
            bool lootbag = false;



            if (mail != null)
            {
                info = ItemService.GetItem_Info(mail.id);
            }

            if (SlotId != 0 && !frombuildrepairitem)
            {
                Out.WriteUInt16(SlotId);
            }

            if (info != null && info.Entry >= 2500000 && info.Entry < 2600000)
            {
                BuildRepairableItem(ref Out, itm, info, mail, SlotId, Count, Plr);
                return;
            }
            if (!frombuildrepairitem)
            {
                Out.WriteByte(0); // repairable item
            }
            Out.WriteUInt32(info?.Entry ?? 0);

            if (info == null)
            {
                return;
            }

            //if (info.Bind == 1 || (info.Bind == 2 && itm != null && itm.BoundtoPlayer))
            //    Out.WriteUInt32(info.Entry << 2);
            //else
            //    Out.WriteUInt32(info.Entry);

            if (info.Entry == 9980 || info.Entry == 9940 || info.Entry == 9941 || info.Entry == 9942 || info.Entry == 9943)      // lootbags
            {
                lootbag = true;
            }


            Out.WriteUInt16((ushort)info.ModelId);      // Valid 1.4.8

            //Appearance
            if (itm != null && itm.AltAppearanceEntry > 0 && itm.Info.Type != 24)
            {
                Item_Info tmp = ItemService.GetItem_Info(itm.AltAppearanceEntry);

                if (tmp == null)
                {
                    itm.AltAppearanceEntry = 0;
                    Out.Fill(0, 7);
                }
                else
                {
                    Out.WriteUInt16((ushort)tmp.ModelId);    // DisplayId
                    Out.WriteUInt32(itm.AltAppearanceEntry); // Id
                    Out.WritePascalString(tmp.Name);         //name
                }
            }
            else
            {
                Out.Fill(0, 7);
            }

            Out.WriteUInt16(info.SlotId);      // Valid 1.4.8
            Out.WriteByte(info.Type);          // Valid 1.4.8

            Out.WriteByte(info.MinRank);       // Min Level
            Out.WriteByte(info.ObjectLevel);   // 1.3.5, Object Level
            Out.WriteByte(info.MinRenown);     // 1.3.5, Min Renown
            Out.WriteByte(info.MinRenown);     // ?
            Out.WriteByte(info.UniqueEquiped); // Unique - Equiped

            Out.WriteByte(info.Rarity);
            Out.WriteByte(info.Bind);      // This byte should be part of race byte
            Out.WriteByte(info.Race);


            // Trophys have some extra bytes
            if (info.Type == (byte)ItemTypes.ITEMTYPES_TROPHY)
            {
                Out.WriteUInt32(0);
                Out.WriteUInt16(0x00);
            }

            if (info.Type == (byte)ItemTypes.ITEMTYPES_ENHANCEMENT)
            {
                Out.WriteUInt32(0);
            }

            if (SlotId != 0 && info.Type == 24)     // Trophy
            {
                Out.WriteUInt16(0);
                Out.WriteUInt16((ushort)itm.AltAppearanceEntry);
            }
            else
            {
                Out.WriteUInt32(info.Career);
            }


            Out.WriteUInt16(info.BaseColor1);      // basecolor
            Out.WriteUInt16(info.BaseColor2);


            Out.WriteUInt32(info.SellPrice);

            Out.WriteUInt16(info.MaxStack);

            if (mail != null)
            {
                Out.WriteUInt16((ushort)(mail.count > 0 ? mail.count : 1));
            }
            else
            {
                Out.WriteUInt16((ushort)(Count > 0 ? Count : 1));
            }

            Out.WriteUInt32(info.ItemSet);

            Out.WriteUInt32(info.Skills);                          // Valid 1.4.8
            Out.WriteUInt16(info.Dps > 0 ? info.Dps : info.Armor); // Valid 1.4.8
            Out.WriteUInt16(info.Speed);                           // Valid 1.4.8

            Out.WritePascalString(info.Name);                      // Valid 1.4.8  + (info.Bind == 1 || (info.Bind == 2 && itm != null && itm.BoundtoPlayer) ? "_" : "" )

            //66 Bytes + info.Name.Length

            Out.WriteByte((byte)info._Stats.Count);      // Valid 1.4.8
            foreach (KeyValuePair <byte, ushort> Key in info._Stats)
            {
                if (Key.Key == (byte)Stats.AutoAttackSpeed)
                {
                    Out.WriteByte(Key.Key);
                    Out.WriteUInt16(Key.Value);
                    Out.Fill(1, 5);
                }
                else
                {
                    Out.WriteByte(Key.Key);
                    Out.WriteUInt16(Key.Value);
                    Out.Fill(0, 5);
                }
            }

            Out.WriteByte((byte)info.EffectsList.Count);
            foreach (ushort effect in info.EffectsList)
            {
                Out.WriteUInt16(effect);
                Out.WriteUInt32(0);
            }

            if (info.SpellId == 0)
            {
                Out.WriteByte(0);
            }
            else
            {
                Out.WriteByte(1);     // (byte)info._Spells.Count OK

                Out.WriteUInt32(info.SpellId);
                Out.WriteUInt16(AbilityMgr.GetCooldownFor(info.SpellId));       // cooldown time info

                if (Plr == null || itm?.CharSaveInfo == null)
                {
                    Out.WriteUInt16(0);       // current cooldown
                }
                else
                {
                    Out.WriteUInt16(itm.CharSaveInfo.RemainingCooldown);
                }
            }

            // (uint32)entry, uint16 X, uint16 Y

            if (info.Type == 23)       // talisman use craft to store its buff type
            {
                Out.WriteByte(0);
            }
            else
            {
                Out.WriteByte((byte)info._Crafts.Count);     // OK
                foreach (KeyValuePair <byte, ushort> Kp in info._Crafts)
                {
                    Out.WriteByte(Kp.Key);
                    Out.WriteUInt16(Kp.Value);
                }
            }
            Out.WriteByte(0);     // ??

            if (lootbag)
            {
                Out.WriteByte(0);
            }
            else
            {
                Out.WriteByte(info.TalismanSlots);
                Talisman talis = null;
                for (int i = 0; i < info.TalismanSlots; ++i)
                {
                    if (itm != null)
                    {
                        talis = itm.GetTalisman((byte)i);
                    }
                    else if (mail != null)
                    {
                        talis = mail.GetTalisman((byte)i);
                    }

                    if (talis == null)
                    {
                        Out.WriteUInt32(0);     // entry;
                    }
                    else
                    {
                        Item_Info talismanInfo = ItemService.GetItem_Info(talis.Entry);

                        // Out.Fill(0, 2);

                        Out.WriteByte(0);     // slot ???
                        Out.WriteByte(0);
                        Out.WriteUInt16((ushort)talismanInfo.ModelId);
                        Out.WriteByte(talis.Fused);     // 0 fused 1 unfused
                        Out.WriteByte(0);
                        Out.WritePascalString(talismanInfo.Name);
                        Out.WriteByte((byte)talismanInfo._Stats.Count);     // Valid 1.4.8
                        foreach (KeyValuePair <byte, ushort> Key in talismanInfo._Stats)
                        {
                            Out.WriteByte(Key.Key);
                            Out.WriteUInt16(Key.Value);
                            Out.WriteUInt32(talis.Timer);
                            Out.WriteByte(0);
                            //  Out.Fill(0, 5);
                        }
                        Out.WriteByte((byte)talismanInfo.EffectsList.Count);
                        foreach (ushort effect in talismanInfo.EffectsList)
                        {
                            Out.WriteUInt16(effect);
                            Out.WriteUInt32(0);
                        }
                        //if (talismanInfo.SpellId == 0)
                        //    Out.WriteByte(0);
                        //else
                        //{
                        //    Out.WriteByte(1); // (byte)talismanInfo._Spells.Count

                        //    Out.WriteUInt16(talismanInfo.SpellId);
                        //    Out.WriteUInt32(AbilityMgr.GetCooldownFor(talismanInfo.SpellId));
                        //}
                        Out.Fill(0, 3);
                        Out.WriteUInt16(0x041C);
                    }
                }
            }

            Out.WritePascalString(info.Description);

            // Note from wash : this algorithm updates shared

            byte[] Unks = info.Unk27;

            //if (info.Bind == 1 && (itm == null || !itm.BoundtoPlayer))
            //    Unks[5] = (byte)(4);  // bind on pickup, if set to true for one item, all items with have this flag active client side
            //else if (info.Bind == 2 && (itm == null || !itm.BoundtoPlayer)) //
            //    Unks[5] = (byte)(8);   // bind on equip, if set to true for one item, all items with have this flag active client side
            //else
            //    Unks[5] = 0;

            //Unks[5] = 8;

            if (info.DyeAble)
            {
                Unks[6] = (byte)(Unks[6] | 1);     // dyeable
            }
            if (info.Salvageable)
            {
                Unks[6] = (byte)(Unks[6] | 2);     // scavangable
            }
            // Prevents sale
            //   Unks[6] = (byte) (Unks[6] | 32);
            // Allow Conversion text (Ctrl+Right Click)
            //   Unks[6] = (byte) (Unks[6] | 128);


            //if (itm != null && itm.BoundtoPlayer) // info.Bind == 1
            //    Unks[8] = (byte)(1); // bound to player, if set to true for one item, all items with have this flag active client side
            //else
            //    Unks[8] = (byte)(0);


            Out.WriteByte(Unks[0]);     // londo : wut ?
            Out.WriteByte(Unks[1]);     // londo : getUnk7
            Out.WriteByte(Unks[2]);     // londo : getUnk8
            Out.WriteByte(Unks[3]);     // londo : getNoChargeLeftDontDelete
            Out.WriteByte(Unks[4]);     // londo : flag count

            if (info.Bind == 1 && (itm == null || !itm.BoundtoPlayer))
            {
                Out.WriteByte(4);                                           // bind on pickup, if set to true for one item, all items with have this flag active client side
            }
            else if (info.Bind == 2 && (itm == null || !itm.BoundtoPlayer)) //
            {
                Out.WriteByte(8);                                           // bind on equip, if set to true for one item, all items with have this flag active client side
            }
            else
            {
                Out.WriteByte(0);
            }

            Out.WriteByte(Unks[6]);     // dyeable from londo (+ scavangable from RoR ?)
            Out.WriteByte(Unks[7]);     // 0 from londo

            if (info.Bind == 2 && itm != null && itm.BoundtoPlayer)
            {
                Out.WriteByte(1);
            }
            else
            {
                Out.WriteByte(0);
            }

            //Unks[19] = (byte)(Unks[19] | 5); // potion cd

            // 4 can crash the client if changed
            // 5: if 1, hides the crafting level requirement. if 2, shows it.
            // 7 with value of 8 can suppress the Item Level text
            //for (int i = 0; i < 9; i++) //9
            //{
            //    Out.WriteByte(Unks[i]);
            //}

            if (lootbag)
            {
                Out.WriteUInt16(0);
                Out.WriteUInt16(0);
            }
            else
            {
                if (mail != null)
                {
                    Out.WriteUInt16(mail.primary_dye);
                    Out.WriteUInt16(mail.secondary_dye);
                }
                else
                {
                    Out.WriteUInt16(itm?.GetPrimaryDye() ?? 0);
                    Out.WriteUInt16(itm?.GetSecondaryDye() ?? 0);
                }
            }

            // Overwrite Unks27 with the TwoHanded flag
            if (info.TwoHanded)
            {
                Unks[26] = (byte)(Unks[26] | 1);     // bitwise? oh well better to be safe.
            }
            if ((info.SlotId == 14 || info.SlotId == 27) && Plr?.GldInterface.Guild != null)
            {
                Out.Fill(0, 7);
                Out.WriteByte(1);     // 1, Out, 1, 2
                Plr.GldInterface.Guild.BuildHeraldry(Out);
                Out.WriteByte(1);
                Out.WriteByte(1);
                Out.Fill(0, 6);
            }
            else
            {
                // 14: Skill level
                // 15: Flags for Cultivating
                // 20: Crashes the client if nonzero... is set on the Fleet Stag Mantle
                // 21-24: Seconds until decayed
                // 26: two-handed flag
                for (int i = 13; i < /*21*/ 27; i++)
                {
                    Out.WriteByte(Unks[i]);
                }

                /*
                 * 21-26:
                 * Out.WriteUInt32(0); // Seconds until decayed. Set on the Stag Mantle but doesn't show, possible double meaning based on value 20
                 *
                 * Out.WriteByte(Unks[25]);
                 * Out.WriteByte(Unks[26]);
                 */
            }


            //Out.Write(Unks);

            /*Out.WriteByte(0);
             * Out.WriteByte(0);
             * Out.WriteByte(0);
             * Out.WriteByte(0);
             *
             * Out.WriteUInt16(0x0302);
             *
             * Out.Fill(0, 8);
             * Out.WriteByte(0); // Type , Culture, etc etc
             * Out.WriteByte(0); // Type, Recipian , Soil , etc etc
             * Out.Fill(0, 11);*/
        }