PageRenderTime 56ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/Scripts/Gumps/AProperties/APropsGump.cs

https://bitbucket.org/Kel/crepuscule
C# | 1130 lines | 939 code | 181 blank | 10 comment | 390 complexity | e86a8e8b4d447f10bcb3e83c6de24196 MD5 | raw file
  1. using System;
  2. using System.Reflection;
  3. using System.Collections;
  4. using Server;
  5. using Server.Network;
  6. using Server.Menus;
  7. using Server.Menus.Questions;
  8. using Server.Targeting;
  9. using CPA = Server.CommandPropertyAttribute;
  10. using Server.GenericCommands;
  11. using System.Linq;
  12. using System.Collections.Generic;
  13. using Server.Scripts.Commands;
  14. using Server.Scripts.Gumps;
  15. using Server.Guilds;
  16. using Server.Engines.Craft;
  17. using Server.Engines;
  18. namespace Server.Gumps
  19. {
  20. public class APropertiesGump : Gump
  21. {
  22. private ArrayList m_List;
  23. private int m_Page;
  24. private Mobile m_Mobile;
  25. private object m_Object;
  26. private Stack m_Stack;
  27. public static readonly bool OldStyle = PropsConfig.OldStyle;
  28. public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX;
  29. public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY;
  30. public static readonly int TextHue = PropsConfig.TextHue;
  31. public static readonly int TextOffsetX = PropsConfig.TextOffsetX;
  32. public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID;
  33. public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID;
  34. public static readonly int EntryGumpID = PropsConfig.EntryGumpID;
  35. public static readonly int BackGumpID = PropsConfig.BackGumpID;
  36. public static readonly int SetGumpID = PropsConfig.SetGumpID;
  37. public static readonly int SetWidth = PropsConfig.SetWidth;
  38. public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY;
  39. public static readonly int SetButtonID1 = PropsConfig.SetButtonID1;
  40. public static readonly int SetButtonID2 = PropsConfig.SetButtonID2;
  41. public static readonly int PrevWidth = PropsConfig.PrevWidth;
  42. public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY;
  43. public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1;
  44. public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2;
  45. public static readonly int NextWidth = PropsConfig.NextWidth;
  46. public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY;
  47. public static readonly int NextButtonID1 = PropsConfig.NextButtonID1;
  48. public static readonly int NextButtonID2 = PropsConfig.NextButtonID2;
  49. public static readonly int OffsetSize = PropsConfig.OffsetSize;
  50. public static readonly int EntryHeight = PropsConfig.EntryHeight;
  51. public static readonly int BorderSize = PropsConfig.BorderSize;
  52. private static bool PrevLabel = OldStyle, NextLabel = OldStyle;
  53. private static readonly int PrevLabelOffsetX = PrevWidth + 1;
  54. private static readonly int PrevLabelOffsetY = 0;
  55. private static readonly int NextLabelOffsetX = -29;
  56. private static readonly int NextLabelOffsetY = 0;
  57. private static readonly int NameWidth = 120; // 107;
  58. private static readonly int ValueWidth = 200; //190; //170;//128;
  59. private static readonly int EntryCount = 20;
  60. private static readonly int TypeWidth = NameWidth + OffsetSize + ValueWidth;
  61. private static readonly int TotalWidth = OffsetSize + NameWidth + OffsetSize + ValueWidth + OffsetSize + SetWidth + OffsetSize;
  62. private static readonly int TotalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (EntryCount + 1));
  63. private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize;
  64. private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize;
  65. public class StackEntry
  66. {
  67. public object m_Object;
  68. public PropertyInfo m_Property;
  69. public bool m_IsList = false;
  70. public StackEntry(object obj, PropertyInfo prop)
  71. {
  72. m_Object = obj;
  73. m_Property = prop;
  74. }
  75. public StackEntry(object obj, PropertyInfo prop, bool isList)
  76. {
  77. m_Object = obj;
  78. m_Property = prop;
  79. m_IsList = isList;
  80. }
  81. }
  82. public APropertiesGump( Mobile mobile, object o ) : base( GumpOffsetX, GumpOffsetY )
  83. {
  84. m_Mobile = mobile;
  85. m_Object = o;
  86. m_List = BuildList();
  87. Initialize( 0 );
  88. }
  89. public APropertiesGump( Mobile mobile, object o, Stack stack, APropertiesGump.StackEntry parent ) : base( GumpOffsetX, GumpOffsetY )
  90. {
  91. m_Mobile = mobile;
  92. m_Object = o;
  93. m_Stack = stack;
  94. m_List = BuildList();
  95. if ( parent != null )
  96. {
  97. if ( m_Stack == null )
  98. m_Stack = new Stack();
  99. m_Stack.Push( parent );
  100. }
  101. Initialize( 0 );
  102. }
  103. public APropertiesGump( Mobile mobile, object o, Stack stack, ArrayList list, int page ) : base( GumpOffsetX, GumpOffsetY )
  104. {
  105. m_Mobile = mobile;
  106. m_Object = o;
  107. m_List = list;
  108. m_Stack = stack;
  109. Initialize( page );
  110. }
  111. private void Initialize( int page )
  112. {
  113. m_Page = page;
  114. int textEntryCounter = 0;
  115. int count = m_List.Count - (page * EntryCount);
  116. if ( count < 0 )
  117. count = 0;
  118. else if ( count > EntryCount )
  119. count = EntryCount;
  120. int lastIndex = (page * EntryCount) + count - 1;
  121. if ( lastIndex >= 0 && lastIndex < m_List.Count && m_List[lastIndex] == null )
  122. --count;
  123. int totalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (count + 1));
  124. AddPage( 0 );
  125. AddBackground( 0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID );
  126. AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), totalHeight, OffsetGumpID );
  127. int x = BorderSize + OffsetSize;
  128. int y = BorderSize + OffsetSize;
  129. int emptyWidth = TotalWidth - PrevWidth - NextWidth - (OffsetSize * 4) - (OldStyle ? SetWidth + OffsetSize : 0);
  130. if ( OldStyle )
  131. AddImageTiled( x, y, TotalWidth - (OffsetSize * 3) - SetWidth, EntryHeight, HeaderGumpID );
  132. else
  133. AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID );
  134. if ( page > 0 )
  135. {
  136. AddButton( x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1, GumpButtonType.Reply, 0 );
  137. if ( PrevLabel )
  138. AddLabel( x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous" );
  139. }
  140. x += PrevWidth + OffsetSize;
  141. if ( !OldStyle )
  142. AddImageTiled( x - (OldStyle ? OffsetSize : 0), y, emptyWidth + (OldStyle ? OffsetSize * 2 : 0), EntryHeight, HeaderGumpID );
  143. x += emptyWidth + OffsetSize;
  144. if ( !OldStyle )
  145. AddImageTiled( x, y, NextWidth, EntryHeight, HeaderGumpID );
  146. if ( (page + 1) * EntryCount < m_List.Count )
  147. {
  148. AddButton( x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 2, GumpButtonType.Reply, 1 );
  149. if ( NextLabel )
  150. AddLabel( x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next" );
  151. }
  152. for ( int i = 0, index = page * EntryCount; i < count && index < m_List.Count; ++i, ++index )
  153. {
  154. x = BorderSize + OffsetSize;
  155. y += EntryHeight + OffsetSize;
  156. object o = m_List[index];
  157. if ( o == null )
  158. {
  159. AddImageTiled( x - OffsetSize, y, TotalWidth, EntryHeight, BackGumpID + 4 );
  160. }
  161. else if (o is ListItemInfo)
  162. {
  163. var prop = (ListItemInfo)o;
  164. var propValue = prop.Object;
  165. var type = propValue.GetType();
  166. Type templateFor = Properties.GetTemplate(type);
  167. bool templateMismatch = CheckTemplateMismatch(templateFor);
  168. AddImageTiled(x, y, NameWidth, EntryHeight, EntryGumpID);
  169. AddLabelCropped(x + TextOffsetX, y, NameWidth - TextOffsetX - 19, EntryHeight, TextHue, type.GetDescriptedName());
  170. x += NameWidth + OffsetSize;
  171. AddImageTiled(x, y, ValueWidth, EntryHeight, EntryGumpID);
  172. if (templateMismatch)
  173. {
  174. AddLabelCropped(x + TextOffsetX, y, ValueWidth - TextOffsetX, EntryHeight, 140, "-impossible-");
  175. AddImageTiled(x + ValueWidth + OffsetSize, y, SetWidth, EntryHeight, SetGumpID);
  176. }
  177. else
  178. {
  179. AddLabelCropped(x + TextOffsetX, y, ValueWidth - TextOffsetX, EntryHeight, TextHue, ValueToString(propValue));
  180. x += ValueWidth + OffsetSize;
  181. if (SetGumpID != 0)
  182. AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID);
  183. AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, i + 3, GumpButtonType.Reply, 0);
  184. }
  185. }
  186. else if (o is CustomGroupInfo)
  187. {
  188. CustomGroupInfo type = (CustomGroupInfo)o;
  189. AddImageTiled(x, y, TypeWidth, EntryHeight, EntryGumpID);
  190. AddLabelCropped(x + TextOffsetX, y, TypeWidth - TextOffsetX, EntryHeight, type.TextHue, type.GroupName);
  191. x += TypeWidth + OffsetSize;
  192. if (SetGumpID != 0)
  193. AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID);
  194. }
  195. else if (o is Type)
  196. {
  197. Type type = (Type)o;
  198. AddImageTiled(x, y, TypeWidth, EntryHeight, EntryGumpID);
  199. AddLabelCropped(x + TextOffsetX, y, TypeWidth - TextOffsetX, EntryHeight, TextHue, type.GetDescriptedName());
  200. x += TypeWidth + OffsetSize;
  201. if (SetGumpID != 0)
  202. AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID);
  203. }
  204. else if (o is PropertyInfo)
  205. {
  206. PropertyInfo prop = (PropertyInfo)o;
  207. Type type = prop.PropertyType;
  208. CPA cpa = Properties.GetCPA(prop);
  209. Type templateFor = Properties.GetTemplate(prop);
  210. bool isTemplate = templateFor != null;
  211. bool noSetIfNull = Properties.GetNSIF(prop);
  212. bool templateMismatch = CheckTemplateMismatch(templateFor);
  213. var propValue = prop.GetValue(m_Object, null);
  214. AddImageTiled(x, y, NameWidth, EntryHeight, EntryGumpID);
  215. AddLabelCropped(x + TextOffsetX, y, NameWidth - TextOffsetX - 19, EntryHeight, TextHue, prop.GetDescriptedName());
  216. x += NameWidth + OffsetSize;
  217. AddImageTiled(x, y, ValueWidth, EntryHeight, EntryGumpID);
  218. if (templateMismatch)
  219. {
  220. AddLabelCropped(x + TextOffsetX, y, ValueWidth - TextOffsetX, EntryHeight, 140, "-impossible-");
  221. }
  222. else if (IsType(type, typeofBool))
  223. {
  224. var value = (bool)prop.GetValue(m_Object, null);
  225. AddLabelCropped(x + TextOffsetX, y, ValueWidth - TextOffsetX, EntryHeight, value ? 175 : 140, value ? "Oui" : "Non");
  226. }
  227. else if (IsType(type, typeofString) && prop.CanWrite && cpa != null && m_Mobile.AccessLevel >= cpa.WriteLevel)
  228. {
  229. var value = prop.GetValue(m_Object, null);
  230. AddTextEntry(x + TextOffsetX, y, ValueWidth - TextOffsetX, EntryHeight, TextHue, textEntryCounter, value == null ? "" : ValueToString(prop));
  231. if (!TextAreas.ContainsKey(index))
  232. TextAreas.Add(index, textEntryCounter);
  233. textEntryCounter++;
  234. }
  235. else
  236. {
  237. AddLabelCropped(x + TextOffsetX, y, ValueWidth - TextOffsetX, EntryHeight, TextHue, ValueToString(prop));
  238. }
  239. x += ValueWidth + OffsetSize;
  240. if (SetGumpID != 0)
  241. AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID);
  242. if (prop.CanWrite && cpa != null && m_Mobile.AccessLevel >= cpa.WriteLevel && !templateMismatch && !(propValue == null && noSetIfNull))
  243. {
  244. if (prop.IsNullable() ||
  245. prop.PropertyType.IsNullable() ||
  246. IsType(prop.PropertyType, typeofMobile) ||
  247. IsType(prop.PropertyType, typeofItem) ||
  248. IsType(prop.PropertyType, typeofString))
  249. {
  250. AddButton(x - ValueWidth - 19, y + SetOffsetY, 4034, 4035, 5000 + i + 3, GumpButtonType.Reply, 0);
  251. }
  252. int actionID1 = 5538;
  253. int actionID2 = 5539;
  254. if (IsType(type, typeof(PropertyAction)) || IsType(type, typeofString))
  255. {
  256. AddButton(x + SetOffsetX - 3, y + SetOffsetY - 2, actionID1, actionID2, i + 3, GumpButtonType.Reply, 0);
  257. }
  258. else if (IsType(type, typeofBool))
  259. {
  260. var value = (bool)prop.GetValue(m_Object, null);
  261. AddButton(x + SetOffsetX - 2, y + SetOffsetY - 2, value ? actionID2 : actionID1, value ? actionID1 : actionID2, i + 3, GumpButtonType.Reply, 0);
  262. }
  263. else
  264. {
  265. AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, i + 3, GumpButtonType.Reply, 0);
  266. }
  267. }
  268. // Type manager links
  269. if (propValue != null)
  270. {
  271. var propValueType = propValue.GetType();
  272. if (m_Mobile.AccessLevel >= AccessLevel.GameMaster &&
  273. (
  274. (IsType(propValueType, typeofItem) && ManagerConfig.Items.ContainsKey(propValueType)) ||
  275. (IsType(propValueType, typeofMobile) && ManagerConfig.Creatures.ContainsKey(propValueType))
  276. ))
  277. {
  278. AddButton(1, y + SetOffsetY + 2, 2435, 2436, 10000 + i + 3, GumpButtonType.Reply, 0);
  279. }
  280. }
  281. }
  282. }
  283. }
  284. private bool CheckTemplateMismatch(Type templateFor)
  285. {
  286. bool isTemplate = templateFor != null;
  287. bool templateMismatch = false;
  288. if (!isTemplate) return false;
  289. if (isTemplate && IsType(m_Object.GetType(), typeof(GameItemType)))
  290. {
  291. var itemType = (m_Object as GameItemType);
  292. templateMismatch = !IsType(itemType.Type, templateFor);
  293. }
  294. else if (isTemplate && IsType(m_Object.GetType(), typeof(CreatureType)))
  295. {
  296. var mobileType = (m_Object as CreatureType);
  297. templateMismatch = !IsType(mobileType.Type, templateFor);
  298. }
  299. return templateMismatch;
  300. }
  301. private Dictionary<int, int> TextAreas = new Dictionary<int, int>();
  302. public static string[] m_BoolNames = new string[]{ "Vrai", "Faux" };
  303. public static object[] m_BoolValues = new object[]{ true, false };
  304. public static string[] m_PoisonNames = new string[]{ "None", "Lesser", "Regular", "Greater", "Deadly", "Lethal" };
  305. public static object[] m_PoisonValues = new object[]{ null, Poison.Lesser, Poison.Regular, Poison.Greater, Poison.Deadly, Poison.Lethal };
  306. public override void OnResponse( NetState state, RelayInfo info )
  307. {
  308. Mobile from = state.Mobile;
  309. if ( !Server.GenericCommands.BaseCommand.IsAccessible( from, m_Object ) )
  310. {
  311. from.SendMessage( "You may no longer access their properties." );
  312. return;
  313. }
  314. switch ( info.ButtonID )
  315. {
  316. case 0: // Closed
  317. {
  318. if ( m_Stack != null && m_Stack.Count > 0 )
  319. {
  320. APropertiesGump.StackEntry entry = (APropertiesGump.StackEntry)m_Stack.Pop();
  321. var entryType = entry.m_Object.GetType();
  322. if (entryType == typeof(LootPacksList) || entryType == typeof(TradesList) || entryType == typeof(CraftSystemsList))
  323. return;
  324. if(!entry.m_IsList)
  325. from.SendGump(new APropertiesGump(from, entry.m_Object, m_Stack, null));
  326. }
  327. break;
  328. }
  329. case 1: // Previous
  330. {
  331. if ( m_Page > 0 )
  332. from.SendGump( new APropertiesGump( from, m_Object, m_Stack, m_List, m_Page - 1 ) );
  333. break;
  334. }
  335. case 2: // Next
  336. {
  337. if ( (m_Page + 1) * EntryCount < m_List.Count )
  338. from.SendGump( new APropertiesGump( from, m_Object, m_Stack, m_List, m_Page + 1 ) );
  339. break;
  340. }
  341. default:
  342. {
  343. int index = (m_Page * EntryCount) + (info.ButtonID - 3);
  344. if(index >= 10000)
  345. {
  346. // Type links
  347. index -= 10000;
  348. var prop = m_List[index] as PropertyInfo;
  349. //from.SendGump(new APropertiesGump(from, m_Object, m_Stack, m_List, m_Page));
  350. var value = prop.GetValue(m_Object, null);
  351. if (value != null)
  352. {
  353. var type = value.GetType();
  354. if (IsType(type, typeofItem) && ManagerConfig.Items.ContainsKey(type))
  355. {
  356. from.SendGump(new APropertiesGump(from, ManagerConfig.Items[type], m_Stack, new StackEntry(m_Object, prop)));
  357. }
  358. else if (IsType(type, typeofMobile) && ManagerConfig.Creatures.ContainsKey(type))
  359. {
  360. from.SendGump(new APropertiesGump(from, ManagerConfig.Creatures[type], m_Stack, new StackEntry(m_Object, prop)));
  361. }
  362. }
  363. }
  364. else if (index >= 5000)
  365. {
  366. // Nullable
  367. index -= 5000;
  368. var prop = m_List[index] as PropertyInfo;
  369. try
  370. {
  371. prop.SetValue(m_Object, null, null);
  372. APropertiesGump.OnValueChanged(m_Object, prop, m_Stack, -1);
  373. }
  374. catch { }
  375. from.SendGump(new APropertiesGump(from, m_Object, m_Stack, m_List, m_Page));
  376. }
  377. else if (index >= 0 && index < m_List.Count)
  378. {
  379. if (m_List[index] is ListItemInfo)
  380. {
  381. var prop = m_List[index] as ListItemInfo;
  382. if (prop == null)
  383. return;
  384. from.SendGump(new APropertiesGump(from, prop.Object, m_Stack, new StackEntry(m_Object, prop.List) ));
  385. }
  386. else
  387. {
  388. var prop = m_List[index] as PropertyInfo;
  389. if (prop == null)
  390. return;
  391. CPA attr = Properties.GetCPA(prop);
  392. if (!prop.CanWrite || attr == null || from.AccessLevel < attr.WriteLevel)
  393. return;
  394. Type type = prop.PropertyType;
  395. if (IsType(type, typeofMobile) || IsType(type, typeofItem))
  396. from.SendGump(new ASetObjectGump(prop, from, m_Object, m_Stack, type, m_Page, m_List, -1));
  397. else if (IsType(type, typeofBool))
  398. {
  399. try
  400. {
  401. prop.SetValue(m_Object, !((bool)prop.GetValue(m_Object, null)), null);
  402. from.SendGump(new APropertiesGump(from, m_Object, m_Stack, m_List, m_Page));
  403. APropertiesGump.OnValueChanged(m_Object, prop, m_Stack, -1);
  404. }
  405. catch { }
  406. }
  407. else if (IsType(type, typeofString))
  408. {
  409. if (TextAreas.ContainsKey(index))
  410. {
  411. var entry = info.GetTextEntry(TextAreas[index]);
  412. prop.SetValue(m_Object, entry.Text, null);
  413. APropertiesGump.OnValueChanged(m_Object, prop, m_Stack, -1);
  414. }
  415. from.SendGump(new APropertiesGump(from, m_Object, m_Stack, m_List, m_Page));
  416. }
  417. else if (IsType(type, typeof(PropertyAction)))
  418. {
  419. // Is a action-type property
  420. from.SendGump(new APropertiesGump(from, m_Object, m_Stack, m_List, m_Page));
  421. var action = new PropertyAction(from);
  422. prop.SetValue(m_Object, action, null);
  423. APropertiesGump.OnValueChanged(m_Object, prop, m_Stack, -1);
  424. }
  425. else if (IsType(type, typeofType))
  426. {
  427. // New via unified search
  428. //from.SendGump(new APropertiesGump(from, m_Object, m_Stack, m_List, m_Page));
  429. from.SendGump(new CategorizedAddGump(from, prop, m_Object, m_Stack, m_List, m_Page));
  430. // Original: from object target
  431. // from.Target = new ASetObjectTarget(prop, from, m_Object, m_Stack, type, m_Page, m_List, -1);
  432. }
  433. else if (IsType(type, typeof(WeakChoice<>)) || type.GetInterfaces().Contains(typeof(IWeakChoice)))
  434. {
  435. var choice = prop.GetValue(m_Object, null) as IWeakChoice;
  436. if (choice != null)
  437. {
  438. var list = choice.GetChoiceList(m_Object);
  439. var values = list.Select(item => item.First).ToArray();
  440. var names = list.Select(item => item.Second).ToArray();
  441. from.SendGump(new ASetListOptionGump(prop, from, m_Object, m_Stack, m_Page, m_List, names, values, -1));
  442. }
  443. }
  444. else if (IsType(type, typeofPoint3D))
  445. from.SendGump(new ASetPoint3DGump(prop, from, m_Object, m_Stack, m_Page, m_List, -1));
  446. else if (IsType(type, typeofPoint2D))
  447. from.SendGump(new ASetPoint2DGump(prop, from, m_Object, m_Stack, m_Page, m_List, -1));
  448. else if (IsType(type, typeofTimeSpan))
  449. from.SendGump(new ASetTimeSpanGump(prop, from, m_Object, m_Stack, m_Page, m_List, -1));
  450. else if (IsType(type, typeofDateTime))
  451. from.SendGump(new ASetDateTimeGump(prop, from, m_Object, m_Stack, m_Page, m_List, -1));
  452. else if (IsCustomEnum(type))
  453. from.SendGump(new ASetCustomEnumGump(prop, from, m_Object, m_Stack, m_Page, m_List, GetCustomEnumNames(type), -1));
  454. else if (IsType(type, typeofEnum))
  455. from.SendGump(new ASetListOptionGump(prop, from, m_Object, m_Stack, m_Page, m_List, Enum.GetNames(type), GetObjects(Enum.GetValues(type)), -1));
  456. else if (IsType(type, typeofBool))
  457. from.SendGump(new ASetListOptionGump(prop, from, m_Object, m_Stack, m_Page, m_List, m_BoolNames, m_BoolValues, -1));
  458. else if (IsType(type, typeofString) || IsType(type, typeofReal) || IsType(type, typeofNumeric))
  459. from.SendGump(new ASetGump(prop, from, m_Object, m_Stack, m_Page, m_List, -1));
  460. else if (IsType(type, typeofPoison))
  461. from.SendGump(new ASetListOptionGump(prop, from, m_Object, m_Stack, m_Page, m_List, m_PoisonNames, m_PoisonValues, -1));
  462. else if (IsType(type, typeofMap))
  463. from.SendGump(new ASetListOptionGump(prop, from, m_Object, m_Stack, m_Page, m_List, Map.GetMapNames(), Map.GetMapValues(), -1));
  464. else if (IsType(type, typeof(List<TradeInfo>)))
  465. from.SendGump(new ASetListGump<TradeInfo>(prop, from, m_Object, m_Stack, m_Page, m_List));
  466. else if (IsType(type, typeof(List<GameCraftCategory>)))
  467. from.SendGump(new ASetListGump<GameCraftCategory>(prop, from, m_Object, m_Stack, m_Page, m_List));
  468. else if (IsType(type, typeof(List<GameLootItem>)))
  469. from.SendGump(new ASetListGump<GameLootItem>(prop, from, m_Object, m_Stack, m_Page, m_List));
  470. else if (IsType(type, typeof(List<GameLootPack>)))
  471. from.SendGump(new ASetListGump<GameLootPack>(prop, from, m_Object, m_Stack, m_Page, m_List));
  472. else if (IsArrayListOf(m_Object, typeof(Mobile)))
  473. from.SendGump(new ASetListGump<Mobile>(prop, from, m_Object, m_Stack, m_Page, m_List));
  474. else if (IsType(type, typeof(List<Mobile>)))
  475. from.SendGump(new ASetListGump<Mobile>(prop, from, m_Object, m_Stack, m_Page, m_List));
  476. else if (IsType(type, typeof(List<Item>)))
  477. from.SendGump(new ASetListGump<Item>(prop, from, m_Object, m_Stack, m_Page, m_List));
  478. else if (IsType(type, typeof(List<Single>)))
  479. from.SendGump(new ASetListGump<Single>(prop, from, m_Object, m_Stack, m_Page, m_List));
  480. else if (IsType(type, typeof(List<Double>)))
  481. from.SendGump(new ASetListGump<Double>(prop, from, m_Object, m_Stack, m_Page, m_List));
  482. else if (IsType(type, typeof(List<Byte>)))
  483. from.SendGump(new ASetListGump<Byte>(prop, from, m_Object, m_Stack, m_Page, m_List));
  484. else if (IsType(type, typeof(List<Int16>)))
  485. from.SendGump(new ASetListGump<Int16>(prop, from, m_Object, m_Stack, m_Page, m_List));
  486. else if (IsType(type, typeof(List<Int32>)))
  487. from.SendGump(new ASetListGump<Int32>(prop, from, m_Object, m_Stack, m_Page, m_List));
  488. else if (IsType(type, typeof(List<Int64>)))
  489. from.SendGump(new ASetListGump<Int64>(prop, from, m_Object, m_Stack, m_Page, m_List));
  490. else if (IsType(type, typeof(List<SByte>)))
  491. from.SendGump(new ASetListGump<SByte>(prop, from, m_Object, m_Stack, m_Page, m_List));
  492. else if (IsType(type, typeof(List<String>)))
  493. from.SendGump(new ASetListGump<String>(prop, from, m_Object, m_Stack, m_Page, m_List));
  494. else if (IsType(type, typeof(List<Boolean>)))
  495. from.SendGump(new ASetListGump<Boolean>(prop, from, m_Object, m_Stack, m_Page, m_List));
  496. else if (IsType(type, typeof(List<Type>)))
  497. from.SendGump(new ASetListGump<Type>(prop, from, m_Object, m_Stack, m_Page, m_List));
  498. else if (IsType(type, typeof(List<TimeSpan>)))
  499. from.SendGump(new ASetListGump<TimeSpan>(prop, from, m_Object, m_Stack, m_Page, m_List));
  500. else if (IsType(type, typeof(List<DateTime>)))
  501. from.SendGump(new ASetListGump<DateTime>(prop, from, m_Object, m_Stack, m_Page, m_List));
  502. else if (IsType(type, typeof(List<Point3D>)))
  503. from.SendGump(new ASetListGump<Point3D>(prop, from, m_Object, m_Stack, m_Page, m_List));
  504. else if (IsType(type, typeof(List<Point2D>)))
  505. from.SendGump(new ASetListGump<Point2D>(prop, from, m_Object, m_Stack, m_Page, m_List));
  506. else if (IsType(type, typeof(List<GuildType>)))
  507. from.SendGump(new ASetListGump<GuildType>(prop, from, m_Object, m_Stack, m_Page, m_List));
  508. else if (IsType(type, typeof(List<Enum>)))
  509. from.SendGump(new ASetListGump<Enum>(prop, from, m_Object, m_Stack, m_Page, m_List));
  510. else if (IsType(type, typeof(List<Poison>)))
  511. from.SendGump(new ASetListGump<Poison>(prop, from, m_Object, m_Stack, m_Page, m_List));
  512. else if (IsType(type, typeof(List<Map>)))
  513. from.SendGump(new ASetListGump<Map>(prop, from, m_Object, m_Stack, m_Page, m_List));
  514. else if (IsType(type, typeofSkills) && m_Object is Mobile)
  515. {
  516. from.SendGump(new APropertiesGump(from, m_Object, m_Stack, m_List, m_Page));
  517. from.SendGump(new SkillsGump(from, (Mobile)m_Object));
  518. }
  519. else if (HasAttribute(type, typeofPropertyObject, true))
  520. {
  521. object o = prop.GetValue(m_Object, null);
  522. if (o != null)
  523. from.SendGump(new APropertiesGump(from, o, m_Stack, new APropertiesGump.StackEntry(m_Object, prop)));
  524. }
  525. }
  526. }
  527. break;
  528. }
  529. }
  530. }
  531. public static object[] GetObjects( Array a )
  532. {
  533. object[] list = new object[a.Length];
  534. for ( int i = 0; i < list.Length; ++i )
  535. list[i] = a.GetValue( i );
  536. return list;
  537. }
  538. public static bool IsCustomEnum( Type type )
  539. {
  540. return type.IsDefined( typeofCustomEnum, false );
  541. }
  542. public static void OnValueChanged( object obj, PropertyInfo prop, Stack stack, int index )
  543. {
  544. if ( stack == null || stack.Count == 0 )
  545. return;
  546. if ( !prop.PropertyType.IsValueType )
  547. return;
  548. APropertiesGump.StackEntry peek = (APropertiesGump.StackEntry)stack.Peek();
  549. if (peek.m_Property.CanWrite)
  550. {
  551. if (index >= 0)
  552. {
  553. object[] indexes = new object[] { index };
  554. peek.m_Property.SetValue(peek.m_Object, obj, indexes);
  555. }
  556. else peek.m_Property.SetValue(peek.m_Object, obj, null);
  557. }
  558. }
  559. public static string[] GetCustomEnumNames( Type type )
  560. {
  561. object[] attrs = type.GetCustomAttributes( typeofCustomEnum, false );
  562. if ( attrs.Length == 0 )
  563. return new string[0];
  564. CustomEnumAttribute ce = attrs[0] as CustomEnumAttribute;
  565. if ( ce == null )
  566. return new string[0];
  567. return ce.Names;
  568. }
  569. public static bool HasAttribute( Type type, Type check, bool inherit )
  570. {
  571. object[] objs = type.GetCustomAttributes( check, inherit );
  572. return ( objs != null && objs.Length > 0 );
  573. }
  574. private static bool IsArrayListOf(object obj, Type check)
  575. {
  576. if (obj != null && obj is ArrayList && (obj as ArrayList).Count > 0)
  577. {
  578. return IsType((obj as ArrayList)[0].GetType(), check);
  579. }
  580. return false;
  581. }
  582. private static bool IsType( Type type, Type check )
  583. {
  584. return type == check || type.IsSubclassOf( check );
  585. }
  586. private static bool IsType( Type type, Type[] check )
  587. {
  588. for ( int i = 0; i < check.Length; ++i )
  589. if ( IsType( type, check[i] ) )
  590. return true;
  591. return false;
  592. }
  593. private static Type typeofMobile = typeof( Mobile );
  594. private static Type typeofItem = typeof( Item );
  595. private static Type typeofType = typeof( Type );
  596. private static Type typeofPoint3D = typeof( Point3D );
  597. private static Type typeofPoint2D = typeof( Point2D );
  598. private static Type typeofTimeSpan = typeof( TimeSpan );
  599. private static Type typeofDateTime = typeof(DateTime);
  600. private static Type typeofCustomEnum = typeof(CustomEnumAttribute);
  601. private static Type typeofEnum = typeof( Enum );
  602. private static Type typeofBool = typeof( Boolean );
  603. private static Type typeofString = typeof( String );
  604. private static Type typeofPoison = typeof( Poison );
  605. private static Type typeofMap = typeof( Map );
  606. private static Type typeofSkills = typeof( Skills );
  607. private static Type typeofPropertyObject = typeof( PropertyObjectAttribute );
  608. private static Type typeofNoSort = typeof( NoSortAttribute );
  609. private static Type[] typeofReal = new Type[]
  610. {
  611. typeof( Single ),
  612. typeof( Double )
  613. };
  614. private static Type[] typeofNumeric = new Type[]
  615. {
  616. typeof( Byte ),
  617. typeof( Int16 ),
  618. typeof( Int32 ),
  619. typeof( Int64 ),
  620. typeof( SByte ),
  621. typeof( UInt16 ),
  622. typeof( UInt32 ),
  623. typeof( UInt64 )
  624. };
  625. private string ValueToString( PropertyInfo prop )
  626. {
  627. return ValueToString( m_Object, prop );
  628. }
  629. public static string ValueToString( object obj, PropertyInfo prop )
  630. {
  631. try
  632. {
  633. return ValueToString( prop.GetValue( obj, null ) );
  634. }
  635. catch ( Exception e )
  636. {
  637. return String.Format( "!{0}!", e.GetType() );
  638. }
  639. }
  640. public static string ValueToString( object o )
  641. {
  642. if ( o == null )
  643. {
  644. return "-null-";
  645. }
  646. else if ( o is string )
  647. {
  648. return (string)o;
  649. //return String.Format( "\"{0}\"", (string)o );
  650. }
  651. else if ( o is bool )
  652. {
  653. return o.ToString();
  654. }
  655. else if ( o is char )
  656. {
  657. return String.Format( "0x{0:X} '{1}'", (int)(char)o, (char)o );
  658. }
  659. else if ( o is Serial )
  660. {
  661. Serial s = (Serial)o;
  662. if ( s.IsValid )
  663. {
  664. if ( s.IsItem )
  665. {
  666. return String.Format( "(I) 0x{0:X}", s.Value );
  667. }
  668. else if ( s.IsMobile )
  669. {
  670. return String.Format( "(M) 0x{0:X}", s.Value );
  671. }
  672. }
  673. return String.Format( "(?) 0x{0:X}", s.Value );
  674. }
  675. else if ( o is byte || o is sbyte || o is short || o is ushort || o is int || o is uint || o is long || o is ulong )
  676. {
  677. return String.Format( "{0} (0x{0:X})", o );
  678. }
  679. else if ( o is Mobile )
  680. {
  681. return String.Format( "(M) 0x{0:X} \"{1}\"", ((Mobile)o).Serial.Value, ((Mobile)o).Name );
  682. }
  683. else if ( o is Item )
  684. {
  685. return String.Format( "(I) 0x{0:X}", ((Item)o).Serial.Value );
  686. }
  687. else if ( o is Type )
  688. {
  689. return ((Type)o).Name;
  690. }
  691. else
  692. {
  693. return o.ToString();
  694. }
  695. }
  696. private ArrayList BuildList()
  697. {
  698. Type type = m_Object.GetType();
  699. PropertyInfo[] props = type.GetProperties( BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public );
  700. ArrayList groups = GetGroups( type, props );
  701. ArrayList list = new ArrayList();
  702. for ( int i = 0; i < groups.Count; ++i )
  703. {
  704. DictionaryEntry de = (DictionaryEntry)groups[i];
  705. ArrayList groupList = (ArrayList)de.Value;
  706. if (de.Key is Type && !HasAttribute( (Type)de.Key, typeofNoSort, false ) )
  707. groupList.Sort( PropertySorter.Instance );
  708. if ( i != 0 )
  709. list.Add( null );
  710. list.Add( de.Key );
  711. list.AddRange( groupList );
  712. }
  713. return list;
  714. }
  715. private class ListItemInfo
  716. {
  717. public ListItemInfo(PropertyInfo list, object obj)
  718. {
  719. List = list;
  720. Object = obj;
  721. }
  722. public PropertyInfo List { get; set; }
  723. public object Object { get; set; }
  724. }
  725. private class CustomGroupInfo
  726. {
  727. public CustomGroupInfo(string label, int hue)
  728. {
  729. GroupName = label;
  730. TextHue = hue;
  731. }
  732. public string GroupName { get; set; }
  733. public int TextHue { get; set; }
  734. }
  735. private static Type typeofObject = typeof(object);
  736. private ArrayList GetGroups( Type objectType, PropertyInfo[] props )
  737. {
  738. Hashtable groups = new Hashtable();
  739. bool isNoSort = objectType.GetCustomAttributes(typeof(NoSortAttribute),false).Length != 0;
  740. CustomGroupInfo cgi = null;
  741. for ( int i = 0; i < props.Length; ++i )
  742. {
  743. PropertyInfo prop = props[i];
  744. if ( prop.CanRead )
  745. {
  746. var attr = Properties.GetCPA( prop );
  747. var type = prop.DeclaringType;
  748. var list = cgi != null ? (ArrayList)groups[cgi] : (ArrayList)groups[type];
  749. if (Properties.IsObjectPropertyList(prop))
  750. {
  751. var listValue = prop.GetValue(m_Object, null);
  752. if (listValue is List<IItemTemplate>)
  753. {
  754. var l = listValue as List<IItemTemplate>;
  755. foreach (var item in l)
  756. list.Add(new ListItemInfo(prop, item));
  757. }
  758. }
  759. else if ( attr != null && m_Mobile.AccessLevel >= attr.ReadLevel )
  760. {
  761. while ( true )
  762. {
  763. Type baseType = type.BaseType;
  764. if ( baseType == null || baseType == typeofObject )
  765. break;
  766. if ( baseType.GetProperty( prop.Name, prop.PropertyType ) != null )
  767. type = baseType;
  768. else
  769. break;
  770. }
  771. if (isNoSort)
  772. {
  773. var sg = Properties.GetStartGroup(prop);
  774. if (sg != null)
  775. {
  776. cgi = new CustomGroupInfo(sg.GroupName, sg.TextHue);
  777. groups[cgi] = list = new ArrayList();
  778. }
  779. else
  780. {
  781. if (list == null)
  782. groups[type] = list = new ArrayList();
  783. }
  784. }
  785. else
  786. {
  787. if (list == null)
  788. groups[type] = list = new ArrayList();
  789. }
  790. list.Add(prop);
  791. }
  792. }
  793. }
  794. ArrayList sorted = new ArrayList( groups );
  795. sorted.Sort(new GroupComparer(objectType));
  796. return sorted;
  797. }
  798. public static object GetObjectFromString( Type t, string s )
  799. {
  800. if ( t == typeof( string ) )
  801. {
  802. return s;
  803. }
  804. else if ( t == typeof( byte ) || t == typeof( sbyte ) || t == typeof( short ) || t == typeof( ushort ) || t == typeof( int ) || t == typeof( uint ) || t == typeof( long ) || t == typeof( ulong ) )
  805. {
  806. if ( s.StartsWith( "0x" ) )
  807. {
  808. if ( t == typeof( ulong ) || t == typeof( uint ) || t == typeof( ushort ) || t == typeof( byte ) )
  809. {
  810. return Convert.ChangeType( Convert.ToUInt64( s.Substring( 2 ), 16 ), t );
  811. }
  812. else
  813. {
  814. return Convert.ChangeType( Convert.ToInt64( s.Substring( 2 ), 16 ), t );
  815. }
  816. }
  817. else
  818. {
  819. return Convert.ChangeType( s, t );
  820. }
  821. }
  822. else if ( t == typeof( double ) || t == typeof( float ) )
  823. {
  824. return Convert.ChangeType( s, t );
  825. }
  826. else if ( t.IsDefined( typeof( ParsableAttribute ), false ) )
  827. {
  828. MethodInfo parseMethod = t.GetMethod( "Parse", new Type[]{ typeof( string ) } );
  829. return parseMethod.Invoke( null, new object[]{ s } );
  830. }
  831. throw new Exception( "bad" );
  832. }
  833. private static string GetStringFromObject( object o )
  834. {
  835. if ( o == null )
  836. {
  837. return "-null-";
  838. }
  839. else if ( o is string )
  840. {
  841. return String.Format( "\"{0}\"", (string)o );
  842. }
  843. else if ( o is bool )
  844. {
  845. return o.ToString();
  846. }
  847. else if ( o is char )
  848. {
  849. return String.Format( "0x{0:X} '{1}'", (int)(char)o, (char)o );
  850. }
  851. else if ( o is Serial )
  852. {
  853. Serial s = (Serial)o;
  854. if ( s.IsValid )
  855. {
  856. if ( s.IsItem )
  857. {
  858. return String.Format( "(I) 0x{0:X}", s.Value );
  859. }
  860. else if ( s.IsMobile )
  861. {
  862. return String.Format( "(M) 0x{0:X}", s.Value );
  863. }
  864. }
  865. return String.Format( "(?) 0x{0:X}", s.Value );
  866. }
  867. else if ( o is byte || o is sbyte || o is short || o is ushort || o is int || o is uint || o is long || o is ulong )
  868. {
  869. return String.Format( "{0} (0x{0:X})", o );
  870. }
  871. else if ( o is Mobile )
  872. {
  873. return String.Format( "(M) 0x{0:X} \"{1}\"", ((Mobile)o).Serial.Value, ((Mobile)o).Name );
  874. }
  875. else if ( o is Item )
  876. {
  877. return String.Format( "(I) 0x{0:X}", ((Item)o).Serial.Value );
  878. }
  879. else if ( o is Type )
  880. {
  881. return ((Type)o).Name;
  882. }
  883. else
  884. {
  885. return o.ToString();
  886. }
  887. }
  888. private class PropertySorter : IComparer
  889. {
  890. public static readonly PropertySorter Instance = new PropertySorter();
  891. private PropertySorter()
  892. {
  893. }
  894. public int Compare( object x, object y )
  895. {
  896. if ( x == null && y == null )
  897. return 0;
  898. else if ( x == null )
  899. return -1;
  900. else if ( y == null )
  901. return 1;
  902. PropertyInfo a = x as PropertyInfo;
  903. PropertyInfo b = y as PropertyInfo;
  904. if ( a == null || b == null )
  905. throw new ArgumentException();
  906. return a.Name.CompareTo( b.Name );
  907. }
  908. }
  909. private class GroupComparer : IComparer
  910. {
  911. private Type m_Start;
  912. public GroupComparer( Type start )
  913. {
  914. m_Start = start;
  915. }
  916. private static Type typeofObject = typeof( Object );
  917. private int GetDistance( Type type )
  918. {
  919. Type current = m_Start;
  920. int dist;
  921. for ( dist = 0; current != null && current != typeofObject && current != type; ++dist )
  922. current = current.BaseType;
  923. return dist;
  924. }
  925. public int Compare( object x, object y )
  926. {
  927. if ( x == null && y == null )
  928. return 0;
  929. else if ( x == null )
  930. return -1;
  931. else if ( y == null )
  932. return 1;
  933. if ( !(x is DictionaryEntry) || !(y is DictionaryEntry) )
  934. throw new ArgumentException();
  935. DictionaryEntry de1 = (DictionaryEntry)x;
  936. DictionaryEntry de2 = (DictionaryEntry)y;
  937. if (de2.Key is CustomGroupInfo && de1.Key is CustomGroupInfo)
  938. return 0;
  939. if (de1.Key is CustomGroupInfo && de2.Key is Type)
  940. return 1;
  941. if (de2.Key is CustomGroupInfo && de1.Key is Type)
  942. return -1;
  943. Type a = (Type)de1.Key;
  944. Type b = (Type)de2.Key;
  945. return GetDistance( a ).CompareTo( GetDistance( b ) );
  946. }
  947. }
  948. }
  949. }