Code:
public static void Text(GameClient Client, string str_text)
{
str_text = str_text.Replace("~", " ") + "\n";
const int BaseSize = 0x11;
byte* ptr = stackalloc byte[BaseSize];
NpcClickPacket* Reply;
Reply = NpcClickPacket.Create(ptr, str_text.Length);
Reply->ResponseID = NpcClickID.Dialogue;
Reply->Input = str_text;
Client.Send(Reply);
}
public static void Avatar(GameClient Client, ushort str_avatar)
{
const int BaseSize = 0x11;
byte* ptr = stackalloc byte[BaseSize];
NpcClickPacket* Reply;
Reply = NpcClickPacket.Create(ptr, 0);
Reply->ResponseID = NpcClickID.Avatar;
Reply->Avatar = str_avatar;
Client.Send(Reply);
}
public static void Link(GameClient Client, string str_text, byte link)
{
str_text = str_text.Replace("~", " ") + "\n";
const int BaseSize = 0x11;
byte* ptr = stackalloc byte[BaseSize];
NpcClickPacket* Reply;
Reply = NpcClickPacket.Create(ptr, str_text.Length);
Reply->ResponseID = NpcClickID.Option;
Reply->OptionID = link;
Reply->Input = str_text;
Client.Send(Reply);
}
public static void Input(GameClient Client, string str_text, byte link)
{
const int BaseSize = 0x11;
byte* ptr = stackalloc byte[BaseSize];
NpcClickPacket* Reply;
Reply = NpcClickPacket.Create(ptr, 0);
Reply->ResponseID = NpcClickID.Input;
Reply->MaxInputLength = (ushort)str_text.Length;
Reply->OptionID = link;
Client.Send(Reply);
}
public static void Finish(GameClient Client)
{
const int BaseSize = 0x11;
byte* ptr = stackalloc byte[BaseSize];
NpcClickPacket* Reply;
Reply = NpcClickPacket.Create(ptr, 0);
Reply->ResponseID = NpcClickID.Finish;
Reply->DontDisplay = false;
Client.Send(Reply);
}
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ConquerServer_v2.Packet_Structures
{
public enum NpcClickID : byte
{
None = 0x00,
Dialogue = 0x01,
Option = 0x02,
Input = 0x03,
Avatar = 0x04,
Finish = 0x64,
DeleteGuildMember = 0x66
}
[StructLayout(LayoutKind.Explicit)]
/// <summary>
/// 0x7EF (Client->Server),
/// 0x7F0 (Client->Server)
///
/// </summary>
public unsafe struct NpcClickPacket
{
[FieldOffset(0)]
public ushort Size;
[FieldOffset(2)]
public ushort Type;
[FieldOffset(4)]
public uint NpcID;
[FieldOffset(8)]
public ushort Avatar;
[FieldOffset(8)]
public ushort MaxInputLength;
[FieldOffset(10)]
public byte OptionID;
[FieldOffset(11)]
public NpcClickID ResponseID;
[FieldOffset(12)]
public bool DontDisplay;
[FieldOffset(13)]
public byte InputLength;
[FieldOffset(14)]
private sbyte szInput;
public string Input
{
get { fixed (sbyte* ptr = &szInput) { return new string(ptr, 0, InputLength); } }
set { fixed (sbyte* ptr = &szInput) { value.CopyTo(ptr); } }
}
/// <summary>
/// Initializes a memory-block to be a NpcClickPacket, of type 0x7F0
/// </summary>
/// <param name="Ptr">The memory-block (make sure this has sufficient size for your string).</param>
/// <param name="TextLength">The length of your input string.</param>
/// <returns></returns>
public static NpcClickPacket* Create(void* Ptr, int TextLength)
{
NpcClickPacket* packet = (NpcClickPacket*)Ptr;
packet->Size = (ushort)(0x11 + TextLength);
packet->Type = 0x7F0;
packet->OptionID = 0xFF;
packet->DontDisplay = true;
packet->InputLength = (byte)TextLength;
return packet;
}
}
}
Original code in the source:
Code:
public static int Dialog(INpcPlayer Player, string[] Dlg)
{
const int BaseSize = 0x11;
byte* ptr = stackalloc byte[BaseSize];
int string_size = 0;
NpcClickPacket* Reply;
foreach (string parse_dlg in Dlg)
{
if (parse_dlg.StartsWith("AVATAR"))
{
string str_avatar = parse_dlg.Substring(7, parse_dlg.Length - 7);
Reply = NpcClickPacket.Create(ptr, 0);
Reply->ResponseID = NpcClickID.Avatar;
Reply->Avatar = ushort.Parse(str_avatar);
Player.Send(Reply);
}
else if (parse_dlg.StartsWith("TEXT"))
{
string str_text = parse_dlg.Substring(5, parse_dlg.Length - 5);
if (string_size < str_text.Length)
{
string_size = str_text.Length;
byte* temp = stackalloc byte[BaseSize + string_size];
ptr = temp;
}
Reply = NpcClickPacket.Create(ptr, str_text.Length);
Reply->ResponseID = NpcClickID.Dialogue;
Reply->Input = str_text;
Player.Send(Reply);
}
else if (parse_dlg.StartsWith("OPTION"))
{
string str_op_num = parse_dlg.Substring(6, parse_dlg.IndexOf(' ') - 6);
string str_op_text = parse_dlg.Substring(6 + str_op_num.Length + 1, parse_dlg.Length - 6 - str_op_num.Length - 1);
if (string_size < str_op_text.Length)
{
string_size = str_op_text.Length;
byte* temp = stackalloc byte[BaseSize + string_size];
ptr = temp;
}
Reply = NpcClickPacket.Create(ptr, str_op_text.Length);
Reply->ResponseID = NpcClickID.Option;
Reply->OptionID = (byte)short.Parse(str_op_num);
Reply->Input = str_op_text;
Player.Send(Reply);
}
else if (parse_dlg.StartsWith("INPUT"))
{
string str_in_num = parse_dlg.Substring(5, parse_dlg.IndexOf(' ') - 5);
string str_txt_len = parse_dlg.Substring(5 + str_in_num.Length + 1, parse_dlg.Length - 5 - str_in_num.Length - 1);
Reply = NpcClickPacket.Create(ptr, 0);
Reply->ResponseID = NpcClickID.Input;
Reply->MaxInputLength = ushort.Parse(str_txt_len);
Reply->OptionID = (byte)short.Parse(str_in_num);
Player.Send(Reply);
}
else if (parse_dlg.StartsWith("NOP"))
continue;
else
throw new ArgumentException("Failed to parse npc dialog statement `" + parse_dlg + "`");
}
Reply = NpcClickPacket.Create(ptr, 0);
Reply->ResponseID = NpcClickID.Finish;
Reply->DontDisplay = false;
Player.Send(Reply);
return 0;
}